在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 );
}