反色变换
推荐B站UP,十四阿哥很nice
几节图像处理课讲的很清楚。
用于增强暗背景下的图像,使人眼能够观看到更多细节。
假设原始图像的灰度范围是[0,L],L表示该图像最大的灰度值,则反色变换为output = L - input
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 1,反色变换
# 假设原始图像的灰度范围是[0,L],L表示该图像最大的灰度值
# 则反色变换为output = L - input
def image_inverse(input):
value_max = np.max(input)
output = value_max - input
return output
gray_img = np.asarray(Image.open('X.jpg').convert('L'))
inv_img = image_inverse(gray_img)
plt.subplot(121)
plt.title('original')
plt.imshow(gray_img, cmap='gray', vmin=0, vmax=255)
plt.subplot(122)
plt.title('inverse')
plt.imshow(inv_img, cmap='gray', vmin=0, vmax=255)
plt.show()
对数变换
对数变换,目的是压缩图像矩阵值域的动态范围,让我们可以看到更多细节
假设原始图像灰度取值范围是[x1,x2], (x1>=x2>=0)
则对数变换为 output = log(1 + input)
log输入为0时输出为负无穷,+1就是为了避免此情况(或者理解为偏置)
imshow绘图时,若不指定vmin,vmax,默认输入最小值为vmin对应0,vmax对应255
def set_Chinese():
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
def image_log(input):
return np.log(1 + input)
set_Chinese() # 解决中文乱码问题
input = np.array([[10, 150],
[250, 25500]])
output = image_log(input)
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.set_title('对数变换前', fontsize=12)
ax1.imshow(input, cmap='gray', vmin=0, vmax=25500)
ax2 = fig.add_subplot(122)
ax2.set_title('对数变换后', fontsize=12)
ax2.imshow(output, cmap='gray')
plt.show()
伽马变换
又称幂律变换,因为使用幂函数来操作输入图像,表达式
- gamma次幂称为伽马系数,在伽马变换中规定这个数必须为正数
- eps 称为补偿系数,默认0(如果没有eps,当input中有为0时,对该像素的伽马变换就失效了,0的任意次幂都为0)
但幂运算又导致图像输出动态范围过大,引入归一化(8bit像素):
def gamma_trans(input, gamma=2, eps=0):
return 255.*(((input + eps) / 255.) ** gamma)
def update_gamma(val):
gamma = slider1.val
output = gamma_trans(input_arr, gamma=gamma, eps=0.5)
print('------------\n', output)
ax1.set_title('伽马变换后,gamma = ' + str(gamma))
ax1.imshow(output, cmap='gray', vmin=0, vmax=255)
set_Chinese()
input_arr = np.array([[0, 50, 100, 150],
[0, 50, 100, 150],
[0, 50, 100, 150],
[0, 50, 100, 150]])
fig = plt.figure()
ax0 = fig.add_subplot(121)
ax0.set_title('输入矩阵')
ax0.imshow(input_arr, cmap='gray', vmin=0, vmax=255)
ax1 = fig.add_subplot(122)
plt.subplots_adjust(bottom=0.3) # 划分一块滑动条,从底部向上30%
# 设置属性和颜色
s1 = plt.axes([0.25, 0.1, 0.55, 0.03], facecolor='lightgoldenrodyellow')
# 创建滑动条,范围0-2,初始为1,步长0.1
slider1 = Slider(s1, '参数gamma', 0.0, 2.0, valfmt='%.f', valinit=1.0, valstep=0.1)
slider1.on_changed(update_gamma)
plt.show()
肉眼观测的话gamma(>1)越大图像越黑,gamma(<1)越小图像越亮。
应用:
- 矫正显示失真
CRT显示器的物理特性导致送入显示器的灰度值并非线性输出,而是以幂函数的形式非线性输出。不同厂家的幂不一样,一般介于1.8-2.5所以我们先对输入做伽马变换,gamma = 1 /(厂家的幂)处理,保证线性输出。
'''
【功能】利用γ变换提前矫正图像,从而实现图像在CRT显示器中正常显示
【B站/YouTube】轩辕十四很nice
【开源协议】The MIT License (MIT)
'''
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
def set_chinese(): # 中文显示工具函数
import matplotlib
print("[INFO] matplotlib版本为:%s" % matplotlib.__version__)
matplotlib.rcParams['font.sans-serif'] = ['FangSong']
matplotlib.rcParams['axes.unicode_minus'] = False
def gamma_trans(input, gamma=2, eps=0 ):
return 255. * (((input + eps)/255.) ** gamma)
def crt_distortion(input, gamma=2): # 模拟CRT失真(做了归一化)
return 255. * ((input/255.) ** gamma)
def update_gamma(val):
gamma = slider1.val # 获取"失真γ"
# 图像送入CRT前,先做伽马变换预处理
gamma_ = 1 / gamma # "矫正γ" 为 "失真γ" 的倒数
correct_img = gamma_trans(gray_img, gamma_, 0) #
ax1.set_title("伽马矫正,矫正γ = 1/" + str(round(gamma,2)))
ax1.imshow(correct_img, cmap='gray',vmin=0,vmax=255)
# 简易模拟CRT输出
output = crt_distortion(correct_img, gamma)
print(output)
ax2.set_title("模拟CRT输出,失真γ = " + str(round(gamma,2)))
ax2.imshow(output, cmap='gray',vmin=0,vmax=255)
if __name__ == '__main__':
set_chinese()
gray_img = np.asarray(Image.open('./intensity_ramp.tif').convert('L'))
fig = plt.figure()
ax0 = fig.add_subplot(131)
ax1 = fig.add_subplot(132)
ax2 = fig.add_subplot(133)
ax0.set_title("原始图片")
ax0.imshow(gray_img, cmap='gray',vmin=0,vmax=255)
plt.subplots_adjust(bottom=0.3)
s1 = plt.axes([0.25, 0.1, 0.55, 0.03], facecolor='lightgoldenrodyellow')
slider1 = Slider(s1, 'CRT失真γ: ', 0.0, 4.0,
valfmt='%.f', valinit=1.0, valstep=0.1)
slider1.on_changed(update_gamma)
slider1.reset()
slider1.set_val(2)
plt.show()
数学原理:
伽马变换可以调节图片对比度,进而体现更多细节。
- gamma < 1,提亮图像,扩展暗部的动态范围,压缩亮部的动态范围
- gamma > 1,变暗图像,压缩暗部动态范围,扩展亮部动态范围
伽马变换:通过幂函数扩展后的动态范围没有变,只是改变了直方图的数据分布。
但伽马变换的曲线总是存在斜率约等于1的部分,如果图片的像素分布落在斜率等于1的区间,伽马变换的效果就比较微弱了。
所以引入分段线性变换
分段线性变换
顾名思义,是个分段函数,分多少段也看需求。假设分成三段。