在MFC中使用OpenCV2.3.1


最近要做数字图像处理的项目,大家都说VS+MFC+OpenCV很好用,于是我就试着弄了下。首先我到OpenCV ChinaOpenCV中文版主页找了一些很不错的教程开始做了。我用的是Visual Studio 2005,OpenCV的版本是2.3.1。但是OpenCV China里好像只有关于VS2005基础上的较低版本的OpenCV的环境搭建方法,或者VS2008、VS2010等平台上才介绍了OpenCV2.0以上的版本环境搭建。由于我使用过VS2010、VS2005,感觉两个编译器相比于VS2005和VC6.0的差别还是很小的,于是我就按照在VS2008/VS2010上建立OpenCV2.3.1环境的方法在VS2005上成功建立了OpenCV2.3.1的环境。
下一步我就开始做基于MFC的OpenCV变成了,我是按照OpenCV China上的相关教程并参考了很多帖子做的快速在MFC中使用OpenCV,我几乎是一步一步的模仿,然后还是报了不少错误。为了修改这些Bug,我真是费劲了九牛二虎之力才搞定。现将工程出错信息、如何修改等问题陈述如下,希望对大家有所帮助。
按照官网的教程一步一步地做完后出现下面的错误:


生成日志      生成 已启动: 项目: COpenCV_ex2,配置: Debug|Win32
 命令行      正在创建临时文件“d:\image C++\C++\COpenCV_ex2\COpenCV_ex2\Debug\RSP00000149925924.rsp”,其内容为
[
/Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /Gm /EHsc /RTC1 /MTd /Yu"stdafx.h" /Fp"Debug\COpenCV_ex2.pch" /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /c /Wp64 /ZI /TP ".\CvvImage.cpp"

".\COpenCV_ex2View.cpp"

".\COpenCV_ex2Doc.cpp"

".\COpenCV_ex2.cpp"
]
正在创建命令行“cl.exe @"d:\image C++\C++\COpenCV_ex2\COpenCV_ex2\Debug\RSP00000149925924.rsp" /nologo /errorReport:prompt”
 输出窗口      正在编译...
CvvImage.cpp
正在生成代码...
正在编译...
COpenCV_ex2.cpp
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C2146: 语法错误 : 缺少“;”(在标识符“m_image”的前面)
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
COpenCV_ex2Doc.cpp
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C2146: 语法错误 : 缺少“;”(在标识符“m_image”的前面)
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.cpp(90) : error C2065: “m_image”: 未声明的标识符
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.cpp(90) : error C2228: “.Load”的左边必须有类/结构/联合
        类型是“'unknown-type'”
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.cpp(101) : error C2228: “.Save”的左边必须有类/结构/联合
        类型是“'unknown-type'”
COpenCV_ex2View.cpp
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C2146: 语法错误 : 缺少“;”(在标识符“m_image”的前面)
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(18) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2view.cpp(58) : error C2065: “CImage”: 未声明的标识符
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2view.cpp(58) : error C2065: “img”: 未声明的标识符
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2view.cpp(58) : error C2039: “m_image”: 不是“CCOpenCV_ex2Doc”的成员
        d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(10) : 参见“CCOpenCV_ex2Doc”的声明
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2view.cpp(61) : error C2228: “.DrawToHDC”的左边必须有类/结构/联合
        类型是“'unknown-type'”
正在生成代码...
 结果      生成日志保存在“file://d:\image C++\C++\COpenCV_ex2\COpenCV_ex2\Debug\BuildLog.htm”
COpenCV_ex2 - 16 个错误,0 个警告
  

解释:这是因为标准教程用的是较低版本的OpenCV,CImage没有定义,需要添加CvvImage.h和CvvImage.cpp两个文件到工程里:

CvvImage.h

#pragma once
#ifndef CVVIMAGE_CLASS_DEF
#define CVVIMAGE_CLASS_DEF
#include "opencv.hpp"
/* CvvImage class definition */
class  CvvImage
{
public:
	CvvImage();
	virtual ~CvvImage();
	/* Create image (BGR or grayscale) */
	virtual bool  Create( int width, int height, int bits_per_pixel, int image_origin = 0 );
	/* Load image from specified file */
	virtual bool  Load( const char* filename, int desired_color = 1 );
	/* Load rectangle from the file */
	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
	/* Save entire image to specified file. */
	virtual bool  Save( const char* filename );
	/* Get copy of input image ROI */
	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);
	/* width and height of ROI */
	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 );
	/* draw to highgui window */
	virtual void  Show( const char* window );

#if defined WIN32 || defined _WIN32
	/* draw part of image to the specified DC */
	virtual void  Show( HDC dc, int x, int y, int width, int height,
		int from_x = 0, int from_y = 0 );
	/* draw the current image ROI to the specified rectangle of the destination DC */
	virtual void  DrawToHDC( HDC hDCDst, RECT* pDstRect );
#endif
protected:
	IplImage*  m_img;
};
typedef CvvImage CImage;
#endif


CvvImage.cpp

#include "StdAfx.h"
#include "CvvImage.h"
//
// Construction/Destruction
//
CV_INLINE RECT NormalizeRect( RECT r );
CV_INLINE RECT NormalizeRect( RECT r )
{
	int t;
	if( r.left > r.right )
	{
		t = r.left;
		r.left = r.right;
		r.right = t;
	}
	if( r.top > r.bottom )
	{
		t = r.top;
		r.top = r.bottom;
		r.bottom = t;
	}


	return r;
}
CV_INLINE CvRect RectToCvRect( RECT sr );
CV_INLINE CvRect RectToCvRect( RECT sr )
{
	sr = NormalizeRect( sr );
	return cvRect( sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top );
}
CV_INLINE RECT CvRectToRect( CvRect sr );
CV_INLINE RECT CvRectToRect( CvRect sr )
{
	RECT dr;
	dr.left = sr.x;
	dr.top = sr.y;
	dr.right = sr.x + sr.width;
	dr.bottom = sr.y + sr.height;


	return dr;
}
CV_INLINE IplROI RectToROI( RECT r );
CV_INLINE IplROI RectToROI( RECT r )
{
	IplROI roi;
	r = NormalizeRect( r );
	roi.xOffset = r.left;
	roi.yOffset = r.top;
	roi.width = r.right - r.left;
	roi.height = r.bottom - r.top;
	roi.coi = 0;


	return roi;
}
void  FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
{
	assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));


	BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);


	memset( bmih, 0, sizeof(*bmih));
	bmih->biSize = sizeof(BITMAPINFOHEADER);
	bmih->biWidth = width;
	bmih->biHeight = origin ? abs(height) : -abs(height);
	bmih->biPlanes = 1;
	bmih->biBitCount = (unsigned short)bpp;
	bmih->biCompression = BI_RGB;
	if( bpp == 8 )
	{
		RGBQUAD* palette = bmi->bmiColors;
		int i;
		for( i = 0; i < 256; i++ )
		{
			palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
			palette[i].rgbReserved = 0;
		}
	}
}
CvvImage::CvvImage()
{
	m_img = 0;
}
void CvvImage::Destroy()
{
	cvReleaseImage( &m_img );
}
CvvImage::~CvvImage()
{
	Destroy();
}
bool  CvvImage::Create( int w, int h, int bpp, int origin )
{
	const unsigned max_img_size = 10000;


	if( (bpp != 8 && bpp != 24 && bpp != 32) ||
		(unsigned)w >=  max_img_size || (unsigned)h >= max_img_size ||
		(origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL))
	{
		assert(0); // most probably, it is a programming error
		return false;
	}
	if( !m_img || Bpp() != bpp || m_img->width != w || m_img->height != h )
	{
		if( m_img && m_img->nSize == sizeof(IplImage))
			Destroy();
		/* prepare IPL header */
		m_img = cvCreateImage( cvSize( w, h ), IPL_DEPTH_8U, bpp/8 );
	}
	if( m_img )
		m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL;
	return m_img != 0;
}
void  CvvImage::CopyOf( CvvImage& image, int desired_color )
{
	IplImage* img = image.GetImage();
	if( img )
	{
		CopyOf( img, desired_color );
	}
}
#define HG_IS_IMAGE(img)                                                  \
	((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && \
	((IplImage*)img)->imageData != 0)
void  CvvImage::CopyOf( IplImage* img, int desired_color )
{
	if( HG_IS_IMAGE(img) )
	{
		int color = desired_color;
		CvSize size = cvGetSize( img ); 
		if( color < 0 )
			color = img->nChannels > 1;
		if( Create( size.width, size.height,
			(!color ? 1 : img->nChannels > 1 ? img->nChannels : 3)*8,
			img->origin ))
		{
			cvConvertImage( img, m_img, 0 );
		}
	}
}
bool  CvvImage::Load( const char* filename, int desired_color )
{
	IplImage* img = cvLoadImage( filename, desired_color );
	if( !img )
		return false;


	CopyOf( img, desired_color );
	cvReleaseImage( &img );


	return true;
}
bool  CvvImage::LoadRect( const char* filename,
						 int desired_color, CvRect r )
{
	if( r.width < 0 || r.height < 0 ) return false;


	IplImage* img = cvLoadImage( filename, desired_color );
	if( !img )
		return false;
	if( r.width == 0 || r.height == 0 )
	{
		r.width = img->width;
		r.height = img->height;
		r.x = r.y = 0;
	}
	if( r.x > img->width || r.y > img->height ||
		r.x + r.width < 0 || r.y + r.height < 0 )
	{
		cvReleaseImage( &img );
		return false;
	}
	/* truncate r to source image */
	if( r.x < 0 )
	{
		r.width += r.x;
		r.x = 0;
	}
	if( r.y < 0 )
	{
		r.height += r.y;
		r.y = 0;
	}
	if( r.x + r.width > img->width )
		r.width = img->width - r.x;


	if( r.y + r.height > img->height )
		r.height = img->height - r.y;
	cvSetImageROI( img, r );
	CopyOf( img, desired_color );
	cvReleaseImage( &img );
	return true;
}
bool  CvvImage::Save( const char* filename )
{
	if( !m_img )
		return false;
	cvSaveImage( filename, m_img );
	return true;
}
void  CvvImage::Show( const char* window )
{
	if( m_img )
		cvShowImage( window, m_img );
}
void  CvvImage::Show( HDC dc, int x, int y, int w, int h, int from_x, int from_y )
{
	if( m_img && m_img->depth == IPL_DEPTH_8U )
	{
		uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
		BITMAPINFO* bmi = (BITMAPINFO*)buffer;
		int bmp_w = m_img->width, bmp_h = m_img->height;
		FillBitmapInfo( bmi, bmp_w, bmp_h, Bpp(), m_img->origin );
		from_x = MIN( MAX( from_x, 0 ), bmp_w - 1 );
		from_y = MIN( MAX( from_y, 0 ), bmp_h - 1 );
		int sw = MAX( MIN( bmp_w - from_x, w ), 0 );
		int sh = MAX( MIN( bmp_h - from_y, h ), 0 );
		SetDIBitsToDevice(
			dc, x, y, sw, sh, from_x, from_y, from_y, sh,
			m_img->imageData + from_y*m_img->widthStep,
			bmi, DIB_RGB_COLORS );
	}
}
void  CvvImage::DrawToHDC( HDC hDCDst, RECT* pDstRect ) 
{
	if( pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData )
	{
		uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
		BITMAPINFO* bmi = (BITMAPINFO*)buffer;
		int bmp_w = m_img->width, bmp_h = m_img->height;
		CvRect roi = cvGetImageROI( m_img );
		CvRect dst = RectToCvRect( *pDstRect );
		if( roi.width == dst.width && roi.height == dst.height )
		{
			Show( hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y );
			return;
		}
		if( roi.width > dst.width )
		{
			SetStretchBltMode(
				hDCDst,           // handle to device context
				HALFTONE );
		}
		else
		{
			SetStretchBltMode(
				hDCDst,           // handle to device context
				COLORONCOLOR );
		}
		FillBitmapInfo( bmi, bmp_w, bmp_h, Bpp(), m_img->origin );
		::StretchDIBits(
			hDCDst,
			dst.x, dst.y, dst.width, dst.height,
			roi.x, roi.y, roi.width, roi.height,
			m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY );
	}
}
void  CvvImage::Fill( int color )
{
	cvSet( m_img, cvScalar(color&255,(color>>8)&255,(color>>16)&255,(color>>24)&255) );
}

添加这些代码后,别忘了把.h文件添加至..View.h文件中。再重新编译,发现还是会报错:

输出窗口      正在编译...
COpenCV_ex2Doc.cpp
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.cpp(90) : error C2664: “CvvImage::Load”: 不能将参数 1 从“LPCTSTR”转换为“const char *”
        与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.cpp(101) : error C2664: “CvvImage::Save”: 不能将参数 1 从“LPCTSTR”转换为“const char *”
        与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
COpenCV_ex2View.cpp
d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2view.cpp(61) : error C2039: “GetSafeHdc”: 不是“CCOpenCV_ex2Doc”的成员
        d:\image c++\c++\copencv_ex2\copencv_ex2\copencv_ex2doc.h(10) : 参见“CCOpenCV_ex2Doc”的声明
正在生成代码...
 结果      生成日志保存在“file://d:\image C++\C++\COpenCV_ex2\COpenCV_ex2\Debug\BuildLog.htm”
COpenCV_ex2 - 3 个错误,0 个警告
 

原因是:前两个错误是因为环境字符集使用了Uincode字符集导致的,把该选项改成“未设置”即可。

第二个错误是因为copencv_ex2view.cpp文件中的void CCOpenCV_ex2View::OnDraw(CDC* /*pDC*/)函数中的pDC被注释起来了,把注释打开并把函数中的一句img.DrawToHDC(pDoc->GetSafeHdc() ,r)中的pDoc换成pDC即可。修改好的代码如下:

void CCOpenCV_ex2View::OnDraw(CDC* pDC)
{
	CCOpenCV_ex2Doc* pDoc = GetDocument();
	//ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	CImage & img = pDoc ->m_image;
	CRect r;
	GetClientRect (&r);
	img.DrawToHDC(pDC->GetSafeHdc() ,r);
}

改好之后运行,发现还是有错误:1>LINK : fatal error LNK1104: 无法打开文件“cxcore.lib”

原因是这些库的名字是OpenCV较低版本的库文件,对于OpenCV2.3.1而言,需要换个名字。选择“工程属性->链接器->输入->附加依赖项”,将里面的内容换掉:




即将cxcore.lib cv.lib highgui.lib换成opencv_core231d.lib
opencv_highgui231d.lib
opencv_imgproc231d.lib
opencv_legacy231d.lib
opencv_ml231d.lib
opencv_objdetect231d.lib
opencv_ts231d.lib
opencv_video231d.lib

其中有些项目是不需要的,不过我也不知道哪些该要哪些不该要,索性就全部填进去了。然后点确定就OK了,编译通过。我把修改好的整个解决方案都上传到CSDN了,欢迎大家下载使用。资源名字为“VS2005在MFC中使用OpenCV2.3.1 “
。我相信这个教程不仅可以在VS2005上运行良好,在VS2008、VS2010上一样可以运行得很好!

万事开头难,我相信有了这个好的开头,再做起来就容易多了!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值