第2章 图像变换
- **写得比较粗错,详解后续跟上。**
- 第2章 图像变换
- 2.1 反色变换
- 2.1.1 基本原理
- 2.1.2 源码
- 2.1.3 样例
- 2.2 线性变换
- 2.2.1 基本原理
- 2.2.2 源码
- 2.2.3 样例
- 加入滚动条
- 2.3 对数变换
- 2.3.1 基本原理
- 2.3.2 源码
- 2.3.3 样例
- 加入滚动条
- 2.4 gamma变换
- 2.4.1 基本原理
- 2.4.2 源码
- 2.4.3 样例
- 使用滑动条操作
- 2.5 分段线性变换
- 2.5.1 基本原理
- 2.5.2 源码
- 2.5.3 样例
写得比较粗错,详解后续跟上。
第2章 图像变换
图像变换主要通过调节像素数值,调节色彩明暗度,显示图像细节,方便人眼观察。图像变换的本质是调节像素分布。本节主要讲述常用的线性变换和非线性变换。
本节要点:
- 反色变换
- 线性变换
- 对数变换
- gamma变换
- 分段线性变换
2.1 反色变换
反色变换是一种非常简单实用的线性变换,适用于过暗或者过亮的图片,通过反色,使得暗色区域变得明亮,凸显图像中关注的部分。
2.1.1 基本原理
反色变换的基本原理将灰度图像素值翻转,即用图像最大值减去所有的像素值,使黑白色发生翻转。
2.1.2 源码
反色变换的步骤:
- 求取图像的最大值
- 最大值减去原像素值
# 2.1 反色变换,可以让暗色区域变亮,
def col_invert(img):
max_p = np.max(img)
table = [max_p-i for i in range(255)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img,table)
2.1.3 样例
在图像变换过程中先计算每个像素值变换后的数值,并存放在table变量中,然后用cv2.LUT()函数在table中查找像素变换后对应的数值,这样减少重复计算,加快运算速度。
import cv2
import numpy as np
import matplotlib.pyplot as plt
def col_invert(img):
max_p = np.max(img)
table = [max_p-i for i in range(255)] # 把像素变换后的值放入table中,方便cv2.LUT()查找。
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img,table) # cv2.LUT()是批量对像素进行查找和扫描,节省重复计算。
img = cv2.imread('f1.png',0)
img1 = col_invert(img)
plt.subplot(121)
plt.title('img')
plt.imshow(img,'gray')
plt.subplot(122)
plt.title('img1')
plt.imshow(img1,'gray')
plt.show()
2.2 线性变换
图像通过线性变换可以增加图片的对比度,调节图像的亮度。
2.2.1 基本原理
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,1,100)
y_05 = 0.5*x
y_1 = x
y_2 = 2*x
plt.plot(x,y_05,'-',label = '0.5')
plt.plot(x,y_1,'--',label = '1')
plt.plot(x,y_2,'-.',label = '2')
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('line_convert')
plt.scatter(0.2,0.4)
plt.scatter(0.4,0.8)
plt.scatter(0.2,0.1)
plt.scatter(0.4,0.2)
plt.text(0.2,0.45,'A1(0.2,0.4)')
plt.text(0.4,0.85,'A2(0.4,0.8)')
plt.text(0.2,0.15,'B1(0.2,0.1)')
plt.text(0.4,0.25,'B2(0.4,0.2)')
img1 = c*img+b
c:调节像素映射后的区间,c大于1,变换后的区间就越大,数据越离散;反之,c小于1,像素变换后就越聚集,颜色对比度就越小。
b:决定像素直方图的中心位置,b值越大,图像就越亮,反之,越暗。
2.2.2 源码
def line_convert(img,c,b):
table = [c * i+b for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
2.2.3 样例
import cv2
import numpy as np
import matplotlib.pyplot as plt
def line_convert(img,c,b):
table = [c * i+b for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
img = cv2.imread('f4.png',1)
img1 = line_convert(img,3,1)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()
加入滚动条
import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image # pip install pillow
def set_chinese():
import matplotlib as mp
mp.rcParams['font.sans-serif']=['SimHei']
mp.rcParams['axes.unicode_minus'] = False
def line_convert(img,c,b):
table = [c * i+b for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
def update_para(val):
c = slider_1.val
b = slider_2.val # 得到滑动条数值
img1 = line_convert(img,c,b)
ax2.set_title('c=%f,c=%f'%(c,b))
ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)
if __name__ == '__main__':
set_chinese()
img = cv2.imread('f4.png',1) # base = 86
fig = plt.figure()
ax0 = fig.add_subplot(121)
ax0.set_title('原图')
ax0.imshow(img[...,::-1],vmin=0,vmax=255)
ax2 = fig.add_subplot(122) # 设置第二幅图
# 添加滑动条
plt.subplots_adjust(bottom=0.3) # [0.25,0.1,0.45,0.03]
s1 = plt.axes([0.25,0.1,0.55,0.03],facecolor='lightgoldenrodyellow')
slider_1 = Slider(s1,'c',0.,10.,valfmt='%.f',valinit=5.0,valstep=0.5) # 0.0,2.0 是参数取值范围
# 把监控到的gamma变换传入update_gamma函数中去
slider_1.on_changed(update_para)
s2 = plt.axes([0.25, 0.16, 0.55, 0.03], facecolor='lightgoldenrodyellow')
slider_2 = Slider(s2, 'b', 0., 255., valfmt='%.f', valinit=0, valstep=1)
slider_2.on_changed(update_para)
slider_1.reset()
slider_1.set_val(1)
slider_2.reset()
slider_2.set_val(1)
2.3 对数变换
对图像进行对数变换,可以压缩图像像素的取值范围,使得图像以肉眼可分辨的灰度值显示出来,即图像经过对数变换可以显示更多的细节。
def log(base,x):
return np.log(1+base*x)/np.log(base+1)
x = np.linspace(0,1,100)
y = 1*x
y_1 = log(1,x)
y_10 = log(10,x)
y_30 = log(30,x)
y_100 = log(100,x)
y_300 = log(300,x)
plt.plot(x,y,label = 'origin')
plt.plot(x,y_1,label = 'b=1')
plt.plot(x,y_10,label = 'b=10')
plt.plot(x,y_30,label = 'b=30')
plt.plot(x,y_100,label = 'b=100')
plt.plot(x,y_300,label = 'b=300')
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('log_line')
plt.xlabel('input intensity level')
plt.ylabel('output intensity level')
plt.text(0.35,0.350,'origin')
plt.text(0.32,0.43,'b=1')
plt.text(0.23,0.52,'b=10')
plt.text(0.2,0.6,'b=30')
plt.text(0.18,0.66,'b=100')
plt.text(0.16,0.75,'b=300')
plt.show()
2.3.1 基本原理
img1 = c*log_{base+1}(1+base*img/255)*255
2.3.2 源码
import cv2
import numpy as np
import matplotlib.pyplot as plt
def log(base,x):
return np.log(x)/np.log(base+1)
def log_convert(img,base,c):
table = [c*log(base,(1+i)/255)*255 for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img,table)
2.3.3 样例
import cv2
import numpy as np
import matplotlib.pyplot as plt
def log(base,x):
return np.log(x)/np.log(base+1)
def log_convert(img,base,c):
table = [c*log(base,1+(base)*i/255)*255 for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img,table)
img = cv2.imread('yejing.png',1)
img1 = log_convert(img,80,0.9)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()
加入滚动条
import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image # pip install pillow
def set_chinese():
import matplotlib as mp
mp.rcParams['font.sans-serif']=['SimHei']
mp.rcParams['axes.unicode_minus'] = False
def log(base, x):
return np.log(x) / np.log(base + 1)
def log_convert(img, base, c=1):
table = [c * log(base, 1 + (base) * i / 255) * 255 for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
def update_gamma(val):
base = slider1.val # 得到滑动条数值
img1 = log_convert(img, base, c=1)
ax2.set_title('base=%f'%(base))
ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)
if __name__ == '__main__':
set_chinese()
img = cv2.imread('2.png',1)
fig = plt.figure()
ax0 = fig.add_subplot(121)
ax0.set_title('原图')
ax0.imshow(img[...,::-1],vmin=0,vmax=255)
ax2 = fig.add_subplot(122) # 设置第二幅图
# 添加滑动条
plt.subplots_adjust(bottom=0.3) # [0.25,0.1,0.45,0.03]
s1 = plt.axes([0.25,0.1,0.45,0.03],facecolor='lightgoldenrodyellow')
slider1 = Slider(s1,'base',0.,200.,valfmt='%.f',valinit=50.0,valstep=2) # 0.0,2.0 是参数取值范围
# 把监控到的gamma变换传入update_gamma函数中去
slider1.on_changed(update_gamma)
slider1.reset()
slider1.set_val(1)
2.4 gamma变换
def gamma_line(x,r):
return x**r
x = np.linspace(0,1,100)
y = gamma_line(x,1)
y_1 = gamma_line(x,2.5)
y_2 = gamma_line(x,0.4)
plt.plot(x,y,'-',label = 'r=1')
plt.plot(x,y_1,'--',label = 'r=2.5')
plt.plot(x,y_2,'-.',label = 'r=0.4')
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('gamma_line')
plt.xlabel('input intensity level')
plt.ylabel('output intensity level')
plt.show()
2.4.1 基本原理
步骤:
· 归一化
·
·
·
img1 = c*(\frac{img+\epsilon}{255} )^\gamma*255+r
2.4.2 源码
def gamma_convert(img,c,r):
table = [c * ((i+0.1)/255)**r * 255 for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
2.4.3 样例
import cv2
import numpy as np
import matplotlib.pyplot as plt
def gamma_convert(img,c,r):
table = [c * ((i+0.1)/255)**r * 255 for i in range(256)]
table = np.round(np.array(table)).astype(np.uint8)
return cv2.LUT(img, table)
img = cv2.imread('beijing2.png',1)
img1 = gamma_convert(img,1,0.5)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()
使用滑动条操作
import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image # pip install pillow
def set_chinese():
import matplotlib as mp
mp.rcParams['font.sans-serif']=['SimHei']
mp.rcParams['axes.unicode_minus'] = False
def gamma_convert(img,gamma,eps=0):
return (255*(((img+eps)/255.)**gamma)).astype(np.uint8)
def update_gamma(val):
gamma = slider1.val # 得到滑动条数值
img1 = gamma_convert(img, gamma, eps=0)
ax2.set_title('gamma=%f'%(gamma))
ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)
if __name__ == '__main__':
set_chinese()
img = cv2.imread('luna_baoguang.png',1)
fig = plt.figure()
ax0 = fig.add_subplot(121)
ax0.set_title('露娜')
ax0.imshow(img[...,::-1],vmin=0,vmax=255)
ax2 = fig.add_subplot(122) # 设置第二幅图
# 添加滑动条
plt.subplots_adjust(bottom=0.3)
s1 = plt.axes([0.25,0.1,0.55,0.03],facecolor='lightgoldenrodyellow')
slider1 = Slider(s1,'para :gamma',0.0,10.0,valfmt='%.f',valinit=5.0,valstep=0.1) # 0.0,2.0 是参数取值范围
# 把监控到的gamma变换传入update_gamma函数中去
slider1.on_changed(update_gamma)
slider1.reset()
slider1.set_val(1)
2.5 分段线性变换
2.5.1 基本原理
2.5.2 源码
def three_line_convert(img,x1,y1,x2,y2):
if x1==x2 or x2 == 255:
return None
m1 = (img<x1)
m2 = (x1<=img)&(img<=x2)
m3 = (img>x2)
img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
img1 = img1.astype(np.uint8)
return img1
2.5.3 样例
import cv2
import numpy as np
import matplotlib.pyplot as plt
def three_line_convert(img,x1,y1,x2,y2):
if x1==x2 or x2 == 255:
return None
m1 = (img<x1)
m2 = (x1<=img)&(img<=x2)
m3 = (img>x2)
img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
img1 = img1.astype(np.uint8)
return img1
img = cv2.imread('fen3.png',1)
img1 = three_line_convert(img,36,76,178,228)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
加入滚动条
import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
def three_line_convert(img,x1,y1,x2,y2):
if x1==x2 or x2 == 255:
return None
m1 = (img<x1)
m2 = (x1<=img)&(img<=x2)
m3 = (img>x2)
img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
# 绘制函数图像
x_point = np.arange(0,256,1)
cond2 = [True if(i>=x1 and i<=x2) else False for i in x_point]
y_point = (y1/x1*x_point)*(x_point<x1)+ \
((y2-y1)/(x2-x1)*(x_point-x1)+y1)*cond2+ \
((255-y2)/(255-x2)*(x_point-x2)+y2)*(x_point>x2)
return img1,x_point,y_point
def update_trans(val):
# 1 读入滑动条的值
x1,y1 = slider_x1.val,slider_y1.val
x2, y2 = slider_x2.val, slider_y2.val
# 2 执行分段线性变换
img1,x_point,y_point = three_line_convert(img,x1,y1,x2,y2)
img1 = img1.astype(np.uint8)
# 3 显示变换结果
ax2.clear()
ax2.set_title('result',fontsize=8)
ax2.imshow(img1[...,::-1],vmin=0,vmax=255)
# 4 绘制函数
ax3.clear()
ax3.annotate('(%d,%d)'%(x1,y1),xy=(x1,y1),xytext=(x1-15, y1+15))
ax3.annotate('(%d,%d)'%(x2,y2), xy=(x2,y2), xytext=(x2+15, y2-15))
ax3.set_title('fun', fontsize=8)
ax3.grid(True,linestyle=':',linewidth=1)
ax3.plot([x1,x2],[y1,y2],'ro')
ax3.plot(x_point, y_point, 'g')
# 显示变换后的直方图
ax5.clear()
ax5.grid(True,linestyle=':',linewidth=1)
ax5.set_title('hist',fontsize=8)
ax5.set_xlim(0,255)
ax5.set_ylim(0, 0.06)
ax5.hist(img1[...,::-1].flatten(),bins=50,density=True,color='r',edgecolor='k')
img = cv2.imread('hua.png',1) # [x1,y1,x2,y2] [36,76,178,228]
fig = plt.figure()
ax1 = fig.add_subplot(231)
ax2 = fig.add_subplot(232)
ax3 = fig.add_subplot(233)
ax4 = fig.add_subplot(234)
ax5 = fig.add_subplot(235)
ax1.set_title('origin',fontsize=8)
ax1.imshow(img[...,::-1],vmin=0,vmax=255)
ax4.grid(True,linestyle=':',linewidth=1)
ax4.set_title('origin indensity',fontsize=8)
ax4.set_xlim(0,255)
ax4.set_ylim(0,0.06)
ax4.hist(img[...,0].flatten(),bins=50,density=True,color='r',edgecolor='k')
plt.subplots_adjust(bottom=0.3)
x1 = plt.axes([0.25,0.20,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_x1 = Slider(x1,'Para_x1',0.,255.,valfmt='%.f',valinit=100,valstep=1)
slider_x1.on_changed(update_trans)
y1 = plt.axes([0.25,0.15,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_y1 = Slider(y1,'Para_y1',0.,255.,valfmt='%.f',valinit=0,valstep=1)
slider_y1.on_changed(update_trans)
x2 = plt.axes([0.25,0.1,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_x2 = Slider(x2,'Para_x2',0.,255.,valfmt='%.f',valinit=100,valstep=1)
slider_x2.on_changed(update_trans)
y2 = plt.axes([0.25,0.05,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_y2 = Slider(y2,'Para_y2',0.,255.,valfmt='%.f',valinit=0,valstep=1)
slider_y2.on_changed(update_trans)