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

        在用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 objiect
				DispalyImage(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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/587777.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux进程管理与监控

一、相关概念 1、进程的的基本定义 在自身的虚拟地址空间运行的一个独立的程序&#xff0c;从操作系统的角度来看&#xff0c;所有在系统上运行的东西&#xff0c;都可以称为一个进程。 2、进程的分类 系统进程&#xff1a;可以执行内存资源分配和进程切换等管理工作&am…

C#知识|泛型集合List相关方法

哈喽&#xff0c;你好&#xff0c;我是雷工&#xff01; 以下为泛型集合List相关方法的学习笔记。 01 集合定义 集合定义的时候&#xff0c;无需规定元素的个数。 02 泛型说明 泛型表示一种程序特性&#xff0c;也就是在定义的时候&#xff0c;无需指定特定的类型&#xff…

C语言嵌入Lua解释器的方法

Lua语言是一个轻量的脚本语言&#xff0c;可以用很少的资源运行其解释器 C语言是一个很常用的语言&#xff0c;广泛用于嵌入式等底层场景 这两个语言结合&#xff0c;可以应用于嵌入式等多个场景。比如&#xff0c;一些硬件公司会允许开发者使用Lua语言操作其硬件 Lua的安装…

搭建Kafka源码环境并测试

文章目录 一、前言二、环境准备三、环境搭建3.1 JDK 环境搭建3.2 Scala 环境搭建3.2.1 配置 Scala 环境变量3.2.2 验证 3.3 Gradle 环境搭建3.3.1 配置 Gradle 环境变量3.3.2 验证 3.4 Zookeeper 环境搭建3.4.1 配置 Zookeeper 环境变量3.4.2 验证 3.5 Kafka 源码搭建3.5.1 导入…

数据可视化宝典:Matplotlib图形实战

在数据分析领域&#xff0c;图形化展示数据是非常重要的环节。Python中的matplotlib库是绘制各类图形的强大工具。本文将介绍如何使用matplotlib绘制折线图、直方图、饼图、散点图和柱状图等数据分析中常见的图形&#xff0c;并附上相应的代码示例&#xff0c;可以当初matplotl…

【C++】——类和对象(初始列表,Static成员,友元)

创作不易&#xff0c;多多支持&#xff01; &#xff01;&#x1f618;&#x1f618; 前言 因为前面的构造函数还有些地方不够清晰&#xff0c;所以这里需要再继续补充一些 一 初始化列表 1.1认识初始化 对于默认的构造函数来说&#xff0c;我们都知道它是起到了初始化的…

3-4STM32C8T6按键控制LED开与关

实物接线如下&#xff1a; 为了代码的简洁性&#xff0c;这里需要对LED与KEY进行封装如下&#xff1a; #include "stm32f10x.h" // Device headervoid LED_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GP…

WSL2-Ubuntu使用Conda配置百度飞浆paddlepaddle虚拟环境

0x00 缘起 本文将介绍在WSL2-Ubuntu系统中,使用Conda配置百度飞浆paddlepaddle虚拟环境中所出现的各种问题以及解决方法,最终运行"run_check()"通过测试。 在WSL2中配置paddlepaddle不像配置Pytorch那样顺滑,会出现各种问题(如:库的文件缺失、不知道如何匹配C…

工厂模式和策略模式区别

工厂模式和策略模式都是面向对象设计模式&#xff0c;但它们的目的和应用场景有所不同。 工厂模式是一种创建型设计模式&#xff0c;旨在通过使用一个工厂类来创建对象&#xff0c;而不是直接使用new关键字来创建对象。这样做可以使系统更容易扩展和维护&#xff0c;因为新的对…

模型智能体开发之metagpt-单智能体实践

需求分析 根据诉求完成函数代码的编写&#xff0c;并实现测试case&#xff0c;输出代码 代码实现 定义写代码的action action是动作的逻辑抽象&#xff0c;通过将预设的prompt传入llm&#xff0c;来获取输出&#xff0c;并对输出进行格式化 具体的实现如下 定义prompt模版 …

Cisco IOS XE Web UI 权限提升漏洞复现(CVE-2023-20198)

0x01 产品简介 Web UI 是一种基于GUI的嵌入式系统管理工具,能够提供系统配置、简化系统部署和可管理性以及增强用户体验。它带有默认映像,因此无需在系统上启用任何内容或安装任何许可证。Web UI 可用于构建配置以及监控系统和排除系统故障,而无需CLI专业知识。 0x02 漏洞…

redis 高可用 Sentinel 详解

写在前面 redis 在我们日常的业务开发中是十分常见的&#xff0c;而redis的可用性就必须要有很高的要求&#xff0c;那么 redis集群的高可用由有一个或者多个 Sentinel(哨兵) 实例组成的 哨兵系统来保证的。 哨兵 由一个或者多个 Sentinel 实例组成的 Sentinel 系统可以监控任…

Java项目:基于SSM框架实现的高校专业信息管理系统设计与实现(ssm+B/S架构+源码+数据库+毕业论文+PPT+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的高校专业信息管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

Python3.11修改并运行oneforall

遇到的问题 使用python3.11默认无法运行oneforall脚本&#xff0c;出现如下报错 # 解决方案 修改 /usr/local/lib/python3.11/dist-packages/exrex.py exrex.py具体文件路径报错中会显示 vim /usr/local/lib/python3.11/dist-packages/exrex.py# 修改前 from re import sre…

基于Hyperf的CMS,企业官网通用php-swoole后台管理系统

2023年9月11日10:47:00 仓库地址&#xff1a; https://gitee.com/open-php/zx-hyperf-cms CMS&#xff0c;企业官网通用PHP后台管理系统 框架介绍 hyperf SCUI 后端开发组件 php 8.1 hyperf 3.1 数据库 sql(使用最新日期文件) hyperf\doc\sql_bak mysql 8. 系统默认账号…

微软如何打造数字零售力航母系列科普05 - Azure中计算机视觉的视觉指南

Azure中计算机视觉的视觉指南 什么是计算机视觉&#xff1f;如何使用Microsoft Azure将计算机视觉功能集成到应用程序和工作流中&#xff1f; 作者&#xff1a;Nitya Narasimhan 编辑&#xff1a;数字化营销工兵 •11分钟阅读 什么是计算机视觉&#xff1f;如何使用Microso…

最快成型的前端框架Layuimini本地项目部署演示

最快成型的前端框架Layuimini本地项目部署演示 本篇以LayuiMini-v2在线页面预览为例 点击上述链接跳转页面 1. 准备工作 环境准备 WindowsNginxWeb项目资源包&#xff08;Layuimini-v2&#xff09; 2. 页面加载 拉取到本地后直接访问时会出现如下弹窗&#xff0c;无法加载页…

LeetCode LCR 179. 和为s的两个数字

原题链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目的意思&#xff1a;通过给定的数组&#xff0c;找出两个值&#xff0c;相加并等于目标值。 第一种思路&#xff0c;暴力枚举&#xff0c;伪代码如下&#xff1a; for (…

暴雨服务器引领信创算力新潮流

去年大模型的空前发展&#xff0c;人工智能也终于迎来了属于自己的“文艺复兴”&#xff0c;众多的模型相继发布&#xff0c;继而催生了整个行业对于智能算力需求的激增。 市场需求与技术驱动仿佛现实世界的左右脚&#xff0c;催动着世界文明的齿轮向前滚动。在全球经济角逐日…

【计算机网络】FTP站点配置搭建教程以及相关问题解决方案(超详细)

文章目录 1、安装Window Server 20082、搭建FTP环境&#xff08;1&#xff09;安装FTP服务器&#xff08;2&#xff09;配置FTP服务器&#xff08;3&#xff09;测试FTP连接 3、遇到的问题以及解决方案&#xff08;1&#xff09;Windows无法访问此文件夹&#xff08;2&#xff…