OpenCV 2.2版本号以上显示图片到 MFC 的 Picture Control 控件中

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 控件的ID
cvReleaseImage(&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();
时间: 2024-10-14 02:51:48

OpenCV 2.2版本号以上显示图片到 MFC 的 Picture Control 控件中的相关文章

OpenCV 2.2版本以上显示图片到 MFC 的 Picture Control 控件中

OpenCV 2.2 以及后面的版本取消掉了 CvvImage.h 和CvvImage.cpp 两个文件,直接导致了苦逼的程序员无法调用里面的显示函数来将图片显示到 MFC 的 Picture Control 控件中.为此,网上很多人表示只要将那两个文件人为的提取出来然后放到工程里面就解决问题了,也提供了两个文件的下载,但是这麻烦不说,还会导致一些奇奇怪怪的报错(至少本人是这样的,很崩溃!).所以在了解了一些gdi绘图之后结合网上的代码写了如下的函数,只需调用就可以将OpenCV的图片显示在上面

OpenCV 通过 MFC 的 Picture Control 控件操作图像

如果希望对显示在MFC Picture Control 控件里的图像进行操作,比如画线画点之类的,可以利用 OpenCV 结合 MFC 本身的鼠标响应函数来实现. 如何将图像显示到 Picture Control 控件不谈,本文是采用的这篇博客所介绍的方法实现的. 点击打开链接 给对话框添加 WM_LBUTTONDOWN 鼠标左键点击消息,在消息响应函数中添加如下代码: void CMFCOpenCVShowDlg::OnLButtonDown(UINT nFlags, CPoint point

对话框上动态控件的创建、在Picture Control控件上显示图片

1  MFC对话框之上的动态控件的创建 对话框上的控件是MFC类的一个具体对象. 当在对话框之上使用静态控件时,可以根据类向导来为每个控件添加消息.响应函数以及变量. 当需要在对话框中动态的创建某个控件时,就需要手动来代替类向导为动态控件添加消息.响应函数及变量. 动态创建控件时,可按照以下步骤进行: (1) 明确控件所属于的类 每一个控件都对应着一个类(例如按钮Button所属于的类为CButton). 如,在程序中我们需要用CButton类创建一个具体的按钮对象,并用函数指示它在对话框之上的

[Android] 拍照、截图、保存并显示在ImageView控件中

最近在做Android的项目,其中部分涉及到图像处理的内容.这里先讲述如何调用Camera应用程序进行拍照,并截图和保存显示在ImageView控件中以及遇到的困难和解决方法. PS:作者购买了本<Android第一行代码 著:郭霖>,参照里面的内容完成(推荐该书,前面的布局及应用非常不错).网上这类资料非常多,作者仅仅分享给初学者同时在线记录些内容,希望对大家有所帮助. 首先,设置activity_main.xml为LinearLayout布局且 android:orientation=&q

MFC 对话框Picture Control(图片控件)中静态和动态显示Bmp图片

最近有同学问我如何实现MFC基于对话框在图片控件中加载图片?其实使用MFC显示图片的方法各种各样,但是还是有些同学不知道怎样显示.以前在<数字图像处理>课程中完成的软件都是基于单文档的程序,这里介绍两种在对话框picthre控件中显示BMP图片的最简单基础的方法. ~~方法可能并不完美,高手忽略,但是提供一种能运行的方法,希望对刚接触这方面知识的同学有所帮助.可能你觉得文章过于简单或者有些过于详细叙述(点到即可我并不反对),但也为哪些入门同学想想,当初自己也是一头雾水. 一.静态显示bmp图片

Android实现图片轮显效果——自定义ViewPager控件

一.问题概述 使用ViewPager控件实现可横向翻页.水平切换图片等效果,但ViewPager需要手动滑动才能切换页面,图片轮显效果的效果本质上就是在ViewPager控件的基础上让它能自动的进行切换,所以实现图片轮显步骤如下: 1.  扩展ViewPager自定义一个MyScrollImageView类 2.  为MyScrollImageView定义适配器,装载图片信息 3.  定义图片滑动动画时间控制类 接下来我们就一步步实现下图案例: 二.实现套路 1.为自定义ViewPager控件编

C#在listview控件中显示数据库数据

一.了解listview控件的属性 view:设置为details columns:设置列 items:设置行 1.将listview的view设置为details 2.设置列属性 点击添加,添加一列 设置一列的Text属性,这就是列名 添加三列 3.编辑items属性,添加一行数据 编辑Text属性,添加一行的第一个数据 编辑subitems属性,添加一行中的其他数据 添加两个数据 填写结果 二.在listview中显示数据库数据 //在listview中显示数据库数据 private voi

【转】PropertyGrid控件中的多级显示

运行效果: 解决方案: MainForm.cs public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { CProvincialCapital proCap = new CProvincialCapital("南京市", 10000000); CProvince pro

Winform状态栏控件中Label靠右显示的方法

设计器: 代码: 在Form_Load事件中添加 : statusStripMain.LayoutStyle= ToolStripLayoutStyle.HorizontalStackWithOverflow; lbl单位.Alignment = ToolStripItemAlignment.Right; lblCompany.Alignment = ToolStripItemAlignment.Right; lbl联系电话.Alignment = ToolStripItemAlignment.