RGB源数据操作:图片顺时针180°镜像、顺时针180°旋转

简介: RGB源数据操作:图片顺时针180°镜像、顺时针180°旋转

一、BMP图片顺时针180°镜像

1.1 原图片

image.png

1.2 编译运行过程

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ls
1.bmp  1.c  2.c  666.bmp  888.bmp  a.out  app.c  test.c
[wbyq@wbyq linux_c]$ ./a.out 
传入的参数格式: ./a.out <原图片的名称> <新图片的名称>
[wbyq@wbyq linux_c]$ ./a.out 888.bmp 2.bmp
原图片头读取14字节.
原图片类型:BM.
原文件大小:3529754.
原文件的数据偏移量:54.
原图片参数结构读取40字节.
原图片宽:1566
原图片高:751
原图片像素位:24
新图片头成功写入:14 字节.
新图片的参数结构成功写入:40 字节.

1.3 镜像的效果

image.png

1.4 源代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma pack(1) //强制1个字节对齐
//BMP的文件头
struct _BMP_HEAD
{
    char type[2]; //图片的类型 "BM"
    unsigned int size; //文件大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //数据偏移字节(真实像素点数据)
};
//BMP的参数信息
struct _BMP_INFO
{
    unsigned int size; //当前结构体大小
    unsigned int w; //宽度
    unsigned int h; //高度
    unsigned short flag; //固定为1
    unsigned short bit; //像素点的位数
    unsigned int r1; //压缩方式  0
    unsigned int r2; //水平分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //关键色彩
};
int main(int argc,char **argv)
{
    int cnt;
    if(argc!=3)
    {
        printf("传入的参数格式: ./a.out <原图片的名称> <新图片的名称>\n");
        return 0;
    }
    /*1. 打开原图片*/
    FILE *src_fp=fopen(argv[1],"rb");
    if(src_fp==NULL)
    {
        printf("%s 图片打开失败.\n",argv[1]);
        return 0;
    }
    /*2. 读取图片的头信息*/
    struct _BMP_HEAD src_bmp_head;
    cnt=fread(&src_bmp_head,1,sizeof(struct _BMP_HEAD),src_fp);
    printf("原图片头读取%d字节.\n",cnt);
    printf("原图片类型:%c%c.\n",src_bmp_head.type[0],src_bmp_head.type[1]);
    printf("原文件大小:%d.\n",src_bmp_head.size);
    printf("原文件的数据偏移量:%d.\n",src_bmp_head.seek);
    /*3. 读取图片的参数信息*/
    struct _BMP_INFO src_bmp_info;
    cnt=fread(&src_bmp_info,1,sizeof(struct _BMP_INFO),src_fp);
    printf("原图片参数结构读取%d字节.\n",cnt);
    printf("原图片宽:%d\n",src_bmp_info.w);
    printf("原图片高:%d\n",src_bmp_info.h);
    printf("原图片像素位:%d\n",src_bmp_info.bit);
    /*4. 创建一张新的BMP图片*/
    FILE *new_fp=fopen(argv[2],"wb");
    if(new_fp==NULL)
    {
        printf("%s 文件创建失败.\n",argv[2]);
        return 0;
    }
    /*5. 创建BMP的文件头*/
    struct _BMP_HEAD new_bmp_head;
    memset(&new_bmp_head,0,sizeof(struct _BMP_HEAD));
    //图片的类型
    new_bmp_head.type[0]='B';
    new_bmp_head.type[1]='M';
    //文件大小
    new_bmp_head.size=54+src_bmp_info.w*src_bmp_info.h*3;
    //数据偏移量
    new_bmp_head.seek=54;
    //写文件头
    cnt=fwrite(&new_bmp_head,1,sizeof(struct _BMP_HEAD),new_fp);
    printf("新图片头成功写入:%d 字节.\n",cnt);
    /*6. 写文件参数信息*/
    struct _BMP_INFO new_bmp_info;
    memset(&new_bmp_info,0,sizeof(struct _BMP_INFO));
    //当前结构体大小
    new_bmp_info.size=sizeof(struct _BMP_INFO);
    //图片的宽度和高度
    new_bmp_info.w=src_bmp_info.w;
    new_bmp_info.h=src_bmp_info.h;
    //图片的颜色位数
    new_bmp_info.bit=24;
    //标志位
    new_bmp_info.flag=1;
    //写入文件参数信息
    cnt=fwrite(&new_bmp_info,1,sizeof(struct _BMP_INFO),new_fp);
    printf("新图片的参数结构成功写入:%d 字节.\n",cnt);
    /*7. 写入位图数据*/
    int w,h;
    int one_line_byte=src_bmp_info.w*3;  //一行的字节数
    while(one_line_byte%4!=0)one_line_byte++;  //补齐4的倍数
    char *one_line_data=malloc(one_line_byte);
    for(h=src_bmp_info.h-1;h>=0;h--)
    {
        //从头开始偏移
        fseek(src_fp,one_line_byte*h+54,SEEK_SET);
        fread(one_line_data,1,one_line_byte,src_fp); //读取图片数据
        fwrite(one_line_data,1,one_line_byte,new_fp); //写数据
    }
    /*8. 关闭文件*/
    fclose(new_fp);
    fclose(src_fp);
    free(one_line_data);
    return 0;
}

二、BMP图片顺时针180°翻转

2.1 原图片

image.png

2.2 编译运行过程  

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ./a.out 666.bmp 1.bmp
原图片头读取14字节.
原图片类型:BM.
原文件大小:919254.
原文件的数据偏移量:54.
原图片参数结构读取40字节.
原图片宽:800
原图片高:383
原图片像素位:24
新图片头成功写入:14 字节.
新图片的参数结构成功写入:40 字节.
需要补齐:0字节.
[wbyq@wbyq linux_c]$ eog 1.bmp 

2.3 翻转后的效果

image.png

2.6 代码--支持任意尺寸图片

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma pack(1) //强制1个字节对齐
//BMP的文件头
struct _BMP_HEAD
{
    char type[2]; //图片的类型 "BM"
    unsigned int size; //文件大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //数据偏移字节(真实像素点数据)
};
//BMP的参数信息
struct _BMP_INFO
{
    unsigned int size; //当前结构体大小
    unsigned int w; //宽度
    unsigned int h; //高度
    unsigned short flag; //固定为1
    unsigned short bit; //像素点的位数
    unsigned int r1; //压缩方式  0
    unsigned int r2; //水平分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //关键色彩
};
int main(int argc,char **argv)
{
    int cnt;
    if(argc!=3)
    {
        printf("传入的参数格式: ./a.out <原图片的名称> <新图片的名称>\n");
        return 0;
    }
    /*1. 打开原图片*/
    FILE *src_fp=fopen(argv[1],"rb");
    if(src_fp==NULL)
    {
        printf("%s 图片打开失败.\n",argv[1]);
        return 0;
    }
    /*2. 读取图片的头信息*/
    struct _BMP_HEAD src_bmp_head;
    cnt=fread(&src_bmp_head,1,sizeof(struct _BMP_HEAD),src_fp);
    printf("原图片头读取%d字节.\n",cnt);
    printf("原图片类型:%c%c.\n",src_bmp_head.type[0],src_bmp_head.type[1]);
    printf("原文件大小:%d.\n",src_bmp_head.size);
    printf("原文件的数据偏移量:%d.\n",src_bmp_head.seek);
    /*3. 读取图片的参数信息*/
    struct _BMP_INFO src_bmp_info;
    cnt=fread(&src_bmp_info,1,sizeof(struct _BMP_INFO),src_fp);
    printf("原图片参数结构读取%d字节.\n",cnt);
    printf("原图片宽:%d\n",src_bmp_info.w);
    printf("原图片高:%d\n",src_bmp_info.h);
    printf("原图片像素位:%d\n",src_bmp_info.bit);
    /*4. 创建一张新的BMP图片*/
    FILE *new_fp=fopen(argv[2],"wb");
    if(new_fp==NULL)
    {
        printf("%s 文件创建失败.\n",argv[2]);
        return 0;
    }
    /*5. 创建BMP的文件头*/
    struct _BMP_HEAD new_bmp_head;
    memset(&new_bmp_head,0,sizeof(struct _BMP_HEAD));
    //图片的类型
    new_bmp_head.type[0]='B';
    new_bmp_head.type[1]='M';
    //文件大小
    new_bmp_head.size=54+src_bmp_info.w*src_bmp_info.h*3;
    //数据偏移量
    new_bmp_head.seek=54;
    //写文件头
    cnt=fwrite(&new_bmp_head,1,sizeof(struct _BMP_HEAD),new_fp);
    printf("新图片头成功写入:%d 字节.\n",cnt);
    /*6. 写文件参数信息*/
    struct _BMP_INFO new_bmp_info;
    memset(&new_bmp_info,0,sizeof(struct _BMP_INFO));
    //当前结构体大小
    new_bmp_info.size=sizeof(struct _BMP_INFO);
    //图片的宽度和高度
    new_bmp_info.w=src_bmp_info.w;
    new_bmp_info.h=src_bmp_info.h;
    //图片的颜色位数
    new_bmp_info.bit=24;
    //标志位
    new_bmp_info.flag=1;
    //写入文件参数信息
    cnt=fwrite(&new_bmp_info,1,sizeof(struct _BMP_INFO),new_fp);
    printf("新图片的参数结构成功写入:%d 字节.\n",cnt);
  int one_line_byte=src_bmp_info.w*3;
  while(one_line_byte%4!=0)one_line_byte++;
  int val_byte=one_line_byte-src_bmp_info.w*3; //相差的字节数
  printf("需要补齐%d字节.\n",val_byte);
    /*7. 写入位图数据*/
    int w,h;
    int seek=0;
    int c=0;
    for(h=src_bmp_info.h;h>=0;h--)
    {
        seek=h*one_line_byte+54;
    seek-=val_byte; //减去原图片的补齐数据
        for(w=0;w<src_bmp_info.w;w++)
        {
            seek-=3;
            //从头开始偏移
            fseek(src_fp,seek,SEEK_SET);
            fread(&c,1,3,src_fp); //读取图片数据
            fwrite(&c,1,3,new_fp); //写数据
        }
    if(val_byte)fwrite(&c,1,val_byte,new_fp); //如果需要补齐,就写补齐数据
    }
    /*8. 关闭文件*/
    fclose(new_fp);
    fclose(src_fp);
    return 0;
}


目录
相关文章
|
人工智能 算法 PyTorch
TorchAcc:基于 TorchXLA 的分布式训练框架
阿里云研究员、阿里云人工智能平台 PAI 技术负责人--林伟在GTC 2024 大会 China AI Day 线上中文演讲专场上介绍了TorchAcc,这是一个基于 PyTorch/XLA 的大模型分布式训练框架。
|
PHP 计算机视觉
罗德里格斯公式推导,以及如何使用cv2.Rodrigues进行旋转矩阵和旋转向量之间的相互转化
罗德里格斯公式推导,以及如何使用cv2.Rodrigues进行旋转矩阵和旋转向量之间的相互转化
691 0
|
11月前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
本篇将带你实现一个虚拟音乐控制台。用户可以通过界面控制音乐的播放、暂停、切换歌曲,并查看当前播放的歌曲信息。页面还支持调整音量和动态显示播放进度,是音乐播放器界面开发的基础功能示例。
439 80
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
|
人工智能 计算机视觉 Python
【超详细】【YOLOV8使用说明】一套框架解决CV的5大任务:目标检测、分割、姿势估计、跟踪和分类任务【含源码】(1)
【超详细】【YOLOV8使用说明】一套框架解决CV的5大任务:目标检测、分割、姿势估计、跟踪和分类任务【含源码】
【超详细】【YOLOV8使用说明】一套框架解决CV的5大任务:目标检测、分割、姿势估计、跟踪和分类任务【含源码】(1)
|
10月前
|
人工智能 数据可视化 数据处理
《人工智能可视化:数据洞察的新窗口》
在数字化时代,数据爆炸式增长带来巨大挑战。人工智能可视化技术应运而生,通过动态图表和智能选择最佳展示方式,突破传统静态图表的局限,深入挖掘数据潜在关系,如电商商品关联分析。它支持实时交互与反馈,助力金融等领域即时决策,并增强企业决策支持,以直观形式呈现市场趋势和预测结果,提升数据处理效率,挖掘潜在价值,推动各行业发展。
281 18
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
672 1
|
弹性计算 小程序 Android开发
你信吗?有人用云电脑玩《黑神话:悟空》Mac党有福了
本教程详细介绍如何利用阿里云无影云电脑轻松畅玩《黑神话·悟空》游戏,无需下载游戏客户端,开机即可体验。首先需下载无影客户端并购买个人铂金款云电脑(14.9元首月)。随后输入WeGame版或Steam版镜像分享码并选择电竞模式进行配置。最后在云电脑内启动WeGame客户端,添加并更新游戏后即可开始游戏。请注意游戏本身需额外购买。游戏结束后记得关闭云电脑以避免额外收费。更多详情参见阿里云官方文档。
696 1
|
程序员 C#
C#抽象类和抽象方法详解
C#抽象类和抽象方法详解
367 0
|
存储 边缘计算 人工智能
边缘计算问题之边缘计算的定义如何解决
边缘计算问题之边缘计算的定义如何解决
602 0
|
计算机视觉
halcon系列基础之Scale_image_range
halcon系列基础之Scale_image_range
768 0