文章目录

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

图像灰度变化

灰度变换介绍

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

Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理


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

灰度变换是将输入图像中的每个像素Python opencv 灰度处理 opencv灰度线性变换_灰度_02通过映射函数Python opencv 灰度处理 opencv灰度线性变换_opencv_03变换成输出图像中的灰度值Python opencv 灰度处理 opencv灰度线性变换_灰度_04
Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_05

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

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

灰度线性变换

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

设原图像灰度取值Python opencv 灰度处理 opencv灰度线性变换_opencv_06,线性变换后的图像灰度取值Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_07 则灰度线性变换为:
Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_08

Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_09


式子中,Python opencv 灰度处理 opencv灰度线性变换_opencv_10为线性变换函数(直线)的斜率。

  • 扩展动态范围,Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_11
  • 缩小动态范围,Python opencv 灰度处理 opencv灰度线性变换_python_12

灰度线性变化示例:

Python opencv 灰度处理 opencv灰度线性变换_灰度_13

Python opencv 灰度处理 opencv灰度线性变换_opencv_14的时候,就变为加常数线性变换Python opencv 灰度处理 opencv灰度线性变换_python_15,可以压缩动态范围,降低对比度。

Python opencv 灰度处理 opencv灰度线性变换_灰度_16

加常数线性变换实例:

Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_17

灰度分段线性变换

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

在实际应用中:

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

举例:

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

Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_18


灰度分段线性变换实例:

Python opencv 灰度处理 opencv灰度线性变换_python_19

图像点运算

定义:

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

设输入图像和输出图像在Python opencv 灰度处理 opencv灰度线性变换_灰度_20处的灰度值分别是 Python opencv 灰度处理 opencv灰度线性变换_python_21Python opencv 灰度处理 opencv灰度线性变换_python_22,则点运算可表示为 Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_23,Python opencv 灰度处理 opencv灰度线性变换_opencv_03

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

图像的点运算包括:

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

灰度非线性变换

非线性变换定义:

  • 对于Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_25,如果Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_26是非线性变换函数,那么该变换为非线性变换。
  • 常用的非线性变换有对数变换、幂次变换(伽马变换)等。

线性点运算

输出输入的灰度值成线性函数关系:Python opencv 灰度处理 opencv灰度线性变换_opencv_27

  • Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_28 控制对比度(不同级别灰度的明暗差异):
  • a > 1,对比度变大;
  • a < 1,对比度变小。
  • a 为负值,实现负片效果
  • Python opencv 灰度处理 opencv灰度线性变换_python_29 控制输出图像的整体亮度:
  • 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()

Python opencv 灰度处理 opencv灰度线性变换_灰度_30


灰度的线性变换不利于突出感兴趣区域,且容易出现饱和、截止等情况。

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

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

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

对数变换的一般表达式为:
Python opencv 灰度处理 opencv灰度线性变换_opencv_31

式中,Python opencv 灰度处理 opencv灰度线性变换_灰度_32为尺度比例系数,用来调节变换后的灰度值的动态范围,使其更符合实际需要。对数变换可以扩展图像的低灰度值范围,同时压缩高灰度值范围,使图像灰度值分布均匀,更加匹配人的视觉特性,示例图如下图所示。

Python opencv 灰度处理 opencv灰度线性变换_opencv_33

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

Python opencv 灰度处理 opencv灰度线性变换_灰度_34

附:

灰度对数变换(可增强暗部细节): Python opencv 灰度处理 opencv灰度线性变换_灰度_35
灰度反对数变换(可增强亮部细节): Python opencv 灰度处理 opencv灰度线性变换_灰度_36

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

伽玛变换又称为 指数变换 或 幂次变换,是另一种常用的灰度非线性变换。
网上大多数给的指数函数的基本形式为:Python opencv 灰度处理 opencv灰度线性变换_灰度_37
实际使用公式:Python opencv 灰度处理 opencv灰度线性变换_灰度_38

Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_39 为补偿系数(一般为0),Python opencv 灰度处理 opencv灰度线性变换_python_40 为伽马系数
Python opencv 灰度处理 opencv灰度线性变换_opencv_41 时,低亮度区域对比度增强
Python opencv 灰度处理 opencv灰度线性变换_灰度_42 时, 高亮度区域对比度增强
Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_43时,该灰度变换是线性的,此时通过线性方式改变原图像。

这里给出更加详细的一般表达式:Python opencv 灰度处理 opencv灰度线性变换_opencv_44

式中,参数Python opencv 灰度处理 opencv灰度线性变换_灰度_32为常数,可以改变指数变换曲线的变换速率。参数Python opencv 灰度处理 opencv灰度线性变换_灰度_46为常数,可以改变指数变换曲线的起始位置。参数Python opencv 灰度处理 opencv灰度线性变换_opencv_47也为常数,其取值对变换函数的特性有很大的影响。
指数变换函数曲线如下图所示。

  • 图(a)表示Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_48时的指数变换函数曲线。当Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_48时,指数变换的作用与对数变换类似,输入的高灰度范围被压缩,低灰度范围被拉伸,实现了强化暗部压缩亮部的图像增强效果。
  • 图(b)表示Python opencv 灰度处理 opencv灰度线性变换_灰度_50时的指数变换函数曲线。当Python opencv 灰度处理 opencv灰度线性变换_灰度_50时,输入的低灰度范围被压缩,高灰度范围被拉伸,实现了强化亮部压缩暗部的图像增强效果。

不同Python opencv 灰度处理 opencv灰度线性变换_灰度_52值的变换曲线如下图所示:

Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_53


指数变换拉大了不同点的灰度值距离,提高了图像的对比度。对图像采用不同Python opencv 灰度处理 opencv灰度线性变换_opencv_47值的指

数变换结果如下图所示。其中,图(a)是原图像,图(b)是Python opencv 灰度处理 opencv灰度线性变换_灰度_55时的指数变换的结果,

图©是Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_56时的指数变换的结果。

Python opencv 灰度处理 opencv灰度线性变换_python_57

附代码实现:

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

    return s

Python opencv 灰度处理 opencv灰度线性变换_计算机视觉_58


分段线性变换和伽马变换例子:

#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()

Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_59


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

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

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

Python opencv 灰度处理 opencv灰度线性变换_灰度_60

# 非线性变化:对比拉伸
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

Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_61

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

S 形灰度变换曲线,降低较亮和较暗部分的对比度,加强中间灰度级物体对比度: Python opencv 灰度处理 opencv灰度线性变换_python_62 S 形灰度变换曲线,加强较亮和较暗部分的对比度,降低灰度级中间物体对比度: Python opencv 灰度处理 opencv灰度线性变换_灰度_63

Python opencv 灰度处理 opencv灰度线性变换_opencv_64

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

阈值变换可以将灰度图像转换成黑白二值图像,用户指定一阈值T,灰度低于T置0,高于T置255。 Python opencv 灰度处理 opencv灰度线性变换_Python opencv 灰度处理_65

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

    return r

Python opencv 灰度处理 opencv灰度线性变换_python_66

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

灰度切割(灰度分层):突出感兴趣灰度范围

Python opencv 灰度处理 opencv灰度线性变换_灰度_67