visual Studio MFC 平台实现图像增强中的线性变换(负变换)和非线性变换(对数与幂律)

MFC 实现数字图像处理中的图像增强操作

本文使用visual Studio MFC 平台实现图像增强中典型的三种图像增强的方法中的两大类,包括线性变换–>负变换,非线性变换–>对数变换和幂律变换;其中第三大类分段式变换可以参考MFC实现图像增强–分段式变换(灰度级切片,对比度拉伸,Bit-plane slicing)
关于基础工程的创建请参考
01-Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线

02-visual Studio MFC 绘制单一颜色三角形、渐变颜色边框三角形、渐变填充三角形、边框渐变的正方形与填充渐变的正方形实例
03-visual Studio MFC 平台实现对灰度图添加椒盐噪声,并进行均值滤波与中值滤波

文章目录

  • MFC 实现数字图像处理中的图像增强操作
    • 一、线性(负变换和单位变换)
      • 线性变换的原理
      • 线性变换-负变换实现
      • 线性变换--负变换效果图
    • 对数(对数和对数逆变换)
      • 对数变换的原理
      • 对数变换原理
      • 对数逆变换原理
      • 应用场景
      • 对数变换的实现
      • 实现效果图
    • 幂律(n次幂和n次根变换)
      • 幂律(n次幂和n次根变换)的原理
      • 幂律(n次幂和n次根变换)的代码实现
      • 实现效果图

一、线性(负变换和单位变换)

线性变换的原理

图像增强中的线性变换是一种基本的像素值变换方法,通常涉及负变换和单位变换。

  1. 负变换: 负变换是通过反转图像的灰度级别,使得原来的较亮的像素变暗,较暗的像素变亮。这可以通过下面的公式表示:

    s = L − r s = L - r s=Lr

    其中,$ s $ 是输出像素的灰度级别,$ L $ 是灰度级别的最大值,$ r $ 是输入像素的灰度级别。这样的变换能够产生图像的底片效果,强调图像中原本较亮的区域。

  2. 单位变换: 单位变换是一种线性变换,它保持图像的原始灰度级别不变。单位变换的公式如下:

    s = r s = r s=r

    这种变换并不改变图像的外观,但在图像增强中,它可能作为其他变换的基础或作为恢复操作的一部分。

这两种变换是线性的,因为它们都可以表示为输入像素值 $ r $ 与某个常数或者 $ L $的线性关系。线性变换是图像处理中一类简单而有效的操作,但对于一些更高级的增强技术,可能需要非线性的操作。

线性变换-负变换实现

void CMFCApplication1View::OnNegativetransform()
{
 // TODO: 在此添加命令处理程序代码
 if (gray_data != nullptr) 
 {

  // 创建临时数组用于对比度拉伸处理
  unsigned char* neg_transformed_data = new unsigned char[bmpWidth * bmpHeight];
  // 负变换的处理代码
  for (int i = 0; i < bmpWidth * bmpHeight; ++i) {
   neg_transformed_data[i] = 255 - gray_data[i];
  }
  // 获取绘图设备
  CClientDC dc(this);
  CDC* pDC = &dc;

  // 绘制负变换后的灰度图
  m_pBmp->drawGrayBmp(pDC, neg_transformed_data, bmpWidth, bmpHeight, offset_left + 700, offset_top);

  // 在图片下方添加文字
  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR gdiplusToken;
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
  {
   Graphics graphics(pDC->m_hDC);
   Gdiplus::Font font(L"Arial", 12);
   SolidBrush brush(Color(255, 128, 0, 128));  // 文字颜色为紫色

   // 文字的位置
   PointF point(offset_left +700, offset_top + bmpHeight + 10);

   // 绘制文字
   graphics.DrawString(L"负变换后的灰度图", -1, &font, point, &brush);
  }
  GdiplusShutdown(gdiplusToken);

  // 释放负变换后的数据的内存
  delete[] neg_transformed_data;
 }
 else {
  // 处理图像未加载的情况
  AfxMessageBox(_T("未加载图片"));

 }
}

线性变换–负变换效果图

在这里插入图片描述

对数(对数和对数逆变换)

对数变换的原理

图像增强中的对数变换是一种常用的变换方法,它可以调整图像的灰度级分布,增强图像的对比度。对数变换的原理如下:

对数变换原理

对数变换的公式为:

s = c ⋅ log ⁡ ( 1 + r ) s = c \cdot \log(1 + r) s=clog(1+r)

其中:

  • s 是输出像素值(变换后的像素值),
  • r 是输入像素值(原始像素值),
  • c 是常数,用于调整变换的幅度。

对数变换的特点是对较低灰度级的输入像素值进行拉伸,对较高灰度级的像素值进行压缩,从而增强了图像的对比度。

对数逆变换原理

对数逆变换是对数变换的反操作,可以将经过对数变换的图像恢复到原始状态。对数逆变换的公式为:

r = exp ⁡ ( s c ) − 1 r = \exp\left(\frac{s}{c}\right) - 1 r=exp(cs)1

其中:

  • r r r 是原始像素值,
  • s s s 是经过对数变换后的像素值,
  • c c c 是与对数变换中的 c c c 相同的常数。

对数逆变换的目的是使图像能够从经过对数变换的状态回到原始状态。

应用场景

对数变换常用于增强图像的低灰度级部分,特别是当图像的信息主要集中在较低灰度级时。例如,在医学图像处理中,对数变换常用于增强 X 射线图像的细节。

总体而言,对数变换适用于对比度较低的图像,能够提升图像的显示效果。

对数变换的实现

void CMFCApplication1View::OnLogtransform()
{
 // TODO: 在此添加命令处理程序代码
 if (gray_data != nullptr)
 {
  // 创建临时数组用于对数变换处理
  unsigned char* log_transformed_data = new unsigned char[bmpWidth * bmpHeight];

  // 对数变换的处理代码
  const double c = 40.0;  // 可根据需要调整的常数
  for (int i = 0; i < bmpWidth * bmpHeight; ++i) {
   log_transformed_data[i] = static_cast<unsigned char>(c * log(1 + gray_data[i]));
  }

  // 获取绘图设备
  CClientDC dc(this);
  CDC* pDC = &dc;

  // 绘制对数变换后的灰度图
  m_pBmp->drawGrayBmp(pDC, log_transformed_data, bmpWidth, bmpHeight, offset_left , offset_top+ bmpHeight+50);

  // 在图片下方添加文字
  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR gdiplusToken;
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
  {
   Graphics graphics(pDC->m_hDC);
   Gdiplus::Font font(L"Arial", 12);
   SolidBrush brush(Color(255, 128, 0, 128));  // 文字颜色为紫色

   // 文字的位置
   PointF point(offset_left , offset_top + 2*bmpHeight+50);

   // 绘制文字
   graphics.DrawString(L"对数变换后的灰度图", -1, &font, point, &brush);
  }
  GdiplusShutdown(gdiplusToken);

  // 释放对数变换后的数据的内存
  delete[] log_transformed_data;
 }
 else {
  // 处理图像未加载的情况
  AfxMessageBox(_T("未加载图片"));
 }
}

实现效果图

幂律(n次幂和n次根变换)

在这里插入图片描述

幂律(n次幂和n次根变换)的原理

幂律变换(Power Law Transformation)是一种图像增强的方法,通过对图像的像素值进行非线性映射来调整图像的对比度。该变换的一般形式如下:

g ( x , y ) = c ⋅ [ f ( x , y ) ] γ g(x, y) = c \cdot [f(x, y)]^{\gamma} g(x,y)=c[f(x,y)]γ

其中:

  • g ( x , y ) g(x, y) g(x,y) 是输出图像的像素值。
  • f ( x , y ) f(x, y) f(x,y) 是输入图像的像素值。
  • c c c 是常数,用于缩放输出的像素值范围。
  • γ \gamma γ是幂律指数,控制像素值的非线性映射。

通过调整 $ \gamma $的值,可以实现不同程度的图像增强。当 γ > 1 \gamma > 1 γ>1 时,会增强图像的高亮部分,降低暗部的对比度;而当 0 < γ < 1 0 < \gamma < 1 0<γ<1 时,会增强暗部的对比度,减小亮部的差异。

在实际应用中,一般会将 f ( x , y ) f(x, y) f(x,y) 归一化到 [0, 1] 的范围,应用变换后再将结果缩放到原图像的像素值范围。

幂律变换的应用场景包括调整图像的对比度、增强细节等。这种变换在图像处理和计算机视觉中经常用于图像增强的预处理阶段。

幂律(n次幂和n次根变换)的代码实现

//幂律(n次幂和n次根变换)
void CMFCApplication1View::OnPowerlawtransform()
{
 // TODO: 在此添加命令处理程序代码
 if (gray_data != nullptr) {
  // 创建临时数组用于幂律变换处理
  unsigned char* power_law_transformed_data = new unsigned char[bmpWidth * bmpHeight];
  double gamma = 2.0; // 幂律指数,可以根据需要调整

  // 幂律变换的处理代码
  for (int i = 0; i < bmpWidth * bmpHeight; ++i) {
   double normalized_pixel_value = static_cast<double>(gray_data[i]) / 255.0;
   double transformed_value = 255.0 * pow(normalized_pixel_value, gamma);
   power_law_transformed_data[i] = static_cast<unsigned char>(transformed_value);
  }

  // 获取绘图设备
  CClientDC dc(this);
  CDC* pDC = &dc;

  // 绘制幂律变换后的灰度图
  m_pBmp->drawGrayBmp(pDC, power_law_transformed_data, bmpWidth, bmpHeight, offset_left+250, offset_top + bmpHeight + 50);
}

实现效果图

在这里插入图片描述

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

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

相关文章

Presto基础学习--学习笔记

1&#xff0c;Presto背景 2011年&#xff0c;FaceBook的数据仓库存储在少量大型hadoop/hdfs集群&#xff0c;在这之前&#xff0c;FaceBook的科学家和分析师一直靠hive进行数据分析&#xff0c;但hive使用MR作为底层计算框架&#xff0c;是专为批处理设计的&#xff0c;但是随…

孩子都能学会的FPGA:第十九课——FPGA实现流水线操作

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

Rust国内sparse镜像源配置

文章目录 1. 遇到问题1.1 问题现象1.2 解决办法 2. 重新设置最新 sparse源3. 更多参考资料3.1 字节源3.2 ustc 源3.3 清华源3.4 其他人的总结 1. 遇到问题 有好一阵子没有更新源和安装软件了&#xff0c; 使用ustc的源&#xff0c; 更新了好一阵子&#xff0c; 最后安装居然还出…

养身馆推拿会员管理系统,佳易王推拿会员管理软件短信设置教程

养身馆推拿会员管理系统&#xff0c;佳易王推拿会员管理软件短信设置教程 一、佳易王会员管理软件大众版 部分功能简介&#xff1a; 1、会员信息登记 &#xff1a;可以直接使用手机号登记&#xff0c;也可以使用实体卡片&#xff0c;推荐用手机号即可。 2、会员卡类型 &…

压缩docker在主机的虚拟磁盘容量

我们在windows里使用docker时会发现&#xff0c;即使我们已经删除了无用的镜像和容器&#xff0c;主机里挂在docker虚拟磁盘的那个盘&#xff0c;可用空间也没有增加&#xff0c;这是因为虚拟磁盘不会自动缩小&#xff0c;这里我分享一个可用的解决方案。 1.先通过docker回收空…

大小堆的实现(C语言)

目录 前言 一种完全二叉树&#xff1a;堆 堆的概念 堆的性质 建堆的时间复杂度 建堆的空间复杂度&#xff1a; 小堆的实现 必要补充 堆的初始化 堆的销毁 向上调整算法 堆的插入 向下调整算法 堆的删除 获取堆顶元素 获取堆中元素个数 堆的判空 最终代码 He…

保育员个人简历精选7篇

想要在保育员职位的求职过程中脱颖而出吗&#xff0c;参考这7篇精选的保育员简历案例&#xff01;无论您的经验如何&#xff0c;都能找到适合自己的简历样式及参考内容。 保育员个人简历模板下载&#xff08;可在线编辑制作&#xff09;&#xff1a;来幻主简历&#xff0c;做好…

免费HTTPS证书

什么是HTTPS呢&#xff1f;HTTPS全称为Hyper Text Transfer Protocol Secure&#xff0c;即超文本传输安全协议。它是在HTTP的基础上加入了SSL/TLS协议&#xff0c;可以对传输的数据进行加密&#xff0c;有效防止数据被第三方截取或篡改&#xff0c;从而保障了用户的信息安全。…

Docker Compose简单入门

Docker Compose 简介 Docker Compose 是一个编排多容器发布式部署的工具&#xff0c;提供命令集管理容器化应用的完整开发周期&#xff0c;包括服务构建&#xff0c;启动和停止。 Docker Compose 真正的作用是在一个文件&#xff08;docker-compose.yml&#xff09;中定义并运…

Fiddler抓包工具之fiddler设置抓HTTPS的请求证书安装

设置抓HTTPS的请求包 基础配置&#xff1a; 路径&#xff1a;启动Fiddler 》Tools》Options》HTTPS 注意&#xff1a;Option更改完配置需重启Fiddler才能生效 选中"Decrpt HTTPS traffic", Fiddler就可以截获HTTPS请求&#xff0c;如果是第一次会弹出证书安装提…

JS构造函数

构造函数是一种特殊的函数&#xff0c;主要用来初始化对象 使用场景&#xff1a;比如我对象与其他对象都相似&#xff0c;此时可以通过构造函数来快速创建多个类似的对象。 举个例子&#xff1a; // 大头儿子const Son {name:"大头儿子",age:6,gender:"男"…

C++基础 -33- 单目运算符重载

单目运算符重载格式 a和a通过形参确定 data1 operator() {this->a;return *this; }data1 operator(int) {data1 temp*this;this->a;return temp; }举例使用单目运算符重载 #include "iostream"using namespace std;class data1 {public :int a;data1(int…

maven篇---第一篇

系列文章目录 文章目录 系列文章目录前言一、什么是maven?二、Maven能为我们解决什么问题?三、说说maven有什么优缺点?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码…

react native 环境准备

一、必备安装 1、安装node 注意 Node 的版本应大于等于 16&#xff0c;安装完 Node 后建议设置 npm 镜像&#xff08;淘宝源&#xff09;以加速后面的过程&#xff08;或使用科学上网工具&#xff09;。 node下载地址&#xff1a;Download | Node.js设置淘宝源 npm config s…

qnx修改tcp和udp缓冲区默认大小

拷贝/home/test/qnx/qos223/target/qnx7/aarch64le/sbin/sysctl进系统中 https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.utilities/topic/s/sysctl.html kern.sbmax 默认262144&#xff0c;这个限制住了发送、接收缓冲器大小 ./sysctl -w kern.sbmax10000…

免费AI洗稿软件【2023最新】

很多时候我们需要通过文字来表达观点、推广产品或服务。然而&#xff0c;长时间的文稿创作不仅费时费力&#xff0c;还容易陷入表达瓶颈。许多写手和从业者纷纷寻找一款方便、高效的AI洗稿工具。 文心一言洗稿软件。这款软件以其独特的文风生成和洗稿功能而备受瞩目。用户只需…

【Qt开发流程】之事件系统3:键盘事件

序章 以下链接是拖放事件介绍和使用示例&#xff1a; 【Qt开发流程】之拖放操作1:介绍链接: https://blog.csdn.net/MrHHHHHH/article/details/134626484 【Qt开发流程】之拖放操作2:使用链接: https://blog.csdn.net/MrHHHHHH/article/details/134632006 以下链接是事件系统…

页面表格高度自适应

前言 现在后端管理系统主页面基本都是由三部分组成 查询条件&#xff0c;高度不固定&#xff0c;可能有的页面查询条件多&#xff0c;有的少表格&#xff0c;高度不固定&#xff0c;占据页面剩余高度分页&#xff0c;高度固定 这三部分加起来肯定是占满全屏的&#xff0c;那么我…

JavaWeb 分页查询

由于html不能直接从域当中直接拿数据 所以我们引入了jsp文件 数据存在了requets域当中 如果数据量很大,不可能把所有数据全部在页面展示: 数据全部在页面展示缺点: SQL执行时间过长 用户查看数据,滚动滚动条,用户体验不高 在实际开发中,分页查询&#xff0c; 实现: sql语句…

idea新建spring boot starter

什么是spring boot starter Spring Boot Starter 是一种 Maven 或 Gradle 依赖&#xff0c;它能够轻松地将相关库和框架集成到 Spring Boot 应用程序中。Starter 是一种对常见依赖项和设置的易于复用的封装&#xff0c;它们通常被开发人员用于创建可插拔的 Spring Boot 应用程序…
最新文章