(续)一个demo弄清楚位图在内存中的存储结构

本来续---数字图像处理之位图在计算机中的存储结构一文,通过参考别人的代码,进行修改和测试终于成功运行


该实例未使用任何API和相关类,相信如果对此实例能够完全理解那么将有进一步进行数字图像处理的能力。

该实例实现三个功能:

1.读取位图文件数据。

2.将位图中像素数据保存到TXT中。

3.根据读取的位图函数中的数据保存位图文件。

具体代码如下,并附有详细注释:


头文件BmpNew.h如下:

 1 typedef unsigned char BYTE;
 2 typedef unsigned short WORD;
 3 typedef unsigned int DWORD;
 4 typedef long LONG;
 5 
 6 //位图文件头定义;
 7 //其中不包含文件类型信息(由于结构体的内存结构决定,
 8 //要是加了的话将不能正确读取文件信息)
 9 typedef struct  tagBITMAPFILEHEADER{
10     //WORD bfType;//文件类型,必须是0x424D,即字符“BM”
11     DWORD bfSize;//文件大小
12     WORD bfReserved1;//保留字
13     WORD bfReserved2;//保留字
14     DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
15 }BITMAPFILEHEADER;
16 
17 typedef struct tagBITMAPINFOHEADER{
18     DWORD biSize;//信息头大小
19     LONG biWidth;//图像宽度
20     LONG biHeight;//图像高度
21     WORD biPlanes;//位平面数,必须为1
22     WORD biBitCount;//每像素位数
23     DWORD  biCompression; //压缩类型
24     DWORD  biSizeImage; //压缩图像大小字节数
25     LONG  biXPelsPerMeter; //水平分辨率
26     LONG  biYPelsPerMeter; //垂直分辨率
27     DWORD  biClrUsed; //位图实际用到的色彩数
28     DWORD  biClrImportant; //本位图中重要的色彩数
29 }BITMAPINFOHEADER; //位图信息头定义
30 
31 typedef struct tagRGBQUAD{
32     BYTE rgbBlue; //该颜色的蓝色分量
33     BYTE rgbGreen; //该颜色的绿色分量
34     BYTE rgbRed; //该颜色的红色分量
35     BYTE rgbReserved; //保留值
36 }RGBQUAD;//调色板定义

源文件BmpNew.cpp如下:

  1 #include<math.h>  
  2 #include <iomanip.h>   
  3 #include <stdlib.h>  
  4 #include <windows.h>  
  5 #include <stdio.h>  
  6 #include <stdlib.h>  
  7 #include <fstream.h>        
  8 
  9 
 10 
 11 
 12 /************************************************************************/
 13 
 14 /*以下该模块是完成BMP图像(彩色图像是24bit RGB各8bit)的像素获取,
 15 
 16                 并存在文件名为xiang_su_zhi.txt中  
 17                                                                     */
 18 /************************************************************************/
 19 
 20 //用到的全局变量 
 21   
 22 unsigned char *pBmpBuf;//读入图像数据的指针 
 23        
 24 int bmpWidth;//图像的宽  
 25 
 26 int bmpHeight;//图像的高 
 27  
 28 RGBQUAD *pColorTable;//颜色表指针  
 29 
 30 int biBitCount;//图像类型,每像素位数  
 31 
 32 
 33 
 34 /************************************************************************/
 35 
 36 /*                读图像的位图数据、宽、高、颜色表及
 37 
 38             每像素位数等数据进内存,存放在相应的全局变量中      
 39                                                                 */
 40 /************************************************************************/    
 41 
 42 bool readBmp(char *bmpName)   
 43 {
 44     
 45     FILE *fp=fopen(bmpName,"rb");//二进制只读方式打开指定的图像文件  
 46     
 47     if(fp==0)            //判断文件是否正确打开
 48         return 0;  
 49 
 50 
 51     //跳过位图文件头结构BITMAPFILEHEADER,使得文件指针指向信息头的开始 
 52      fseek(fp, sizeof(BITMAPFILEHEADER),0);  
 53 
 54     //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中,为了获取图像的宽,高,每像素所占位数 
 55     BITMAPINFOHEADER head;   
 56     fread(&head, sizeof(BITMAPINFOHEADER), 1,fp); 
 57 
 58     //获取图像宽、高、每像素所占位数等信息  
 59     bmpWidth = head.biWidth;  
 60     bmpHeight = head.biHeight;
 61     biBitCount = head.biBitCount;
 62 
 63     //定义变量,计算图像每行像素所占的字节数(必须是4的倍数)    
 64     int lineByte=(bmpWidth * biBitCount/8+3)/4*4;
 65 
 66     //灰度图像有颜色表(调色板),且颜色表表项为256  
 67     if(biBitCount==8) 
 68     {  
 69         //申请颜色表所需要的空间,读颜色表进内存  
 70         pColorTable=new RGBQUAD[256];     //申请256种颜色表大小的内存
 71         fread(pColorTable,sizeof(RGBQUAD),256,fp);  //读取概灰度图的颜色表到pColorTable所指向的内存中
 72     }   
 73 
 74     //申请位图数据所需要的空间,读位图数据进pBmpBuf指向的内存  
 75     pBmpBuf=new unsigned char[lineByte * bmpHeight];  
 76     fread(pBmpBuf,1,lineByte * bmpHeight,fp); 
 77     
 78 
 79     fclose(fp);//关闭文件   
 80     return 1;//读取文件成功 
 81     
 82 }
 83 
 84 
 85 
 86 
 87 /************************************************************************/
 88 
 89 /*        给定一个图像位图数据、宽、高、颜色表指针及
 90 
 91         每像素所占的位数等信息,将其写到指定文件中
 92                                                                       */
 93 /************************************************************************/
 94 
 95 bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)  
 96 {    
 97     //如果位图数据指针为0,则没有数据传入,函数返回  
 98     if(!imgBuf)  
 99         return 0;  
100 
101     //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0        
102         int colorTablesize=0;  
103 
104         if(biBitCount==8)  
105                 colorTablesize=1024;//一个RGBQUAD(颜色)结构占四个字节,对于8位的灰度图而言,一共有256*4=1024个字节大小的颜色表   
106 
107         //待存储图像数据每行字节数为4的倍数    
108         int lineByte=(width * biBitCount/8+3)/4*4; 
109         
110         //以二进制写的方式打开文件   
111         FILE *fp=fopen(bmpName,"wb");  
112         if(fp==0)  
113             return 0;  
114 
115         //申请位图文件头结构变量,填写文件头信息  
116         BITMAPFILEHEADER fileHead;    
117         fileHead.bfType = 0x4D42;//bmp类型  
118 
119         //bfSize是图像文件4个组成部分之和   
120         fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;  
121         fileHead.bfReserved1 = 0;        
122         fileHead.bfReserved2 = 0; 
123         
124 
125         //bfOffBits是图像文件前3个部分所需空间之和        
126         fileHead.bfOffBits=54+colorTablesize;  
127 
128         //写文件头进文件  
129         fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);  
130         
131 
132         //申请位图信息头结构变量,填写信息头信息  
133          BITMAPINFOHEADER head;   
134           head.biBitCount=biBitCount;  
135           head.biClrImportant=0;  
136           head.biClrUsed=0;  
137           head.biCompression=0;  
138           head.biHeight=height;        
139           head.biPlanes=1;  
140           head.biSize=40;        
141           head.biSizeImage=lineByte*height;  
142           head.biWidth=width;  
143           head.biXPelsPerMeter=0;        
144           head.biYPelsPerMeter=0; 
145           
146         //写位图信息头进内存   
147         fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);    
148 
149         //如果灰度图像,有颜色表,写入文件   
150             if(biBitCount==8)  
151                 fwrite(pColorTable, sizeof(RGBQUAD),256, fp);  
152 
153         //写位图数据进文件  
154         fwrite(imgBuf, height*lineByte, 1, fp); 
155            
156         //关闭文件    
157         fclose(fp);  
158         return 1;        
159 }  
160 
161 /************************************************************************/
162 
163 /*                以下为像素的读取函数                                    */
164 
165 /************************************************************************/ 
166 void doIt()  
167 {  
168     //读入指定BMP文件进内存        
169     char readPath[]="test.bmp";  
170 
171     //读取图像信息
172     readBmp(readPath); 
173     
174     //输出图像的信息  宽度(单位像素) 高度(单位像素) 每个像素的位数
175      cout<<"width="<<bmpWidth<<" height="<<bmpHeight<<" biBitCount="<<biBitCount<<endl;     
176      
177      //循环变量,图像的坐标  
178      //每行字节数  
179          int lineByte=(bmpWidth*biBitCount/8+3)/4*4;
180          
181          //循环变量,针对彩色图像,遍历每像素的三个分量
182           int m=0,n=0,count_xiang_su=0;  
183 
184          //将图像左下角1/4部分置成黑色         
185          ofstream outfile("test2.txt",ios::in|ios::trunc); //概txt文档用于保存图像的像素数据,以8*8的矩阵形式输出
186          
187          if(biBitCount==8) //对于灰度图像  
188          { 
189 
190              /************************************************************************/
191 
192              /*    以下完成图像的分割成8*8小单元,并把像素值存储到指定文本中
193 
194              由于BMP图像的像素数据是从左下角:由左往右,由下往上逐行扫描的*/
195              
196              /************************************************************************/
197 
198              int L1=0;  
199              int hang=63;  
200              int lie=0;  
201              //int L2=0;  
202              //int fen_ge=8; 
203              
204              //-----------------------------------------------------------------
205               //最外层for循环控制行,一次八行
206              //-----------------------------------------------------------------
207              for(int fen_ge_hang=0;fen_ge_hang<8;fen_ge_hang++)//64*64矩阵行循环  
208              {   
209                  //-----------------------------------------------
210                    //第三层for循环按列循环,循环8次8列,至此最后8列被分成了8个8*8矩阵保存在文本文档中
211                  //-----------------------------------------------
212                  for(int fen_ge_lie=0;fen_ge_lie<8;fen_ge_lie++)//64*64列矩阵循环  
213                  {   
214                      //----------------------------------------------------------------
215                        //最内层的两个for循环循环从最后一行左边开始读取8*8矩阵到txt文件中
216                      //----------------------------------------------------------------  
217                      for(L1=hang;L1>hang-8;L1--)//8*8矩阵行  
218                      {  
219                          for(int L2=lie;L2<lie+8;L2++)//8*8矩阵列  
220                          {  
221                              m=*(pBmpBuf+L1*lineByte+L2);
222                              
223                              outfile<<m<<" "; 
224                                  
225                              count_xiang_su++; 
226                              
227                              if(count_xiang_su%8==0)//每8*8矩阵读入文本文件  
228                                  outfile<<endl;  
229                          }  
230                      }
231                     //---------------------------------------------
232 
233                      hang=63-fen_ge_hang*8;//64*64矩阵行变换 
234                      
235                      lie+=8;//64*64矩阵列变换  
236 
237                         //该一行(64)由8个8*8矩阵的行组成  
238                  }  
239                  hang-=8;//64*64矩阵的列变换
240                  
241                  lie=0;//64*64矩阵
242              }  
243          }  
244          
245          //判断概灰度图像数据是否写入到文本文档中
246          if(!outfile)  
247          {  
248              cout<<"open error!"<<endl;  
249 
250              exit(1);  
251          }  
252 
253 
254 
255          else    if(biBitCount==24)  
256          {
257              //彩色图像  
258              //-------------------------------------------------------
259                 //彩色图像的读取是每次读一行从左上角开始读,最外层控制行
260                     //第二次for控制列,而彩色图每个像素由三个字节的颜色描述
261                     //所以第三个for是将每个像素的R,G,B分量依次读入到文本
262                     //文档中
263              //-------------------------------------------------------
264              for(int i=0;i<bmpHeight;i++)  
265              {  
266                  for(int j=0;j<bmpWidth;j++)  
267                  {  
268                      for(int k=0;k<3;k++)//每像素RGB三个分量分别置0才变成黑色  
269                      {   
270                          m=*(pBmpBuf+i*lineByte+j*3+k);  
271 
272                          outfile<<m<<" ";  
273 
274                          count_xiang_su++;  
275 
276                          if(count_xiang_su%8==0)  
277                          {  
278                              outfile<<endl;  
279                          }                        
280                      }  
281                      n++;   //计算RGB图的像素
282                  }  
283                  
284              }  
285              cout<<"总的像素个素为:"<<n<<endl;  
286              cout<<"----------------------------------------------------"<<endl;  
287          }  
288          
289 
290 
291          //将图像数据存盘  
292          
293          char writePath[]="f.bmp";
294 
295          //图片处理后再存储  
296          saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable); 
297          
298 
299          //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间  
300          delete []pBmpBuf;  
301          
302          if(biBitCount==8)  
303              delete []pColorTable;  
304     }  
305 
306 
307 
308 /************************************************************************/
309 
310 /*                             主函数                                      */
311 
312 /************************************************************************/
313 
314 
315 void main()  
316 {  
317     doIt();  
318 }

测试的test.bmp图片如下:



输出保存的图片如下f.tmp:



保存的text2.txt截图如下:



至此,对于一张灰度BMP图像数据的读取,像素数据保存,以及存盘显示就已经完整的实现了,代码中或许

会有bug,请读者批评指正,共同完善。

作者:vpoet
点击这里给我发消息
出处:http://www.cnblogs.com/vpoet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/vpoet/p/4659775.html