BMP图片读写实践:rgb转bgr

news2025/1/23 5:58:40

本实理论上支持24位图和32位图,实际上只测试了24位。原理很简单,就是RGB中的蓝色字节和红色字节交换。

 测试代码1:


#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <jpeglib.h>

#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d -- "format"\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif


//Gray = 0.30 * R + 0.59 * G + 0.11 * B
uint8_t rgb888_to_gray(uint8_t r,uint8_t g,uint8_t b){
    return (uint8_t)(0.3 *(float)r + 0.59 * (float)g + 0.11 * (float)b);
}

typedef uint16_t WORD;
typedef uint32_t DWORD;
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER{
    WORD bfType;//2
    DWORD bfSize;//4
    WORD bfReserved1;//2
    WORD bfReserved2;//2
    DWORD bfOffBits;//4
} BITMAPFILEHEADER;
#pragma pack()
typedef int32_t LONG; 
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER; 

int main(int argc, char **argv)
{
    char *filename = "RGB.bmp";
    int fd = open(filename , O_RDONLY);
    if(fd <= 0){
        perror("open:");
        return -1;
    }
    struct tagBITMAPFILEHEADER * bit_map_file_header = malloc(sizeof(struct tagBITMAPFILEHEADER));
    struct tagBITMAPINFOHEADER * bit_map_info_header = malloc(sizeof(struct tagBITMAPINFOHEADER));

    DEBUG_INFO("%d %d",sizeof(struct tagBITMAPFILEHEADER),sizeof(struct tagBITMAPINFOHEADER));

    if(bit_map_file_header == NULL || bit_map_info_header == NULL){
        perror("malloc:");
        return -1;
    }
    
    //读取bmp的头信息
    read(fd , bit_map_file_header , 14);
    if(bit_map_file_header->bfType != 0x4D42){
        DEBUG_INFO("这不是BMP图片");
        return -1;
    }
    DEBUG_INFO("bfOffBits = %d",bit_map_file_header->bfOffBits);
    read(fd , bit_map_info_header , 40);
    DEBUG_INFO("width = %d,height = %d,biBitCount = %d\n" , bit_map_info_header->biWidth , bit_map_info_header->biHeight,bit_map_info_header->biBitCount);
    if(bit_map_info_header->biBitCount < 24){
        DEBUG_INFO("仅支持24位和32位的BMP图片");
        return -1;
    }

    if(bit_map_info_header->biWidth < 0){
        bit_map_info_header->biWidth = abs(bit_map_info_header->biWidth);
    }
    if(bit_map_info_header->biHeight < 0){
        bit_map_info_header->biHeight = abs(bit_map_info_header->biHeight);
    }
    DEBUG_INFO("width = %d,%d,biBitCount = %d\n" , 
        bit_map_info_header->biWidth , 
        bit_map_info_header->biHeight,
        bit_map_info_header->biBitCount);
    // return 0;
    int bmp_data_len = bit_map_info_header->biWidth * bit_map_info_header->biHeight * bit_map_info_header->biBitCount;
    DEBUG_INFO("bmp_data_len = %d",bmp_data_len);
    unsigned char *bmp_buf = malloc(bmp_data_len);
    if(bmp_buf == NULL){
        DEBUG_INFO("malloc error");
        return -1;
    }
    int ret = read(fd,bmp_buf,bmp_data_len);
    if(ret < 0){
        DEBUG_INFO("read error");
        return -1;
    }
    //把RGB转换成BGR,就是调用R和G的位置
    int index = 0;
    unsigned char tmp;
    while(bmp_data_len > index){
        tmp = bmp_buf[index + 0];
        bmp_buf[index + 0] = bmp_buf[index + 2];
        bmp_buf[index + 2] = tmp;
        index += (bit_map_info_header->biBitCount >> 3);
    }

    int bgr_bmp_fd = open("BGR.bmp",O_WRONLY | O_TRUNC | O_CREAT,0660);
    if(fd <= 0){
        perror("open:");
        return -1;
    }
    write(bgr_bmp_fd,bit_map_file_header,sizeof(struct tagBITMAPFILEHEADER));
    write(bgr_bmp_fd,bit_map_info_header,sizeof(struct tagBITMAPINFOHEADER));
    write(bgr_bmp_fd,bmp_buf,bmp_data_len);
    close(bgr_bmp_fd);
    close(fd);
    free(bmp_buf);
    return 0;
}

调试信息:

测试结果:

左边是转换之前,右边是转换之后。

 

由调试信息可知,选取的图片是720X336,也就是行4字节对齐的。换成721X336的图片,测试结果如下:果然出错了。 

测试代码2:

修改后的颜色转换部分如下所示:这里主要解决了行4字节对齐的问题。


#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <jpeglib.h>

#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d -- "format"\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif


//Gray = 0.30 * R + 0.59 * G + 0.11 * B
uint8_t rgb888_to_gray(uint8_t r,uint8_t g,uint8_t b){
    return (uint8_t)(0.3 *(float)r + 0.59 * (float)g + 0.11 * (float)b);
}

typedef uint16_t WORD;
typedef uint32_t DWORD;
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER{
    WORD bfType;//2
    DWORD bfSize;//4
    WORD bfReserved1;//2
    WORD bfReserved2;//2
    DWORD bfOffBits;//4
} BITMAPFILEHEADER;
#pragma pack()
typedef int32_t LONG; 
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER; 

char *src_file_name = "RGB2.bmp";
char *dst_file_name = "BGR2.bmp";

int main(int argc, char **argv)
{
    int fd = open(src_file_name , O_RDONLY);
    if(fd <= 0){
        perror("open:");
        return -1;
    }
    struct tagBITMAPFILEHEADER * bit_map_file_header = malloc(sizeof(struct tagBITMAPFILEHEADER));
    struct tagBITMAPINFOHEADER * bit_map_info_header = malloc(sizeof(struct tagBITMAPINFOHEADER));

    DEBUG_INFO("%d %d",sizeof(struct tagBITMAPFILEHEADER),sizeof(struct tagBITMAPINFOHEADER));

    if(bit_map_file_header == NULL || bit_map_info_header == NULL){
        perror("malloc:");
        return -1;
    }
    
    //读取bmp的头信息
    read(fd , bit_map_file_header , 14);
    if(bit_map_file_header->bfType != 0x4D42){
        DEBUG_INFO("这不是BMP图片");
        return -1;
    }
    DEBUG_INFO("biSizebfOffBits = %d,bfSize = %d",bit_map_file_header->bfOffBits,bit_map_file_header->bfSize);
    read(fd , bit_map_info_header , 40);
    DEBUG_INFO("biSize = %d,width = %d,height = %d,biBitCount = %d,biPlanes = %d,\n\
    biCompression = %d,biSizeImage = %d,\n\
    biXPelsPerMeter = %d,biYPelsPerMeter = %d,\n\
    biClrUsed = %d,biClrImportant = %d\n" , 
    bit_map_info_header->biSize,
    bit_map_info_header->biWidth , 
    bit_map_info_header->biHeight,
    bit_map_info_header->biBitCount,
    bit_map_info_header->biPlanes,
    bit_map_info_header->biCompression,
    bit_map_info_header->biSizeImage,
    bit_map_info_header->biXPelsPerMeter,
    bit_map_info_header->biYPelsPerMeter,
    bit_map_info_header->biClrUsed,
    bit_map_info_header->biClrImportant);

    if(bit_map_info_header->biBitCount < 24){
        DEBUG_INFO("仅支持24位和32位的BMP图片");
        return -1;
    }

    if(bit_map_info_header->biWidth < 0){
        bit_map_info_header->biWidth = abs(bit_map_info_header->biWidth);
    }
    if(bit_map_info_header->biHeight < 0){
        bit_map_info_header->biHeight = abs(bit_map_info_header->biHeight);
    }
    DEBUG_INFO("width = %d,%d,biBitCount = %d\n" , 
        bit_map_info_header->biWidth , 
        bit_map_info_header->biHeight,
        bit_map_info_header->biBitCount);
    // return 0;
    unsigned char *bmp_buf = malloc(bit_map_file_header->bfSize);
    unsigned char *dst_bmp_buf = malloc(bit_map_file_header->bfSize);
    if(bmp_buf == NULL){
        DEBUG_INFO("malloc error");
        return -1;
    }
    int ret = read(fd,bmp_buf,bit_map_file_header->bfSize - 54);
    if(ret < 0){
        DEBUG_INFO("read error");
        return -1;
    }
    int w = bit_map_info_header->biWidth;
    int h = bit_map_info_header->biHeight;
    int biBitCount = bit_map_info_header->biBitCount;

    int color_byte = biBitCount/8;
    int offset_step;
    if((w * color_byte)%4){
        offset_step =((w*color_byte)/4+1)*4;
    }else{
        offset_step = w*color_byte;
    }
    DEBUG_INFO("offset_step = %d",offset_step);
    
    //把RGB转换成BGR,就是调用R和G的位置
    int index = 0;
    unsigned char tmp;
    int offset = 0;
    DEBUG_INFO("color_byte = %d",color_byte);
    int line=0;
    for(int i = 0 ; i < h; i++){
        for(int j = 0 ; j < w ; j++){
            int index = offset + j * color_byte;
            tmp = bmp_buf[index + 0 ];
            bmp_buf[index + 0 ] = bmp_buf[index + 2 ];
            bmp_buf[index + 2 ] = tmp;   
        }
        offset += offset_step;
    }

    int bgr_bmp_fd = open(dst_file_name,O_WRONLY | O_TRUNC | O_CREAT,0660);
    if(fd <= 0){
        perror("open:");
        return -1;
    }
    write(bgr_bmp_fd,bit_map_file_header,sizeof(struct tagBITMAPFILEHEADER));
    write(bgr_bmp_fd,bit_map_info_header,sizeof(struct tagBITMAPINFOHEADER));
    write(bgr_bmp_fd,bmp_buf,bit_map_file_header->bfSize - 54);
    close(bgr_bmp_fd);
    close(fd);
    free(bmp_buf);
    return 0;
}

测试721x336,OK

 在测一个571X673的,效果还是不错的。

调试信息:宽571,高673,行宽2284字节。

 

小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/924786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【【Verilog典型电路设计之log函数的Verilog HDL设计】】

Verilog典型电路设计之log函数的Verilog HDL设计 log函数是一种典型的单目计算函数&#xff0c;与其相应的还有指数函数、三角函数等。对于单目计算函数的硬件加速器设计一般两种简单方法:一种是查找表的方式;一种是使用泰勒级数展开成多项式进行近似计算。这两种方式在设计方…

Linux —— nfs文件系统

简介 NFS 是Network File System的缩写&#xff0c;即网络文件系统。一种使用于分散式文件系统的协定&#xff0c;由Sun公司开发&#xff0c;于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据&#xff0c;让应用程序在客户端通过网络访问位…

08-pandas 入门-pandas的数据结构

要使用pandas&#xff0c;你首先就得熟悉它的两个主要数据结构&#xff1a;Series和DataFrame。虽然它们并不能解决所有问题&#xff0c;但它们为大多数应用提供了一种可靠的、易于使用的基础。 一、Series Series是一种类似于一维数组的对象&#xff0c;它由一组数据&#x…

redux中间件理解,常见的中间件,实现原理。

文章目录 一、Redux中间件介绍1、什么是Redux中间件2、使用redux中间件 一、Redux中间件介绍 1、什么是Redux中间件 redux 提供了类似后端 Express 的中间件概念&#xff0c;本质的目的是提供第三方插件的模式&#xff0c;自定义拦截 action -> reducer 的过程。变为 actio…

AIGC ChatGPT 实现动态多维度分析雷达图制作

雷达图在多维度分析中是一种非常实用的可视化工具&#xff0c;主要有以下优势&#xff1a; 易于理解&#xff1a;雷达图使用多边形或者圆形的形式展示多维度的数据&#xff0c;直观易于理解。多维度对比&#xff1a;雷达图可以在同一张图上比较多个项目或者实体在多个维度上的…

网络安全入口设计模式

网络安全入口涵盖了几种设计模式&#xff0c;包括全局路由模式、全局卸载模式和健康终端监控模式。网络安全入口侧重于&#xff1a;全局路由、低延迟故障切换和在边缘处减轻攻击。 上图包含了3个需求。 •网络安全入口模式封装了全局路由模式。因此&#xff0c;实现可以将请求路…

扩散模型实战(五):采样过程

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 ​扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#…

stm32串口通信(PC--stm32;中断接收方式;附proteus电路图;开发方式:cubeMX)

单片机型号STM32F103R6: 最后实现的效果是&#xff0c;开机后PC内要求输入1或0&#xff0c;输入1则打开灯泡&#xff0c;输入0则关闭灯泡&#xff0c;输入其他内容则显示错误&#xff0c;值得注意的是这个模拟的东西只能输入英文 之所以用2个LED灯是因为LED电阻粗略一算就是1…

UWB高精度人员定位系统源码,微服务+java+ spring boot+ vue+ mysql技术开发

工业物联网感知预警体系&#xff0c;大中小企业工业数字化转型需求的工业互联网平台 工厂人员定位系统是指能够对工厂中的人员、车辆、设备等进行定位&#xff0c;实现对人员和车辆的实时监控与调度的系统&#xff0c;是智慧工厂建设中必不可少的一环。由于工厂的工作环境比较…

Hive中的DQL操作

文章目录 语法及注意事项基本查询&#xff08;where、gruop by、join&#xff09;排序函数系统内置函数窗口函数自定义函数 语法及注意事项 SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BY col_list] [ORDER…

同源政策与CORS

CORS意为跨源资源共享&#xff08;Cross origin resource sharing&#xff09;&#xff0c;它是一个W3C标准&#xff0c;由一系列HTTP Header组成&#xff0c;这些 HTTP Header决定了浏览器是否允许JavaScript 代码成功获得跨源请求的服务器响应。 在说CORS之前&#xff0c;先…

多功能租车平台微信小程序源码 汽车租赁平台源码 摩托车租车平台源码 汽车租赁小程序源码

多功能租车平台微信小程序源码是一款用于汽车租赁的平台程序源码。它提供了丰富的功能&#xff0c;可以用于租赁各种类型的车辆&#xff0c;包括汽车和摩托车。 这个小程序源码可以帮助用户方便地租赁车辆。用户可以通过小程序浏览车辆列表&#xff0c;查看车辆的详细信息&…

浙大陈越何钦铭数据结构07-图6 旅游规划

题目: 有了一张自驾旅游路线图&#xff0c;你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序&#xff0c;帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的&#xff0c;那么需要输出最便宜的一条路径。 输入…

汽车电子笔记之:AUTOSA架构下的OS概述

目录 1、实时操作系统&#xff08;RTOS&#xff09; 2、OSEK操作系统 2.1、OSEK概述 2.2、OSEK处理等级 2.3、OSEK任务符合类 2.4、OSEK优先级天花板模式 3、AUTOSAR OS 3.1、 AUTOSAR OS对OSEK OS的继承和扩展 3.2、AUTOSAR OS的调度表 3.3、AUTOSAR OS的时间保护 3…

PID直观感受简述

0、仿真控制框图 1、增加p的作用&#xff08;增加响应&#xff09;P 2、增加I的作用&#xff08;消除稳差&#xff09;PI 3、增加D的作用&#xff08;抑制波动&#xff09;PID 加入对噪声很敏 4、综合比对

java maven项目打jar包发布(精简版)

目录 一、maven打包 二、安装jdk环境 三、安装mysql 四、jar包传输到服务器 一、maven打包 先clean再package target文件夹下面有生成一个jar包 二、安装jdk环境 1、下载jdk cd /usr/local wget https://repo.huaweicloud.com/java/jdk/8u201-b09/jdk-8u201-linux-x64.tar.…

[谦实思纪 02]整理自2023雷军年度演讲——《成长》(下篇)创业之旅(创业与成长)

文章目录 [谦实思纪]整理自2023雷军年度演讲 ——《成长》&#xff08;下篇&#xff09;创业之旅&#xff08;创业与成长&#xff09;0. 写在前面1. 创业&#xff01;&#xff08;创业与成长&#xff09;1.1 找互补的朋友一起干&#xff0c;更容易成功1.2 创业中必须要有领导者…

Verilog 基础语法(题目)

Verilog 基础语法&#xff08;题目&#xff09; **本内容来自 牛客网Verilog基础语法** 1、四选一多路器 制作一个四选一的多路选择器&#xff0c;要求输出定义上为线网类型 状态转换&#xff1a; d0 11 d1 10 d2 01 d3 00 信号示意图&#xff1a; 波形示意图&#xff1a; …

抖音seo矩阵系统源代码开发部署分享

一、 开发步骤分享 抖音SEO矩阵系统源代码开发部署分享&#xff0c;需要经验丰富的开发人员和服务器管理人员&#xff0c;以下是大致的步骤&#xff1a; 确定你需要的功能和设计&#xff0c;确定开发人员和设计师的角色和任务分配&#xff0c;以及开发进度和计划。 确定服务器…

分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测

分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测 目录 分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 先利用平均影响值MIV算法对特征进行排序&#xff0c;确定分类特征…