- Visual C++程序开发范例宝典(软件工程师典藏版)
- 刘志铭 李贺 高茹编著
- 7字
- 2020-06-27 11:09:48
3.4 图片颜色转换
实例104 图像的锐化处理
本实例可以方便操作、提高效率
实例位置:光盘\mingrisoft\03\104
实例说明
图像的锐化处理能够使图像的主体轮廓更加清晰,因此在图像处理和图像识别程序中应用得非常广泛。本实例演示了图像的锐化效果,如图3.23、图3.24所示。
图3.23 锐化前的效果
图3.24 锐化后的效果
技术要点
本实例中实现图像的锐化处理是通过调整像素点的颜色来实现的。在介绍“提取图片中的对象”实例时,讲解了CDC类的GetPixel方法和SetPixel方法可以获取和设置某一点的颜色,本实例通过这两个方法实现图像的锐化处理。
实现过程
(1)新建一个基于对话框的应用程序。
(2)在对话框中添加图片和按钮控件。
(3)主要程序代码如下:
void CImagesharpDlg::OnSharp() { CDC * m_dc; CRect m_rect; m_image1.GetClientRect(m_rect); //获得控件的客户区域 m_dc=m_image1.GetDC(); //获得设备上下文 int r1,g1,b1,r2,g2,b2; for(int i=1;i<m_rect.right+1;i++) //根据宽度循环 for(int j=1;j<m_rect.bottom+1;j++) //根据高度循环 { //锐化处理 COLORREF color = m_dc->GetPixel(i,j); COLORREF nextcolor = m_dc->GetPixel(i-1,j-1); r1 = (color & 0xFF); g1 = (int)(color & 62580) / 256; b1 = (int)(color & 0xFF0000) / 65536; r2 = (nextcolor & 0xFF); g2 = (int)(nextcolor & 62580) / 256; b2 = (int)(nextcolor & 0xFF0000) / 65536; r1+= (r1- r2) /2; g1+= (g1-g2)/2; b1+= (b1-b2)/2; if ( r1 > 255) r1 = 255; if ( r1 < 0 ) r1 = 0; if ( b1 > 255) b1 = 255; if (b1 < 0) b1 = 0; if( g1 > 255) g1 = 255; if ( g1 < 0 ) g1 = 0; m_dc->SetPixel(i,j,RGB(r1,g1,b1)); } }
举一反三
根据本实例,读者可以:
设计渐变效果程序启动界面。
实例105 图片反色处理
本实例是一个提高效率的程序
实例位置:光盘\mingrisoft\03\105
实例说明
图片反色处理是将图片中的像素值取反。例如,原来的白色像素点取反后会成为黑色的像素点。图片的反色处理是一个逆运算过程,即对一幅图片进行两次取反处理,还应是原来的图片效果。本实例实现了图片的反色处理。反色处理前后的效果如图3.25、图3.26所示。
图3.25 处理前的效果图
图3.26 处理后的效果图
技术要点
要实现图像的反色处理可以有多种方法。例如可以获取图片中每个像素点的颜色值,然后对颜色值进行取反,代码如下:
CDC* pDC = m_image.GetDC(); CRect m_rect; m_image.GetClientRect(m_rect); BYTE r,g,b; for (int i=1; i<]m_rect.Width();i++) for (int j=1;j<m_rect.Height();j++) { COLORREF clr= pDC->GetPixel(i,j); r = GetRValue(clr); g = GetGValue(clr); b = GetBValue(clr); r = abs(255-r); g = abs(255-g); b = abs(255-b); pDC->SetPixel(i,j,RGB(r,g,b)); }
此外,还有一种更简单的方法,就是调用CDC类的InvertRgn方法,该方法将指定区域的颜色取反,语法如下:
BOOL InvertRgn( CRgn* pRgn );
参数说明:
● pRgn:是一个区域对象指针。
与第一种方法相比,该方法计算速度更快,而且也相对简单,本实例也是采用该方法实现的,关键代码如下:
CDC* pDC = m_image.GetDC(); CRect m_rect; m_image.GetClientRect(m_rect); CRgn m_rgn; m_rgn.CreateRectRgn(m_rect.left,m_rect.top,m_rect.right,m_rect.bottom); pDC->InvertRgn(&m_rgn);
实现过程
(1)新建一个基于对话框的应用程序。
(2)在对话框中添加图片和按钮控件。
(3)主要程序代码如下:
void CReverseColorDlg::OnOK() { CDC*pDC=m_image.GetDC(); //获得设备上下文 CRect m_rect; m_image.GetClientRect(m_rect); //获得控件客户区域 CRgn m_rgn; m_rgn.CreateRectRgn(m_rect.left,m_rect.top,m_rect.right,m_rect.bottom);//设置区域 pDC->InvertRgn(&m_rgn); //颜色取反处理 }
举一反三
根据本实例,读者可以:
设计具有透明效果的图像。
实例106 图像的灰度化转换
本实例是一个提高效率的程序
实例位置:光盘\mingrisoft\03\106
实例说明
在图像识别领域,经常涉及图像的灰度化转换,即将彩色图像转换为黑白图像。因为黑白图像更容易进行运算。本实例将实现图像的灰度化转换,效果如图3.27、图3.28所示。
图3.27 转换前图像
图3.28 转换后图像
技术要点
实现图像的灰度化转换没有一定的标准,通常根据图片中像素的RGB分量以及它们的权重来获取。本实例中RGB分量的权重分别为0.38、0.49、0.1。在其他应用中,用户可以根据实际情况设置不同的权重。在图像的灰度化过程中,首先需要获取像素点的红、绿、蓝分量值,然后将其乘以相应的分量,最后重新设置像素的颜色,例如下面的代码:
m_color = pDC->GetPixel(i,j); r = GetRValue(m_color); g = GetGValue(m_color); b = GetRValue(m_color); m_gray = (0.38*r+0.49*g+0.1*b); m_color = RGB(m_gray,m_gray,m_gray); pDC->SetPixel(i,j,m_color);
实现过程
(1)新建一个基于对话框的应用程序。
(2)在对话框中添加图片控件和按钮控件。
(3)主要程序代码如下:
void CSingleImageDlg::OnOK() { CDC*pDC=m_image.GetDC(); //获得设备上下文 CRect m_rect ; m_image.GetClientRect(m_rect); //获得控件区域 COLORREF m_color; DWORD m_gray; BYTE r,g,b; for (int i = 0; i<m_rect.right;i++) for (int j = 0;j<m_rect.bottom;j++) { m_color=pDC->GetPixel(i,j); //获得颜色 r = GetRValue(m_color); g = GetGValue(m_color); b = GetRValue(m_color); m_gray=(0.38*r+0.49*g+0.1*b); //设置灰度颜色值 m_color = RGB(m_gray,m_gray,m_gray); pDC->SetPixel(i,j,m_color); //用灰度颜色画点 } }
举一反三
根据本实例,读者可以:
利用抠图技术设计特殊形状的窗体。
实例107 显示JPG图片
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\03\107
实例说明
用过Delphi的读者知道,使用VCL提供的TImage可以方便地显示JPG图像。在Visual C++中,MFC类库却没有提供相应的控件显示JPG图像。本实例实现了JPG图片的显示,效果如图3.29所示。
图3.29 显示JPG图片
技术要点
JPG图像采用压缩形式存储,存储结构比较复杂。为了简单化,可以采用流的形式读取JPG文件。首先利用CFile对象读取JPG文件,获取JPG文件的长度,然后利用GlobalAlloc函数在堆中划分一个和文件大小相同的区域,接着调用GlobalLock函数锁定该区域,返回一个指向堆的指针,将文件数据写入该区域,最后调用CreateStreamOnHGlobal函数在堆中创建流对象,调用OleLoadPicture函数根据流对象创建图像对象IPicture,调用IPicture的Render方法将图像显示在指定的画布上。
在实现JPG图像的过程中,需要用到多个函数,下面逐一进行介绍。
(1)GlobalAlloc函数。该函数用于在堆上分配指定大小的空间。语法如下:
HGLOBAL GlobalAlloc(UINT uFlags, DWORD dwBytes);
参数说明:
● uFlags:标识如何分配空间,为GMEM_FIXED时表示空间是固定的;为GMEM_MOVEABLE时表示空间可以移动。
● dwBytes:标识分配空间的大小。
● 返回值:分配的空间对象句柄。
(2)GlobalLock函数。该函数用于锁定一个全局内存对象,并返回一个指向内存的指针。语法如下:
LPVOID GlobalLock(HGLOBAL hMem );
参数说明:
● hMem:全局内存对象句柄,通常是GlobalAlloc函数的返回值。
● 返回值:函数返回指向全局内存的指针。
(3)CreateStreamOnHGlobal函数。该函数用于创建一个存储在堆中的流对象。语法如下:
WINOLEAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL fDeleteOnRelease, LPSTREAM * ppstm );
参数说明:
● hGlobal:标识全局内存对象句柄。
● fDeleteOnRelease:确定在流对象释放时是否释放全局内存空间。
● ppstm:标识Istream接口指针。
(4)OleLoadPicture函数。该函数根据流对象的内容创建一个图像对象。语法如下:
STDAPI OleLoadPicture( IStream * pStream,LONG lSize, BOOL fRunmode,REFIID riid, VOID ppvObj );
参数说明:
● pStream:标识流对象指针。
● lSize:标识从流中读取数据的数量。
● fRunmode:确定是否采用与图像初始属性相反的属性值。
● riid:确定接口指针的类型。
● ppvObj:标识与riid对应的图像对象指针。
实现过程
(1)新建一个基于对话框的应用程序。
(2)在对话框中添加静态文本、编辑框、按钮和图片控件。
(3)处理按钮的单击事件,加载并显示JPG图像,代码如下:
void CShowJPGDlg::OnOK()
{ CFileDialog m_dlg(TRUE,"JPG",NULL,NULL,"JPG(*.jpg)|*.JPG|gif|*.gif",this); if (m_dlg.DoModal()==IDOK) { CString m_filename =m_dlg.GetPathName(); m_dir.SetWindowText(m_filename); CFile m_file(m_filename,CFile::modeRead ); //获取文件长度 DWORD m_filelen = m_file.GetLength(); //在堆上分配空间 HGLOBAL m_hglobal = GlobalAlloc(GMEM_MOVEABLE,m_filelen); LPVOID pvdata = NULL; //锁定堆空间,获取指向堆空间的指针 pvdata = GlobalLock(m_hglobal); //将文件数据读取到堆中 m_file.ReadHuge(pvdata,m_filelen); IStream* m_stream; GlobalUnlock(m_hglobal); //在堆中创建流对象 CreateStreamOnHGlobal(m_hglobal,TRUE,&m_stream); //利用流加载图像 OleLoadPicture(m_stream,m_filelen,TRUE,IID_IPicture,(LPVOID*)&m_picture); m_picture->get_Width(&m_width); m_picture->get_Height(&m_height); CDC* dc = GetDC(); m_IsShow = TRUE; CRect rect; GetClientRect(rect); SetScrollRange(SB_VERT,0,(int)(m_height/26.45)-rect.Height()); SetScrollRange(SB_HORZ,0,(int)(m_width/26.45)-rect.Width()); m_picture->Render(*dc,1,50,(int)(m_width/26.45),(int)(m_height/26.45), 0,m_height,m_width,-m_height,NULL); } }
举一反三
根据本实例,读者可以:
浏览GIF动画。