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. SQL笔记---分页

    随用随想,随用随记. 通过实际应用掌握SQL语句. 一. SQL分页 1. 第一种方法:利用ID大于多少进行筛选 SELECT TOP 20        *FROM    dbo.WMS_Stock ...

  2. INNER JOIN与LEFT JOIN在SQL Server的性能

    我创建了INNER JOIN 9桌,反正需要很长的(超过五分钟).所以,我的民歌改变INNER JOIN来LEFT JOIN LEFT JOIN的性能较好,在首次尽管我所知道的.之后我变了,查询的速度 ...

  3. [ASP.NET]关于DOT NET的IIS配置LocalHost访问和127.0.0.1访问的区别

    项目上遇到一个问题跟大家分享下,配置的localhost地址本地无法访问接口,外网却可以访问,查其原因百度资料比较全面的解释 localhost与127.0.0.1的概念和工作原理之不同 要比较两个东 ...

  4. vs2017 xamarin新建单独UWP类库提示不兼容

    One or more projects are incompatible with UAP,Version=v10.0 (win10-arm). One or more projects are i ...

  5. ASP.NET MVC 富文本Ueditor编辑 后台传值前端乱码解决方案

    只是将当前内容String当成Html插入,我想是跟数据类型转换差不多 //把内容赋值给ueditor var ue = UE.getEditor('editor');//实例化 ue.ready(f ...

  6. Regularjs是什么

    本文由作者郑海波授权网易云社区发布. 此文摘自regularjs的指南, 目前指南正在全面更新, 把老文档的[接口/语法部分]统一放到了独立的 Reference页面. Regularjs是基于动态模 ...

  7. 程序媛计划——python数据库

    #实例:用数据库存储日记,实现日记本功能 #流程 #创建数据库 #coding:utf-8 import sqlite3 connect=sqlite3.connect('test.db') conn ...

  8. A - Subsequence (算法 二分 )

    点击打开链接 A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 1 ...

  9. python打造渗透工具集

    python是门简单易学的语言,强大的第三方库让我们在编程中事半功倍,今天我们就来谈谈python在渗透测试中的应用,让我们自己动手打造自己的渗透工具集. 难易程度:★★★阅读点:python;web ...

  10. 【xsy1172】 染色 dp

    题目大意:现有$n$条排成一行的木板,每个木板有一个目标颜色.你每次能将一个区间内的木板分别染成它们的目标颜色,而这次染色的代价为这个区间内不同目标颜色的木板的数量的平方.问将全部木板染成目标颜色的最 ...