OpenCV+VS2010+MFC 静态链接 显示一张图片(使用CvvImage)

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

 

 

 

posted @ 2014-03-18 14:35  鬼蜮流风  阅读(2553)  评论(1编辑  收藏  举报