从零开始学OpenCV——图像灰度变换详解(线性与非线性变换)

news2024/11/15 0:22:07

文章目录

  • 图像灰度变化
      • 灰度变换介绍
      • 灰度线性变换
      • 灰度分段线性变换
      • 图像点运算
      • 灰度非线性变换
      • 线性点运算
      • 灰度的非线性变换:对数变换
      • 灰度的非线性变换:伽马变换
      • 灰度的非线性变换:对比拉伸
      • 灰度的非线性变换: S形灰度变换
      • 灰度的非线性变换:阈值变换
      • 灰度的非线性变换:灰度切割

图像灰度变化

灰度变换介绍

  • 由于外部环境光照影响,或由于成像设备的非线性和图像记录设备动态范围太窄等,
    获取到的图像可能不够理想,细节分辨不清,即对比度不足。
  • 简单来说,对比度是最白与最黑亮度单位的比值。白色越亮、黑色越暗,则对比度就越高。
  • 可以使用灰度变换方法解决对比度不足的问题。

在这里插入图片描述
曝光过度的照片整体过亮,曝光不足的照片整体过暗。这两种情况下图片里的物体都缺乏细节辨识度。

灰度变换是将输入图像中的每个像素 f ( x , y ) f(x, y) f(x,y)通过映射函数 T T T变换成输出图像中的灰度值 g ( x , y ) g(x, y) g(x,y)
g ( x , y ) = T [ f ( x , y ) ] g(x,y)=T[f(x,y)] g(xy)=T[f(xy)]

根据变换函数的性质不同,灰度变换可以分为:

  • 灰度线性变换
  • 灰度分段线性变换
  • 灰度非线性变换

灰度线性变换

  • 采用线性函数对图像的每一个像素作线性扩展,扩展图像的动态范围。
  • 对图像作灰度线性或分段线性变换,扩大图像的对比度,将有效地改善图像视觉效果。

设原图像灰度取值 f ( x , y ) ∈ [ a , b ] f(x,y)\in[a,b] f(x,y)[a,b],线性变换后的图像灰度取值 g ( x , y ) ∈ [ c , d ] g(x,y)\in[c,d] g(x,y)[c,d] 则灰度线性变换为:
g ( x , y ) = k [ f ( x , y ) − a ] + c g(x,y)=k[f(x,y)-a]+c g(x,y)=k[f(x,y)a]+c

在这里插入图片描述
式子中, k = d − c b − a k=\frac{d-c}{b-a} k=badc为线性变换函数(直线)的斜率。

  • 扩展动态范围, k > 1 k>1 k>1
  • 缩小动态范围, 0 < k < 1 0<k<1 0<k<1

灰度线性变化示例:

在这里插入图片描述

k = 1 k=1 k=1的时候,就变为加常数线性变换 g ( x , y ) = f ( x , y ) + c g(x,y)=f(x,y)+c g(x,y)=f(x,y)+c,可以压缩动态范围,降低对比度。

在这里插入图片描述

加常数线性变换实例:

在这里插入图片描述

灰度分段线性变换

灰度线性变换的缺点:
不够灵活,将原始图像中的灰度值不加区别的扩展。

在实际应用中:

  • 为了突出图像中感兴趣的研究对象,常常需要局部扩展某一范围的灰度值;
  • 对不同范围的灰度值进行不同程度的扩展。

举例:
设图像的整个灰度范围比较宽,为[0, M],但感兴趣的某两个灰度值之间的动态范围较窄,为[a, b]。采用灰度分段线性变换来扩展感兴趣的[a, b]区间。具体情况有两种,对应的变换关系如下图所示。其中,图(a)是“扩展感兴趣区域,牺牲其他区域”处理的函数图形示例,图(b)是“扩展感兴趣区域,压缩其他区域”处理的函数图形示例。
在这里插入图片描述
灰度分段线性变换实例:
在这里插入图片描述

图像点运算

定义:

对图像中的每个像素进行灰度变换运算。
输出图象每个象素点的灰度值仅由输入图像相同位置象素点的灰度值决定。

设输入图像和输出图像在 ( x , y ) (x,y) (x,y)处的灰度值分别是 r r r s s s,则点运算可表示为 s = T ( r ) s = T(r) s=T(r), T T T 表示输入图像与输出图像像素的灰度映射关系。

运算的用途:实现对比度增强等。

图像的点运算包括:

  • 灰度变换
    • 线性变换
    • 非线性变换(对数变换、伽马变换、阈值变换,分段线性变换等)
  • 位图切割

灰度非线性变换

非线性变换定义:

  • 对于 g ( x , y ) = T [ f ( x , y ) ] g(x,y)=T[f(x,y)] g(x,y)=T[f(x,y)],如果 T [ ⋅ ] T[·] T[]是非线性变换函数,那么该变换为非线性变换。
  • 常用的非线性变换有对数变换、幂次变换(伽马变换)等。

线性点运算

输出输入的灰度值成线性函数关系: s = f ( r ) = a r + b s =f(r)=ar+b s=f(r)=ar+b

  • a a a 控制对比度(不同级别灰度的明暗差异):
    • a > 1,对比度变大;
    • a < 1,对比度变小。
    • a 为负值,实现负片效果
  • b b b 控制输出图像的整体亮度:
    • b > 0 增大亮度
    • b < 0 则减小亮度
import cv2 as cv

# 线性变换
def linear(img,a,b):
    """
    s =f(r)=ar+b
    """
    r = np.copy(img)
    s = a*r+b
    return s
if __name__=="__main__":
    img = cv.imread("3.png")
    img = cv.cvtColor(img,cv.COLOR_RGB2GRAY)
    # 调节 a,b值观察图像变化
    a = 1
    b = 255
    re_img = linear(img,a,b)
    cv.imshow('img',img)
    cv.imshow('re_img,a={},b={}'.format(a,b),re_img)
    cv.waitKey(0)
    cv.destroyAllWindows()

在这里插入图片描述
灰度的线性变换不利于突出感兴趣区域,且容易出现饱和、截止等情况。

灰度的非线性变换:对数变换

灰度的线性变换不利于突出感兴趣区域,且容易出现饱和、截止等情况。有时原图含有较多的暗部区域,某些显示设备呈现低灰度的能力有限,如果直接使用原图,则一部分细节可能丢失。

解决办法:进行非线性变换,即对原图进行对数变换,增强暗部区域的对比度。

对数变换的一般表达式为:
g ( x , y ) = λ l g [ f ( x , y ) + 1 ] \mathbf{g(x,y)=\lambda lg[f(x,y)+1]} g(x,y)=λlg[f(x,y)+1]

式中, λ λ λ为尺度比例系数,用来调节变换后的灰度值的动态范围,使其更符合实际需要。对数变换可以扩展图像的低灰度值范围,同时压缩高灰度值范围,使图像灰度值分布均匀,更加匹配人的视觉特性,示例图如下图所示。
在这里插入图片描述

对数变换尤其适用于灰度范围特别大的情况。
例:傅里叶频谱的灰度范围可能超过8位灰度图像的范围,例如

在这里插入图片描述

附:

灰度对数变换(可增强暗部细节): s = c l o g ( 1 + r )   c 为常数,建议值 c = 255 / l o g ( 256 ) s = clog(1+r)\ c为常数,建议值c = 255/log(256) s=clog(1+r) c为常数,建议值c=255/log(256)
灰度反对数变换(可增强亮部细节): s = e x p ( r / c ) − 1 s = exp(r/c) - 1 s=exp(r/c)1

灰度的非线性变换:伽马变换

伽玛变换又称为 指数变换 或 幂次变换,是另一种常用的灰度非线性变换。
网上大多数给的指数函数的基本形式为: s = c r γ   c ≥ 0 , γ ≥ 0 ; s = cr^\gamma \ c\geq0,\gamma\geq0; s=crγ c0,γ0;
实际使用公式: s = 255 × ( r 255 + e p s ) γ s = 255\times(\frac{r}{255+eps})^\gamma s=255×(255+epsr)γ

e p s eps eps 为补偿系数(一般为0), γ \gamma γ 为伽马系数
γ < 1 \gamma<1 γ<1 时,低亮度区域对比度增强
γ > 1 \gamma>1 γ>1 时, 高亮度区域对比度增强
γ = 1 \gamma=1 γ=1时,该灰度变换是线性的,此时通过线性方式改变原图像。

这里给出更加详细的一般表达式: g ( x , y ) = λ [ f ( x , y ) + ξ ] γ g(x,y)=\lambda[f(x,y)+\xi]^{\gamma} g(x,y)=λ[f(x,y)+ξ]γ

式中,参数 λ λ λ为常数,可以改变指数变换曲线的变换速率。参数 ε ε ε为常数,可以改变指数变换曲线的起始位置。参数 γ γ γ也为常数,其取值对变换函数的特性有很大的影响。
指数变换函数曲线如下图所示。

  • 图(a)表示 γ < 1 γ<1 γ<1时的指数变换函数曲线。当 γ < 1 γ<1 γ<1时,指数变换的作用与对数变换类似,输入的高灰度范围被压缩,低灰度范围被拉伸,实现了强化暗部压缩亮部的图像增强效果。
  • 图(b)表示 γ > 1 γ>1 γ>1时的指数变换函数曲线。当 γ > 1 γ>1 γ>1时,输入的低灰度范围被压缩,高灰度范围被拉伸,实现了强化亮部压缩暗部的图像增强效果。
    在这里插入图片描述

不同 γ \gamma γ值的变换曲线如下图所示:
在这里插入图片描述
指数变换拉大了不同点的灰度值距离,提高了图像的对比度。对图像采用不同 γ γ γ值的指
数变换结果如下图所示。其中,图(a)是原图像,图(b)是 γ = 0.6 γ=0.6 γ=0.6时的指数变换的结果,
图©是 γ = 1.7 γ=1.7 γ=1.7时的指数变换的结果。
在这里插入图片描述

附代码实现:

# 非线性变化:γ变换
def gamma(img,gamma):
    """
    s = c * r^gamma
    """
    r = np.copy(img)
    s = np.power(r/255,gamma)

    return s

在这里插入图片描述
分段线性变换和伽马变换例子:

#1、导入包
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt


#2、读入图片
gray_img = cv2.imread('spine.tif',0)
cv2.imshow('gray_img',gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

#3、构造跟原图同样大小的零值图,用于保存分段线性变换结果
piecewise_linear_img = np.zeros((gray_img.shape[0],gray_img.shape[1]),np.uint8)

#4、设置分段线性函数参数
r1,s1 = 40,100
r2,s2 = 200,250
k1 = s1/r1
k2 = (s2-s1)/(r2-r1)
k3 = (255-s2)/(255-r2)

#5、便利图像每个像素,按公式进行变换
for i in range(gray_img.shape[0]):
    for j in range(gray_img.shape[1]):
        if gray_img[i,j] <= r1:
            piecewise_linear_img[i,j] = k1*gray_img[i,j]
        elif r1 <= gray_img[i,j] <= r2:
            piecewise_linear_img[i,j] = k2*(gray_img[i,j]-r1) + s1
        else:
            piecewise_linear_img[i,j] = k3*(gray_img[i,j]-r2) + s2

#6、构造跟原图同样大小的零值图,用于保存伽马变换的结果
gamma_img = np.zeros((gray_img.shape[0],gray_img.shape[1],1),dtype=np.float32)

#7、遍历图像每个像素值,按公式进行变换
for i in range(gray_img.shape[0]):
    for j in range(gray_img.shape[1]):
        gamma_img[i,j] = math.pow(gray_img[i,j],0.5)
cv2.normalize(gamma_img,gamma_img,0,255,cv2.NORM_MINMAX)#将伽马变换后的图像像素值统一到0-255
cv2.convertScaleAbs(gamma_img)#将图片转换为uint8类型

#显示变换结果,进行效果对比
plt.subplot(321),plt.imshow(gray_img,'gray'),plt.title('srcImg')#plt.subplt(321)指一个三行两列的图从左到右从上到下的第一个位置
plt.subplot(322),plt.hist(gray_img.ravel(),256,[0,256]),plt.title('Histogram'),plt.xlim([0,256]) #plt.hist直方图,ravel()方法将矩阵拉成一维数组
plt.subplot(323),plt.imshow(piecewise_linear_img,'gray'),plt.title('piecewise_linear')
plt.subplot(324),plt.hist(piecewise_linear_img.ravel(),256,[0,256]),plt.title('Histogram'),plt.xlim([0,256])
plt.subplot(325),plt.imshow(gamma_img,'gray'),plt.title('gamma_img')
plt.subplot(326),plt.hist(gamma_img.ravel(),256,[0,256]),plt.title('Histogram'),plt.xlim([0,256])
plt.tight_layout()

在这里插入图片描述
本案例分别采用分段线性变换和伽马变换对成像不佳的骨骼X光片进行了改善。从改善后的直方图来看,图像的对比度均得到了改善;其中伽马变换直方图更为分散,变换后的图像对比度更好。

灰度的非线性变换:对比拉伸

在实际应用中,为了突出图像中感兴趣的研究对象,常常要求增强某一灰度范围的对比度,或对不同范围的灰度值进行不同的处理,即分段线性拉伸。分段线性拉伸是仅将某一范围的灰度值进行拉伸,而其余范围的灰度值实际上被压缩了。
在这里插入图片描述

# 非线性变化:对比拉伸
def constr(img):
    """
    s = 0.2*r  r<90
    s = 3*r    90<r<160
    s = 0.8*r  其他
    """
    r = np.copy(img)
    row,col = r.shape
    for i in range(row):
        for j in range(col):
            if r[i][j] < 90:
                r[i][j] *=0.2
            if r[i][j] > 90 and r[i][j] < 160:
                r[i][j] *= 3
            if r[i][j] > 160:
                r[i][j] *= 0.8

    return r

在这里插入图片描述

灰度的非线性变换: S形灰度变换

S 形灰度变换曲线,降低较亮和较暗部分的对比度,加强中间灰度级物体对比度: s = 255 2 1 + 1 s i n ( a π 2 ) s i n [ a π ( r 255 − 1 2 ) ] s = \frac{255}{2}{1+\frac{1}{sin(a\frac{\pi}{2})}sin[a\pi(\frac{r}{255}-\frac{1}{2})]} s=22551+sin(a2π)1sin[(255r21)] S 形灰度变换曲线,加强较亮和较暗部分的对比度,降低灰度级中间物体对比度: s = 255 2 1 + 1 t a n ( a π 2 ) t a n [ a π ( r 255 − 1 2 ) ] s = \frac{255}{2}{1+\frac{1}{tan(a\frac{\pi}{2})}tan[a\pi(\frac{r}{255}-\frac{1}{2})]} s=22551+tan(a2π)1tan[(255r21)]

在这里插入图片描述

灰度的非线性变换:阈值变换

阈值变换可以将灰度图像转换成黑白二值图像,用户指定一阈值T,灰度低于T置0,高于T置255。 s = { 0 , r < T   255 , r ≥ T s = \begin{cases} 0,& r<T\ 255,& r\geq T \end{cases} s={0,r<T 255,rT 通过阈值变换有助于进行图像分割。

# 非线性变化:阈值变换
def threshold(img,T):
    r = np.copy(img)
    r[r>T] = 255
    r[r<T] = 0

    return r

在这里插入图片描述

灰度的非线性变换:灰度切割

灰度切割(灰度分层):突出感兴趣灰度范围
在这里插入图片描述

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

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

相关文章

tomcat中出现RFC7230和RFC3986问题解析

问题截图 问题分析 出现上述问题&#xff0c;是因为各版本tomcat中对特殊字符和请求路径中携带中文参数而产生的错误提示。 解决办法 1、调整tomcat版本 tomcat 7.0.76之前的版本不会出现类似问题 2、tomcat9之前&#xff0c;修改tomcat目录底下的/conf/catalina.properti…

233:vue+openlayers绘制渐变填充色的圆形、多边形

第233个 点击查看专栏目录 本示例的目的是介绍如何在vue+openlayer中绘制带有渐变填充色的圆形、多边形。这里用canvas的方式去渲染,用到了DEVICE_PIXEL_RATIO,设备上的物理像素与设备无关像素 (dips) 之间的比率 (window.devicePixelRatio)。 直接复制下面的 vue+openlayer…

用ChatGPT创建一个REST API

ChatGPT是OpenAI公司开发的大型语言模型。在本文中&#xff0c;主要探讨如何使用ChatGPT在C#中创建REST API。 一、简介 ChatGPT是由人工智能研究中心OpenAI创建的尖端自然语言处理模型&#xff0c;OpenAI公司是由埃隆马斯克、萨姆奥特曼和格雷格布罗克曼共同创办的。该模型于…

360浏览器+Adobe Acrobat DC实现在线预览PDF大样校对

甲方&#xff1a;实现方正PDF文字大样校对&#xff0c;校对后在360浏览器中新开一个页面在线预览PDF文字大样校对结果。 我方实现过程&#xff1a; 1.方案选择 方案零&#xff1a;使用浏览器自带的PDF阅览器&#xff0c;经测试360极速模型,谷歌等软件能预览但是标记的PDF内容…

【笔记】大模型,大资料

大模型&#xff0c;大资料&#xff0c;loss会降低&#xff0c;准确率会增加 1大模型 1.1模型的顿悟时刻 举了一个一知半解的例子 1.2 模型 chain of thought 模型足够大时才会有比较好的作用 calibration 检测模型对于答案的confidence 会出现 “u-shape” 2.大资料 文法…

系统复杂度之【高可用】

接着&#xff0c;我们聊聊复杂度的第二个要求高可用。 参考维基百科&#xff0c;先来看看高可用的定义。 系统无中断地执行其功能的能力&#xff0c;代表系统的可用性程度&#xff0c;是进行系统设计时的准则之一。 这个定义的关键在于“ 无中断”&#xff0c;但恰好难点也在“…

Java 并发编程面试题——Future

目录1.什么是 Future 模式&#xff1f;Java 中是如何实现的&#xff1f;2.Callable、Future 与 FutureTask 分别是什么&#xff1f;2.1.Callable 接口2.2.Future 接口2.3.FutureTask 类3.CompletableFuture 类有什么用&#xff1f;1.什么是 Future 模式&#xff1f;Java 中是如…

windows系统管理_Windows server 2016 组管理与授权

组账户的概述 在 windows 服务器中&#xff0c;当我们需要为多个用户设置相同的权限时&#xff0c;一个一个的逐一设置会比较 麻烦&#xff0c;这个时候我们就需要用到另一种模式&#xff0c;组账户&#xff0c;使用此账户来进行简化操作。 在以后的职场中&#xff0c;每家公司…

Flink 优化 (五) --------- Job 优化

目录一、使用 DataGen 造数据1. DataStream 的 DataGenerator2. SQL 的 DataGenerator二、算子指定 UUID三、链路延迟测量四、开启对象重用五、细粒度滑动窗口优化一、使用 DataGen 造数据 开发完 Flink 作业&#xff0c;压测的方式很简单&#xff0c;先在 kafka 中积压数据&a…

全景图像畸变校正

1.简介 理想的相机基本上是小孔成像的&#xff0c;在小孔成像模型中&#xff0c;如果焦距一定&#xff0c;那么图像传感器像素平面的面积直接决定了相机视场角的大小&#xff0c;超过这个视场角范围的物体不会被镜头获取到。因此基于透镜成像原理的相机&#xff0c;视场角无法…

JAVA解析XML时的内存消耗问题

问题出现 最近一个项目中&#xff0c;有个需求功能是从外部传入的XML读取数据&#xff0c;然后写入到数据库中。 写完之后&#xff0c;有在本地电脑上的Tomcat跑了一下&#xff0c;正常读取到XML中的数据&#xff0c;并整理好后&#xff0c;插入了数据库保存了。但是线上运行的…

C语言文件操作复习回顾(2)

TIPS 文件的顺序读写&#xff1a;fgetc, fputc, fputs&#xff08;一行字符串的输出\n注意一下&#xff09;, fgets&#xff08;一行字符串的输入\n三特性&#xff09;&#xff0c;fprintf&#xff08;格式化字符串的输出联想printf很简单&#xff09;&#xff0c;fscanf&…

pyspark 实验二,rdd编程

1.环境准备 start-all.sh启动Hadoop ./bin start-all.sh 启动spark 上传数据集 1.求该系总共多少学生 linessc.textFile("file:///home/data.txt") res lines.map(lambda x:x.split(",")).map(lambda x:x[0]) sumres.distinct() sum.cont() 2.求该系设置…

【MybatisPlus快速入门】—— 进阶入门

进阶篇 1.1 映射专题 Mybatis 框架之所以能够简化数据库操作&#xff0c;是因为他内部的映射机制&#xff0c;通过自动映射&#xff0c;进行数据的封装&#xff0c;我们只要符合映射规则&#xff0c;就可以快速高效的完成SQL操作的实现既然 MybatisPlus 是基于Mybatis 的增强…

程序员如何能提高自己的编程水平?

这些实用的小建议&#xff0c;能帮你迅速地提高编程水平&#xff1a; 不要做无意义的奋斗 拒绝喊口号和无意义的奋斗&#xff0c;包括但不限于&#xff1a; ①做了计划表却从未有执行的一天&#xff1b; ②每天都是最早来、最晚走&#xff0c;但是工作进度趋近于0&#xff1b…

ASP.NET Core MVC 从入门到精通之接化发(一)

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

PathCore:IAD文献解读

论文链接&#xff1a;[Towards Total Recall in Industrial Anomaly Detection]Towards Total Recall in Industrial Anomaly Detection &#xff1a;数据集&#xff0c; &#xff1a;标签 : 在ImageNet上预训练后的网络 第 张图 网络中第 层 1. Locall…

Sentinel学习笔记

Sentinel 官方文档&#xff1a; https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 SpringCloud Alibaba&#xff1a; https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel 是什么…

丝滑的打包部署,一套带走~

以下文章来源于悟空聊架构 &#xff0c;作者悟空聊架构 本文主要内容如下&#xff1a; 目录 一、背景 Docker打包部署方案 项目背景&#xff1a;新项目的后端框架是刚起步&#xff0c;搭建的是一套微服务框架&#xff0c;基础服务有网关 Gateway&#xff0c; Nacos 注册中心…

为什么stm32gpio引脚的翻转速度最大只有18Mhz

(1). GPIO 引脚速度&#xff1a;GPIO_Speed_2MHz (10MHz, 50MHz) ; 又称输出驱动电路的响应速度&#xff1a;&#xff08;芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路&#xff0c;用户可以根据自己的需要选择合适的驱动电路&#xff0c;通过选择速度来选择…