在MFC中調用opencv顯示一張圖片,一般用到CvvImage類。這個文件Opencv2.2版本以上已經剔除了,但可以從低版本拷貝過來。
OpenCV+VS2010+MFC動態鏈接相對比較容易,但靜態鏈接需要注意到一些坑。
為了有個比較,先說下動態鏈接。
動態鏈接
1、項目屬性-常規-MFC的使用,選擇“在共享DLL中使用MFC”。“C/C++”-代碼生成-運行庫,選擇“多線程DLL(/MD)”,若是Debug則選擇“多線程調試DLL(/MDd)”。
2、OpenCV相關頭文件和庫路徑、庫文件的添加:庫文件路徑記得選“build\x86\vc10\lib”,而非“build\x86\vc10\staticlib”。
3、生成后,要在其他未配置OpenCV和VS2010的地方運行,需要拷貝OpenCV相關dll文件以及VS2010相關dll(若是Degug版本,拷貝msvcp100d.dll以及msvcr100d.dll;若是Release版本,則對應拷貝msvcp100.dll以及msvcr100.dll)。此外,tbb_debug.dll(Release版本對應tbb.dll),一般也是需要的。tbb_debug.dll和tbb.dll在OpenCV2.3.1及以上版本中時沒有的,可在OpenCV2.3.0中拷貝(目錄build\x86\vc10\bin下)
4、拷貝到XP系統上運行時,一般還需要拷貝文件mfc100d.dll。
5、如果用了特征檢測的函數,除了拷貝dll文件opencv_features2d***d.dll外(Release版本對應opencv_features2d***.dll),一般還需要拷貝opencv_flann***d.dll(Release版本對應opencv_flann231.dll)。
注:文件msvcp100d.dll以及msvcr100d.dll可在目錄Microsoft Visual Studio 10.0\VC\redist\x86下找,或者直接在網上下載也可。
靜態鏈接
靜態鏈接相比動態鏈接,有幾個坑需要注意。
1、MFC的使用:選擇在靜態庫中使用MFC。
2、“C/C++”-代碼生成-運行庫:選擇“多線程(/MT)”,若是Debug版本則選擇“多線程調試(/MTd)”。這一點尤其注意。
3、OpenCV庫文件路徑選擇“build\x86\vc10\staticlib”,然后添加相關庫文件名即可。
4、由於OpenCV的庫依賴於一些圖像庫,所以靜態鏈接時如果不加入這些庫,將導致鏈接錯誤。這些庫文件包括
libjasper.lib
libjpeg.lib
libpng.lib
libtiff.lib
zlib.lib
OpenCV2.3.1及以上版本若沒有這些文件,可從OpenCV2.3.0版本目錄“\build\x86\vc10\staticlib”下拷貝過去。
5、opencv_highgui***.lib和CvvImage類中函數void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)可能會出現重定義,這樣鏈接時會導致錯誤。這時可以把CvvImage.cpp中三處FillBitmapInfo改個名字即可,如均改為FillBitmapInfo2。
附CvvImage類文件和顯示圖片對應代碼:
CvvImage.h
#pragma once #ifndef CVVIMAGE_CLASS_DEF #define CVVIMAGE_CLASS_DEF #include <opencv2\opencv.hpp> class CvvImage { public: CvvImage(); virtual ~CvvImage(); virtual bool Create( int width, int height, int bits_per_pixel, int image_origin = 0 ); virtual bool Load( const char* filename, int desired_color = 1 ); virtual bool LoadRect( const char* filename, int desired_color, CvRect r ); #if defined WIN32 || defined _WIN32 virtual bool LoadRect( const char* filename, int desired_color, RECT r ) { return LoadRect( filename, desired_color, cvRect( r.left, r.top, r.right - r.left, r.bottom - r.top )); } #endif virtual bool Save( const char* filename ); virtual void CopyOf( CvvImage& image, int desired_color = -1 ); virtual void CopyOf( IplImage* img, int desired_color = -1 ); IplImage* GetImage() { return m_img; }; virtual void Destroy(void); int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; }; int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height;}; int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; }; virtual void Fill( int color ); virtual void Show( const char* window ); #if defined WIN32 || defined _WIN32 virtual void Show( HDC dc, int x, int y, int width, int height, int from_x = 0, int from_y = 0 ); virtual void DrawToHDC( HDC hDCDst, RECT* pDstRect ); #endif protected: IplImage * m_img; }; typedef CvvImage CImage; #endif
CvvImage.cpp(注意63行、212行、249行對應FillBitmapInfo已修改為FillBitmapInfo2)
1 #include "StdAfx.h" 2 #include "CvvImage.h" 17 CV_INLINE RECT NormalizeRect( RECT r ); 18 CV_INLINE RECT NormalizeRect( RECT r ) 19 { 20 int t; 21 if( r.left > r.right ) 22 { 23 t = r.left; 24 r.left = r.right; 25 r.right = t; 26 } 27 if( r.top > r.bottom ) 28 { 29 t = r.top; 30 r.top = r.bottom; 31 r.bottom = t; 32 } 33 return r; 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 CV_INLINE RECT CvRectToRect( CvRect sr ); 42 CV_INLINE RECT CvRectToRect( CvRect sr ) 43 { 44 RECT dr; 45 dr.left = sr.x; 46 dr.top = sr.y; 47 dr.right = sr.x + sr.width; 48 dr.bottom = sr.y + sr.height; 49 return dr; 50 } 51 CV_INLINE IplROI RectToROI( RECT r ); 52 CV_INLINE IplROI RectToROI( RECT r ) 53 { 54 IplROI roi; 55 r = NormalizeRect( r ); 56 roi.xOffset = r.left; 57 roi.yOffset = r.top; 58 roi.width = r.right - r.left; 59 roi.height = r.bottom - r.top; 60 roi.coi = 0; 61 return roi; 62 } 63 void FillBitmapInfo2( BITMAPINFO* bmi, int width, int height, int bpp, int origin ) 64 { 65 assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); 66 BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); 67 memset( bmih, 0, sizeof(*bmih)); 68 bmih->biSize = sizeof(BITMAPINFOHEADER); 69 bmih->biWidth = width; 70 bmih->biHeight = origin ? abs(height) : -abs(height); 71 bmih->biPlanes = 1; 72 bmih->biBitCount = (unsigned short)bpp; 73 bmih->biCompression = BI_RGB; 74 if( bpp == 8 ) 75 { 76 RGBQUAD* palette = bmi->bmiColors; 77 int i; 78 for( i = 0; i < 256; i++ ) 79 { 80 palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; 81 palette[i].rgbReserved = 0; 82 } 83 } 84 } 85 CvvImage::CvvImage() 86 { 87 m_img = 0; 88 } 89 void CvvImage::Destroy() 90 { 91 cvReleaseImage( &m_img ); 92 } 93 CvvImage::~CvvImage() 94 { 95 Destroy(); 96 } 97 bool CvvImage::Create( int w, int h, int bpp, int origin ) 98 { 99 const unsigned max_img_size = 10000; 100 if( (bpp != 8 && bpp != 24 && bpp != 32) || 101 (unsigned)w >= max_img_size || (unsigned)h >= max_img_size || 102 (origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL)) 103 { 104 assert(0); // most probably, it is a programming error 105 return false; 106 } 107 if( !m_img || Bpp() != bpp || m_img->width != w || m_img->height != h ) 108 { 109 if( m_img && m_img->nSize == sizeof(IplImage)) 110 Destroy(); 111 112 m_img = cvCreateImage( cvSize( w, h ), IPL_DEPTH_8U, bpp/8 ); 113 } 114 if( m_img ) 115 m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL; 116 return m_img != 0; 117 } 118 void CvvImage::CopyOf( CvvImage& image, int desired_color ) 119 { 120 IplImage* img = image.GetImage(); 121 if( img ) 122 { 123 CopyOf( img, desired_color ); 124 } 125 } 126 #define HG_IS_IMAGE(img) \ 127 ((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && \ 128 ((IplImage*)img)->imageData != 0) 129 void CvvImage::CopyOf( IplImage* img, int desired_color ) 130 { 131 if( HG_IS_IMAGE(img) ) 132 { 133 int color = desired_color; 134 CvSize size = cvGetSize( img ); 135 if( color < 0 ) 136 color = img->nChannels > 1; 137 if( Create( size.width, size.height, 138 (!color ? 1 : img->nChannels > 1 ? img->nChannels : 3)*8, 139 img->origin )) 140 { 141 cvConvertImage( img, m_img, 0 ); 142 } 143 } 144 } 145 bool CvvImage::Load( const char* filename, int desired_color ) 146 { 147 IplImage* img = cvLoadImage( filename, desired_color ); 148 if( !img ) 149 return false; 150 CopyOf( img, desired_color ); 151 cvReleaseImage( &img ); 152 return true; 153 } 154 bool CvvImage::LoadRect( const char* filename, 155 int desired_color, CvRect r ) 156 { 157 if( r.width < 0 || r.height < 0 ) return false; 158 IplImage* img = cvLoadImage( filename, desired_color ); 159 if( !img ) 160 return false; 161 if( r.width == 0 || r.height == 0 ) 162 { 163 r.width = img->width; 164 r.height = img->height; 165 r.x = r.y = 0; 166 } 167 if( r.x > img->width || r.y > img->height || 168 r.x + r.width < 0 || r.y + r.height < 0 ) 169 { 170 cvReleaseImage( &img ); 171 return false; 172 } 173 174 if( r.x < 0 ) 175 { 176 r.width += r.x; 177 r.x = 0; 178 } 179 if( r.y < 0 ) 180 { 181 r.height += r.y; 182 r.y = 0; 183 } 184 if( r.x + r.width > img->width ) 185 r.width = img->width - r.x; 186 if( r.y + r.height > img->height ) 187 r.height = img->height - r.y; 188 cvSetImageROI( img, r ); 189 CopyOf( img, desired_color ); 190 cvReleaseImage( &img ); 191 return true; 192 } 193 bool CvvImage::Save( const char* filename ) 194 { 195 if( !m_img ) 196 return false; 197 cvSaveImage( filename, m_img ); 198 return true; 199 } 200 void CvvImage::Show( const char* window ) 201 { 202 if( m_img ) 203 cvShowImage( window, m_img ); 204 } 205 void CvvImage::Show( HDC dc, int x, int y, int w, int h, int from_x, int from_y ) 206 { 207 if( m_img && m_img->depth == IPL_DEPTH_8U ) 208 { 209 uchar buffer[sizeof(BITMAPINFOHEADER) + 1024]; 210 BITMAPINFO* bmi = (BITMAPINFO*)buffer; 211 int bmp_w = m_img->width, bmp_h = m_img->height; 212 FillBitmapInfo2( bmi, bmp_w, bmp_h, Bpp(), m_img->origin ); 213 from_x = MIN( MAX( from_x, 0 ), bmp_w - 1 ); 214 from_y = MIN( MAX( from_y, 0 ), bmp_h - 1 ); 215 int sw = MAX( MIN( bmp_w - from_x, w ), 0 ); 216 int sh = MAX( MIN( bmp_h - from_y, h ), 0 ); 217 SetDIBitsToDevice( 218 dc, x, y, sw, sh, from_x, from_y, from_y, sh, 219 m_img->imageData + from_y*m_img->widthStep, 220 bmi, DIB_RGB_COLORS ); 221 } 222 } 223 void CvvImage::DrawToHDC( HDC hDCDst, RECT* pDstRect ) 224 { 225 if( pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData ) 226 { 227 uchar buffer[sizeof(BITMAPINFOHEADER) + 1024]; 228 BITMAPINFO* bmi = (BITMAPINFO*)buffer; 229 int bmp_w = m_img->width, bmp_h = m_img->height; 230 CvRect roi = cvGetImageROI( m_img ); 231 CvRect dst = RectToCvRect( *pDstRect ); 232 if( roi.width == dst.width && roi.height == dst.height ) 233 { 234 Show( hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y ); 235 return; 236 } 237 if( roi.width > dst.width ) 238 { 239 SetStretchBltMode( 240 hDCDst, // handle to device context 241 HALFTONE ); 242 } 243 else 244 { 245 SetStretchBltMode( 246 hDCDst, // handle to device context 247 COLORONCOLOR ); 248 } 249 FillBitmapInfo2( bmi, bmp_w, bmp_h, Bpp(), m_img->origin ); 250 ::StretchDIBits( 251 hDCDst, 252 dst.x, dst.y, dst.width, dst.height, 253 roi.x, roi.y, roi.width, roi.height, 254 m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY ); 255 } 256 } 257 void CvvImage::Fill( int color ) 258 { 259 cvSet( m_img, cvScalar(color&255,(color>>8)&255,(color>>16)&255,(color>>24)&255) ); 260 }
顯示圖片函數代碼
void TestDlg::ShowImage(IplImage* img, UINT ID) { CDC *pDC = GetDlgItem(ID)->GetDC(); HDC hDC= pDC->GetSafeHdc(); CRect rect; GetDlgItem(ID)->GetClientRect(&rect); CvvImage cimg; cimg.CopyOf( img ); // 復制圖片 cimg.DrawToHDC( hDC, &rect ); // 將圖片繪制到顯示控件的指定區域內 ReleaseDC( pDC ); }