本文参考自https://blog.csdn.net/byxdaz/article/details/88091164
本人测试代码如下:
// ShowImageInMFCDlg.h : 头文件 // #pragma once #include <vector> #include <string> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; // CShowImageInMFCDlg 对话框 class CShowImageInMFCDlg : public CDialogEx { // 构造 public: CShowImageInMFCDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_SHOWIMAGEINMFC_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedBtnReadimg(); private: CRect m_rectPic; // 方法1:将opencv的显示窗口与MFC的控件链接起来,效果是opencv的窗口恰好覆盖在控件 HWND hNameWindowParent = nullptr; bool showImage(const std::string &cvWindowName, UINT nControlID, cv::Mat mat, bool bRoomToControlSize = false); bool detachWindow(const std::string &cvWindowName, HWND hNameWindowParent); bool attachWindow(const std::string &cvWindowName, HWND &hNameWindowParent, UINT nControlID); // 方法2:使用CvvImage类 // 方法3:MFC的绘图函数,将opencv图像数据先copy到缓冲区然后在控件上绘制处理 void DrawMat(cv::Mat &img, UINT nControlID, bool bRoomToControlSize = false); public: afx_msg void OnBnClickedBtnRaed2(); afx_msg void OnBnClickedBtnRaed3(); };
// ShowImageInMFCDlg.cpp : 实现文件 // #include "stdafx.h" #include "ShowImageInMFC.h" #include "ShowImageInMFCDlg.h" #include "afxdialogex.h" #include "CvvImage.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CShowImageInMFCDlg 对话框 CShowImageInMFCDlg::CShowImageInMFCDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_SHOWIMAGEINMFC_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CShowImageInMFCDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CShowImageInMFCDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_READIMG, &CShowImageInMFCDlg::OnBnClickedBtnReadimg) ON_BN_CLICKED(IDC_BTN_RAED2, &CShowImageInMFCDlg::OnBnClickedBtnRaed2) ON_BN_CLICKED(IDC_BTN_RAED3, &CShowImageInMFCDlg::OnBnClickedBtnRaed3) END_MESSAGE_MAP() // CShowImageInMFCDlg 消息处理程序 BOOL CShowImageInMFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 //// TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CShowImageInMFCDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CShowImageInMFCDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CShowImageInMFCDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } // 方法1: void CShowImageInMFCDlg::OnBnClickedBtnReadimg() { // TODO: 在此添加控件通知处理程序代码 CFileDialog openFileDlg(TRUE,/*FileOpen*/ _T("*.bmp"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY /*| OFN_ALLOWMULTISELECT 可以开启多选模式*/, _T("Image Files(*.bmp;*.png;*.jpg;*.raw)|*.bmp; *.png; *.jpg; *.raw|All Files (*.*)|*.*||")); openFileDlg.m_ofn.lpstrTitle = _T("选择图片"); // 设置对话框的标题 if (openFileDlg.DoModal() != IDOK) { return; } CString filePath = openFileDlg.GetPathName(); USES_CONVERSION; char *s = T2A(filePath); if (hNameWindowParent) { //不显示图像或销毁图像 detachWindow("win", hNameWindowParent); } attachWindow("win", hNameWindowParent, IDC_STATIC_IMAGE); Mat mat = imread(s, true); showImage("win", IDC_STATIC_IMAGE, mat); } bool CShowImageInMFCDlg::attachWindow(const std::string &cvWindowName, HWND &hNameWindowParent, UINT nControlID) { cv::destroyWindow(cvWindowName); cv::namedWindow(cvWindowName, WINDOW_AUTOSIZE); HWND hWnd = (HWND)cvGetWindowHandle(cvWindowName.c_str()); hNameWindowParent = ::GetParent(hWnd); ::SetParent(hWnd, GetDlgItem(nControlID)->m_hWnd); ::ShowWindow(hNameWindowParent, SW_HIDE); return true; } bool CShowImageInMFCDlg::detachWindow(const std::string &cvWindowName, HWND hNameWindowParent) { cv::destroyWindow(cvWindowName); if (hNameWindowParent) { ::ShowWindow(hNameWindowParent, SW_HIDE); ::PostMessage(hNameWindowParent, WM_CLOSE, 0, 0); } return true; } bool CShowImageInMFCDlg::showImage(const std::string &cvWindowName, UINT nControlID, cv::Mat mat, bool bRoomToControlSize) { CRect rect; GetDlgItem(nControlID)->GetClientRect(&rect); if (bRoomToControlSize) { cv::resize(mat, mat, cv::Size(rect.Width(), rect.Height())); } imshow(cvWindowName, mat); return true; } // 方法2: void CShowImageInMFCDlg::OnBnClickedBtnRaed2() { // TODO: 在此添加控件通知处理程序代码 CFileDialog openFileDlg(TRUE,/*FileOpen*/ _T("*.bmp"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY /*| OFN_ALLOWMULTISELECT 可以开启多选模式*/, _T("Image Files(*.bmp;*.png;*.jpg;*.raw)|*.bmp; *.png; *.jpg; *.raw|All Files (*.*)|*.*||")); openFileDlg.m_ofn.lpstrTitle = _T("选择图片"); // 设置对话框的标题 if (openFileDlg.DoModal() != IDOK) { return; } CString filePath = openFileDlg.GetPathName(); USES_CONVERSION; char *s = T2A(filePath); //利用CvvImage显示图像 IplImage *image; image = cvLoadImage(s); CvvImage cimg; CRect rect; GetDlgItem(IDC_STATIC_IMAGE)->GetClientRect(&rect); CDC *pDC = GetDlgItem(IDC_STATIC_IMAGE)->GetDC(); cimg.CopyOf(image); cimg.DrawToHDC(pDC->GetSafeHdc(), &rect); ReleaseDC(pDC); } // 方法3: void CShowImageInMFCDlg::OnBnClickedBtnRaed3() { CFileDialog openFileDlg(TRUE,/*FileOpen*/ _T("*.bmp"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY /*| OFN_ALLOWMULTISELECT 可以开启多选模式*/, _T("Image Files(*.bmp;*.png;*.jpg;*.raw)|*.bmp; *.png; *.jpg; *.raw|All Files (*.*)|*.*||")); openFileDlg.m_ofn.lpstrTitle = _T("选择图片"); // 设置对话框的标题 if (openFileDlg.DoModal() != IDOK) { return; } CString filePath = openFileDlg.GetPathName(); USES_CONVERSION; char *s = T2A(filePath); // TODO: 在此添加控件通知处理程序代码 Mat image; image = imread(s); DrawMat(image, IDC_STATIC_IMAGE, true); return; } void CShowImageInMFCDlg::DrawMat(cv::Mat &img, UINT nControlID, bool bRoomToControlSize) { cv::Mat imgTmp; CRect rect; GetDlgItem(nControlID)->GetClientRect(&rect); // 获取控件大小 if (bRoomToControlSize) { cv::resize(img, imgTmp, cv::Size(rect.Width(), rect.Height()));// 缩小或放大Mat并备份 } else { img.copyTo(imgTmp); } switch (imgTmp.channels()) { case 1: cv::cvtColor(imgTmp, imgTmp, CV_GRAY2BGRA); // GRAY单通道 break; case 3: cv::cvtColor(imgTmp, imgTmp, CV_BGR2BGRA); // BGR三通道 break; default: break; } int pixelBytes = imgTmp.channels()*(imgTmp.depth() + 1); // 计算一个像素多少个字节 // 制作bitmapinfo(数据头) BITMAPINFO bitInfo; bitInfo.bmiHeader.biBitCount = 8 * pixelBytes; bitInfo.bmiHeader.biWidth = imgTmp.cols; bitInfo.bmiHeader.biHeight = -imgTmp.rows; bitInfo.bmiHeader.biPlanes = 1; bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bitInfo.bmiHeader.biCompression = BI_RGB; bitInfo.bmiHeader.biClrImportant = 0; bitInfo.bmiHeader.biClrUsed = 0; bitInfo.bmiHeader.biSizeImage = 0; bitInfo.bmiHeader.biXPelsPerMeter = 0; bitInfo.bmiHeader.biYPelsPerMeter = 0; // Mat.data + bitmap数据头 -> MFC CDC *pDC = GetDlgItem(nControlID)->GetDC(); pDC->SetStretchBltMode(COLORONCOLOR); if (bRoomToControlSize) { ::StretchDIBits(pDC->GetSafeHdc() , 0, 0, rect.Width(), rect.Height() , 0, 0, imgTmp.cols, imgTmp.rows, imgTmp.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY); } else { int minWidth = min(imgTmp.cols, rect.Width()); int minHeight = min(imgTmp.rows, rect.Height()); ::StretchDIBits( pDC->GetSafeHdc(), 0, 0, minWidth, minHeight, 0, 0, minWidth, minHeight, imgTmp.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY ); } ReleaseDC(pDC); }
CvvImage类的头文件及其实现:
1 #pragma once 2 3 #ifndef CVVIMAGE_CLASS_DEF 4 #define CVVIMAGE_CLASS_DEF 5 6 #include <opencv/cv.h> 7 #include <opencv/highgui.h> 8 9 /* CvvImage class definition */ 10 class CvvImage 11 { 12 public: 13 CvvImage(); 14 virtual ~CvvImage(); 15 16 /* Create image (BGR or grayscale) */ 17 virtual bool Create(int width, int height, int bits_per_pixel, int image_origin = 0); 18 19 /* Load image from specified file */ 20 virtual bool Load(const char* filename, int desired_color = 1); 21 22 /* Load rectangle from the file */ 23 virtual bool LoadRect(const char* filename, 24 int desired_color, CvRect r); 25 26 #if defined WIN32 || defined _WIN32 27 virtual bool LoadRect(const char* filename, 28 int desired_color, RECT r) 29 { 30 return LoadRect(filename, desired_color, 31 cvRect(r.left, r.top, r.right - r.left, r.bottom - r.top)); 32 } 33 #endif 34 35 /* Save entire image to specified file. */ 36 virtual bool Save(const char* filename); 37 38 /* Get copy of input image ROI */ 39 virtual void CopyOf(CvvImage& image, int desired_color = -1); 40 virtual void CopyOf(IplImage* img, int desired_color = -1); 41 42 IplImage* GetImage() { return m_img; }; 43 virtual void Destroy(void); 44 45 /* width and height of ROI */ 46 int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; }; 47 int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height; }; 48 int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; }; 49 50 virtual void Fill(int color); 51 52 /* draw to highgui window */ 53 virtual void Show(const char* window); 54 55 #if defined WIN32 || defined _WIN32 56 /* draw part of image to the specified DC */ 57 virtual void Show(HDC dc, int x, int y, int width, int height, 58 int from_x = 0, int from_y = 0); 59 /* draw the current image ROI to the specified rectangle of the destination DC */ 60 virtual void DrawToHDC(HDC hDCDst, RECT* pDstRect); 61 #endif 62 63 protected: 64 65 IplImage* m_img; 66 }; 67 68 typedef CvvImage CImage; 69 #endif
1 #include "stdafx.h" 2 #include "CvvImage.h" 3 4 // 5 // Construction/Destruction 6 // 7 8 9 CV_INLINE RECT NormalizeRect(RECT r); 10 CV_INLINE RECT NormalizeRect(RECT r) 11 { 12 int t; 13 14 15 if (r.left > r.right) 16 { 17 t = r.left; 18 r.left = r.right; 19 r.right = t; 20 } 21 22 23 if (r.top > r.bottom) 24 { 25 t = r.top; 26 r.top = r.bottom; 27 r.bottom = t; 28 } 29 30 31 return r; 32 } 33 34 35 CV_INLINE CvRect RectToCvRect(RECT sr); 36 CV_INLINE CvRect RectToCvRect(RECT sr) 37 { 38 sr = NormalizeRect(sr); 39 return cvRect(sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top); 40 } 41 42 43 CV_INLINE RECT CvRectToRect(CvRect sr); 44 CV_INLINE RECT CvRectToRect(CvRect sr) 45 { 46 RECT dr; 47 dr.left = sr.x; 48 dr.top = sr.y; 49 dr.right = sr.x + sr.width; 50 dr.bottom = sr.y + sr.height; 51 return dr; 52 } 53 54 55 CV_INLINE IplROI RectToROI(RECT r); 56 CV_INLINE IplROI RectToROI(RECT r) 57 { 58 IplROI roi; 59 r = NormalizeRect(r); 60 roi.xOffset = r.left; 61 roi.yOffset = r.top; 62 roi.width = r.right - r.left; 63 roi.height = r.bottom - r.top; 64 roi.coi = 0; 65 return roi; 66 } 67 68 69 void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin) 70 { 71 assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); 72 73 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); 74 memset(bmih, 0, sizeof(*bmih)); 75 bmih->biSize = sizeof(BITMAPINFOHEADER); 76 bmih->biWidth = width; 77 bmih->biHeight = origin ? abs(height) : -abs(height); 78 bmih->biPlanes = 1; 79 bmih->biBitCount = (unsigned short)bpp; 80 bmih->biCompression = BI_RGB; 81 82 83 if (bpp == 8) 84 { 85 RGBQUAD* palette = bmi->bmiColors; 86 int i; 87 for (i = 0; i < 256; i++) 88 { 89 palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; 90 palette[i].rgbReserved = 0; 91 } 92 } 93 } 94 95 96 CvvImage::CvvImage() 97 { 98 m_img = 0; 99 } 100 101 102 void CvvImage::Destroy() 103 { 104 cvReleaseImage(&m_img); 105 } 106 107 108 CvvImage::~CvvImage() 109 { 110 Destroy(); 111 } 112 113 114 bool CvvImage::Create(int w, int h, int bpp, int origin) 115 { 116 const unsigned max_img_size = 10000; 117 118 119 if ((bpp != 8 && bpp != 24 && bpp != 32) || 120 (unsigned)w >= max_img_size || (unsigned)h >= max_img_size || 121 (origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL)) 122 { 123 assert(0); // most probably, it is a programming error 124 return false; 125 } 126 127 128 if (!m_img || Bpp() != bpp || m_img->width != w || m_img->height != h) 129 { 130 if (m_img && m_img->nSize == sizeof(IplImage)) 131 Destroy(); 132 133 134 /* prepare IPL header */ 135 m_img = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, bpp / 8); 136 } 137 138 139 if (m_img) 140 m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL; 141 142 143 return m_img != 0; 144 } 145 146 147 void CvvImage::CopyOf(CvvImage& image, int desired_color) 148 { 149 IplImage* img = image.GetImage(); 150 if (img) 151 { 152 CopyOf(img, desired_color); 153 } 154 } 155 156 157 #define HG_IS_IMAGE(img) 158 ((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && 159 ((IplImage*)img)->imageData != 0) 160 161 162 void CvvImage::CopyOf(IplImage* img, int desired_color) 163 { 164 if (HG_IS_IMAGE(img)) 165 { 166 int color = desired_color; 167 //CvSize size = cvGetSize(img);//opencv3.4.4中调用cvGetSize出错,使用以下语句替换 168 CvSize size; 169 size.width = img->width; 170 size.height = img->height; 171 172 if (color < 0) 173 color = img->nChannels > 1; 174 175 if (Create(size.width, size.height, 176 (!color ? 1 : img->nChannels > 1 ? img->nChannels : 3) * 8, 177 img->origin)) 178 { 179 cvConvertImage(img, m_img, 0); 180 } 181 } 182 } 183 184 185 bool CvvImage::Load(const char* filename, int desired_color) 186 { 187 IplImage* img = cvLoadImage(filename, desired_color); 188 if (!img) 189 return false; 190 191 CopyOf(img, desired_color); 192 cvReleaseImage(&img); 193 return true; 194 } 195 196 197 bool CvvImage::LoadRect(const char* filename, 198 int desired_color, CvRect r) 199 { 200 if (r.width < 0 || r.height < 0) return false; 201 202 203 IplImage* img = cvLoadImage(filename, desired_color); 204 if (!img) 205 return false; 206 207 208 if (r.width == 0 || r.height == 0) 209 { 210 r.width = img->width; 211 r.height = img->height; 212 r.x = r.y = 0; 213 } 214 215 216 if (r.x > img->width || r.y > img->height || 217 r.x + r.width < 0 || r.y + r.height < 0) 218 { 219 cvReleaseImage(&img); 220 return false; 221 } 222 223 224 /* truncate r to source image */ 225 if (r.x < 0) 226 { 227 r.width += r.x; 228 r.x = 0; 229 } 230 if (r.y < 0) 231 { 232 r.height += r.y; 233 r.y = 0; 234 } 235 236 237 if (r.x + r.width > img->width) 238 r.width = img->width - r.x; 239 240 241 if (r.y + r.height > img->height) 242 r.height = img->height - r.y; 243 244 245 cvSetImageROI(img, r); 246 CopyOf(img, desired_color); 247 248 249 cvReleaseImage(&img); 250 return true; 251 } 252 253 254 bool CvvImage::Save(const char* filename) 255 { 256 if (!m_img) 257 return false; 258 cvSaveImage(filename, m_img); 259 return true; 260 } 261 262 263 void CvvImage::Show(const char* window) 264 { 265 if (m_img) 266 cvShowImage(window, m_img); 267 } 268 269 270 void CvvImage::Show(HDC dc, int x, int y, int w, int h, int from_x, int from_y) 271 { 272 if (m_img && m_img->depth == IPL_DEPTH_8U) 273 { 274 uchar buffer[sizeof(BITMAPINFOHEADER) + 1024]; 275 BITMAPINFO* bmi = (BITMAPINFO*)buffer; 276 int bmp_w = m_img->width, bmp_h = m_img->height; 277 FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin); 278 from_x = MIN(MAX(from_x, 0), bmp_w - 1); 279 from_y = MIN(MAX(from_y, 0), bmp_h - 1); 280 int sw = MAX(MIN(bmp_w - from_x, w), 0); 281 int sh = MAX(MIN(bmp_h - from_y, h), 0); 282 SetDIBitsToDevice( 283 dc, x, y, sw, sh, from_x, from_y, from_y, sh, 284 m_img->imageData + from_y*m_img->widthStep, 285 bmi, DIB_RGB_COLORS); 286 } 287 } 288 289 290 void CvvImage::DrawToHDC(HDC hDCDst, RECT* pDstRect) 291 { 292 if (pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData) 293 { 294 uchar buffer[sizeof(BITMAPINFOHEADER) + 1024]; 295 BITMAPINFO* bmi = (BITMAPINFO*)buffer; 296 int bmp_w = m_img->width, bmp_h = m_img->height; 297 298 CvRect roi = cvGetImageROI(m_img); 299 CvRect dst = RectToCvRect(*pDstRect); 300 if (roi.width == dst.width && roi.height == dst.height) 301 { 302 Show(hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y); 303 return; 304 } 305 306 if (roi.width > dst.width) 307 { 308 SetStretchBltMode( 309 hDCDst, // handle to device context 310 HALFTONE); 311 } 312 else 313 { 314 SetStretchBltMode( 315 hDCDst, // handle to device context 316 COLORONCOLOR); 317 } 318 319 FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin); 320 321 ::StretchDIBits( 322 hDCDst, 323 dst.x, dst.y, dst.width, dst.height, 324 roi.x, roi.y, roi.width, roi.height, 325 m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY); 326 } 327 } 328 329 330 void CvvImage::Fill(int color) 331 { 332 cvSet(m_img, cvScalar(color & 255, (color >> 8) & 255, (color >> 16) & 255, (color >> 24) & 255)); 333 }
效果图: