BMP图片读写实践:rgb转bgr

本实理论上支持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.mfbz.cn/a/93856.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效…

初试Eureka注册中心

Eureka是spring cloud中的一个负责服务注册与发现的组件。遵循着CAP理论中的A(可用性)P(分区容错性)。一个Eureka中分为eureka server和eureka client。其中eureka server是作为服务的注册与发现中心。 搭建eureka服务 引入eureka依赖 引入SpringCloud为eureka提供的starter依…

橙河:海外賺美金的项目有哪些?

大家好&#xff0c;我是橙河老师。现在呢&#xff0c;很多人去国外打工&#xff0c;大家在短视频上也经常能看到&#xff0c;他们在国外挣了几年钱&#xff0c;回来就能买车买房。 其实呢&#xff0c;他们在国外的工作&#xff0c;工资也就是几千块一个月&#xff0c;不过他们…

C语言数值表示——进制、数值存储方式

进制 进制也就是进位制&#xff0c;是人们规定的一种进位方法对于任何一种进制—X进制&#xff0c;就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一&#xff0c;十六进制是逢十六进一&#xff0c;二进制就是逢二进一&#xff0c;以此类推&#xff0c;x进制就是逢x进位…

通俗理解DDPM到Stable Diffusion原理

代码1&#xff1a;stabel diffusion 代码库代码2&#xff1a;diffusers 代码库论文&#xff1a;High-Resolution Image Synthesis with Latent Diffusion Models模型权重&#xff1a;runwayml/stable-diffusion-v1-5 文章目录 1. DDPM的通俗理解1.1 DDPM的目的1.2 扩散过程1.3 …

编写Dockerfile制作Web应用系统nginx镜像,生成镜像nginx:v1.1,并推送其到私有仓库。

环境&#xff1a; CentOS 7 Linux 3.10.0-1160.el7.x86_64 具体要求如下&#xff1a; &#xff08;1&#xff09;基于centos基础镜像&#xff1b; &#xff08;2&#xff09;指定作者信息&#xff1b; &#xff08;3&#xff09;安装nginx服务&#xff0c;将提供的dest目录…

Linux学习之DNS服务的原理

DNS服务一些理论 域名系统&#xff08;Domain Name System&#xff0c;DNS&#xff09;是互联网的核心应用服务&#xff0c;可以通过IP地址查询到域名&#xff0c;也可以通过域名查询到IP地址。 FQDN&#xff08;Full Qualified Domain Name&#xff09;是完全限定域名&#xf…

Apache Paimon 实时数据湖 Streaming Lakehouse 的存储底座

摘要&#xff1a;本文整理自阿里云开源大数据表存储团队负责人&#xff0c;阿里巴巴高级技术专家李劲松&#xff08;之信&#xff09;&#xff0c;在 Streaming Lakehouse Meetup 的分享。内容主要分为四个部分&#xff1a; 流计算邂逅数据湖 Paimon CDC 实时入湖 Paimon 不止…

java八股文面试[多线程]——死锁、活锁、饥饿

DCL双重锁&#xff1a;TODO 如何预防死锁&#xff1a; 如何查看线程死锁&#xff1a; 知识来源&#xff1a; 【2023年面试】描述一下线程安全活跃态问题&#xff0c;以及竞态条件_哔哩哔哩_bilibili 【2023年面试】如何预防死锁_哔哩哔哩_bilibili 【并发与线程】阿里一面&…

element Collapse 折叠面板 绑定事件

1. 点击面板触发事件 change <el-collapse accordion v-model"activeNames" change"handleChange"><el-collapse-item title"一致性 Consistency"><div>与现实生活一致&#xff1a;与现实生活的流程、逻辑保持一致&#xff0c…

迅为RK3588开发板Android12 设置系统默认不锁屏

修改 frameworks/base/packages/SettingsProvider/res/values/defaults.xml 文件&#xff0c;修改为如下 所示&#xff1a; - <bool name"def_lockscreen_disabled">false</bool> <bool name"def_lockscreen_disabled">true</bool&…

怎么建设ITIIL运维管理体系?

市场上大多数ITIL解决方案都过于复杂&#xff0c;让我们举一个客户希望实施ITIL方案的例子。首先&#xff0c;客户要通过ITIL咨询来定义ITIL流程&#xff0c;并使其与业务目标保持一致。接下来就是购买ITIL软件&#xff1b;大多数ITIL解决方案将事件、问题和变更管理作为不同的…

一生一芯9——ubuntu22.04安装valgrind

这里安装的valgrind版本是3.19.0 下载安装包 在选定的目录下打开终端&#xff0c;输入以下指令 wget https://sourceware.org/pub/valgrind/valgrind-3.19.0.tar.bz2直至下载完成 解压安装包 输入下面指令解压安装包 tar -xvf valgrind-3.19.0.tar.bz2.tar.bz2注&#xf…

Jmeter(二十八):beanshell的使用

Beanshell 是一种轻量级的 Java 脚本,纯 Java 编写的,能够动态的执行标准 java 语法及一些扩展脚本语法,类似于 javaScript,在工作中可能用的多的就是: Beanshell 取样器:跟Http取样器并列Beanshell前置处理器:一般放在Http请求下,在请求前处理一些数据Beanshell后置处…

1.6 服务器处理客户端请求

客户端进程向服务器进程发送一段文本&#xff08;MySQL语句&#xff09;&#xff0c;服务器进程处理后再向客户端进程发送一段文本&#xff08;处理结果&#xff09;。 从图中我们可以看出&#xff0c;服务器程序处理来自客户端的查询请求大致需要经过三个部分&#xff0c;分别…

关于disriminative 和 generative这两种模型

但是&#xff0c;其实&#xff0c;根据李宏毅老师讲到的&#xff0c;generative model是做了一些假设的&#xff0c;比如&#xff0c;如果使用Naive Bayes的话&#xff0c;不同特征x1,x2...之间相互独立的话&#xff0c;其实是很容易出现较大的偏差的&#xff0c;因为不同特征变…

在kaggle中用GPU使用CGAN生成指定mnist手写数字

文章目录 1项目介绍2参考文章3代码的实现过程及对代码的详细解析独热编码定义生成器定义判别器打印我们的引导信息模型训练迭代过程中生成的图片损失函数的变化 4总结5 模型相关的文件 1项目介绍 在GAN的基础上进行有条件的引导生成图片cgan 2参考文章 GAN实战之Pytorch 使用…

UbuntuDDE 23.04发布,体验DeepinV23的一个新选择

UbuntuDDE 23.04发布&#xff0c;体验DeepinV23的一个新选择 昨晚网上搜索了一圈&#xff0c;无意看到邮箱一条新闻&#xff0c;UbuntuDDE 23.04发布了 因为前几天刚用虚拟机安装过&#xff0c;所以麻溜的从网站下载了ISO文件&#xff0c;安装上看看。本来没多想&#xff0c;…

什么是字体图标(Icon Font)?如何在网页中使用字体图标?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 字体图标&#xff08;Icon Font&#xff09;⭐ 如何在网页中使用字体图标⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…

9.4 集成功率放大电路

OTL、OCL 和 BTL 电路均有各种不同输出功率和不同电压增益的集成电路。应当注意&#xff0c;在使用 OTL 电路时&#xff0c;需外接输出电容。为了改善频率特性&#xff0c;减小非线性失真&#xff0c;很多电路内部还引入深度负反馈。这里以低频功放为例。 一、集成功率放大电路…
最新文章