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位图转化为二值图的更多相关文章

  1. c语言实现灰度图转换为二值图

    将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 /* 2015年6月2日11:16:22 灰度图转换为二值图 blog:http ...

  2. BMP彩色转成黑色二值图

    一天半把彩色bmp转成黑白了. 原理是: 第一步:读出位图数据的偏移位置:即第11个字节,用fseek即可. 然后将偏移位置之前的数据全部写入新的bmp图中. 第二步:用fseek移到位图数据这前,判 ...

  3. Windows下BMP位图格式介绍

    BMP图片,是Bitmap(位图)的简称,它是windows下显示图片的基本格式.在windows下任何格式的图片文件(包括视频播放)都要转化为位图才能显示出来.各种格式的图片文件也都是在位图格式的基 ...

  4. Linux C语言解析并显示.bmp格式图片

    /************************* *bmp.h文件 *************************/ #ifndef __BMP_H__ #define __BMP_H__ # ...

  5. 怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图?

      分类: OpenCV [Q1]怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图? 进行灰度化,IplImage* pImg = cvLoadImage( "C:\\1.b ...

  6. 将文件内容隐藏在bmp位图中

    首先要实现这个功能,你必须知道bmp位图文件的格式,这里我就不多说了,请看:http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html 接 ...

  7. 浅析BMP位图文件结构(含Demo)

    浅析BMP位图文件结构(含Demo) 作者:一点一滴的Beer http://beer.cnblogs.com/   关于BMP位图格式在网上可以找到比较详细的相关文档,有兴趣的可以搜索标题为“BMP ...

  8. gnu-ucos 增加 bmp 位图显示

    昨天又下了点功夫弄了个在tft屏幕上显示bmp位图的. 我选择的是24位tft真彩測显示方式所以也要选择真彩色位图.网上给出的16位位图数组无法使用.在csdn上下载了2个制作工具,一个是c代码的,一 ...

  9. BMP位图图像格式简介

    1. 文件结构 位图文件可看成由4个部分组成:位图文件头(bitmap-fileheader).位图信息头(bitmap-informationheader).彩色表(colortable)和定义位图 ...

随机推荐

  1. LeetCode145:Binary Tree Postorder Traversal

    题目: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given bin ...

  2. Python: pyinstaller打包exe(含file version信息)

    最近项目上一直都是用Spyder直接运行.py文件的方式来执行每日的自动化程序,每天都要手动去点击Run来执行一次,所以考虑把.py文件直接打包成exe,然后用windows的task schedul ...

  3. C#检测并安装https站点的数字证书,CefSharp和HttpWebRequest通过会话Cookie实现自动登录访问https站点

    HttpUtil工具类: using System; using System.Collections.Generic; using System.IO; using System.Linq; usi ...

  4. EF 多对多循环引用序列化失败 解决办法

    错误:Self referencing loop detected with type 'System.Data.Entity.DynamicProxies.tbldph_901D48A194FB31 ...

  5. 【cocos2d-x 手游研发小技巧(2)循环无限滚动的登陆背景】

    原创文章,转载请附上链接:http://www.cnblogs.com/zisou/p/cocos2d-xARPG6.html 首先让大家知道我们想要实现的最终效果是什么样的? 看一个<逆天仙魔 ...

  6. TDDL与Spring Boot集成Version报错——跟踪与解决

    先说背景:公司采用diamond+tddl,这套技术来做web管理.本人处于好奇率先体验了下spring-boot,于是就有了spring-boot+tddl的组合.但是jar包上线后,屡屡发现一条e ...

  7. tomcat安装配置常见问题详解

    历经波折,终于把tomcat装好了.记录下过程供自己和后来的初学者参考吧! 本文先后介绍了tomcat的下载安装方法.安装和启动不成功的常见原因 以及启动tomcat后如何配置上下文. 一.下载安装 ...

  8. Hive导出表数据

    法一: hive (stuchoosecourse) > insert overwrite local directory '/home/landen/文档/exportDir'         ...

  9. WSGI学习系列WebOb

    1. WSGI Server <-----> WSGI Middleware<-----> WSGI Application  1.1 WSGI Server wsgi ser ...

  10. jQuery中的100个技巧(译)

    1.当document文档就绪时执行JavaScript代码. 我们为什么使用jQuery库呢?原因之一就在于我们可以使jQuery代码在各种不同的浏览器和存在bug的浏览器上完美运行. <sc ...