博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenCV 2.2版本号以上显示图片到 MFC 的 Picture Control 控件中
阅读量:6453 次
发布时间:2019-06-23

本文共 7696 字,大约阅读时间需要 25 分钟。

    OpenCV 2.2 以及后面的版本号取消掉了 CvvImage.h 和CvvImage.cpp 两个文件,直接导致了苦逼的程序猿无法调用里面的显示函数来将图片显示到 MFC 的 Picture Control 控件中。为此,网上非常多人表示仅仅要将那两个文件人为的提取出来然后放到project里面就解决这个问题了,也提供了两个文件的下载,可是这麻烦不说。还会导致一些奇奇怪怪的报错(至少本人是这种,非常崩溃!)。所以在了解了一些gdi画图之后结合网上的代码写了例如以下的函数,仅仅需调用就能够将OpenCV的图片显示在上面了(仅仅支持三通道不支持单通道),初步測试效率跟原来两个文件差点儿相同。假设有大神请帮我完好这份代码!

    配置好 OpenCV 后,在文件头部加入例如以下一行代码:

#define   WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数
    在对话框类中声明函数:

void drawpic(IplImage* img, unsigned int id);//画图到 MFC 的 Picture Control 控件相关函数。參数一为 OpenCV 的图像数据结构类。參数二为 Picture Control 控件的id

    定义函数例如以下:

void CMFCDrawDlg::drawpic(IplImage* img, unsigned int id)//CMFCDrawDlg为对话框类名{	BITMAPINFO *pbmi;//位图信息	BYTE *bmibuf;//位图信息空间	BYTE *g_pBits;	HDC g_hMemDC;	HBITMAP g_hBmp;	CDC *pDC;	CStatic *pic;	int width, height;	CRect rect;	//位图信息初始化	bmibuf = new BYTE[sizeof(BITMAPINFO)+256 * sizeof(RGBQUAD)];	memset(bmibuf, 0, sizeof(bmibuf));	pbmi = (BITMAPINFO*)bmibuf;	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);	pbmi->bmiHeader.biWidth = img->width;	pbmi->bmiHeader.biHeight = img->height;	pbmi->bmiHeader.biPlanes = 1;	pbmi->bmiHeader.biBitCount = 24;	pbmi->bmiHeader.biCompression = BI_RGB;	//获得设备DC和显示宽高	pDC = GetDlgItem(id)->GetDC();	pic = (CStatic*)GetDlgItem(id);	pic->GetClientRect(&rect);	width = rect.Width();	height = rect.Height();	g_hMemDC = CreateCompatibleDC(pDC->m_hDC);//创建兼容设备环境的内存DC	g_hBmp = CreateDIBSection(g_hMemDC, pbmi, DIB_RGB_COLORS, (void**)&g_pBits, 0, 0);//创建应用程序能够直接写入的、与设备无关的位图	//改动图像内容:g_pBits	int l_width = WIDTHBYTES(img->width* pbmi->bmiHeader.biBitCount);	for (int row = 0; row < img->height; row++)		memcpy(&g_pBits[row*l_width], &img->imageData[(img->height - row - 1)*l_width], l_width);	SelectObject(g_hMemDC, g_hBmp);//将位图对象选入g_hMemDC内存DC中	//拉伸画图	TransparentBlt(pDC->m_hDC, 0, 0, width, height, g_hMemDC, 0, 0, img->width, img->height, RGB(1, 0, 0));//RGB值原本设置为(0,0,0),只是似乎在这里画图会有bug,是故改为(1,0,0)	//释放内存资源	ReleaseDC(pDC);	DeleteDC(g_hMemDC);	DeleteObject(pic);	DeleteObject(g_hBmp);}
 
    在须要将图片显示到 Picture Control 控件的地方加入例如以下代码就可以:

char *filename = "pic1.jpg";//图像路径IplImage* img = cvLoadImage(filename);drawpic(img, IDC_STATIC_SHOW);//IDC_STATIC_SHOW 为Picture Control 控件的IDcvReleaseImage(&img);

    离最開始写这篇文章已经非常久了,因为近期须要进行画图方面的工作且该工作要求画图效率非常高,是故又回过头来看这份东西。发现了一些错误,也把错误的地方改动掉了。相信有GDI画图基础的人应该早就看出来了,实在羞愧。

    对于上面的那份代码,是能够适用于普通情况的画图工作的。然而假设须要进一步优化性能还是大有可为的,比方将程序拆分成“初始化”,“主体部分”,“内存释放”三个部分。便不用每次显示图片都进行初始化和内存释放,会进一步的提高程序的效率。以下将改动版本号的代码也放上来。

    声明一个类用以存放位图和设备环境等相关信息:

class drawBitmapobj{public:	//位图对象	BITMAPINFO *pbmi;//位图信息	BYTE *bmibuf;//位图信息空间	BYTE *g_pBits;	HBITMAP g_hBmp;	CDC *pDC;	CRect rect;	CStatic *pic;	HDC g_hMemDC;};
    在对话框类中声明函数:
void drawpicinit(IplImage* img, unsigned int id, drawBitmapobj &mybmpobj);//初始化函数。參数一为 OpenCV的图像数据结构类,參数二为控件id,參数三为位图和设备信息对象void drawpic(IplImage* img, drawBitmapobj &mybmpobj);//画图到MFC的 Picture Control 控件相关函数。參数一为 OpenCV的图像数据结构类,參数二为位图和设备信息对象void drawrelease(drawBitmapobj &mybmpobj);//释放画图对象
    由于涉及到位图,须要四字节对齐。所以将该公式也放在须要用到的文件头部:
#define   WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数

    分别定义三个函数:

void  CMFCDrawDlg::drawpicinit(IplImage* img, unsigned int id, drawBitmapobj &mybmpobj){	//位图信息初始化	mybmpobj.bmibuf = new BYTE[sizeof(BITMAPINFO)+256 * sizeof(RGBQUAD)];	memset(mybmpobj.bmibuf, 0, sizeof(mybmpobj.bmibuf));	mybmpobj.pbmi = (BITMAPINFO*)mybmpobj.bmibuf;	mybmpobj.pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);	mybmpobj.pbmi->bmiHeader.biWidth = img->width;	mybmpobj.pbmi->bmiHeader.biHeight = img->height;	mybmpobj.pbmi->bmiHeader.biPlanes = 1;	mybmpobj.pbmi->bmiHeader.biBitCount = 24;	mybmpobj.pbmi->bmiHeader.biCompression = BI_RGB;		mybmpobj.pDC = GetDlgItem(id)->GetDC();	mybmpobj.pic = (CStatic*)GetDlgItem(id);	mybmpobj.pic->GetClientRect(&mybmpobj.rect);	mybmpobj.g_hMemDC = CreateCompatibleDC(mybmpobj.pDC->m_hDC);//创建兼容设备环境的内存DC	mybmpobj.g_hBmp = CreateDIBSection(mybmpobj.g_hMemDC, mybmpobj.pbmi, DIB_RGB_COLORS, (void**)&mybmpobj.g_pBits, 0, 0);//创建应用程序能够直接写入的、与设备无关的位图}void CMFCDrawDlg::drawpic(IplImage* img, drawBitmapobj &mybmpobj)//CMFCOpenCVShowDlg 为对话框类名{	//改动图像内容:g_pBits	//这里这么做一则为BMP图像的四字节对齐机制。二则是由于BMP图像是从图像的左下角開始算起的,假设直接拷贝会导致图像上下颠倒	int l_width = WIDTHBYTES(img->width* mybmpobj.pbmi->bmiHeader.biBitCount);	for (int row = 0; row < img->height; row++)		memcpy(&mybmpobj.g_pBits[row*l_width], &img->imageData[(img->height - row - 1)*l_width], l_width);	SelectObject(mybmpobj.g_hMemDC, mybmpobj.g_hBmp);//将位图对象选入g_hMemDC内存DC中	//拉伸画图	TransparentBlt(mybmpobj.pDC->m_hDC, 0, 0, mybmpobj.rect.Width(), mybmpobj.rect.Height(), mybmpobj.g_hMemDC, 0, 0, img->width, img->height, RGB(1, 0, 0));//RGB值原本设置为(0,0,0),只是似乎在这里画图会有bug,是故改为(1,0,0)}void CMFCDrawDlg::drawrelease(drawBitmapobj &mybmpobj){	//释放内存资源	        delete[]mybmpobj.bmibuf;	DeleteDC(mybmpobj.g_hMemDC);	DeleteObject(mybmpobj.pic);	DeleteObject(mybmpobj.g_hBmp);	ReleaseDC(mybmpobj.pDC);}

    做完上面那些就OK了,调用的方式例如以下:

drawBitmapobj mybmpobj;char *filename = "1.jpg";//图像路径IplImage* img = cvLoadImage(filename);drawpicinit(img, IDC_STATIC_SHOW, mybmpobj);long begintime = clock();int i = 8;while (i--){	drawpic(img, mybmpobj);//IDC_STATIC_SHOW 为Picture Control 控件的ID}printf("消耗时间:%dms\n", (clock() - begintime)/8);cvReleaseImage(&img);drawrelease(mybmpobj);

    当然。也能够进一步直接将其封装成一个类

#include "stdafx.h"#include "afxdialogex.h"/******************************名字:绘制图像类**功能:Opencv输入的IplImage图像对象绘制图像到指定窗口的控件中**解释:showWnd为指定窗口,id为指定窗口id。img为输入图像对象**作者:weixinhum**时间:2015/10/29****************************/class PaintImgToScreenControls : public CDialogEx{public:	//位图对象	BITMAPINFO *pbmi;//位图信息	BYTE *bmibuf;//位图信息空间	BYTE *g_pBits;	HBITMAP g_hBmp;	CDC *pDC;	CRect rect;	CStatic *pic;	HDC g_hMemDC;	void drawpicinit(IplImage* img, unsigned int id, CWnd* showWnd);//初始化函数。參数一为 OpenCV的图像数据结构类,參数二为控件id	void drawpic(IplImage* img);//画图到MFC的 Picture Control 控件相关函数,參数一为 OpenCV的图像数据结构类	void drawrelease();//释放画图对象	CWnd* mShowWnd;};#define   WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数  void  PaintImgToScreenControls::drawpicinit(IplImage* img, unsigned int id, CWnd* showWnd){	//位图信息初始化	bmibuf = new BYTE[sizeof(BITMAPINFO)+256 * sizeof(RGBQUAD)];	memset(bmibuf, 0, sizeof(bmibuf));	pbmi = (BITMAPINFO*)bmibuf;	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);	pbmi->bmiHeader.biWidth = img->width;	pbmi->bmiHeader.biHeight = img->height;	pbmi->bmiHeader.biPlanes = 1;	pbmi->bmiHeader.biBitCount = 24;	pbmi->bmiHeader.biCompression = BI_RGB;	mShowWnd = showWnd;	pDC = mShowWnd->GetDlgItem(id)->GetDC();	pic = (CStatic*)mShowWnd->GetDlgItem(id);	pic->GetClientRect(&rect);	g_hMemDC = CreateCompatibleDC(pDC->m_hDC);//创建兼容设备环境的内存DC	g_hBmp = CreateDIBSection(g_hMemDC, pbmi, DIB_RGB_COLORS, (void**)&g_pBits, 0, 0);//创建应用程序能够直接写入的、与设备无关的位图}void PaintImgToScreenControls::drawpic(IplImage* img)//CMFCOpenCVShowDlg 为对话框类名{	//改动图像内容:g_pBits	//这里这么做一则为BMP图像的四字节对齐机制,二则是由于BMP图像是从图像的左下角開始算起的。假设直接拷贝会导致图像上下颠倒	int l_width = WIDTHBYTES(img->width* pbmi->bmiHeader.biBitCount);	for (int row = 0; row < img->height; row++)		memcpy(&g_pBits[row*l_width], &img->imageData[(img->height - row - 1)*l_width], l_width);	SelectObject(g_hMemDC, g_hBmp);//将位图对象选入g_hMemDC内存DC中	//拉伸画图	TransparentBlt(pDC->m_hDC, 0, 0, rect.Width(), rect.Height(), g_hMemDC, 0, 0, img->width, img->height, RGB(1, 0, 0));//RGB值原本设置为(0,0,0),只是似乎在这里画图会有bug,是故改为(1,0,0)}void PaintImgToScreenControls::drawrelease(){	//释放内存资源		delete[]bmibuf;	DeleteDC(g_hMemDC);	DeleteObject(pic);	DeleteObject(g_hBmp);	mShowWnd->ReleaseDC(pDC);}
    然后调用

PaintImgToScreenControls paintObj;char *filename = "pano.jpg";//图像路径IplImage* img = cvLoadImage(filename);paintObj.drawpicinit(img, IDC_STATIC_PANO, this);int i = 8;while (i--){	paintObj.drawpic(img);//IDC_STATIC_SHOW 为Picture Control 控件的ID}cvReleaseImage(&img);paintObj.drawrelease();

转载地址:http://rpfzo.baihongyu.com/

你可能感兴趣的文章
Run as ant build每次都执行两次
查看>>
自己的TableDataEntity、手工代码绑定实体、反射绑定实体性能对比
查看>>
apk动态调试
查看>>
sql 语句整理
查看>>
POJ1389:Area of Simple Polygons——扫描线线段树题解+全套代码注释
查看>>
BZOJ1911:[Apio2010]特别行动队——题解
查看>>
14:开发脚本入侵检测与报警案例
查看>>
python 重要模块
查看>>
单词王(kingWord)
查看>>
javascript数据变量类型判断(JS变量是否是数组,是否是函数的判断)
查看>>
css知多少(9)——float下篇(转)
查看>>
JavaScript中科学计数法转化为数值字符串形式
查看>>
thrift语法
查看>>
杀死进程
查看>>
Kafka之生产者消费者示例
查看>>
CMS:文章管理之模型和Store
查看>>
【FTP】java FTPClient 文件上传内容为空,文件大小为0
查看>>
新项目经理必读:分析什么是项目经理
查看>>
微信“摇一摇&#183;周边”正式开放
查看>>
java jdbc与odbc数据库的连接mysql数据库
查看>>