[图像处理] MFC载入图片并进行二值化处理和灰度处理及其效果显示

news2024/11/29 2:52:31

文章目录

  • 工程效果
  • 重要代码
  • 完整代码
  • 参考

工程效果

载入图片,并在左侧显示原始图片、二值化图片和灰度图片。
双击左侧的图片控件,可以在右侧的大控件中,显示双击的图片。

初始画面:
在这里插入图片描述
载入图片:
在这里插入图片描述
双击左侧的第二个控件,显示图片:
在这里插入图片描述
//对图片显示在控件中的位置没有进行优化。

重要代码

主要是用的MFC Image控件。

载入图片:

void CGDITESTDlg::OnBnClickedBtnStart()
{
	//获取图像文件
	CFileDialog filedlg(
		TRUE,
		_T("png"),
		NULL,
		0,
		TEXT("image Files(*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png|all files(*.*)|(*.*)||"),
		this);
	filedlg.DoModal();
	m_cstr_filepath = filedlg.GetPathName();
	m_cstr_filename = filedlg.GetFileName();
	if (m_cstr_filepath.IsEmpty() || m_cstr_filename.IsEmpty())
	{
		AfxMessageBox(TEXT("打开文件失败"));
		return ;
	}	
	image_origin.Load(m_cstr_filepath);
	image_binarization.Load(m_cstr_filepath);
	image_grey.Load(m_cstr_filepath);

	//获取图像尺寸
	imgw = image_origin.GetWidth();
	imgh = image_origin.GetHeight();
	img_t = imgw / imgh;

	//根据图像尺寸,调整控件客户区尺寸比例
	CRect rect_ctl;
	m_ctl_pic_origin.GetClientRect(&rect_ctl);
	float rectw = rect_ctl.Width();
	float recth = rect_ctl.Height();
	float rect_t = rectw / recth;
	if(rect_t < img_t)
	{
		rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Width(), rect_ctl.Width() / img_t ));
	}
	else
	{
		rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Height() * img_t, rect_ctl.Height()));
	}
	//显示图像到控件客户区
	CDC* pdc = m_ctl_pic_origin.GetDC();
	m_ctl_pic_origin.SetBitmap(NULL);	
	image_origin.Draw(pdc->m_hDC, rect_ctl);

	//图像二值化处理
	ImageBinarizationProcess(image_binarization);
	//根据图像尺寸,调整控件客户区尺寸比例
	CRect rect_ctl_binarization;
	m_ctl_pic_binarization.GetClientRect(&rect_ctl_binarization);
	float rectw_ = rect_ctl_binarization.Width();
	float recth_ = rect_ctl_binarization.Height();
	float rect_t_ = rectw / recth;
	if (rect_t_ < img_t)
	{
		rect_ctl_binarization = CRect(rect_ctl_binarization.TopLeft(), CSize(rect_ctl_binarization.Width(), rect_ctl_binarization.Width() / img_t));
	}
	else
	{
		rect_ctl_binarization = CRect(rect_ctl_binarization.TopLeft(), CSize(rect_ctl_binarization.Height() * img_t, rect_ctl_binarization.Height()));
	}
	//显示图像到控件客户区
	CDC* pdc_ = m_ctl_pic_binarization.GetDC();
	m_ctl_pic_binarization.SetBitmap(NULL);
	image_binarization.Draw(pdc_->m_hDC, rect_ctl_binarization);

	//图像灰度处理
	ImageGreyProcess(image_grey);
	//根据图像尺寸,调整控件客户区尺寸比例
	CRect rect_ctl_grey;
	m_ctl_pic_grey.GetClientRect(&rect_ctl_grey);
	float rectw__ = rect_ctl_grey.Width();
	float recth__ = rect_ctl_grey.Height();
	float rect_t__ = rectw / recth;
	if (rect_t__ < img_t)
	{
		rect_ctl_grey = CRect(rect_ctl_grey.TopLeft(), CSize(rect_ctl_grey.Width(), rect_ctl_grey.Width() / img_t));
	}
	else
	{
		rect_ctl_grey = CRect(rect_ctl_grey.TopLeft(), CSize(rect_ctl_grey.Height() * img_t, rect_ctl_grey.Height()));
	}
	//显示图像到控件客户区
	CDC* pdc__ = m_ctl_pic_grey.GetDC();
	m_ctl_pic_grey.SetBitmap(NULL);
	image_grey.Draw(pdc__->m_hDC, rect_ctl_grey);

	isLoadedImage = true;
	
	m_ctl_pic_origin.ReleaseDC(pdc);
	m_ctl_pic_binarization.ReleaseDC(pdc);
	m_ctl_pic_grey.ReleaseDC(pdc);
}

图像二值化处理:
算法来源:C++MFC打开图片、彩图,以及对图像进行简单算法处理

void CGDITESTDlg::ImageBinarizationProcess(CImage &image)
{
	BYTE* pimagedata = (BYTE*)image.GetBits();	//获取到图片内存点的位置
	int width = image.GetWidth();
	int height = image.GetHeight();
	int pit = image.GetPitch();//图像每行字节数
	int bytes_per_pixel = image.GetBPP() / 8; //获取每像素的位数除以8得到每个像素占的字节数
	std::vector<int> gray(256); //初始化时自动存0,用来存放256种颜色出现的次数
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			gray.at((int)*(pimagedata + pit * i + bytes_per_pixel * j)) += 1;
		}
	}

	int max = 0;
	int sec = 0;
	int localmax = 0;
	int localsec = 0;

	for (int i = 0; i < 256; i++)
	{
		if (gray[i] > max)
		{
			max = gray[i];
			localmax = i;
		}
	}
	for (int i = 0; i < 256; i++)
	{
		if (gray[i] > sec && abs(i - localmax) > 10)
		{
			sec = gray[i];
			localsec = i;
		}
	}
	int mid = (localmax + localsec) / 2;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if ((int)(*(pimagedata + pit * i + j * bytes_per_pixel)) < mid)
			{
				*(pimagedata + pit * i + j * bytes_per_pixel) = 0;
				*(pimagedata + pit * i + j * bytes_per_pixel + 1) = 0;
				*(pimagedata + pit * i + j * bytes_per_pixel + 2) = 0;
			}
			else
			{
				*(pimagedata + pit * i + j * bytes_per_pixel) = 255;
				*(pimagedata + pit * i + j * bytes_per_pixel + 1) = 255;
				*(pimagedata + pit * i + j * bytes_per_pixel + 2) = 255;
			}
		}
	}
}

灰度处理:
算法来源:C++MFC打开图片、彩图,以及对图像进行简单算法处理

void CGDITESTDlg::ImageGreyProcess(CImage& image)
{
	BYTE* pimagedata = (BYTE*)image.GetBits();	//获取到图片内存点的位置
	int width = image.GetWidth();
	int height = image.GetHeight();
	int pit = image.GetPitch();//图像每行字节数
	int bytes_per_pixel = image.GetBPP() / 8; //获取每像素的位数除以8得到每个像素占的字节数
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			*(pimagedata + pit * i + j * bytes_per_pixel) *= 0.114;
			*(pimagedata + pit * i + j * bytes_per_pixel + 1) *= 0.587;
			*(pimagedata + pit * i + j * bytes_per_pixel + 2) *= 0.299;
		}
	}

}

双击左侧控件的响应:
在这里插入图片描述

void CGDITESTDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	if (!isLoadedImage) //如果没有加载图片,则不会执行后续代码
		return;
	//未使用,仅测试
	CPoint ptCursor;
	GetCursorPos(&ptCursor);//获取执行此函数时的鼠标位置,屏幕坐标
	
	ClientToScreen(&point); //point是双击时的鼠标位置,坐标系是窗口客户区,所以要转换成屏幕坐标
	
	//未使用,仅测试
	CPoint ptCursor1(GetCurrentMessage()->pt); //双击时的鼠标位置,屏幕坐标

	GetDlgItem(IDC_PIC_ORIGIN)->GetWindowRect(&rc_origin);//控件的rect,屏幕坐标
	if (rc_origin.PtInRect(point))//如果右键在picture control区域抬起则放大显示灰度图片
	{
		CRect rect_ctl;
		m_ctl_pic_dsp.GetClientRect(&rect_ctl);
		float rectw = rect_ctl.Width();
		float recth = rect_ctl.Height();
		float rect_t = rectw / recth;

		if (rect_t < img_t)
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Width(), rect_ctl.Width() / img_t));
		}
		else
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Height() * img_t, rect_ctl.Height()));
		}

		CDC* pdc = m_ctl_pic_dsp.GetDC();
		m_ctl_pic_dsp.SetBitmap(NULL);
		image_origin.Draw(pdc->m_hDC, rect_ctl);
		m_ctl_pic_dsp.ReleaseDC(pdc);
		return;
	}

	GetDlgItem(IDC_PIC_PROCESS)->GetWindowRect(&rc_binarization);
	if (rc_binarization.PtInRect(point))//如果右键在picture control区域抬起则放大显示灰度图片
	{
		CRect rect_ctl;
		m_ctl_pic_dsp.GetClientRect(&rect_ctl);
		float rectw = rect_ctl.Width();
		float recth = rect_ctl.Height();
		float rect_t = rectw / recth;

		if (rect_t < img_t)
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Width(), rect_ctl.Width() / img_t));
		}
		else
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Height() * img_t, rect_ctl.Height()));
		}
		CDC* pdc = m_ctl_pic_dsp.GetDC();
		m_ctl_pic_dsp.SetBitmap(NULL);
		image_binarization.Draw(pdc->m_hDC, rect_ctl);
		m_ctl_pic_dsp.ReleaseDC(pdc);
		return;
	}

	GetDlgItem(IDC_PIC_PROCESS2)->GetWindowRect(&rc_grey);
	if (rc_grey.PtInRect(point))//如果右键在picture control区域抬起则放大显示灰度图片
	{
		CRect rect_ctl;
		m_ctl_pic_dsp.GetClientRect(&rect_ctl);
		float rectw = rect_ctl.Width();
		float recth = rect_ctl.Height();
		float rect_t = rectw / recth;

		if (rect_t < img_t)
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Width(), rect_ctl.Width() / img_t));
		}
		else
		{
			rect_ctl = CRect(rect_ctl.TopLeft(), CSize(rect_ctl.Height() * img_t, rect_ctl.Height()));
		}
		CDC* pdc = m_ctl_pic_dsp.GetDC();
		m_ctl_pic_dsp.SetBitmap(NULL);
		image_grey.Draw(pdc->m_hDC, rect_ctl);
		m_ctl_pic_dsp.ReleaseDC(pdc);
		return;
	}

	CDialogEx::OnLButtonDblClk(nFlags, point);
}

以上是通过窗口的双击时间回调函数,判断双击时鼠标的坐标,是否在控件的坐标Rect中,如果是,则执行对应代码。

也可以把双击的空间的notify属性设置为true,然后再时间中设置双击消息回调函数。
在这里插入图片描述
在这里插入图片描述

完整代码

MFC简单的图片处理工程-Gitee

参考

C++MFC打开图片、彩图,以及对图像进行简单算法处理

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT记事本

QT记事本 1.概述 2.界面  2.1 界面布局  2.2 UI美化stylesheet   2.2.1 准备   2.2.2 stylesheet   2.2.3 效果 2.3 窗口大小调整与子控件自适应 3.信号与槽  3.1 简述  3.2 信号与槽设置   3.2.1 UI控件设置   3.2.2 UI转到槽&#xff08;自动连接&am…

Go 源码之 gin 框架

Go 源码之 gin 框架 go源码之gin - Jxy 博客 一、总结 gin.New()初始化一个实例&#xff1a;gin.engine&#xff0c;该实例实现了http.Handler接口。实现了ServeHTTP方法 注册路由、注册中间件&#xff0c;调用addRoute将路由和中间件注册到 methodTree 前缀树&#xff08;节…

flutter官方案例context_menus

1&#xff1a;根据项目中的案例进行部署 2&#xff1a;运行查看有什么用&#xff0c;可不可以直接复制粘贴 案例地址 https://github.com/flutter/samples/tree/main/context_menus案例展示方法 直接把这个文件夹中的文件复制到lib文件夹中 3&#xff0c;19&#xff0c;4的fl…

关系型数据库mysql(10)MHA的高可用

一. MHA 的相关知识 1. 什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。MHA 的出现就是解决MySQL 单点的问题。MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。MHA能在故障…

[Windows]防火墙,出入站规则失效。

场景&#xff1a; 因为具体需要&#xff0c;在内网中&#xff0c;不想别人发现我们的nacos端口8848&#xff0c;因此我们设置了入站规则&#xff0c;特定的ip地址才能访问。但是实际测试中发现并不起作用。。。 经过一番排查得到一下结果。 为什么有些应用绕过了防火墙配置 有…

JimuReport积木报表 v1.7.4 公测版本发布,免费的JAVA报表工具

项目介绍 一款免费的数据可视化报表&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完成报…

Linux速览(2)——环境基础开发工具篇(其一)

本章我们来介绍一些linux的常用工具 目录 一. Linux 软件包管理器 yum 1.什么是软件包? 2. 查看软件包 3. 如何安装软件 4. 如何卸载软件 5.yum补充 6. 关于 rzsz 二. Linux编辑器-vim使用 1. vim的基本概念 2. vim的基本操作 3. vim正常模式命令集 4. vim末行模式…

计算机网络-从输入网址到访问网站的全过程

当我们在浏览器中输入一个网址并按下回车键时&#xff0c;会发生一系列复杂的过程&#xff0c;最终使我们能够看到网页的内容。以下是这个过程的详细步骤&#xff1a; 客户端&#xff1a;首先&#xff0c;用户在浏览器中键入网址&#xff0c;然后浏览器会根据这个网址生成一个H…

vultr ubuntu 服务器远程桌面安装及连接

一. 概述 vultr 上开启一个linux服务器&#xff0c;都是以终端形式给出的&#xff0c;默认不带 ui 桌面的&#xff0c;那其实对于想使用服务器上浏览器时的情形不是很好。那有没有方法在远程服务器安装桌面&#xff0c;然后原程使用呢&#xff1f;至少ubuntu的服务器是有的&am…

C练习题(1)

变种水仙花&#xff08;来自牛课网&#xff09; 题目 变种水仙花数 - Lily Number&#xff1a;把任意的数字&#xff0c;从中间拆分成两个数字&#xff0c;比如1461 可以拆分成&#xff08;1和461&#xff09;,&#xff08;14和61&#xff09;,&#xff08;146和1),如果所有拆…

IDEA 如何快速创建 Springboot 项目,面试题kafka数据丢失问题

&#xff08;3&#xff09;填写并选择&#xff1a; 1&#xff0c;2 处&#xff1a;是 Maven 工程的两个属性唯一标识&#xff0c;随意填。 3处&#xff1a;类型选择 Maven 项目 4处&#xff1a;语言选择 Java 5处&#xff1a;打包方式选择 Jar 6处&#xff1a;Java版本选择…

KeepAlived使用介绍

目录 1、Introduce 2、基本使用 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;配置文件 &#xff08;3&#xff09;使用教程 1、Introduce keepalived是一个用于实现高可用性和负载均衡的开源软件。它提供了一种轻量级的方式来管理多个服务器&#xff0c;并确保…

【Spring Boot 源码学习】ConditionEvaluationReport 日志记录上下文初始化器

《Spring Boot 源码学习系列》 ConditionEvaluationReport 日志记录上下文初始化器 一、引言二、往期内容三、主要内容3.1 源码初识3.2 ConditionEvaluationReport 监听器3.3 onApplicationEvent 方法3.4 条件评估报告的打印展示 四、总结 一、引言 上篇博文《共享 MetadataRe…

【嵌入式智能产品开发实战】(十二)—— 政安晨:通过ARM-Linux掌握基本技能【运行环境】

目录 简述 开始 操作系统环境下的程序运行 裸机环境下的程序运行 程序入口main()函数分析 BSS段的小提示 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 嵌入式智能产品开发实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不…

Python 后端 Flask 使用 Flask-SocketIO、前端 Vue3 实现长连接 Websocket 通信详细教程(更新中)

Flask 安装 Flask-Socketio Flask-SocketIO 第三方库使 Flask 应用程序可以实现客户端和服务器之间的低延迟双向通信。客户端应用程序可以使用 Javascript、Python、C、Java 和 Swift 中的任何 SocketIO 客户端库或任何其他兼容客户端来建立与服务器的永久连接。 Flask-Socke…

施耐德 PLC 控制系统 产品 + 软件总体介绍 2020

参考 2020.7 官方说明视频&#xff1a;https://www.bilibili.com/video/BV1Mi4y1G7Qc/ 总体说明 施耐德作为工业控制界巨头&#xff08;公认的几大巨头&#xff1a;西门子、AB、施耐德&#xff09;&#xff0c;PLC 控制器产品线很庞大&#xff0c;涵盖了高中低的完整产品线&…

代码随想录Day24:回溯算法Part1

回溯算法理论&#xff1a; Leetcode 77. 组合 这道题其实有点绕的我头晕&#xff0c;对于start index的解释我能够理解&#xff0c;但是我很难去想清楚他是如何在一次次递归中变化的因为他在for循环外面扮演我们每一次在一个数字找完了他开头的所有组合之后&#xff0c;就把st…

永磁同步电机PMSM和直流无刷电机BLDCM整理

刚完成的永磁同步电机的助力转向项目&#xff0c;接下来又遇到一个直流无刷电机的项目。刚好有时间将两个电机控制的异同和经典的控制方案总结一下。首先解释一下PMSW和BLDCM的含义。PMSW(Permanent Magnet Synchronous Motor)永磁同步电机的缩写&#xff1b;BLDCM(BrushLess D…

Datacom HCIP笔记-OSPF协议 之三

从骨干区域传来的三类LSA不再传回骨干区域 VLINK 1、只要创建的VLINK的路由器都是ABR 2、VLINK永远属于区域0的链路。 3、VLINK只能在非骨干区域创建&#xff0c;只能跨越一个非骨干区域。 4、特殊区域不能创建VLINK 5、用于修复不连续的骨干区域 6、将非骨干区域和骨干区域直接…

财务管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. …