本节主要内容是将图片显示到控件上。
这里我们借助Visual Studio提供给我们的Gdiplus工具将图片显示到控件上。
一、首先简要介绍Gdiplus的配置方法:
1 在单文档应用程序中使用GDI+创建一个单文档程序
1.1 添加包含文件和类库,方法:在stdafx.h文件中添加下面两行代码
#pragma comment(lib,”gdiplus.lib”) using namespace Gdiplus;
或者【项目】|【属性】,->【链接器】|【输入】->【附加依赖项】,在框中输入gdiplus.lib
1.2 在应用程序项目的应用类中,添加一个成员变量
ULONG_PTR m_gdiplusToken;
其中,ULONG_PTR是一个DWORD数据类型,该成员变量用来保存GDI+被初始化后在应用程序中的GDI+标识,以便能在应用程序退出后,引用该标识来调用Gdiplus:: GdiplusShutdown来关闭GDI+。
1.3 在应用类中添加ExitInstance的重载来关闭GDI+
int CEXXXApp::ExitInstance() { Gdiplus::GdiplusShutdown(m_gdiplusToken); return CWinApp::ExitInstance(); }
1.4 在应用类的InitInstance函数中添加GDI+的初始化代码
BOOL CEx_GDIPlusApp::InitInstance() { ...... CWinApp::InitInstance(); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL); ...... }
2 在基于对话框应用程序中使用GDI+
创建一个对话框应用程序
2.1 添加包含文件和类库,方法:在stdafx.h文件中添加下面两行代码
#pragma comment(lib,”gdiplus.lib”) using namespace Gdiplus;
2.2 步骤同单文档应用程序
3 在VS2010中的MFC中配置GDI+
首先,VS2010中已经有GDI+SDK包的,不需要额外下载
1)在stdafx.h文件中加入下面3行代码,添加相应的头文件和库
#pragma comment( lib, "gdiplus.lib" ) #include "gdiplus.h" using namespace Gdiplus;
2)在应用程序项目的应用类中,添加一个成员变量或者定义一个全局变量ULONG_PTR m_gdiplusToken;
其中,ULONG_PTR是一个DWORD数据类型,该成员变量用来保存GDI+被初始化后在应用程序中的GDI+标识,以便能在应用程序退出后,引用该标识来调用Gdiplus:: GdiplusShutdown来关闭GDI+。
3)使用GDI+函数前,先,最好放在OnInitDialog()中
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
4)使用完GDI+函数后,需要卸载GDI+
Gdiplus::GdiplusShutdown(m_gdiplusToken);
这就是基本的配置了
当然,为了避免命名冲突,也可以将
#pragma comment(lib,”gdiplus.lib”) using namespace Gdiplus;
只添加到我们要使用Gdiplus库的头文件中去。
二、将图片显示到控件上
这里我们插入一个对话框资源:IDC_ThresholdDlg
再为这个资源添加一个类:CThreshholdDlg
/** CThreshholdDlg.h*/
1 #pragma once 2 3 #include "resource.h" 4 #include "Dib.h" 5 #include "Threshold.h" 6 #pragma comment(lib,"gdiplus.lib") 7 #include <GdiPlus.h> 8 using namespace Gdiplus; 9 // CThresholdDlg 对话框 10 11 class CThresholdDlg : public CDialog 12 { 13 DECLARE_DYNAMIC(CThresholdDlg) 14 15 public: 16 CThresholdDlg(CWnd* pParent = NULL); // 标准构造函数 17 virtual ~CThresholdDlg(); 18 19 // 对话框数据 20 enum { IDD = IDD_Threshold }; 21 22 public: 23 CDib dib; 24 CStatic m_staBmp; 25 CString m_BmpFilePath; 26 CString m_BmpFileName; 27 public: 28 CDib* GetDib(); 29 void DrawBitmap(); 30 protected: 31 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 32 33 DECLARE_MESSAGE_MAP() 34 public: 35 afx_msg void OnBnClickedOpenBmp(); 36 afx_msg void OnBnClickedOutsthreshold(); 37 afx_msg void OnBnClickedAdaptivethreshold(); 38 afx_msg void OnBnClickedSaveresult(); 39 };
1 /**ThresholdDlg.cpp*/ 2 // 3 4 #include "stdafx.h" 5 #include "ImgPro.h" 6 #include "ThresholdDlg.h" 7 #include "afxdialogex.h" 8 9 10 // CThresholdDlg 对话框 11 12 IMPLEMENT_DYNAMIC(CThresholdDlg, CDialog) 13 14 CThresholdDlg::CThresholdDlg(CWnd* pParent /*=NULL*/) 15 : CDialog(CThresholdDlg::IDD, pParent) 16 { 17 18 } 19 20 CThresholdDlg::~CThresholdDlg() 21 { 22 } 23 24 void CThresholdDlg::DoDataExchange(CDataExchange* pDX) 25 { 26 CDialog::DoDataExchange(pDX); 27 DDX_Control(pDX,IDC_STATIC,m_staBmp); 28 } 29 30 31 BEGIN_MESSAGE_MAP(CThresholdDlg, CDialog) 32 ON_BN_CLICKED(IDC_Open_BMP, &CThresholdDlg::OnBnClickedOpenBmp) 33 ON_BN_CLICKED(IDC_OutsThreshold, &CThresholdDlg::OnBnClickedOutsthreshold) 34 ON_BN_CLICKED(IDC_AdaptiveThreshold, &CThresholdDlg::OnBnClickedAdaptivethreshold) 35 ON_BN_CLICKED(IDC_SaveResult, &CThresholdDlg::OnBnClickedSaveresult) 36 END_MESSAGE_MAP() 37 38 CDib* CThresholdDlg::GetDib() 39 { 40 return &dib; 41 } 42 43 void CThresholdDlg::DrawBitmap(void) 44 { 45 CDC* pDC=m_staBmp.GetDC(); 46 Graphics graph(pDC->GetSafeHdc()); 47 CRect rect; 48 m_staBmp.GetClientRect(rect); 49 pDC->FillRect(rect, &CBrush(RGB(211, 211, 211))); 50 CSize size; 51 size.cx=rect.Width(); 52 size.cy=rect.Height(); 53 dib.Draw(pDC,CPoint(0,0),size); 54 ReleaseDC(pDC); 55 } 56 // CThresholdDlg 消息处理程序 57 58 59 void CThresholdDlg::OnBnClickedOpenBmp() 60 { 61 // TODO: 在此添加控件通知处理程序代码 62 LPCTSTR lpszFilter=L"BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg)|*.jpg|All Files(*.*)|*.*||"; 63 CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_EXPLORER,lpszFilter,NULL); 64 CFile file; 65 if(dlg.DoModal()==IDOK) 66 { 67 m_BmpFilePath=dlg.GetPathName(); 68 if(file.Open(m_BmpFilePath,CFile::modeRead|CFile::shareDenyNone,NULL)==0) 69 { 70 return; 71 } 72 dib.LoadFromFile(m_BmpFilePath); 73 DrawBitmap(); 74 } 75 } 76 77 78 void CThresholdDlg::OnBnClickedOutsthreshold() 79 { 80 // TODO: 在此添加控件通知处理程序代码 81 CThreshold threshold(GetDib()); 82 //threshold.m_pDib=GetDib(); 83 if(!dib.IsGrade()) 84 { 85 dib.RgbToGrade(); 86 DrawBitmap(); 87 } 88 else 89 {;} 90 threshold.OtusThreshold(); 91 DrawBitmap(); 92 } 93 94 95 void CThresholdDlg::OnBnClickedAdaptivethreshold() 96 { 97 // TODO: 在此添加控件通知处理程序代码 98 CThreshold threshold(GetDib()); 99 //threshold.m_pDib=GetDib(); 100 if(!dib.IsGrade()) 101 { 102 dib.RgbToGrade(); 103 DrawBitmap(); 104 } 105 else 106 {;} 107 threshold.AdaptiveThreshold(); 108 DrawBitmap(); 109 } 110 111 112 void CThresholdDlg::OnBnClickedSaveresult() 113 { 114 // TODO: 在此添加控件通知处理程序代码 115 LPCTSTR lpszFilter=L"BMP Files(*.bmp)|*.bmp|All Files(*.*)|*.*||"; 116 CFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY|OFN_EXPLORER,lpszFilter,NULL); 117 if(dlg.DoModal()!=IDOK) 118 return; 119 dib.SaveToFile(dlg.GetPathName()); 120 }
Threshold.h
/** Threshold.h*/
1 #pragma once 2 3 #include "Dib.h" 4 5 class CThreshold 6 { 7 public: 8 CThreshold(); 9 CThreshold(CDib *pDib); 10 public: 11 ~CThreshold(void); 12 public: 13 void AdaptiveThreshold(void); 14 void OtusThreshold(void); 15 private: 16 CDib * m_pDib; 17 };
Threshold.cpp
/**Threshold.cpp*/
1 #include "StdAfx.h" 2 #include "Threshold.h" 3 #include "math.h" 4 5 CThreshold::CThreshold() 6 { 7 } 8 9 CThreshold::CThreshold(CDib *pDib) 10 { 11 m_pDib = pDib; 12 } 13 14 CThreshold::~CThreshold(void) 15 { 16 } 17 18 //======================================================= 19 // 函数功能: 最大方差阈值分割 20 // 输入参数: 无 21 // 返回值: 无 22 //======================================================= 23 void CThreshold::OtusThreshold(void) 24 { 25 // 循环变量 26 int i, j; 27 28 // 原图数据区指针 29 LPBYTE p_data; 30 p_data = m_pDib->GetData(); 31 32 // 图像每行像素所占的字节数 33 int nLineByte = m_pDib->GetLineByte(); 34 35 // 图像的宽度 36 int nWidth = m_pDib->GetWidth(); 37 38 // 图像的高度 39 int nHeight = m_pDib->GetHeight(); 40 41 // 灰度直方图数组,并初始化 42 int nGrayHistogram[256]; 43 memset(nGrayHistogram, 0, sizeof(nGrayHistogram)); 44 45 // 统计各个灰度级对应的像素个数,并存放到灰度直方图数组中 46 int nPixel; 47 for (j = 0; j < nHeight; j ++) 48 for (i = 0; i < nWidth; i ++) 49 { 50 // 获取当前像素点的灰度值 51 nPixel = p_data[nLineByte * j + i]; 52 53 // 对灰度值统计计数 54 nGrayHistogram[nPixel] ++; 55 } 56 57 // c0组和c1组的均值 58 float u0, u1; 59 60 // c0组和c1组的概率 61 float w0, w1; 62 63 // c0组的像素总数 64 int nCount0; 65 66 // 阈值和最佳阈值(对应方差最大时的阈值) 67 int nT, nBestT; 68 69 // 方差和最大方差 70 float fVaria, fMaxVaria = 0; 71 72 // 统计直方图中像素点的总数,并存放到nSum中 73 int nSum=0; 74 for(i = 0; i < 256; i ++) 75 nSum += nGrayHistogram[i]; 76 77 78 // 令阈值nT从0遍历到255 79 for(nT = 0; nT < 256; nT ++) 80 { 81 // 当阈值为nT时,计算c0组的均值和概率 82 u0 = 0; 83 nCount0 = 0; 84 for(i = 0; i <= nT; i++) 85 { 86 u0 += i * nGrayHistogram[i]; 87 nCount0 += nGrayHistogram[i]; 88 } 89 u0 /= nCount0; 90 w0 = (float) nCount0 / nSum; 91 92 // 当阈值为nT时,计算c1组的均值和概率 93 u1 = 0; 94 for(i = nT+1; i < 256; i ++) 95 u1 += i * nGrayHistogram[i]; 96 u1 /= (nSum - nCount0); 97 w1 = 1 - w0; 98 99 // 计算两组间的方差 100 fVaria = w0 * w1 * (u0 - u1) * (u0 - u1); 101 102 // 记录最大方差和最佳阈值 103 if(fVaria > fMaxVaria) 104 { 105 fMaxVaria = fVaria; 106 nBestT = nT; 107 } 108 } 109 110 // 利用最佳阈值对原图像作分割处理 111 for(j = 0; j < nHeight; j ++) 112 for(i = 0; i < nWidth; i ++) 113 { 114 if(p_data[j * nLineByte + i] < nBestT) 115 p_data[j * nLineByte + i] = 0; 116 else 117 p_data[j * nLineByte + i] = 255; 118 } 119 } 120 121 122 //======================================================= 123 // 函数功能: 自适应阈值分割 124 // 输入参数: 无 125 // 返回值: 无 126 //======================================================= 127 void CThreshold::AdaptiveThreshold(void) 128 { 129 // 循环变量 130 int i,j; 131 132 // 原图像数据区指针 133 LPBYTE p_data; 134 p_data = m_pDib->GetData(); 135 136 // 图像每行像素所占的字节数 137 int nLineByte = m_pDib->GetLineByte(); 138 139 // 图像的宽度 140 int nWidth = m_pDib->GetWidth(); 141 142 // 图像的高度 143 int nHeight = m_pDib->GetHeight(); 144 145 // 局部阈值 146 int nThreshold[2][2]; 147 148 // 子图像的灰度平均值 149 int nAvgValue; 150 151 // 对左上图像逐点扫描,计算该子图像的灰度平均值 152 nAvgValue = 0; 153 for(j = nHeight / 2; j < nHeight; j ++) 154 for(i = 0; i < nWidth / 2; i ++) 155 nAvgValue += p_data[j * nLineByte + i]; 156 nAvgValue /= ((nHeight / 2) * (nLineByte / 2)); 157 158 // 设置阈值为子图像的平均值 159 nThreshold[0][0] = nAvgValue; 160 161 // 对左上图像逐点扫描并进行阈值分割 162 for(j = nHeight / 2; j < nHeight; j ++) 163 for(i = 0; i < nWidth / 2; i ++) 164 { 165 if(p_data[j * nLineByte + i] < nThreshold[0][0]) 166 p_data[j * nLineByte + i] = 0; 167 else 168 p_data[j * nLineByte + i] = 255; 169 } 170 171 // 对右上图像逐点扫描,计算该子图像的灰度平均值 172 nAvgValue = 0; 173 for(j = nHeight / 2; j < nHeight; j ++) 174 for(i = nWidth / 2; i < nWidth; i ++) 175 nAvgValue += p_data[j * nLineByte + i]; 176 nAvgValue /= ((nHeight / 2) * (nLineByte / 2)); 177 178 // 设置阈值为子图像的平均值 179 nThreshold[0][1] = nAvgValue; 180 181 // 对右上图像逐点扫描并进行阈值分割 182 for(j = nHeight / 2; j < nHeight; j ++) 183 for(i = nWidth / 2; i < nWidth; i ++) 184 { 185 if(p_data[j * nLineByte + i] < nThreshold[0][0]) 186 p_data[j * nLineByte + i] = 0; 187 else 188 p_data[j * nLineByte + i] = 255; 189 } 190 191 // 对左下图像逐点扫描,计算该子图像的灰度平均值 192 nAvgValue = 0; 193 for(j = 0; j < nHeight / 2; j ++) 194 for(i = 0; i < nWidth / 2; i ++) 195 nAvgValue += p_data[j * nLineByte + i]; 196 nAvgValue /= ((nHeight / 2) * (nLineByte / 2)); 197 198 // 设置阈值为子图像的平均值 199 nThreshold[1][0] = nAvgValue; 200 201 // 对左下图像逐点扫描并进行阈值分割 202 for(j = 0; j < nHeight / 2; j ++) 203 for(i = 0; i < nWidth / 2; i ++) 204 { 205 if(p_data[j * nLineByte + i] < nThreshold[0][0]) 206 p_data[j * nLineByte + i] = 0; 207 else 208 p_data[j * nLineByte + i] = 255; 209 } 210 211 // 对右下图像逐点扫描,计算该子图像的灰度平均值 212 nAvgValue = 0; 213 for(j = 0; j < nHeight / 2; j ++) 214 for(i = nWidth / 2; i < nWidth; i ++) 215 nAvgValue += p_data[j * nLineByte + i]; 216 nAvgValue /= ((nHeight / 2) * (nLineByte / 2)); 217 218 // 设置阈值为子图像的平均值 219 nThreshold[1][1] = nAvgValue; 220 221 // 对右下下图像逐点扫描并进行阈值分割 222 for(j = 0; j < nHeight / 2; j ++) 223 for(i = nWidth / 2; i < nWidth;i ++) 224 { 225 if(p_data[j * nLineByte + i] < nThreshold[0][0]) 226 p_data[j * nLineByte + i] = 0; 227 else 228 p_data[j * nLineByte + i] = 255; 229 } 230 }
最后我们在视图类的实现(C*View.cpp)文件里添加命令响应函数:
/** C**View.cpp*/
1 void CImgProView::OnThreshhold() 2 { 3 // TODO: 在此添加命令处理程序代码 4 CThresholdDlg thresholddlg; 5 thresholddlg.DoModal(); 6 }
注:Dib.h和Dib.cpp文件在
VC++2010开发数字图像系统1
中给出