1 - 引言
图像处理分为空间域和变换域(在图像的傅里叶变换上进行处理),空间域是指图像平面本身,主要是直接以图像中的像素操作为基础进行图像处理,空间域的处理主要分为灰度变换和空间滤波两类,本文主要介绍灰度变换和空间滤波在图像增强方面的应用,使得输出的图像比原始图像更适合特定需求的一种处理。
下面我们来介绍一下经典的灰度变换和空间滤波技术。
2 - 一些基本的灰度变换函数
灰度变换是所有图像处理技术中最简单的技术。r和s 分别代表处理前后的像素值。
2.1 - 图像反转
使用这种方式反转一副图像的灰度级,可得到等效的照片底片,这种类型的处理特别使用于增强嵌入在一副图像的暗区域中的白色和灰色细节,特别是当黑色面积在尺寸上占主导地位时。
import numpy as np
import cv2 as cv
image = cv.imread('images/timg.jpg')
cv.imshow("imshow_", image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
"""255-原本的颜色就变成了反色"""
image[row, col, cn] = 255 - pv
cv.imshow("imshow_inverse", image)
cv.waitKey(0)
2.2 - 对数变换
对数变换的通用形式为
我们使用这种类型的变换来扩展图像中的暗像素值,同时压缩更高灰度级的值(反对数变换相反)。
主要有两个作用
-
因为对数曲线在像素值较低的区域斜率较大,像素值较高的区域斜率比较低,所以图像经过对数变换之后,在较暗的区域对比度将得到提升,因而能增强图像暗部的细节。
-
图像的傅里叶频谱其动态范围可能宽达 。直接显示频谱的话显示设备的动态范围往往不能满足要求,这个时候就需要使用对数变换,使得傅里叶频谱的动态范围被合理地非线性压缩。
import numpy as np
import cv2 as cv
image = cv.imread('images/16.jpg')
cv.imshow("imshow_", image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
"""使用对数变换可以显示图像黑暗中的细节"""
image[row, col, cn]= 32*np.log10(1+pv)
cv.imshow("image_log", image)
cv.waitKey(0)
可以看到图像中隐藏在黑暗中的细节被展示了出来
2.3 - 幂律(伽马)变换
幂律变换的基本形式为:
与对数变换的情况类似,部分
值的幂律曲线将较窄范围的暗色输入映射为较宽范围的输出值,相反地,对于输入高灰度级值也成立。然而,与对数函数不同的是,我们注意到,随着
值的变化,将简单的得到一族可能的变换曲线。
例 1 使用幂律变换进行对比度增强
当图像整体偏暗的时候,需要扩展活度计,可以使用指数为分数的幂律来变换完成。
import numpy as np
import cv2 as cv
image = cv.imread('images/gamma.jpg')
cv.imshow("imshow_", image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
"""使用幂律可以显示图像黑暗中的细节"""
image[row, col, cn] = 5*np.power(pv,0.6)
cv.imshow("image_gamma", image)
cv.waitKey(0)
例 2 矫正曝光度过高的图片
当伽马值取大于1的时候,可以压缩灰度级。
import numpy as np
import cv2 as cv
image = cv.imread('images/gamma+2.jpg')
cv.imshow("imshow_", image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
"""先使用归一化,再使用幂律可以显示图像黑暗中的细节"""
image[row, col, cn] = np.power(pv/255,4)*255
cv.imshow("image_gamma", image)
cv.waitKey(0)
2.4 - 分段线性变换函数
通过分段线性函数我们可以将我们感兴趣的灰度值突显出来
2.4.1 - 对比度拉伸
通过分段函数来输出不同程度的灰度级扩展,从而来影响输出图像的对比度。
其变换公式为:
我们假设函数为:
g(x,y) = a*f(x,y)+b
- f(x,y)代表源图像x行,y列的像素点的c通道的数值 g(x,y)代表目
- 标图像x行,y列的像素点的c通道的数值
- a参数(a>0)表示放大的倍数(一般在0.0~3.0之间)
- b参数一般称为偏置,用来调节亮度
import numpy as np
import cv2 as cv
a = 3
b = 10
image = cv.imread('images/test_1.jpg')
cv.imshow("imshow_", image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
"""先使用归一化,再使用幂律可以显示图像黑暗中的细节"""
image[row, col, cn] = (pv/255*a+b)*255
cv.imshow("image_gamma", image)
cv.waitKey(0)
2.4.2 - 灰度级分层
突出图像中特定灰度范围的亮度通常是重要的,其应用包括增强特征。
例如一副靠近肾脏区域的大动脉血管造影照片,我们关注的是血管部分,我们使用灰度级分层来突出主要血管,使其更亮一些。
import numpy as np
import cv2 as cv
a = 3
b = 10
image = cv.imread('images/test_2.jpg')
cv.imshow("image",image)
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
if pv > 120:
pv = 255
image[row, col, cn] = pv
else:
pv = 30
image[row, col, cn] = pv
cv.imshow("image_gamma", image)
cv.waitKey(0)
2.4.3 - 比特平面分层
(0~2)对应第1比特层,
(2~4)对应第2比特层,
(4~8)对应第3比特层,
(8~16)对应第4比特层,
(16~32)对应第5比特层,
(32~64)对应第6比特层,
(64~128)对应第7比特层,
(128~256)对应第8比特层。
若图像存在对应比特层的灰度值,像素值赋值为255(白),不在该范围内,赋值
import numpy as np
import cv2 as cv
a = 3
b = 10
image = cv.imread('images/lena.jpg')
shape = image.shape
height = shape[0]
width = shape[1]
channels = shape[2]
for row in range(height):
for col in range(width):
for cn in range(channels):
"""获取image单个像素点的某个通道,顺序是BGR"""
pv = image[row, col, cn]
#分离比特层,从0~8层
if pv > np.power(2,7) and pv < np.power(2,8):
pv = 255
image[row, col, cn] = pv
else:
pv = 0
image[row, col, cn] = pv
cv.imshow("image_gamma", image)
cv.waitKey(0)
原始图像:
第1至4层:
第4至8层: