整体线性变换
首先导入所需的程序包:
In [ ]:
import cv2
import numpy as np
import matplotlib.pyplot as plt
定义绘制直方图的函数:
In [ ]:
def grayHist(img):
h, w = img.shape[:2]
pixelSequence = img.reshape([h * w, ])
numberBins = 256
histogram, bins, patch = plt.hist(pixelSequence, numberBins,
facecolor='black', histtype='bar')
plt.xlabel("gray label")
plt.ylabel("number of pixels")
plt.axis([0, 255, 0, np.max(histogram)])
plt.show()
读取原始图像,绘制处理前的直方图:
In [ ]:
img = cv2.imread('./street.jpg', 0)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img2)
plt.show()
grayHist = calcGrayHist(img)
x = np.arange(256)
plt.plot(x, grayHist, 'r', linewidth=2, c='black')
plt.xlabel("gray Label")
plt.ylabel("number of pixels")
plt.show()
进行线性变换,将所有像素点提亮至原来的2倍,并对超过255的像素截断为255:
In [ ]:
out = 2.0 * img
out[out > 255] = 255
# 数据类型转换
out = np.around(out)
out = out.astype(np.uint8)
查看线性变换后的图像,并绘制处理后的直方图:
In [ ]:
out2 = cv2.cvtColor(out, cv2.COLOR_BGR2RGB)
plt.imshow(out2)
plt.show()
def calcGrayHist(I):
# 计算灰度直方图
h, w = I.shape[:2]
grayHist = np.zeros([256], np.uint64)
for i in range(h):
for j in range(w):
grayHist[I[i][j]] += 1
return grayHist
grayHist = calcGrayHist(out)
x = np.arange(0, 256, 2)
y = [grayHist[i] for i in range(len(grayHist)) if i % 2 == 0]
plt.plot(x, y, 'r', linewidth=2, c='black')
plt.xlabel("gray Label")
plt.ylabel("number of pixels")
plt.show()
以上线性变换是对整个灰度级范围使用了相同的参数,有的时候也需要针对不同灰度级范围进行不同的线性变换,这就是常用的分段线性变换,经常用于降低较亮或较暗区域的对比度来增强灰度级处于中间范围的对比度,或者压低中间灰度级处的对比度来增强较亮或者较暗区域的对比度。
分段线性变换
我们再来看一下未处理的图像的直方图:
In [ ]:
img = cv2.imread('./street.jpg', 0)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
grayHist = calcGrayHist(img)
x = np.arange(256)
plt.plot(x, grayHist, 'r', linewidth=2, c='black')
plt.xlabel("gray Label")
plt.ylabel("number of pixels")
plt.show()
可以看到,图像的灰度主要集中在[0, 50]之间,可以通过一下分段线性变换将主要的灰度级拉伸到[50, 150],对比度拉伸之后应该能比原图看到更多的细节。
In [ ]:
h, w = img.shape[:2]
out = np.zeros(img.shape, np.uint8)
for i in range(h):
for j in range(w):
pix = img[i][j]
if pix < 20:
out[i][j] = min(255, 3.5 * pix)
elif pix < 50:
out[i][j] = min(255, 3 * pix)
elif pix < 150:
out[i][j] = min(255, 2 * pix)
else:
out[i][j] = pix
# 数据类型转换
out = np.around(out)
out = out.astype(np.uint8)
out2 = cv2.cvtColor(out, cv2.COLOR_BGR2RGB)
plt.imshow(out2)
plt.show()
线性变换的参数需要根据不同的应用及图像自身的信息进行合理的选择,可能需要进行多次测试。