OpenCV Mat对象与CImage对象间的数据传输实例

devtools/2024/11/15 8:26:19/

        在用MFC写图像处理程序时,使用OpenCV可以做到事半功倍。但是,如果使用OpenCV4.0或OpenCV4.0以后版本,要显示图像可能会遇到麻烦,因为OpenCV去掉了原有的cvGetWindowHandle()函数,没法再用cvGetWindowHandle()函数来获取OpenCV显示窗口的句柄,也就是说,没法用SetWindowPos()来将OpenCV显示窗口嵌入MFC窗口中。既然OpenCV的显示窗口嵌入MFC窗口比较麻烦,我们可以用MFC来显示图像。有一个ATL/MFC 共享类CImage,该类有多个可用于图像显示的成员函数。OpenCV的图像处理功能强大,可以用OpenCV处理数据,然后从内存中将OpenCV Mat对象的图像数据传送到CImage对象中,用CImage的成员函数来显示图像。如何将OpenCV Mat对象的图像数据传送到CImage对象中呢?下面写一个简单的图像处理程序,来做演示。

        在VS2022中新建一个对话框程序,对话框界面如下:

该对话框的每一个按钮,我都已经给它添加了事件处理函数,暂不去看该函数的代码,不看该程序的代码,先看看该程序的试运行的效果。试运行,结果如下:

点击打开图像,弹出打开对话框:

点击“打开”按钮,结果如下:

试一试,打开别的格式的图像。点击打开图像按钮,选中1.webp

点击对话框中的“打开”按钮,打开图像如下:

点击打开图像按钮,选中2.bmp,

点击对话框中的“打开”按钮,打开图像如下:

 点击打开图像按钮,选中a.jpeg,

点击对话框中的“打开”按钮,打开图像如下:

点击打开图像按钮,选中2.png,

点击对话框中的“打开”按钮,打开图像如下:

可见常见图像格式都可打开。 

 测试一下改变亮度 

为看得更清楚,打开一张更大的图片:

 Step 1  在改变亮度按钮旁的编辑框中输入-50,

点击“改变亮度”按钮,结果如下:

可见图像变暗了。

        Step 2  在改变亮度按钮旁的编辑框中输入30,

点击“改变亮度”按钮,结果如下:

图像明显变亮了,说明改变亮度是有效的。

        测试一下磨皮

        打开一张较粗糙的图片,如下:

这张图像有点小,看不太清楚,把它放大一倍。在“图像比例缩放”按钮旁的输入框中输入2:

再点击“图像比例缩放按钮”,结果如下:

这个脸麻点够多了,需要磨皮一下。点击“磨皮”按钮,结果如下:

再点击两次“磨皮”按钮,结果如下:

再点击4次“磨皮”按钮,结果如下:

 这样看起来好多了,但图像变得有些不清晰,在“增减对比度”按钮旁的按钮中输入1.1,然后再点击“增减对比度”按钮,结果如下:

再点击2次“磨皮”按钮,结果如下:

再点击一次“增减对比度”按钮,结果如下:

在“图像比例缩放”按钮旁的框中输入0.5,点击“图像比例缩放”按钮,结果如下:

        测试转成灰度图

        点击“转成灰度图”按钮,结果如下:

其它图像处理功能就不逐一测试了,要实现这些功能,单用MFC其代码量是很大的,这里由于是用了OpenCV,代码量大大减小,有的仅需几行代码即可实现。下面讨论一下程序代码。

        “打开图像”按钮事件处理函数,代码如下:

void CCImageMatTestDlg::OnBnClickedOpen()
{// TODO: 在此添加控件通知处理程序代码CFileDialog fdlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("All files(*.*)|*.*||"));if (fdlg.DoModal() == IDOK){m_Path = fdlg.GetPathName();m_strEx = fdlg.GetFileExt();m_strName = fdlg.GetFileName();m_Path.ReleaseBuffer();m_strEx.ReleaseBuffer();m_strName.ReleaseBuffer();if(m_strEx == "BMP" || m_strEx == "bmp" || m_strEx == "dib" || m_strEx == "TIF" || m_strEx == "tif" || m_strEx == "tiff" || m_strEx == "PNG" || m_strEx == "png" || m_strEx == "jpg"|| m_strEx == "JPG"|| m_strEx == "jpe" || m_strEx == "jpeg" || m_strEx == "jp2"  || m_strEx == "webp" || m_strEx == "avif" || m_strEx == "pbm"|| m_strEx == "pgm"  || m_strEx == "ppm" || m_strEx == "pxm" || m_strEx == "pnm" || m_strEx == "pfm" || m_strEx == "sr" || m_strEx == "ras" || m_strEx == "exr"|| m_strEx == "hdr" || m_strEx == "pic"){m_str = CT2A(m_Path);src = imread(m_str);dst = src;if (src.empty())MessageBox(_T("打开图像文件失败!"));else{MatToCImage(dst, mImage);	//send Mat object data to CImage objiectDispalyImage(mImage);		//dispaly image}}else{MessageBox(_T("你要打开的文件不是本程序支持的图像文件!",MB_OK));}}
}

其代码量很小,用到了MFC的文件对话框,OpenCV的图像文件读入函数imread(),最后用到了自定义的Mat对象数据传送到CImage 对象函数MatToCImage(),及自定义的图像显示函数DispalyImage()。

        Mat对象数据传送到CImage 对象函数, 其代码如下:

void CCImageMatTestDlg::MatToCImage(Mat& src, CImage& dst) {// 确保Mat不为空且是可支持的类型if (src.empty() || (src.type() != CV_8UC3 && src.type() != CV_8UC1)) {return;}// 如果CImage对象有附加图像就分离并销毁图像if (!dst.IsNull())dst.Destroy();//创建CImage对象附加图像,需与源图像大小类型一致dst.Create(src.cols, src.rows, 8 * src.channels());if (src.channels() == 1){//将源位图转成八位灰度图时,CImage对象需用到颜色表,需定义一个RGBQUAD数组,并填充该数组RGBQUAD* colorTable = new RGBQUAD[256];for (int i = 0; i < 256; i++){colorTable[i].rgbRed = i;colorTable[i].rgbGreen = i;colorTable[i].rgbBlue = i;}//设置颜色表RGB分量值dst.SetColorTable(0, 255, colorTable);}int rows = src.rows;int cols = src.cols;uchar channels = src.channels();//内存中的数据传送,注意这里是逐行传送。for (int i = 0; i < rows; i++) {memcpy(dst.GetPixelAddress(0, i), src.ptr<uchar>(i), cols * channels);}
}

该函数有几个重点,第一,要将Mat对象的图像数据传向 CImage对象,必须将CImage对象的原有解绑可以用Destroy()或Detach()函数。第二,同时需创建一张与Mat对象载入图像同样大小的图像用以接收传入数据。第三,创建设置颜色表,如果Mat对象载入的是8位位图(灰度图),可以不创建设置颜色表,如果将Mat对象载入的图像转成灰度图,没有颜色表就没法显示。第四,使用Memcpy()将Mat对象中的图像数据Copy到CImage对象的图像数据存储内存中。下面将MatToCImage(Mat& src, CImage& dst)函数中的颜色表部分注释掉,测试一下效果。注释后的代码如下:

void CCImageMatTestDlg::MatToCImage(Mat& src, CImage& dst) {// 确保Mat不为空且是可支持的类型if (src.empty() || (src.type() != CV_8UC3 && src.type() != CV_8UC1)) {return;}// 如果CImage对象有附加图像就分离并销毁图像if (!dst.IsNull())dst.Destroy();//创建CImage对象附加图像,需与源图像大小类型一致dst.Create(src.cols, src.rows, 8 * src.channels());/*if (src.channels() == 1){//将源位图转成八位灰度图时,CImage对象需用到颜色表,需定义一个RGBQUAD数组,并填充该数组RGBQUAD* colorTable = new RGBQUAD[256];for (int i = 0; i < 256; i++){colorTable[i].rgbRed = i;colorTable[i].rgbGreen = i;colorTable[i].rgbBlue = i;}//设置颜色表RGB分量值dst.SetColorTable(0, 255, colorTable);}*/int rows = src.rows;int cols = src.cols;uchar channels = src.channels();//内存中的数据传送,注意这里是逐行传送。for (int i = 0; i < rows; i++) {memcpy(dst.GetPixelAddress(0, i), src.ptr<uchar>(i), cols * channels);}
}

试运行,打开图像,结果如下:

     可正常显示,点击“转成灰度图”按钮,结果如下:

没法正常显示图像。打开一张灰度图:

结果如下: 

点击“转成灰度图”按钮,结果如下:

同样没法显示。

        图像显示函数 其代码如下:

void CCImageMatTestDlg::DispalyImage(CImage mImage)
{// TODO: 在此处添加实现代码.if (mImage.IsNull())MessageBox(L"No Image to Display!",L"系统提示",MB_ICONWARNING | MB_OK);else{//Invalidate();OnPaint();CClientDC dc(this);mImage.BitBlt(dc.GetSafeHdc(), 0, 0, SRCCOPY);}
}

该函数使用了BitBlt()函数来显示图像,在前面调用了Invalidate()及OnPaint()函数,目的是刷新窗口,避免图像重叠。

        上面每一个图像处理的函数都调用了MatToCImage()函数与DispalyImage()函数,其它函数与本主题无关这里就不逐一解说了。该示例的源代码已上传到CSDN,如果要查看其源代码可以去下载。示例程序是基于VS2022及OpenCV4.8,在Win10 平台调试通过,OpenCV4.8放在D盘下。示例程序的源代码的下载链接为:https://download.csdn.net/download/billliu66/89248781


http://www.ppmy.cn/devtools/31565.html

相关文章

算法--分治法

分治法是一种算法设计策略&#xff0c;它将一个复杂的问题分解成两个或多个相同或相似的子问题&#xff0c;直到这些子问题可以简单地直接解决。然后&#xff0c;这些子问题的解被合并以产生原始问题的解。 分治法通常遵循以下三个步骤&#xff1a; 分解&#xff1a;将原问题…

分布式与一致性协议之一致哈希算法(二)

一致哈希算法 使用哈希算法有什么问题 通过哈希算法&#xff0c;每个key都可以寻址到对应的服务器&#xff0c;比如&#xff0c;查询key是key-01,计算公式为hash(key-01)%3,警告过计算寻址到了编号为1的服务器节点A&#xff0c;如图所示。 但如果服务器数量发生变化&#x…

基于Springboot的校运会管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校运会管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&a…

用Visual Studio(VS)开发UNIX/Linux项目

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 目录 FTP是免不了的 正确设置…

嵌入式人工智能应用-第三章 opencv操作1

一 函数的基本操作 1.1 图像的存取和显示 有多种方式从现实世界中获取数字图像&#xff1a;数码相机&#xff0c;扫描仪&#xff0c;计算机断层扫描和磁共振成像等等。在任何情况下&#xff0c;人类看到的都是图像。然而&#xff0c;当将其转换为数字设备时&#xff0c;数字设…

vue2 + antvx6 实现流程图功能

导入关键包 npm install antv/x6 --save npm install antv/x6-vue-shape 保存插件 (可选) npm install --save antv/x6-plugin-clipboard antv/x6-plugin-history antv/x6-plugin-keyboard antv/x6-plugin-selection antv/x6-plugin-snapline antv/x6-plugin-stencil antv/…

TCP/IP 协议基础:构建互联网基石

目录 前言 一.网络通信协议 TCP/IP 1.网络通信协议 3.TCP/IP 协议 3.管理的组织和机构 4.RFC 二.OSI 参考模型 1.层次结构 2.通信机制 3.PDU 4.各层的功能 三.TCP/IP 协议簇 1.TCP/IP 与 OSI 的对应关系 2.TCP/IP 各层 3.TCP/IP 封装与分用 4.重要概念 5.分…

外包干了3个多月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…