C語言實現將彩色BMP位圖轉化爲二值圖

CTF作了圖片的隱寫題,尚未造成系統的認識,先來總結一下BMP圖的組成,並經過將彩色圖轉爲二值圖的例子加深下理解。html

只寫了位圖二進制文件的格式和代碼實現,至於諸如RGB色彩和調色板是什麼的一些概念就不囉嗦了。測試

BMP位圖文件格式htm

    BMP文件由文件頭、位圖信息頭、調色板和圖形數據四部分組成,真彩色圖是沒有調色板的。每部分的具體結構在代碼中具體列出並解釋。blog

 

結構體的對齊索引

    定義文件頭部各結構體時要注意對齊的問題,至於什麼是結構體對齊,請看這篇博文,寫的很詳細http://www.cnblogs.com/motadou/archive/2009/01/17/1558438.html圖片

 

位圖的四字節對齊內存

    這個對齊是位圖每行像素的對齊,不要和上面的結構體對齊混淆,每行像素所佔字節數必須是4字節的整數倍,不足的要填充,這時由於內存分配單位是32位的,即4字節,讀入的每行像素是連續的,不能和其餘行共佔一個內存單位get

 

彩色圖轉爲灰度圖it

    RGB共有256種灰色份量,就是R=G=B時的色彩是灰色的,因此能夠用一個字節來表示,將彩色圖轉化爲灰度圖就是讓真彩色圖的三個顏色份量等於一個相同的數值,具體等於多少能夠與多種方法,好比求三個份量的平均值,取三個份量的最大值或者使其中兩個份量等於另外一個份量的值,還有一種經常使用的方法是取加權平均值,根據這個很著名的心理學公式Gray = R*0.299 + G*0.587 + B*0.114io

 

灰度圖轉化爲二值圖

    二值圖只有兩個顏色,黑和白,而灰度有256種顏色,將灰度轉化爲二值是選取一個閾值,將灰度值大於這個閾值的置成白色,反之爲黑色,關於這個閾值如何選取和做用範圍也有多種方法,再也不贅述,爲了簡單我在全局範圍內選用一個固定的閾值190(針對我這張測試圖片,手敲了個190,轉化的效果還能夠)二值圖只有兩個索引,能夠用1bit表示,可是我寫的程序是用1個字節表示的,至於如何壓縮,看你嘍。。。

 

說了這麼多,仍是看代碼吧,這樣更容易理解,額,好像幾乎給每行都寫了註釋╮(╯▽╰)╭,不要嫌我墨跡

複製代碼

1 /*
  2 Author:蔚藍行
  3 Blog:http://www.cnblogs.com/duanv/
  4 */
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 
  8 /*位圖文件頭*/
  9 #pragma pack(1)//單字節對齊
 10 typedef struct tagBITMAPFILEHEADER
 11 {
 12   unsigned char bfType[2];//文件格式
 13   unsigned int bfSize;//文件大小
 14   unsigned short bfReserved1;//保留
 15   unsigned short bfReserved2;//保留
 16   unsigned int bfOffBits;//數據偏移量
 17 }fileHeader;
 18 #pragma pack()
 19 
 20 /*位圖信息頭*/
 21 #pragma pack(1)
 22 typedef struct tagBITMAPINFOHEADER
 23 {
 24   unsigned int biSize;//BITMAPINFOHEADER結構所須要的字數
 25   int biWidth;//圖像寬度,像素爲單位
 26   int biHeight;//圖像高度,像素爲單位,爲正數,圖像是倒序的,爲負數,圖像是正序的
 27   unsigned short biPlanes;//爲目標設備說明顏色平面數,總被置爲1
 28   unsigned short biBitCount;//說明比特數/像素
 29   unsigned int biCompression;//說明數據壓縮類型
 30   unsigned int biSizeImage;//說明圖像大小,字節單位
 31   int biXPixPerMeter;//水平分辨率,像素/米
 32   int biYPixPerMeter;//垂直分辨率
 33   unsigned int biClrUsed;//顏色索引數
 34   unsigned int biClrImportant;//重要顏色索引數,爲0表示都重要
 35 }fileInfo;
 36 #pragma pack()
 37 
 38 /*調色板結構*/
 39 #pragma pack(1)
 40 typedef struct tagRGBQUAD
 41 {
 42   unsigned char rgbBlue;//藍色分亮度
 43   unsigned char rgbGreen;//綠色分亮度
 44   unsigned char rgbRed;//紅色分亮度
 45   unsigned char rgbReserved;
 46 }rgbq;
 47 #pragma pack()
 48 
 49 int main()
 50 {
 51   /*變量聲明*/
 52   FILE *fpBMP,*fpTwoValue;//源文件fpBMP,目標文件fpTwoValue
 53   
 54   fileHeader *fh;//位圖文件頭
 55   fileInfo *fi;//位圖信息頭
 56   rgbq *rg;//調色板
 57 
 58   int i,j,k=0;
 59   unsigned char *a;//存儲源圖每行像素值
 60   unsigned char b;//存儲每一個像素的灰度值或二值
 61   unsigned char *c;//存儲每行像素的二值
 62   
 63   /********************************************************************/
 64 
 65   /*打開源文件,建立輸出文件*/
 66   if((fpBMP=fopen("/Users/SPY/Desktop/1.bmp","rb"))==NULL){
 67     printf("file open failed");
 68     exit(0);
 69   }
 70   
 71   if((fpTwoValue=fopen("/Users/SPY/Desktop/2.bmp","wb"))==NULL){
 72     printf("file creat failed");
 73     exit(0);
 74   }
 75   
 76   /********************************************************************/
 77   
 78   /*建立位圖文件頭,信息頭,調色板*/
 79   fh=(fileHeader *)malloc(sizeof(fileHeader));
 80   fi=(fileInfo *)malloc(sizeof(fileInfo));
 81   rg=(rgbq *)malloc(2*sizeof(rgbq));
 82   
 83   /*讀入源位圖文件頭和信息頭*/
 84   fread(fh,sizeof(fileHeader),1,fpBMP);
 85   fread(fi,sizeof(fileInfo),1,fpBMP);
 86 
 87   /*修改文件頭,信息頭信息*/
 88   fi->biBitCount=8;//轉換成二值圖後,顏色深度由24位變爲8位
 89   fi->biSizeImage=((fi->biWidth+3)/4)*4*fi->biHeight;//每一個像素由三字節變爲單字節,同時每行像素要四字節對齊
 90   fi->biClrUsed=2;//顏色索引表數量,二值圖爲2
 91   fi->biClrImportant=0;//重要顏色索引爲0,表示都重要
 92   fh->bfOffBits=sizeof(fileHeader)+sizeof(fileInfo)+2*sizeof(rgbq);//數據區偏移量,等於文件頭,信息頭,索引表的大小之和
 93   fh->bfSize=fh->bfOffBits+fi->biSizeImage;//文件大小,等於偏移量加上數據區大小
 94   rg[0].rgbBlue=rg[0].rgbGreen=rg[0].rgbRed=rg[0].rgbReserved=0;//調色板顏色爲黑色對應的索引爲0
 95   rg[1].rgbBlue=rg[1].rgbGreen=rg[1].rgbRed=255;//白色對應的索引爲1
 96   rg[1].rgbReserved=0;
 97 
 98   /********************************************************************/
 99   
100   /*將位圖文件頭,信息頭和調色板寫入文件*/
101   fwrite(fh,sizeof(fileHeader),1,fpTwoValue);
102   fwrite(fi,sizeof(fileInfo),1,fpTwoValue);
103   fwrite(rg,2*sizeof(rgbq),1,fpTwoValue);
104 
105   /*將彩色圖轉爲二值圖*/
106   a=(unsigned char *)malloc((fi->biWidth*3+3)/4*4);//給變量a申請源圖每行像素所佔大小的空間,考慮四字節對齊問題
107   c=(unsigned char *)malloc((fi->biWidth+3)/4*4);//給變量c申請目標圖每行像素所佔大小的空間,一樣四字節對齊
108   
109   for(i=0;i<fi->biHeight;i++){//遍歷圖像每行的循環
110     for(j=0;j<((fi->biWidth*3+3)/4*4);j++){//遍歷每行中每一個字節的循環
111         fread(a+j,1,1,fpBMP);//將源圖每行的每個字節讀入變量a所指向的內存空間
112         //printf("%d ",a[j]);
113     }
114     for(j=0;j<fi->biWidth;j++){//循環像素寬度次,就不會計算讀入四字節填充位
115         b=(int)(0.114*(float)a[k]+0.587*(float)a[k+1]+0.299*(float)a[k+2]);//a中每三個字節分別表明BGR份量,乘上不一樣權值轉化爲灰度值
116         //printf("%d",b);
117         if(190<=(int)b) b=1;//將灰度值轉化爲二值,這裏選取的閾值爲190
118         else b=0;
119         c[j]=b;//存儲每行的二值
120         k+=3;
121     }
122     fwrite(c,(fi->biWidth+3)/4*4,1,fpTwoValue);//將二值像素四字節填充寫入文件,填充位沒有初始化,爲隨機值
123     k=0;
124   }
125 
126   /********************************************************************/
127   
128   /*釋放內存空間,關閉文件*/
129   free(fh);
130   free(fi);
131   free(rg);
132   free(a);
133   free(c);
134   fclose(fpBMP);
135   fclose(fpTwoValue);
136   printf("success!\n");
137   return 0;
138 }

複製代碼

相關文章
相關標籤/搜索