第一章:CDib類庫的建立


VC++圖像處理程序設計(第1版)    楊淑瑩 編著     邊奠英 主審
第一章 位圖基礎
Joanna-In-Hdu&Hust 手工打,印象更深刻
使用工具 VS2010 mfc
 整本書的代碼文件、測試圖片和程序運行exe請在這里下載https://github.com/CaptainLYN/VCPictureProcessing
 
圖形是矢量,顯式地表示圖畫內容坐標值;圖像是位圖,適於表現大量細節,一般需要壓縮。
 
紅、綠、藍,簡稱RGB三原色。每一個點都是由RGB三個分量的顏色來共同決定。
分辨率:單位長度內的像素數,單位是每英寸的點數DPI(dots per inch)。
圖像分辨率是實際精度,顯示分辨率是表現精度。
 
單色圖像:0表示黑,1表示白。
灰度圖像:帶有顏色表,共256項,RGB三分量值相同;每個像素由8位組成,0~255,每個圖像的的f(x,y)是顏色表的表項入口。
偽彩色圖像:RGB三分量不全相等;像素8位,每個像素的像素值表示的不是顏色分量而是顏色表的表項入口,整個圖像只有256種顏色。
24位真彩色:不帶有顏色表;RGB三分量各占8位,0~255,,所以每個像素是24位,像素值就是顏色值;從左到右存儲藍、綠、紅顏色值。
 
位圖:位數據以行為單位存儲,每行長度為4字節倍數,不足補0;
位圖行的存儲次序是顛倒的,即第一行對應位圖最底行。
位圖文件頭結構 BITMAPFILEHEADER
位圖信息頭結構 BITMAPINFOHEADER
位圖顏色表 RGBQUAD
位圖像素數據
 
位圖文件頭:
1 typedef struct tagBITMAPFILEHEADER 2 { 3 WORD bftype;//位圖文件的類型,必須為BMP,0x4d42
4 DWORD bfsize;//位圖文件的大小,以字節為單位
5 WORD bfReaserved1;//位圖文件保留字,必須為0
6 WORD bfReaserved2;//位圖文件保留字,必須為0
7 DWORD bfOffBits;//位圖數據的起始位置,相對於位圖文件頭的偏移量表示,以字節為單位
8 }BITMAPFILEHEADER;
位圖信息頭:
 1 typedef struct tagBITMAPINFOHEADER  2 {  3 DWORD biSize;//本結構所占用字節數
 4 LONG biWidth;//位圖的寬度,以像素為單位
 5 LONG biHeight;//位圖的高度,以像素為單位
 6 WORD biPlanes;//目標設備的級別,必須為1
 7 WORD biBitCount;//每個像素所需的位數,1、4、8、24
 8 DWORD biCompression;/*位圖壓縮類型,必須為0(不壓縮)、1(BI_RLE8壓縮類型)、2(BI_RLE4壓縮類型)之一*/
 9 DWORD biSizeImage;//位圖的大小,以字節為單位
10 LONG biXPelsPerMeter;//位圖水平分辨率,每米像素數
11 LONG biYPelsPerMeter;//位圖垂直分辨率,每米像素數
12 DWORD biClrUsed;//位圖實際使用的顏色表的顏色數
13 DWORD biClrImportant;//位圖顯示過程中重要的顏色數
14 }BITMAPINFOHEADER;
顏色表:
1 typedef struct tagRGBQUAD 2 { 3 BYTE rgbBlue;//藍色的亮度(0~255)
4 BYTE rgbGreen;//綠色
5 BYTE rgbRed;//紅色
6 BYTE rgbReserved;//保留,必須為0
7 }RGBQUAD;

 

顏色表中RGBQUAD結構數據的個數由biBitCount來確定:biBitCount=1,4,8時,分別有2,16,256個表項;biBitCount=24時,沒有表項。
 
typedef是用后面代替前面,define是前面代替后面。
 
接下來是CDib.h的代碼:
 1 /*
 2 #ifndef _CDIB_H_ //代表這個頭文件里的變量只編譯一次  3 #define _CDIB_H_  4 */
 5 #pragma once
 6 
 7 class CDib:public CObject  8 {  9 public: 10     RGBQUAD* m_pRGB;//顏色表指針
11     BYTE* m_pData,*m_pData2;//m_pData指向原數據,m_pData2指向灰度數據
12     UINT m_numberOfColors;//位圖顏色數目
13     BOOL m_valid;//是否載入了位圖文件
14     BITMAPFILEHEADER bitmapFileHeader;//位圖文件頭
15     
16     BITMAPINFOHEADER* m_pBitmapInfoHeader;//位圖信息頭
17     BITMAPINFO* m_pBitmapInfo;//位圖信息指針
18     int byBitCount; 19     DWORD dwWidthBytes;//DWORD 就是Double Word,4個字節,32位,位圖的寬度字節數
20     BYTE* pDib;//文件中位圖總數據指針,也就是讀入內存所以數據的第一個
21     DWORD size;//位圖總數據的長度
22 
23 public: 24  CDib(); 25     ~CDib(); 26 
27     char m_fileName[256];//文件名
28     char* GetFileName(); 29     BOOL IsValid();//是否載入了位圖文件
30  DWORD GetSize(); 31  UINT GetWidth(); 32  UINT GetHeight(); 33  UINT GetNumberOfColors(); 34     RGBQUAD* GetRGB();//獲取顏色表指針
35     BYTE* GetData(); 36     BYTE* GetData2(); 37  DWORD GetDibWidthBytes(); 38     BITMAPINFO* GetInfo();//獲取位圖信息結構的指針
39     WORD PaletteSize(LPBYTE IpDIB);//位圖指針指向的位圖調色板的大小
40     WORD DIBNumColors(LPBYTE IpDIB);//。。。。。。顏色的數目
41     void SaveFile(const CString filename); 42     //DWORD GetFilesize();
43 public: 44     void GradetoRGB(); 45     void RGBtoGrade(); 46     void LoadFile(CString dibFileName); 47 }; 48 
49 //#endif

 

然后是DIB.cpp實現文件:  

 

 1 #include"stdafx.h"
 2 #include"CDib.h"
 3 #include<WindowsX.h>
 4 #define WIDTHBYTES(bits) (((bits)+31)/32*4)  //用前面一個代替后面的
 5 CDib::CDib()  6 {  7      
 8 }  9 CDib::~CDib()  10 {  11     GlobalFreePtr(m_pBitmapInfo);//釋放在loadfile函數中在堆中申請的資源
 12 }  13 void CDib::LoadFile(CString m_filename)//靜態不允許修改
 14 {  15     //strcpy(m_fileName,dibFileName);
 16     CFile dibFile(m_filename,CFile::modeRead);//構造函數初始化,制度打開文件,LPCTSTR就是const char*,unicode通用字符集
 17     dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));  18     if(bitmapFileHeader.bfType==0x4d42)//位圖文件的類型,就是十進制19778
 19  {  20         DWORD fileLength=dibFile.GetLength();  21         /*DWORD*/ size=fileLength-sizeof(BITMAPFILEHEADER);//圖像內容的實際大小+顏色表+位圖文件信息頭
 22         /*BYTE**/ pDib=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size);//從堆中分配屬性為GMEM_MOVEABLE(win32平台和GMEM_FIXED固定的已經沒有大區別)、size大小的可移動內存
 23         dibFile.Read((void*)pDib,size);//從上述關聯的文件中讀取size大小的數據放入指針緩沖區,每讀一次讀取指針的位置移動size大小,文件頭已經讀取過了,這是包含信息頭的數據
 24  dibFile.Close();  25 
 26         m_pBitmapInfo=(BITMAPINFO*)pDib;//現在它指向的就是位圖信息,也是位圖信息的第一個成員的位置
 27         m_pBitmapInfoHeader=(BITMAPINFOHEADER*)pDib;  28         m_pRGB=(RGBQUAD*)(pDib+m_pBitmapInfoHeader->biSize);//指向顏色表
 29         int m_numberOfColors=GetNumberOfColors();//2、16、256或者是真彩色
 30         if(m_pBitmapInfoHeader->biClrUsed==0)//位圖實際使用的顏色表中的顏色數是不對的,就修改
 31             m_pBitmapInfoHeader->biClrUsed=m_numberOfColors;  32         DWORD colorTableSize=m_numberOfColors*sizeof(RGBQUAD);//調色板的大小
 33         m_pData=pDib+m_pBitmapInfoHeader->biSize+colorTableSize;//顏色數據的真正起始位置
 34         if(m_pRGB==(RGBQUAD*)m_pData)//如果沒有調色板
 35             m_pRGB=NULL;  36         m_pBitmapInfoHeader->biSizeImage=GetSize();//位圖的大小,以字節為單位
 37         m_valid=TRUE;  38  }  39     else
 40  {  41         m_valid=FALSE;  42         MessageBox(NULL,_T("這不是位圖文件!"),_T("提示"),MB_OK);//這里做了修改,關於書
 43  }  44 }  45 
 46 BOOL CDib::IsValid()  47 {  48     return m_valid;  49 }  50 
 51 char*CDib::GetFileName()  52 {  53     return m_fileName;  54 }  55 
 56 UINT CDib::GetWidth()  57 {  58     return (UINT)m_pBitmapInfoHeader->biWidth;  59 }  60 
 61 UINT CDib::GetHeight()  62 {  63     return (UINT)m_pBitmapInfoHeader->biHeight;  64 }  65 
 66 DWORD CDib::GetSize()  67 {  68     if(m_pBitmapInfoHeader->biSizeImage!=0)//位圖的大小
 69         return m_pBitmapInfoHeader->biSizeImage;  70     else
 71     {//不對就自己計算
 72         DWORD height=(DWORD)GetHeight();  73         DWORD width=(DWORD)GetWidth();  74         return height*/*width */GetDibWidthBytes();  75  }  76 }  77 
 78 
 79 //返回行字節數
 80 DWORD CDib::GetDibWidthBytes()  81 {  82     byBitCount=m_pBitmapInfoHeader->biBitCount;//每個像素所需的位數:1、4、8、真彩色
 83     LONG nWidth=m_pBitmapInfoHeader->biWidth;//位圖的寬度,以像素為單位
 84 
 85     dwWidthBytes=(DWORD)m_pBitmapInfoHeader->biWidth;//位圖的寬度字節數
 86     if(byBitCount==1) dwWidthBytes=(nWidth+7)/8;//一位像素,那按字節計算就應該除8
 87     else if(byBitCount==4) dwWidthBytes=(nWidth+1)/2;  88     else if(byBitCount==24) dwWidthBytes=nWidth*3;//因為真彩色每個像素是24位
 89 
 90     while((dwWidthBytes&3)!=0) dwWidthBytes++;//是否為4的倍數,因為位圖每行為4的倍數,不足補0
 91 
 92     return dwWidthBytes;  93 }  94 
 95 //返回位圖顏色數目
 96 UINT CDib::GetNumberOfColors()  97 {  98     int numberOfColors;  99 
100     if((m_pBitmapInfoHeader->biClrUsed==0)&&(m_pBitmapInfoHeader->biBitCount<9)) 101  { 102         switch(m_pBitmapInfoHeader->biBitCount) 103  { 104         case 1:numberOfColors=2;break; 105         case 4:numberOfColors=16;break; 106         case 8:numberOfColors=256; 107  } 108  } 109     else
110         numberOfColors=(int)m_pBitmapInfoHeader->biClrUsed;//如果是真彩色,就是實際使用的顏色
111     return numberOfColors; 112 } 113 
114 BYTE* CDib::GetData() 115 { 116     return m_pData; 117 } 118 
119 BYTE* CDib::GetData2() 120 { 121     if(GetRGB()) 122         m_pData2=m_pData;//有顏色表的情況下兩個相同
123     return m_pData2; 124 } 125 
126 RGBQUAD* CDib::GetRGB() 127 { 128     return m_pRGB; 129 } 130 
131 BITMAPINFO* CDib::GetInfo() 132 { 133     return m_pBitmapInfo;//位圖信息指針
134 } 135 
136 WORD CDib::PaletteSize(LPBYTE lpDIB)//LPBYTE是BYTE指針
137 { 138     return (DIBNumColors(lpDIB)*sizeof(RGBQUAD/*RGBTRIPLE*/));//位圖指針指向的顏色的數目*每一個顏色的大小,顏色表的位總大小
139 } 140 
141 //應該是返回顏色表中的數據項數
142 WORD CDib::DIBNumColors(LPBYTE lpDIB) 143 { 144     WORD wBitCount;//設備無關圖的位數 145     //wBitCount=((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;//每個顏色的位數
146     wBitCount=((LPBITMAPINFOHEADER)lpDIB)->biBitCount; 147     switch(wBitCount) 148  { 149     case 1:return 2; 150     case 4:return 16; 151     case 8:return 256; 152     default:return 0; 153  } 154 } 155 
156 void CDib::SaveFile(const CString filename) 157 { 158  BITMAPFILEHEADER bmfHdr; 159  LPBITMAPINFOHEADER lpBI; 160  DWORD dwDIBSize; 161 
162     bmfHdr.bfType=0x4d42;//"BM"
163     lpBI=(LPBITMAPINFOHEADER)m_pBitmapInfoHeader; 164 
165     dwDIBSize=*(LPDWORD)lpBI+PaletteSize((LPBYTE)lpBI);//位圖數據和信息頭+顏色表的位大小,這里只有后兩部分 166     // 本結構所占用字節數
167     if((lpBI->biCompression==BI_RLE8)||(lpBI->biCompression==BI_RLE4)) 168         dwDIBSize+=lpBI->biSizeImage;//位圖的大小字節
169     else
170  { 171         DWORD dwBmBitSize;//只表示位圖的位的大小
172         dwBmBitSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))*lpBI->biHeight;//寬度的字節數*高度
173         dwDIBSize+=dwBmBitSize; 174         lpBI->biSizeImage=dwBmBitSize;//位圖數據大小的字節數
175  } 176     bmfHdr.bfSize=dwDIBSize+sizeof(BITMAPFILEHEADER);//位圖文件的大小,指的是整個文件
177     bmfHdr.bfReserved1=0; 178     bmfHdr.bfReserved2=0; 179     bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+lpBI->biSize+PaletteSize((LPBYTE)lpBI); 180 
181     CFile dibFile(filename,CFile::modeWrite|CFile::modeCreate);//|是位或,CFile::modeWrite|CFile::modeCreate??????
182     dibFile.Write(&bmfHdr,sizeof(BITMAPFILEHEADER));//這里必須要寫兩次,但是不知道為什么
183  dibFile.Write(lpBI,dwDIBSize); 184  dibFile.Close(); 185 } 186 
187 //rgb轉成灰度圖
188 void CDib::RGBtoGrade() 189 { 190     if(GetRGB())//如果有顏色表,即不是真彩色24位
191         m_pData2=m_pData;//顏色組號就是顏色,rgb相等
192     else
193  { 194  BYTE r,g,b; 195         int height,wide,size; 196         height=GetHeight(); 197         wide=GetWidth(); 198         size=height*wide; 199         m_pData2=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size); 200         LONG lLineBytes=GetDibWidthBytes(); 201         for(int j=0;j<height;j++) 202  { 203             for(int i=0;i<wide;i++) 204  { 205                 b=m_pData[j*lLineBytes+3*i]; 206                 g=m_pData[j*lLineBytes+3*i+1]; 207                 r=m_pData[j*lLineBytes+3*i+2]; 208                 m_pData2[j*wide+i]=(BYTE)(0.3*r+0.59*g+0.11*b);//wide是像素,一個像素是24位,所以三個rgb映射一個像素值,rgb給予不同的權重,一個值就代表了rgb三個值,因為是灰度圖
209  } 210  } 211  } 212 } 213 
214 //灰度圖轉為rgb
215 void CDib::GradetoRGB() 216 { 217     if(GetRGB()) 218         m_pData=m_pData2;//反正rgb相等就是了
219     else
220  { 221         //BYTE r,g,b;
222         int height,wide; 223         height=GetHeight(); 224         wide=GetWidth(); 225         LONG lLineBytes=GetDibWidthBytes(); 226         for(int j=0;j<height;j++) 227  { 228             for(int i=0;i<wide;i++)//將一個灰度值賦值給三個rgb,從最后一行開始,從一開始應該也是一樣的
229  { 230                 m_pData[(height-j-1)*lLineBytes+3*i]=m_pData2[(height-1-j)*wide+i]; 231                 m_pData[(height-j-1)*lLineBytes+3*i+1]=m_pData2[(height-1-j)*wide+i]; 232                 m_pData[(height-j-1)*lLineBytes+3*i+3]=m_pData2[(height-1-j)*wide+i]; 233  } 234  } 235  } 236 }

 (上述代碼已進行更新)

代碼中的部分函數,不如灰度轉換,沒有用過,所以不確定是否能正確使用,但是絕大部分函數用過都是可以正確運行的。

 現在給出一個測試的調用實例:

1、建立一個菜單,並在mfc的程序中實現這個菜單,如圖:

2、在對話框類中建立一個變量,用於保存文件的路徑:

1 class CMfcPictureProcessingDlg : public CDialogEx 2 { 3     
4  CMenu m_Menu; 5     CString filePath;//就是這個
6 。。。。。 7 };

3、對1中的菜單項“打開”,新建事件處理函數,到對話框類cpp文件中:

 1 void CMfcPictureProcessingDlg::On32771()//打開文件菜單
 2 {  3     TCHAR szFilter[]=_T("所有文件(*.*)|*.*||");//設置過濾器
 4     CFileDialog fileDlg(TRUE,NULL,NULL,0,szFilter,this);//這是一個文件打開對話框
 5     if(IDOK==fileDlg.DoModal())  6  {  7  GetFilePath(fileDlg.GetPathName());  8 
 9         CDib dib;//初始化一個類指針 10         //memset(dib,0,sizeof(CDib));//不行,有中斷出現
11  dib.LoadFile(filePath); 12         if(dib.m_valid)//很重要,要記得判斷
13  { 14         CDC *pDC=GetDC(); 15         CViewImage imageview;//這是第二章的顯示函數,可以不寫
16         imageview.GetDib(&dib);//我給它加了一個函數,用於獲取dib
17  imageview.OnDraw(pDC); 18  } 19  } 20 }

4、為菜單中的“保存”,添加事件處理函數:

 1 void CMfcPictureProcessingDlg::On32799()//保存文件
 2 {  3  CDib dib;  4  dib.LoadFile(filePath);  5     if(dib.m_valid)  6  {  7         //------------------------
 8         CDC* pDC=GetDC();  9  JHBHDib jdib; 10         jdib.GetDib(&dib); 11         jdib.JingXiang(false); 12  CViewImage imageview; 13         imageview.GetDib(&dib); 14         imageview.OnDraw2(pDC,dib.GetWidth()+5,0); 15         //這之間是我隨便選的一個第三章的處理函數,也可以將這部分去掉,先試試是否能直接保存圖片 16         //-------------------------
17         dib.SaveFile(_T("wod.bmp")); 18         //delete((BYTE*)dib.GetInfo());//不需要再釋放了,釋放函數在析構函數中
19  } 20 }

5、程序開啟,試試效果:

(1)菜單中的“打開”:

(2)菜單中的保存:

(3)工程文件夾:

進去找到我們的圖片,我取名是“wod.bmp”:

打開圖片:

//-----------------------------------------------------------------結束

 

零零散散敲了兩天真是酸爽啊,自己敲才能知道哪里不會~

  

http://blog.csdn.net/mad1989/article/details/7920173 講#ifndef、頭文件變量在cpp中重復定義
“其實並不難,是你太悲觀。”看到了這樣一句雞湯,很對。(其實就是鏈接內博客的名字)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM