C语言实现将彩色BMP位图转化为二值图
CTF做了图片的隐写题,还没有形成系统的认识,先来总结一下BMP图的组成,并通过将彩色图转为二值图的例子加深下理解。
只写了位图二进制文件的格式和代码实现,至于诸如RGB色彩和调色板是什么的一些概念就不啰嗦了。
BMP位图文件格式
BMP文件由文件头、位图信息头、调色板和图形数据四部分组成,真彩色图是没有调色板的。每部分的具体结构在代码中具体列出并解释。
结构体的对齐
定义文件头部各结构体时要注意对齐的问题,至于什么是结构体对齐,请看这篇博文,写的很详细http://www.cnblogs.com/motadou/archive/2009/01/17/1558438.html
位图的四字节对齐
这个对齐是位图每行像素的对齐,不要和上面的结构体对齐混淆,每行像素所占字节数必须是4字节的整数倍,不足的要填充,这时因为内存分配单位是32位的,即4字节,读入的每行像素是连续的,不能和其他行共占一个内存单位
彩色图转为灰度图
RGB共有256种灰色分量,就是R=G=B时的色彩是灰色的,所以可以用一个字节来表示,将彩色图转化为灰度图就是让真彩色图的三个颜色分量等于一个相同的数值,具体等于多少可以与多种方法,比如求三个分量的平均值,取三个分量的最大值或者使其中两个分量等于另一个分量的值,还有一种常用的方法是取加权平均值,根据这个很著名的心理学公式Gray = R*0.299 + G*0.587 + B*0.114
灰度图转化为二值图
二值图只有两个颜色,黑和白,而灰度有256种颜色,将灰度转化为二值是选取一个阈值,将灰度值大于这个阈值的置成白色,反之为黑色,关于这个阈值如何选取和作用范围也有多种方法,不再赘述,为了简单我在全局范围内选用一个固定的阈值190(针对我这张测试图片,手敲了个190,转化的效果还可以)二值图只有两个索引,可以用1bit表示,但是我写的程序是用1个字节表示的,至于如何压缩,看你喽。。。
说了这么多,还是看代码吧,这样更容易理解,额,好像几乎给每行都写了注释╮(╯▽╰)╭,不要嫌我墨迹
- /*
- Author:蔚蓝行
- Blog:http://www.cnblogs.com/duanv/
- */
- #include <stdio.h>
- #include <stdlib.h>
- /*位图文件头*/
- #pragma pack(1)//单字节对齐
- typedef struct tagBITMAPFILEHEADER
- {
- unsigned char bfType[];//文件格式
- unsigned int bfSize;//文件大小
- unsigned short bfReserved1;//保留
- unsigned short bfReserved2;//保留
- unsigned int bfOffBits;//数据偏移量
- }fileHeader;
- #pragma pack()
- /*位图信息头*/
- #pragma pack(1)
- typedef struct tagBITMAPINFOHEADER
- {
- unsigned int biSize;//BITMAPINFOHEADER结构所需要的字数
- int biWidth;//图像宽度,像素为单位
- int biHeight;//图像高度,像素为单位,为正数,图像是倒序的,为负数,图像是正序的
- unsigned short biPlanes;//为目标设备说明颜色平面数,总被置为1
- unsigned short biBitCount;//说明比特数/像素
- unsigned int biCompression;//说明数据压缩类型
- unsigned int biSizeImage;//说明图像大小,字节单位
- int biXPixPerMeter;//水平分辨率,像素/米
- int biYPixPerMeter;//垂直分辨率
- unsigned int biClrUsed;//颜色索引数
- unsigned int biClrImportant;//重要颜色索引数,为0表示都重要
- }fileInfo;
- #pragma pack()
- /*调色板结构*/
- #pragma pack(1)
- typedef struct tagRGBQUAD
- {
- unsigned char rgbBlue;//蓝色分亮度
- unsigned char rgbGreen;//绿色分亮度
- unsigned char rgbRed;//红色分亮度
- unsigned char rgbReserved;
- }rgbq;
- #pragma pack()
- int main()
- {
- /*变量声明*/
- FILE *fpBMP,*fpTwoValue;//源文件fpBMP,目标文件fpTwoValue
- fileHeader *fh;//位图文件头
- fileInfo *fi;//位图信息头
- rgbq *rg;//调色板
- int i,j,k=;
- unsigned char *a;//存储源图每行像素值
- unsigned char b;//存储每个像素的灰度值或二值
- unsigned char *c;//存储每行像素的二值
- /********************************************************************/
- /*打开源文件,创建输出文件*/
- if((fpBMP=fopen("/Users/SPY/Desktop/1.bmp","rb"))==NULL){
- printf("file open failed");
- exit();
- }
- if((fpTwoValue=fopen("/Users/SPY/Desktop/2.bmp","wb"))==NULL){
- printf("file creat failed");
- exit();
- }
- /********************************************************************/
- /*创建位图文件头,信息头,调色板*/
- fh=(fileHeader *)malloc(sizeof(fileHeader));
- fi=(fileInfo *)malloc(sizeof(fileInfo));
- rg=(rgbq *)malloc(*sizeof(rgbq));
- /*读入源位图文件头和信息头*/
- fread(fh,sizeof(fileHeader),,fpBMP);
- fread(fi,sizeof(fileInfo),,fpBMP);
- /*修改文件头,信息头信息*/
- fi->biBitCount=;//转换成二值图后,颜色深度由24位变为8位
- fi->biSizeImage=((fi->biWidth+)/)**fi->biHeight;//每个像素由三字节变为单字节,同时每行像素要四字节对齐
- fi->biClrUsed=;//颜色索引表数量,二值图为2
- fi->biClrImportant=;//重要颜色索引为0,表示都重要
- fh->bfOffBits=sizeof(fileHeader)+sizeof(fileInfo)+*sizeof(rgbq);//数据区偏移量,等于文件头,信息头,索引表的大小之和
- fh->bfSize=fh->bfOffBits+fi->biSizeImage;//文件大小,等于偏移量加上数据区大小
- rg[].rgbBlue=rg[].rgbGreen=rg[].rgbRed=rg[].rgbReserved=;//调色板颜色为黑色对应的索引为0
- rg[].rgbBlue=rg[].rgbGreen=rg[].rgbRed=;//白色对应的索引为1
- rg[].rgbReserved=;
- /********************************************************************/
- /*将位图文件头,信息头和调色板写入文件*/
- fwrite(fh,sizeof(fileHeader),,fpTwoValue);
- fwrite(fi,sizeof(fileInfo),,fpTwoValue);
- fwrite(rg,*sizeof(rgbq),,fpTwoValue);
- /*将彩色图转为二值图*/
- a=(unsigned char *)malloc((fi->biWidth*+)/*);//给变量a申请源图每行像素所占大小的空间,考虑四字节对齐问题
- c=(unsigned char *)malloc((fi->biWidth+)/*);//给变量c申请目标图每行像素所占大小的空间,同样四字节对齐
- for(i=;i<fi->biHeight;i++){//遍历图像每行的循环
- for(j=;j<((fi->biWidth*+)/*);j++){//遍历每行中每个字节的循环
- fread(a+j,,,fpBMP);//将源图每行的每一个字节读入变量a所指向的内存空间
- //printf("%d ",a[j]);
- }
- for(j=;j<fi->biWidth;j++){//循环像素宽度次,就不会计算读入四字节填充位
- b=(int)(0.114*(float)a[k]+0.587*(float)a[k+]+0.299*(float)a[k+]);//a中每三个字节分别代表BGR分量,乘上不同权值转化为灰度值
- //printf("%d",b);
- if(<=(int)b) b=;//将灰度值转化为二值,这里选取的阈值为190
- else b=;
- c[j]=b;//存储每行的二值
- k+=;
- }
- fwrite(c,(fi->biWidth+)/*,,fpTwoValue);//将二值像素四字节填充写入文件,填充位没有初始化,为随机值
- k=;
- }
- /********************************************************************/
- /*释放内存空间,关闭文件*/
- free(fh);
- free(fi);
- free(rg);
- free(a);
- free(c);
- fclose(fpBMP);
- fclose(fpTwoValue);
- printf("success!\n");
- return ;
- }
运行的结果如下(不支持上传位图,只能看下效果了):
C语言实现将彩色BMP位图转化为二值图的更多相关文章
- c语言实现灰度图转换为二值图
将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 /* 2015年6月2日11:16:22 灰度图转换为二值图 blog:http ...
- BMP彩色转成黑色二值图
一天半把彩色bmp转成黑白了. 原理是: 第一步:读出位图数据的偏移位置:即第11个字节,用fseek即可. 然后将偏移位置之前的数据全部写入新的bmp图中. 第二步:用fseek移到位图数据这前,判 ...
- Windows下BMP位图格式介绍
BMP图片,是Bitmap(位图)的简称,它是windows下显示图片的基本格式.在windows下任何格式的图片文件(包括视频播放)都要转化为位图才能显示出来.各种格式的图片文件也都是在位图格式的基 ...
- Linux C语言解析并显示.bmp格式图片
/************************* *bmp.h文件 *************************/ #ifndef __BMP_H__ #define __BMP_H__ # ...
- 怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图?
分类: OpenCV [Q1]怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图? 进行灰度化,IplImage* pImg = cvLoadImage( "C:\\1.b ...
- 将文件内容隐藏在bmp位图中
首先要实现这个功能,你必须知道bmp位图文件的格式,这里我就不多说了,请看:http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html 接 ...
- 浅析BMP位图文件结构(含Demo)
浅析BMP位图文件结构(含Demo) 作者:一点一滴的Beer http://beer.cnblogs.com/ 关于BMP位图格式在网上可以找到比较详细的相关文档,有兴趣的可以搜索标题为“BMP ...
- gnu-ucos 增加 bmp 位图显示
昨天又下了点功夫弄了个在tft屏幕上显示bmp位图的. 我选择的是24位tft真彩測显示方式所以也要选择真彩色位图.网上给出的16位位图数组无法使用.在csdn上下载了2个制作工具,一个是c代码的,一 ...
- BMP位图图像格式简介
1. 文件结构 位图文件可看成由4个部分组成:位图文件头(bitmap-fileheader).位图信息头(bitmap-informationheader).彩色表(colortable)和定义位图 ...
随机推荐
- Nginx an upstream response is buffered to a temporary file
1.错误日志:warn:an upstream response is buffered to a temporary file 解决办法:增加fastcgi_buffers 8 4K; fa ...
- SignalR简单封装
需求:Asp.Net MVC 开发客户端,实现与服务器端实时通信. 众所周知,Web开发是基于http的请求响应模型,每次刷新都需要客户端(浏览器)主动发起请求,那么,这个问题怎么解?Asp.Net ...
- JWT+ASP.NET MVC 时间戳防止重放攻击
时间戳作用 客户端在向服务端接口进行请求,如果请求信息进行了加密处理,被第三方截取到请求包,可以使用该请求包进行重复请求操作.如果服务端不进行防重放攻击,就会服务器压力增大,而使用时间戳的方式可以解 ...
- .net core获取服务器本地IP及Request访问端口
string str = (Request.HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString() + ":" + ...
- 违反了引用完整性约束。Dependent Role 具有多个具有不同值的主体。S级乌龙,自己制造的笑话
项目中碰到一个错误,捯饬了一个半小时没解决,吃完饭继续搞~ EF新增多表管理数据时报错:违反了引用完整性约束.Dependent Role 具有多个具有不同值的主体. 最终问题解决后,完全是因为自己的 ...
- [招聘] 上海耐斯特数字招聘3D图形软件工程师
公司介绍 上海耐斯特数字科技有限公司成立于2018年9月,致力于为中国原创动画.影视行业提供新一代核心技术解决方案和全流程技术服务.公司创始团队拥有国内外领先的行业背景与资源,在DCC软件开发方面具有 ...
- 关于margin:-10000px;padding:10000px;的理解
原文链接: 内外补丁负值法是指通过内外补丁的设置来解决一些我们通常方法不能实现的效果.例如:可以通过改变盒模型的样式来使几列div由内容撑开高度但几列div与最高的一栏等高的问题.但是为什么会出现这样 ...
- R语言和RStudio的一些用法,常用命令等
控制台: Up/down 回忆之前的命令 Ctrl+Up 回顾命令列表(可先输入前缀进行查找) 焦点: ctrl+ 移动焦点到source编辑器 ctrl+ 移动焦点到console ctrl+L 清 ...
- beyondCompare试用期到期解决办法
找到beyond Compare 4文件夹下面的BCUnrar.dll,将其删掉或者重命名,再重新打开接着使用! 我这是转的,到期之后试试.
- A Node Influence Based Label Propagation Algorithm for Community detection in networks 文章算法实现的疑问
这是我最近看到的一篇论文,思路还是很清晰的,就是改进的LPA算法.改进的地方在两个方面: (1)结合K-shell算法计算量了节点重重要度NI(node importance),标签更新顺序则按照NI ...