CImage类的用法(转帖)
From: http://elevenguy.blog.163.com/blog/static/616122092010053550593/
我們知道,Visual C++的CBitmap類和靜態(tài)圖片控件的功能是比較弱的,它只能顯示出在資源中的圖標(biāo)、位圖、光標(biāo)以及圖元文件的內(nèi)容,而不像VB中的Image控件可 以顯示出絕大多數(shù)的外部圖像文件(BMP、GIF、JPEG等)。因此,想要在對話框或其他窗口中顯示外部圖像文件則只能借助于第三方提供的控件或代碼。 現(xiàn)在,MFC和ATL共享的新類CImage為圖像處理提供了許多相應(yīng)的方法,這使得Visual C++在圖像方面的缺憾一去不復(fù)返了。
CImage類概述
CImage是MFC和ATL共享的新類,它能從外部磁盤中調(diào)入一個(gè)JPEG、GIF、BMP和PNG格式的圖像文件加以顯示,而且這些文件格式可以 相互轉(zhuǎn)換。由于CImage在不同的Windows操作系統(tǒng)中其某些性能是不一樣的,因此在使用時(shí)要特別注意。例如,CImage::PlgBlt和 CImage::MaskBlt只能在 Windows NT 4.0 或更高版本中使用,但不能運(yùn)行在Windows 95/98 應(yīng)用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000運(yùn)行程序還必須將stdafx.h文件中的WINVER和_WIN32_WINNT的預(yù)定義修改成0x0500才能正常使用。
CImage封裝了DIB(設(shè)備無關(guān)位圖)的功能,因而可以讓我們能夠處理每個(gè)位圖像素。它具有下列最酷特性:
1、AlphaBlend支持像素級的顏色混合,從而實(shí)現(xiàn)透明和半透明的效果。
2、PlgBlt能使一個(gè)矩形區(qū)域的位圖映射到一個(gè)平行四邊形區(qū)域中,而且還可能使用位屏蔽操作。
3、TransparentBlt在目標(biāo)區(qū)域中產(chǎn)生透明圖像,SetTransparentColor用來設(shè)置某種顏色是透明色。
4、MaskBlt在目標(biāo)區(qū)域中產(chǎn)生源位圖與屏蔽位圖合成的效果。
使用CImage的一般方法
使用CImage的一般方法是這樣的過程:
(1) 打開應(yīng)用程序的stdafx.h文件添加CImage類的包含文件:
#include <atlimage.h>
(2) 定義一個(gè)CImage類對象,然后調(diào)用CImage::Load方法裝載一個(gè)外部圖像文件。
(3) 調(diào)用CImage::Draw方法繪制圖像。Draw方法具有如下定義:
程序代碼:
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight, int xSrc, int ySrc,
int nSrcWidth, int nSrcHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc );
BOOL Draw( HDC hDestDC, int xDest, int yDest );
BOOL Draw( HDC hDestDC, const POINT& pointDest );
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest );
其中,hDestDC用來指定繪制的目標(biāo)設(shè)備環(huán)境句柄,(xDest, yDest)和pointDest用來指定圖像顯示的位置,這個(gè)位置和源圖像的左上角點(diǎn)相對應(yīng)。nDestWidth和nDestHeight分別指定圖 像要顯示的高度和寬度,xSrc、ySrc、nSrcWidth和nSrcHeight用來指定要顯示的源圖像的某個(gè)部分所在的位置和大小。 rectDest和rectSrc分別用來指定目標(biāo)設(shè)備環(huán)境上和源圖像所要顯示的某個(gè)部分的位置和大小。
需要說明的是,Draw方法綜合了StretchBlt、TransparentBlt和AlphaBlend函數(shù)的功能。默認(rèn)時(shí),Draw的功能和 StretchBlt相同。但當(dāng)圖像含有透明色或Alpha通道時(shí),它的功能又和TransparentBlt、AlphaBlend相同。因此,在一般 情況下,我們都應(yīng)該盡量調(diào)用CImage::Draw方法來繪制圖像。
例如,下面的示例Ex_Image是實(shí)現(xiàn)這樣的功能:當(dāng)選擇"文件"ò"打開"菜單命令后,彈出一個(gè)文件打開對話框。當(dāng)選定一個(gè)圖像文件后,就會在窗口客戶區(qū)中顯示該圖像文件內(nèi)容。這個(gè)示例的具體步驟如下:
(1) 創(chuàng)建一個(gè)默認(rèn)的單文檔程序項(xiàng)目Ex_Image。
(2) 打開stdafx.h文件中添加CImage類的包含文件atlimage.h。
(3) 在view類中添加成員變量CImage m_Image;
CEx_ImageView類添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代碼:
程序代碼:
void CImageProcessView::OnFileOpen()
{
// TODO: 在此添加命令處理程序代碼
CString strFilter;
CSimpleArray aguidFileTypes;
HRESULT hResult;
// 獲取CImage支持的圖像文件的過濾字符串
hResult = m_Image.GetExporterFilterString(strFilter,aguidFileTypes,
_T( "All Image Files") );
if (FAILED(hResult)) {
MessageBox(_T("GetExporterFilter調(diào)用失敗!"));
return;
}
CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter);
if(IDOK != dlg.DoModal())
return;
m_Image.Destroy();
// 將外部圖像文件裝載到CImage對象中
hResult = m_Image.Load(dlg.GetFileName());
if (FAILED(hResult)) {
MessageBox(_T("調(diào)用圖像文件失敗!"));
return;
}
// 設(shè)置主窗口標(biāo)題欄內(nèi)容
CString str;
str.LoadString(AFX_IDS_APP_TITLE);
AfxGetMainWnd()->SetWindowText(str + _T(" - ") +dlg.GetFileName());
Invalidate(); // 強(qiáng)制調(diào)用OnDraw
}
(4) 定位到CEx_ImageView::OnDraw函數(shù)處,添加下列代碼:
程序代碼:
void CEx_ImageView::OnDraw(CDC* pDC)
{
CImageProcessDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!m_Image.IsNull()) {
m_Image.Draw(pDC->m_hDC,0,0);}
}
(5) 打開Ex_ImageView.h文件,添加一個(gè)公共的成員數(shù)據(jù)m_Image:
程序代碼:
public:
CImage m_Image;
(6) 編譯并運(yùn)行。單擊"打開"工具按鈕,在彈出的對話框中指定一個(gè)圖像文件后,單擊"打開"按鈕,其結(jié)果如圖7.21所示。
將圖片用其它格式保存
CImage::Save方法能將一個(gè)圖像文件按另一種格式來保存,它的原型如下:
程序代碼:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL);
其中,pszFileName用來指定一個(gè)文件名,guidFileType用來指定要保存的圖像文件格式,當(dāng)為GUID_NULL時(shí),其文件格式由 文件的擴(kuò)展名來決定,這也是該函數(shù)的默認(rèn)值。它還可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。
例如,下面的過程是在Ex_Image示例基礎(chǔ)上進(jìn)行的,我們在CEx_ImageView類添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代碼:
程序代碼:
void CEx_ImageView::OnFileSaveAs()
{
// TODO: 在此添加命令處理程序代碼
if (m_Image.IsNull()) {
MessageBox(_T("你還沒有打開一個(gè)要保存的圖像文件!"));
return;
}
CString strFilter;
strFilter ="位圖文件|*.bmp|JPEG 圖像文件|*.jpg|
GIF 圖像文件|*.gif|PNG 圖像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
if ( IDOK != dlg.DoModal())
return;
// 如果用戶沒有指定文件擴(kuò)展名,則為其添加一個(gè)
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if(dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1:
strExtension = "bmp"; break;
case 2:
strExtension = "jpg"; break;
case 3:
strExtension = "gif"; break;
case 4:
strExtension = "png"; break;
default:
break;
}
strFileName = strFileName + _T(".") + strExtension;
}
// 圖像保存
HRESULT hResult = m_Image.Save(strFileName);
if (FAILED(hResult))
{
MessageBox(_T("保存圖像文件失敗!"));
}
}
柔化(平滑)和銳化處理
在圖像處理中,我們通常用一些數(shù)學(xué)手段,對圖像進(jìn)行除去噪聲、強(qiáng)調(diào)或抽取輪廓特征等圖像空間的變換。所謂"圖像空間的變換"是借助于一個(gè)稱之為模板的局部像素域來完成的,不同的模板具有不同的圖像效果。
1. 柔化(平滑)
圖像的柔化是除去圖像中點(diǎn)狀噪聲的一個(gè)有效方法。所謂柔化,是指使圖像上任何一個(gè)像素與其相鄰像素的顏色值的大小不會出現(xiàn)陡突的一種處理方法。設(shè)在一個(gè)3 x 3的模板中其系數(shù)為:
1 1 1
1 1 1??????? *1/9
1 1 1
?
中間有底紋的表示中心元素,即用那個(gè)元素作為處理后的元素。很明顯,上述模板(稱之為Box模板)是將圖像上每個(gè)像素用它近旁(包括它本身)的9個(gè)像素的平均值取代。這樣處理的結(jié)果在除噪的同時(shí),也降低圖像的對比度,使圖像的輪廓模糊。為了避免這一缺陷,我們對各點(diǎn)引入加權(quán)系數(shù)(不都乘1了),將原來的模板改為:
?1 2 1
?2 4 2??? *1/16
?1 2 1
新的模板可一方面除去點(diǎn)狀噪聲,同時(shí)能較好地保留原圖像的對比度,因此該模板得到了廣泛的應(yīng)用。由于這個(gè)模板是通過二維高斯(Gauss)函數(shù)得到的,故稱為高斯模板。
2. 銳化
銳化和柔化恰恰相反,它通過增強(qiáng)高頻分量減少圖像中的模糊,因此又稱為高通濾波。銳化處理在增強(qiáng)圖像邊緣效果的同時(shí)增加了圖像的噪聲。常用的銳化模板是拉普拉斯模板:
-1 -1 -1
-1 9? -1?
-1 -1 -1
用此模板處理后的圖像,輪廓線條將明顯得到增強(qiáng)。輪廓線以外的部分將變得較暗,而輪廓線部分將變得比較明亮。
使用程序?qū)δ0暹M(jìn)行運(yùn)算時(shí),要考慮到溢出點(diǎn)的處理。所謂溢出點(diǎn),指的是大于255或小于0的點(diǎn)。處理時(shí),可令大于255的點(diǎn)取255,而小于0的點(diǎn)取其正值。
3. 實(shí)現(xiàn)代碼
實(shí)現(xiàn)柔化和銳化時(shí),我們先調(diào)用CImage::GetPixel來依次讀取相應(yīng)的像素,然后用柔化和銳化模板進(jìn)行處理,最后調(diào)用CImage::SetPixel函數(shù)將處理后的像素寫回到CImage對象中。具體的代碼如下:
程序代碼:
void FilterImage(CImage* image, int nType)
{
if (image->IsNull())
return;
int smoothGauss[9] = {1,2,1,2,4,2,1,2,1}; // 高斯模板
int sharpLaplacian[9] = {-1,-1,-1,-1,9,-1,-1,-1,-1}; // 拉普拉斯模板
int opTemp[9];
float aver; // 系數(shù)
if ( nType > 1) nType = 0;
switch( nType ){
case 0: // 高斯模板 平滑
aver = (float)(1.0/16.0);
memcpy( opTemp, smoothGauss, 9*sizeof(int));
break;
case 1: // 拉普拉斯模板 銳化
aver = 1.0;
memcpy( opTemp, sharpLaplacian, 9*sizeof(int));
break;
}
int i,j;
int nWidth = image->GetWidth();
int nHeight = image->GetHeight();
for (i = 1; i < nWidth-1; i++){
for (j = 1; j < nHeight-1; j++){
int rr = 0, gg = 0, bb = 0;
int index = 0;
for (int col = -1; col <= 1; col++){
for (int row = -1; row <= 1; row++){
COLORREF clr = image->GetPixel( i+row, j+col);
rr += GetRValue(clr) * opTemp[index];
gg += GetGValue(clr) * opTemp[index];
bb += GetBValue(clr) * opTemp[index];
index++;
}
}
rr = (int)(rr*aver);
gg = (int)(gg*aver);
bb = (int)(bb*aver);
// 處理溢出點(diǎn)
if ( rr > 255 ) rr = 255;
else if ( rr < 0 ) rr = -rr;
if ( gg > 255 ) gg = 255;
else if ( gg < 0 ) gg = -gg;
if ( bb > 255 ) bb = 255;
else if ( bb < 0 ) bb = -bb;
// 錯(cuò)位重寫以避免前一個(gè)像素被新的像素覆蓋
image->SetPixel( i-1, j-1, RGB(rr,gg,bb));
}
}
Invalidate(); // 強(qiáng)制調(diào)用OnDraw
}
圖7.22是使用上述代碼將某個(gè)圖像處理后的結(jié)果。
變成黑白圖片(變?yōu)榛叶葓D)
由于許多圖像文件使用顏色表來發(fā)揮顯示設(shè)備的色彩顯示能力,因而將一張彩色圖片變成黑色圖片時(shí)需要調(diào)用CImage::IsIndexed來判斷是否使用顏色表,若是則修改顏色表,否則直接將像素進(jìn)行顏色設(shè)置。例如下面的代碼:
程序代碼:
void CEx_ImageView::MakeBlackAndwhite(CImage* image)
{
if (image->IsNull()) return;
if (!image->IsIndexed()) {
// 直接修改像素顏色
COLORREF pixel;
int maxY = image->GetHeight(), maxX = image->GetWidth();
byte r,g,b,avg;
for (int x=0; x<maxX; x++) {
for (int y=0; y<maxY; y++) {
pixel = image->GetPixel(x,y);
r = GetRValue(pixel);
g = GetGValue(pixel);
b = GetBValue(pixel);
avg = (int)((r + g + b)/3);
image->SetPixelRGB(x,y,avg,avg,avg);
}
}
} else {
// 獲取并修改顏色表
int MaxColors = image->GetMaxColorTableEntries();
RGBQUAD* ColorTable;
ColorTable = new RGBQUAD[MaxColors];
image->GetColorTable(0,MaxColors,ColorTable);
for (int i=0; i<MaxColors; i++)
{
int avg = (ColorTable[i].rgbBlue + ColorTable[i].rgbGreen + ColorTable[i].rgbRed)/3;
ColorTable[i].rgbBlue = avg;
ColorTable[i].rgbGreen = avg;
ColorTable[i].rgbRed = avg;
}
image->SetColorTable(0,MaxColors,ColorTable);
delete(ColorTable);
}
Invalidate();// 強(qiáng)制調(diào)用OnDraw
}
總結(jié)
以上是生活随笔為你收集整理的CImage类的用法(转帖)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用protues仿真stm32教程
- 下一篇: Servlet 应用程序事件、监听器