BMP格式图像知识点总结并转灰度图

BMP格式图像知识点总结并转灰度图24 位彩图转换为灰度图练习练习目的位图知识点 BMP 图像存储结构位图文件头位图信息头调色板位图数据转灰度图重点代码例程练习目的对 jpg 格式的图片滤波去噪点 并进行边缘提取位图知识点刚拿到任务时觉得图像处理不算难 以前在学校用 matlab 做过简单的数字图像处理作业 如果用 c 写的话调用 OpenCV 的库函数应该也不难 但后来发现要用纯 c 开发 就有点懵逼了 matlab 和 OpenCV 里的封装

练习目的

BMP格式图片灰度化

位图知识点

BMP图像存储结构

块名称 Windows结构体定义 大小(BYTE)
文件信息头 BITMAPFILEHEADER 14
位图信息头 BITMAPINFOHEADER 40
调色板 RGBQUAD 单色、16色、256色图像文件特有,相对应的调色板大小是2,16,256。
RGB像素值阵列 BYTE* 由图像长宽尺寸决定,每一行字节数必须是4的整数倍

位图文件头

提供文件的格式,大小等信息

typedef struct tagBITMAPFILEHEADER { 
    UINT16 bfType; //2BYTES,必须为BM,即0x424D,文件格式,windows位图文件 DWORD bfSize; //4BYTES,整个BMP文件的大小 UINT16 bfReverved1; //2BYTES,保留,值为0 UINT16 bfReverved2; //2BYTES,保留,值为0 DWORD bfOffBits; //4BYTES,文件起始位置到图像像素数据的字节偏移量 }BITMAPFILEHEADER; 

位图信息头

定义如下:

typedef struct _tagBMP_INFOHEADER { 
    DWORD biSize; //4BYTES,INFOHEADER结构体大小 LONG biWidth; //4BYTES,图像宽度(以像素为单位) LONG biHeight; //4BYTES,图像高度。值为正,图像存储顺序从下到上,从左到右;值为负,正好相反。 WORD biPlanes; //2BYTES,图像数据平面,BMP存储RGB数据,因此总为1 WORD biBitCount; //2BYTES,图像像素位数 DWORD biCompression; //4BYTES,0:不压缩;1:RLE8;2:RLE4 DWORD biSizeImage; //4BYTES,4字节对齐的图像数据大小 LONG biXPelsPerMeter; //4BYTES,用像素/米表示的水平分辨率 LONG biYPelsPerMeter; //4BYTES,用像素/米表示的垂直分  DWORD biClrUsed; //4BYTES,实际使用的调色板索引数,0:使用所有的调色板索引 DWORD biClrImportant; //4BYTES,重要的调色板索引数,0:所有的索引都重要 }BMP_INFOHEADER; 

调色板

结构体定义如下:

typedef struct _tagRGBQUAD { 
    BYTE rgbBlue; //指定蓝色强度 BYTE rgbGreen; //指定绿色强度 BYTE rgbRed; //指定红色强度 BYTE rgbReserved; //保留,设0 }RGBQUAD; 

颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项。

当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。

当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。

当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。

当biBitCount=16,24或32时,没有颜色表。

位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节;

Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,

一个扫描行所占的字节数计算方法:

DataSizePerLine= (biWidth* biBitCount+31)/8;

// 一个扫描行所占的字节数

DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数

位图数据的大小(不压缩情况下):

DataSize= DataSizePerLine* biHeight;

转灰度图重点

这里参考了文章:http://blog.sina.com.cn/s/blog_677a04530101244t.html

代码例程

#include  
     #include  
     using namespace std; void main() { 
    FILE* originImg = fopen("E:\\Program test\\imgFiltering\\lena-24.bmp","rb"); if(originImg == NULL) { 
    cout<<"图片不存在"<<endl; system("pause"); return; } int sizeFileHeader = sizeof(BITMAPFILEHEADER); //文件头大小  int sizeInfoHeader = sizeof(BITMAPINFOHEADER); //信息头大小 BITMAPFILEHEADER* bitmapFileHeader = new BITMAPFILEHEADER[sizeFileHeader+1]; // 开辟一个文件头大小的数组,指针指向数组首位 BITMAPINFOHEADER* bitmapInfoHeader = new BITMAPINFOHEADER[sizeInfoHeader+1]; // 信息头指针 memset(bitmapFileHeader, 0, sizeFileHeader+1); //内存初始化,从bitmapFileHeader开始后面sizeFileHeader+1全置0 memset(bitmapInfoHeader, 0, sizeInfoHeader+1); fread(bitmapFileHeader, sizeof(char), sizeFileHeader, originImg); //从originImg中读取sizeFileHeader个char大小的数据到数组bitmapFileHeader中 fseek(originImg, sizeFileHeader, 0); //指针originImg的位置指向以文件头(0指文件头)偏移sizeFileHeader大小的位置,即指向信息头首位 fread(bitmapInfoHeader, sizeof(char), sizeInfoHeader, originImg); //读取原图的信息头到数组bitmapInfoHeader中 int srcImageLineByteCount = (((bitmapInfoHeader->biWidth) * 24 + 31) / 32) * 4; //计算原始24位图每行像素所占的字节数 int grayImageLineByteCount = (((bitmapInfoHeader->biWidth) * 8 + 31) / 32) * 4; //计算8位灰度图每行像素所占的字节数 //位图信息头 //创建了一个高位biHeight,宽为srcImageLineByteCount的二维数组,并对数组初始化 BYTE** origImgData = new BYTE*[bitmapInfoHeader->biHeight]; for(int i = 0; i < bitmapInfoHeader->biHeight; i++) { 
    origImgData[i] = new BYTE[srcImageLineByteCount + 1]; //每行是一个大小为srcImageLineByteCount的数组,行高i< memset(origImgData[i], 0, srcImageLineByteCount + 1); //从origImgData[i]开始,后面srcImageLinneByteCount+1全置0 } //位图数据 fseek(originImg, sizeFileHeader + sizeInfoHeader, 0); //定位到以文件头偏移sizeFileHeader + sizeInfoHeader大小的位置,即位图数据开始的位置 //读取位图数据 for(int i = 0; i < bitmapInfoHeader->biHeight; i++) { 
    for (int j = 0; j < srcImageLineByteCount; j++) //字节数 { 
    fread(&origImgData[i][j], sizeof(BYTE), 1, originImg); //读取原始图像位图数据,以字节为单位读到二维数组origImgData中 } } fclose(originImg); //调色板 RGBQUAD* pRgbQuards = new RGBQUAD[256]; for(int i = 0; i < 256; i++) { 
    pRgbQuards[i].rgbBlue = i; pRgbQuards[i].rgbRed = i; pRgbQuards[i].rgbGreen = i; } //修改信息头 2部分 bitmapInfoHeader->biBitCount = 8; bitmapInfoHeader->biSizeImage = (bitmapInfoHeader->biHeight) * grayImageLineByteCount; //4字节对齐的图像数据大小 宽*高 //修改文件头 2部分 //8为灰度图,有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节 bitmapFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256; //偏移量要加上调色板的大小 bitmapFileHeader->bfSize = bitmapFileHeader->bfOffBits + bitmapInfoHeader->biSizeImage; //整个文件的大小变为 信息头+文件头+调色板+数据,前三项为偏移量 //写数据 BYTE** grayImgData = new BYTE*[bitmapInfoHeader->biHeight]; for (int i = 0; i < bitmapInfoHeader->biHeight; i++) { 
    grayImgData[i] = new BYTE[grayImageLineByteCount]; } //灰度图位图数据的二维数组 for(int i = 0; i < bitmapInfoHeader->biHeight; i++) { 
    for(int j = 0; j < grayImageLineByteCount; j++) //灰度图每行像素所占的字节数 { 
    grayImgData[i][j] = (int)((float)origImgData[i][j*3] * 0.114 + (float)origImgData[i][j*3 + 1] * 0.587 + (float)origImgData[i][3*j+2] * 0.299); } } //写入文件 FILE* grayImg=fopen("E:\\Program test\\imgFiltering\\lena-gray.bmp","wb"); fwrite(bitmapFileHeader, sizeof(char), sizeof(BITMAPFILEHEADER), grayImg); //写文件头 fwrite(bitmapInfoHeader, sizeof(char), sizeof(BITMAPINFOHEADER), grayImg); //写信息头 fwrite(pRgbQuards, sizeof(RGBQUAD), 256, grayImg); // 写调色板 for(int i = 0; i < bitmapInfoHeader->biHeight; i++) { 
    for(int j = 0; j < grayImageLineByteCount; j++) { 
    fwrite(&grayImgData[i][j], sizeof(BYTE), 1, grayImg); //写位图数据 } } fclose(grayImg); cout<<"success"<<endl; cin.get(); //释放内存 for(int i = 0; i < bitmapInfoHeader->biHeight; i++) for (int j = 0; j < grayImageLineByteCount; j++) delete []grayImgData[j]; delete []grayImgData; for(int i = 0; i < bitmapInfoHeader->biHeight; i++) for (int j = 0; j < srcImageLineByteCount; j++) delete []origImgData[j]; delete []origImgData; delete []bitmapFileHeader; delete []bitmapInfoHeader; system("pause"); } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220103.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午9:14
下一篇 2026年3月17日 下午9:14


相关推荐

  • Android补间动画之ScaleAnimation、AlphaAnimation、RotateAnimation、TranslateAnimation、AnimationSet详解「建议收藏」

    Android补间动画之ScaleAnimation、AlphaAnimation、RotateAnimation、TranslateAnimation、AnimationSet详解「建议收藏」首发:http://blog.csdn.net/harvic880925/article/details/40117115一、概述前两篇,我为大家讲述了利用XML来定义动画及插值器,但在代码中,我们常常是动态生成动画的,所以,这篇将为大家讲述如何用代码生成动态生成动画及插值器。先简单写出各个标签对应的类,方便大家理解:scale—— ScaleAnimatio

    2022年10月11日
    5
  • RNAseq数据作图_做RNAseq结果不稳定

    RNAseq数据作图_做RNAseq结果不稳定在RNA-seq项目中,常见的结果包括:火山图、韦恩图、聚类热图、log2(ratios)折线图、有向无环图、散点图、代谢通路图、蛋白互作图等。今天我们先来一起学习火山图、韦恩图、聚类热图和折线图的解读。1、火山图RNA-seq中,火山图(VolcanoPlot)显示了两个重要的指标:foldchange和校正后的pvalue,利用T检验分析出两样本间显著差异表达的基因后,以log2(f…

    2022年10月20日
    4
  • Ubuntu输入法的使用

    Ubuntu输入法的使用更换输入方式系统 1 进入系统设置 ubuntu 桌面的右上角按钮菜单中 nbsp 系统设置 2 进入语言支持 nbsp 点击系统设置中的 nbsp 语言支持 3 更换输入方式系统在语言支持中的 nbsp 输入方式系统 nbsp 中 nbsp 进行选择 前提是你安装了其他的输入平台 例如我安装了 fcitx 所以可以选择 fcitx 添加删除输入法 nbsp 1 进入文本输入设置 nbsp nbsp nbsp nbsp 点击桌面右上角面板上的 nbsp 输入法菜单 nbsp 中的 nbsp 文本输入设置 2 添加输

    2025年8月21日
    7
  • Hadoop集群搭建问题总结

    Hadoop集群搭建问题总结1 问题描述 hadoop 集群启动时 datanode 进程启动不了原因分析 namenode 和 datanode 下 VERSION 文件中的 clusterID 不一致 导致 datanode 启动不了解决方法 进入 hadoop 的配置目录 hadoop 2 7 1 etc hadoop 进入 hdfs site xml 配置文件 找到 namenode 和 datanode 的配置空间 配置 namenode 数据存放的位置 可以不配置 如果不配置 默认用的是 core site xml 里配置的 hadoop t

    2026年3月16日
    1
  • mysql怎么设置远程连接_允许远程连接在哪里

    mysql怎么设置远程连接_允许远程连接在哪里MySql设置远程连接Windows与Linux同理本文使用的是MySQL8.0版本,安装在centos7中,不管是在Windows还是Linux中都是通用的,基于权限修改来达到远程连接的目的Windows与Linux同理打开终端控制面板,输入mysql-uroot-p你的Mysqlroot密码回车…

    2026年4月13日
    3
  • pycharm英文读音_pycharm英文界面翻译

    pycharm英文读音_pycharm英文界面翻译使用的是PyCharm2018.3.4代码的自动补全在PyCharm中找到PowerSaveMode选项,将前面的对勾去掉。在左上角File的展开栏的倒数第二行在PyCharm的最右下角有个????的样子(在????旁边),单击点开就可看到PowerSaveMode选项在这个Currentinspectionprofile中可以设置HighlightingLevel即检查代码严格程度。(过多的不…

    2022年8月27日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号