使用VC++实现分段线性变换,直方图均衡化、锐化处理(使用拉普拉斯算子)

news2024/11/27 4:38:41

图像锐化1

实验要求

5.1实验目的、要求
实验目的:
(1)掌握图像增强的原理与相关方法。
(2)能使用VC++实现图像增强的一些相关功能。
实验要求:
A部分:
(1)对一幅256级灰度图像,使用VC++实现分段线性变换,直方图均衡化。
(2)对一幅256级灰度图像,使用VC++实现锐化处理(使用拉普拉斯算子)。

一、 分段线性变换

1. 分段线性变换的原理

灰度图像分段线性变换是一种调整图像灰度级别的方法,它通过将灰度范围划分为多个分段,然后对每个分段应用线性变换来调整图像的对比度和亮度。这种方法的主要目的是增强或减弱图像中特定灰度范围的细节,以改善图像的视觉效果。

下面是该方法的基本原理:

  1. 分段划分: 将整个灰度范围划分为多个不重叠的分段。每个分段代表图像中的一个灰度范围。这些分段由一个或多个分界点定义,这些分界点将整个灰度范围划分成不同的区域。

  2. 线性变换: 对每个分段应用线性变换。线性变换由斜率和截距两个参数定义。斜率决定了线的倾斜程度,而截距则控制了线的位置。通过调整这两个参数,可以实现对分段内灰度级别的调整。

  3. 像素更新: 对图像的每个像素应用上述的分段线性变换。首先,确定像素所属的分段,然后使用该分段对应的线性变换来更新像素的灰度值。这样,每个像素都会根据其原始灰度值和所属分段的线性变换进行调整。

通过灰度图像分段线性变换,可以实现对图像不同灰度范围的灰度级别进行差异化的调整。例如,可以增强图像中的低对比度区域或减弱过曝区域,从而更好地展现图像细节。这种方法在图像增强和调整方面具有一定的灵活性,但需要根据具体的应用场景和图像特性来选择适当的分段和线性变换参数。

2. 分段线性变换的实验代码

3. 分段线性变换的实验现象

在这里插入图片描述

左:原灰度图
右:灰度图像分段线性变换后
在这里插入图片描述

二、直方图均衡化

1. 直方图均衡化的原理

直方图均衡化是一种用于增强图像对比度的图像处理技术。其基本原理是将图像的灰度直方图变换成一个均匀分布的直方图,从而拉伸图像的灰度范围,使得亮度水平更加均匀,细节更为突出。

具体的步骤如下:

  1. 计算直方图: 统计图像中每个灰度级别的像素数量,形成直方图。

  2. 计算累积分布函数(CDF): 将直方图进行归一化,得到每个灰度级别对应的累积概率。

    C D F ( i ) = ∑ j = 0 i P ( j ) CDF(i) = \sum_{j=0}^{i} P(j) CDF(i)=j=0iP(j)

    其中, P ( j ) P(j) P(j) 是灰度级别 j j j 的概率。

  3. 直方图均衡化变换函数: 将CDF的值映射到新的灰度级别范围。

    H ( i ) = round ( C D F ( i ) × ( L − 1 ) N ) H(i) = \text{round}\left(\frac{CDF(i) \times (L-1)}{N}\right) H(i)=round(NCDF(i)×(L1))

    其中, H ( i ) H(i) H(i) 是新的灰度级别, L L L 是灰度级别的最大值, N N N 是图像的总像素数量。 r o u n d ( ) round() round() 是一个数学函数,通常用于将一个浮点数四舍五入为最接近的整数

  4. 应用变换: 将变换函数应用于图像的每个像素,更新图像的灰度级别。

通过直方图均衡化,原始图像中灰度分布不均匀的区域会被映射到更广泛的灰度范围,从而提高了图像的对比度,使细节更加清晰。

2. 直方图均衡化的实验代码

 BOOL HistogramEqualize(CDib* pDib)
 {
  // 指向源图像的指针
 unsigned char* lpSrc;
 
 // 临时变量
 int nTemp;
 
 // 循环变量
 int i,j;
 // 累积直方图,即灰度映射表
 BYTE byMap[256];
 // 直方图
 int nCount[256];
 // 图象的高度和宽度
 CSize sizeImage;
 sizeImage = pDib->GetDimensions();
 // 获得图象数据存储的高度和宽度
 CSize SizeSaveImage;
 SizeSaveImage = pDib->GetDibSaveDim();
 // 重置计数为0
 for (i = 0; i < 256; i ++)
 {
  // 清零
  nCount[i] = 0;
 }
 
 // 计算各个灰度值的计数,即得到直方图
 for (i = 0; i < sizeImage.cy; i ++)
 {
  for (j = 0; j < sizeImage.cx; j ++)
  {
   lpSrc = (unsigned char *)pDib->m_lpImage + SizeSaveImage.cx * i + j;
   //表示从图像数据的起始位置开始,跳过 i 行,再移动 j 列,最终指向了图像中第 i 行、第 j 列的像素的位置,获取图像中第 i 行、第 j 列的像素的灰度值
   
   // 计数加1
   nCount[*(lpSrc)]++;//以灰度值的大小为下坐标,进行计数
  }
 }
 
 // 计算累积直方图
 for (i = 0; i < 256; i++)
 {
  // 初始为0
  nTemp = 0;
  
  for (j = 0; j <= i ; j++)
  {
   nTemp += nCount[j];
  }
  
  // 计算对应的新灰度值---公式
  byMap[i] = (BYTE) (nTemp * 255 / sizeImage.cy / sizeImage.cx);
 }
 
 // 每行
 for(i = 0; i < sizeImage.cy; i++)
 {
  // 每列
  for(j = 0; j < sizeImage.cx; j++)
  {
   // 指向DIB第i行,第j个象素的指针
   lpSrc = (unsigned char*)pDib->m_lpImage + pDib->GetPixelOffset(i,j);
   
   // 计算新的灰度值x
   *lpSrc = byMap[*lpSrc];//找到当前像素的原始灰度值,并将其映射为新的灰度值。
  }
 }
 // 返回
 return TRUE;
 }

3. 直方图均衡化的实验现象

左:原图
右:直方图均衡化增强后
在这里插入图片描述

三、 拉普拉斯算子实现锐化

拉普拉斯算子的原理

拉普拉斯算子(Laplacian operator)是一种用于图像处理的滤波器,主要用于检测图像中的边缘和细节。它通过计算图像中每个像素点的二阶导数来实现。

拉普拉斯算子的一维形式为:

L ( x ) = d 2 d x 2 L(x) = \frac{d^2}{dx^2} L(x)=dx2d2

而在二维图像上的应用是通过以下离散形式的卷积核:

[ 0 1 0 1 − 4 1 0 1 0 ] \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \\ \end{bmatrix} 010141010

应用拉普拉斯算子的过程是将这个卷积核与图像进行卷积运算。具体而言,对于图像中的每个像素,将其与卷积核中的对应元素相乘,然后将所有相乘的结果相加。这个过程可以用以下的数学表达式表示:

L ( x , y ) = ∑ i = − 1 1 ∑ j = − 1 1 kernel ( i , j ) × image ( x + i , y + j ) L(x, y) = \sum_{i=-1}^{1} \sum_{j=-1}^{1} \text{kernel}(i, j) \times \text{image}(x + i, y + j) L(x,y)=i=11j=11kernel(i,j)×image(x+i,y+j)

其中, kernel ( i , j ) \text{kernel}(i, j) kernel(i,j) 是卷积核中的元素, image ( x + i , y + j ) \text{image}(x + i, y + j) image(x+i,y+j) 是图像中对应位置的像素值。

拉普拉斯算子对图像进行了高通滤波,强调了图像中的高频细节和边缘。应用拉普拉斯算子后,边缘部分的像素值将发生变化,使得图像中的边缘更加明显。然而,拉普拉斯算子也会增加图像中的噪声。因此,在实际应用中,通常会结合其他技术,如平滑(低通滤波)来减少噪声的影响。

拉普拉斯算子的实验代码


/*************************************************************************
 *
 * \函数名称:
 *   LinearSharpen()
 *
 * \输入参数:
 *   LPBYTE lpImage  - 指向图象数据得指针
 *   int nWidth   - 图象数据宽度
 *   int nHeight  - 图象数据高度
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   线性锐化图象增强
 *   本函数采用拉普拉斯算子对图象进行线性锐化
 *   在原来图象上加上拉普拉斯算子锐化的信息
 *
 *************************************************************************
 */
void LinearSharpen (LPBYTE lpImage, int nWidth, int nHeight)
{
 // 遍历图象的纵坐标
 int y;

 // 遍历图象的横坐标
 int x;

 double * pdGrad ;
 pdGrad = new double[nWidth*nHeight];//用于存储图像的梯度信息。

 // 初始化为0
 memset(pdGrad, 0, nWidth*nHeight*sizeof(double)) ;

 // 设置模板系数--设置拉普拉斯算子的卷积核,这是一个 3x3 的矩阵,用于计算图像中每个像素点的梯度。
 static int nWeight[3][3] ;
 nWeight[0][0] = -1 ;   
 nWeight[0][1] = -1 ;   
 nWeight[0][2] = -1 ;   
 nWeight[1][0] = -1 ;   
 nWeight[1][1] =  8 ;   
 nWeight[1][2] = -1 ;   
 nWeight[2][0] = -1 ;   
 nWeight[2][1] = -1 ;   
 nWeight[2][2] = -1 ;   

 //这个变量用来表示Laplacian算子象素值
 int nTmp[3][3];

 // 临时变量
 double dGrad;

 // 模板循环控制变量
 int yy ;
 int xx ;
 for(y=1; y<nHeight-1 ; y++ )
  for(x=1 ; x<nWidth-1 ; x++ )
  {
   dGrad = 0 ; 
   // Laplacian算子需要的各点象素值
   
   // 模板第一行
   nTmp[0][0] = lpImage[(y-1)*nWidth + x - 1 ] ; 
   nTmp[0][1] = lpImage[(y-1)*nWidth + x     ] ; 
   nTmp[0][2] = lpImage[(y-1)*nWidth + x + 1 ] ; 
   
   // 模板第二行
   nTmp[1][0] = lpImage[y*nWidth + x - 1 ] ; 
   nTmp[1][1] = lpImage[y*nWidth + x     ] ; 
   nTmp[1][2] = lpImage[y*nWidth + x + 1 ] ; 
   
   // 模板第三行
   nTmp[2][0] = lpImage[(y+1)*nWidth + x - 1 ] ; 
   nTmp[2][1] = lpImage[(y+1)*nWidth + x     ] ; 
   nTmp[2][2] = lpImage[(y+1)*nWidth + x + 1 ] ; 
   
   // 计算梯度
   for(yy=0; yy<3; yy++)
    for(xx=0; xx<3; xx++)
    {
     dGrad += nTmp[yy][xx] * nWeight[yy][xx] ;
    }
    
    // 梯度值写入内存
    *(pdGrad+y*nWidth+x)=dGrad;
  }
  //将计算得到的梯度值加到原始图像上,实现锐化效果。
 for(y=0; y<nHeight ; y++ )
 {
  for(x=0 ; x<nWidth ; x++ )
  {
   lpImage[y*nWidth+x] = (unsigned char)max(0,min(255,(lpImage[y*nWidth+x] + (int)pdGrad[y*nWidth+x]) ));
  }
 }
 //释放申请的内存
 delete []pdGrad ;
 pdGrad = NULL   ;
}

拉普拉斯算子的实验现象

左:原图
右:经过拉普拉斯锐化
在这里插入图片描述

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

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

相关文章

Linux | 进程间通信

目录 前言 一、进程间通信的基本概念 二、管道 1、管道的基本概念 2、匿名管道 &#xff08;1&#xff09;原理 &#xff08;2&#xff09;测试代码 &#xff08;3&#xff09;读写控制相关问题 a、读端关闭 b、写端关闭 c、读快写慢 d、读慢些快 &#xff08;4&a…

线程的面试八股

Callable接口 Callable是一个interface,相当于给线程封装了一个返回值,方便程序猿借助多线程的方式计算结果. 代码示例: 使用 Callable 版本,创建线程计算 1 2 3 ... 1000, 1. 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型…

高级数据结构——树状数组

树状数组&#xff08;Binary Index Tree, BIT&#xff09;&#xff0c;是一种一般用来处理单点修改和区间求和操作类型的题目的数据结构&#xff0c;时间复杂度为O(log n)。 对于普通数组来说&#xff0c;单点修改的时间复杂度是 O(1)&#xff0c;但区间求和的时间复杂度是 O(n…

【备忘】websocket学习之挖坑埋自己

背景故事 以前没有好好学习过websocket&#xff0c;只知道它有什么用途&#xff0c;也知道是个好东西&#xff0c;平时在工作中没用过&#xff0c;所以对它并不知所以然。如今要做个自己的项目&#xff0c;要在付款的时候实时播报声音。自己是个开发者&#xff0c;也不想用别人…

类加载中的执行顺序

结论&#xff1a; 先静态再实例 实例化一个子类(这个颜色主要是实例化会执行的部分)&#xff1a; 父类静态属性&#xff0d;&#xff1e;父类静态代码块&#xff0d;&#xff1e;子类静态属性&#xff0d;&#xff1e;子类静态代码块&#xff0d;&#xff1e;父类代码块&…

jQuery【jQuery树遍历、jQuery动画(一)、jQuery动画(二)】(四)-全面详解(学习总结---从入门到深化)

目录 jQuery树遍历 jQuery动画(一) jQuery动画(二) jQuery树遍历 1、 .children() 获得子元素&#xff0c;可以传递一个选择器参数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-…

【Effective C++ 笔记】(四)设计与声明

【四】设计与声明 条款18 &#xff1a; 让接口容易被正确使用&#xff0c;不易被误用 Item 18: 让接口容易被正确使用&#xff0c;不易被误用 Make interfaces easy to use correctly and hard to use incorrectly. “让接口容易被正确使用&#xff0c;不易被误用”&#xff0…

OpenCV基础应用(3)— 把.png图像保存为.jpg图像

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本节课就手把手教你如何把.png图像保存为.jpg图像&#xff0c;希望大家学习之后能够有所收获~&#xff01;&#x1f308; 目录 &#x1f680;1.技术介绍 &#x1f680;2.实现代码 &#x1f680;1.技术介绍 如果在电脑某…

web缓存-----squid代理服务

squid相关知识 1 squid的概念 Squid服务器缓存频繁要求网页、媒体文件和其它加速回答时间并减少带宽堵塞的内容。 Squid代理服务器&#xff08;Squid proxy server&#xff09;一般和原始文件一起安装在单独服务器而不是网络服务器上。Squid通过追踪网络中的对象运用起作用。…

渗透测试--实战若依ruoyi框架

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

YOLOv3 学习记录

文章目录 简介整体介绍整体架构图 网络架构的改进Backbone 的改进FPNAnchor 机制 坐标表示与样本匹配目标边界框的预测正负样本匹配 损失函数 简介 关注目标在哪里 目标是什么 目标检测的发展路径&#xff1a; proposal 两阶段 --> anchor-base/ anchor-free --> nms f…

SpringCloud微服务:Nacos的集群、负载均衡、环境隔离

目录 集群 在user-service的yml文件配置集群 启动服务 负载均衡 order-service配置集群 设置负载均衡 当本地集群的服务挂掉时 访问权重 环境隔离 1、Nacos服务分级存储模型 一级是服务&#xff0c;例如userservice 二级是集群&#xff0c;例如杭州或上海 …

计算机网络的发展

目录 一、计算机网络发展的四个阶段 1、第一阶段&#xff1a;面向终端的计算机网络&#xff08;20世纪50年代&#xff09; 2、第二阶段&#xff1a;计算机—计算机网络&#xff08;20世纪60年代&#xff09; 3、第三阶段&#xff1a;开放式标准化网络&#xff08;20世纪70年…

【2023最全教程】python+appium自动化测试元素定位(建议收藏)

关于app自动化测试&#xff0c;元素定位工具有三个&#xff1a; appium自带的Appium Inspector工具 Android ADT原生的工具 python版uiautomator2中的weditor 由于我常用的是前两个&#xff0c;所以下面只介绍前面两种元素定位工具&#xff08;以下内容中均以微博为例子&am…

idea中把spring boot项目打成jar包

打jar包 打开项目&#xff0c;右击项目选中Open Module Settings进入project Structure 选中Artifacts&#xff0c;点击中间的加号&#xff08;Project Settings->Artifacts->JAR->From modules with dependencies &#xff09; 弹出Create JAR from Modules&#…

OpenCV基础应用(4)— 如何改变图像的透明度

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本节课就手把手教你如何改变图像的透明度&#xff0c;希望大家学习之后能够有所收获~&#xff01;&#x1f308; 目录 &#x1f680;1.技术介绍 &#x1f680;2.实现代码 &#x1f680;1.技术介绍 改变图像透明度的实…

从内网到公网:使用Axure RP和内网穿透技术发布静态web页面的完整指南

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

振南技术干货集:比萨斜塔要倒了,倾斜传感器快来!(1)

注解目录 1、倾斜传感器的那些基础干货 1.1 典型应用场景 &#xff08;危楼、边坡、古建筑都是对倾斜敏感的。&#xff09; 1.2 倾斜传感器的原理 1.2.1 滚珠式倾斜开关 1.2.2 加速度式倾斜传感器 1)直接输出倾角 2)加速度计算倾角 3)倾角精度的提高 &#xff08;如果…

JS-项目实战-新增水果库存功能实现

1、fruit.js function $(name) {if (name) {//假设name是 #fruit_tblif (name.startsWith("#")) {name name.substring(1); //fruit_tblreturn document.getElementById(name);} else {return document.getElementsByName(name); //返回的是NodeList类型}} }//当…

一言成文大模型:大模型实践落地之路

百度CEO&#xff0c;李彦宏指出、深度学习技术&#xff0c;大语言模型具备了理解、生成、逻辑、记忆等人工智能的核心基础能力&#xff0c;为通用人工智能带来曙光。 元宇宙_一言成文大模型 一言成文大模型&#xff1a;大模型实践落地之路