数字图像的基本运算

直方图

直方图简单来说就是图像中每个像素值的个数统计,比如说一副灰度图中像素值为 0 的有多少个,1 的多少个……。直方图是一种分析图片的手段。

Numpy 中直方图计算

其中 ravel() 函数将二维矩阵展平变成一维数组:

from matplotlib import pyplot as plt
import cv2
import numpy as np


def getI(fname, show=False):
    img = plt.imread(fname)
    if show:
        plt.imshow(img)
        plt.show()
    return img


fname = r'E:\Data\URLimg\猫\波斯猫\16.jpg'

img = getI(fname, show=True)
%%time
hist, bins = np.histogram(img[:,:,0].ravel(), 256, [0, 256])  # 性能:26.5 ms
Wall time: 28.5 ms
%%time
hist = np.bincount(img[:,:,0].ravel(), minlength=256)  # 性能:13 ms
Wall time: 10 ms

画出直方图

fig, ax = plt.subplots(1, 2, figsize=(12, 5))
colors = ['red', 'green', 'blue']


for i in range(3):
    hist, x = np.histogram(img[:, :, i].ravel(), bins=256, range=(0, 256)) # bins 指定统计区间被等分的个数
    ax[0].plot(.5 * (x[:-1] + x[1:]), hist, label=colors[i], color=colors[i])
    
ax[0].legend(loc='upper left')
ax[0].set_xlim(0, 256)
hist2, x2, y2 = np.histogram2d(img[:,:,0].ravel(), img[:,:,2].ravel(), bins=(100, 100), range=[(0,256), (0,256)])
ax[1].imshow(hist2, extent=(0, 256, 0, 256), origin='lower', cmap='gray')
ax[1].set_ylabel('red')
ax[1].set_xlabel('blue')
plt.show()
数字图像的基本运算_第1张图片
output_5_0.png

其实 Matplotlib 自带了一个计算并绘制直方图的功能,不需要用到上面的函数:

plt.hist(img[:,:,0].ravel(), 256, [0, 256])
plt.show()
数字图像的基本运算_第2张图片
output_7_0.png

OpenCV 中直方图计算

cv2.calcHist(images, channels, mask, histSize, ranges)

  • images:要计算的原图,以方括号的传入,如:[img]
  • channels:度图写[0]就行,彩色图B/G/R分别传入[0]/[1]/[2]
  • mask:要计算的区域,计算整幅图的话,写 None
  • histSize:前面提到的 bins
  • ranges:前面提到的 range
%%time
hist = cv2.calcHist([img], [2, 1, 0], None, [30, 20, 10], [0, 256]*3)  # 性能:2.5 ms
Wall time: 3.52 ms
hist.shape
(30, 20, 10)

直方图均衡化

一副效果好的图像通常在直方图上的分布比较均匀,直方图均衡化就是用来改善图像的全局亮度和对比度。其实从观感上就可以发现,前面那幅图对比度不高,偏灰白。

OpenCV 中用 cv2.equalizeHist() 实现均衡化。我们把两张图片并排显示,对比一下:

equ = cv2.equalizeHist(img[:,:,0])

plt.imshow(np.hstack((img[:,:,0], equ)), cmap = 'gray')  # 并排显示
plt.show()
数字图像的基本运算_第3张图片
output_12_0.png
fig, ax = plt.subplots(1, 2, figsize=(10, 5))

ax[0].hist(img[:,:,0].ravel(), 256, [0, 256])
ax[0].set_title('Hist')
ax[1].hist(equ.ravel(), 256, [0, 256])
ax[1].set_title('equalizeHist')
plt.show()
数字图像的基本运算_第4张图片
output_13_0.png

可以看到均衡化后图片的亮度和对比度效果明显好于原图。不难看出来,直方图均衡化是应用于整幅图片的,这样会模糊掉一部分细节信息。自适应均衡化就是用来解决这一问题的:它在每一个小区域内(默认 )进行直方图均衡化。当然,如果有噪点的话,噪点会被放大,需要对小区域内的对比度进行了限制,所以这个算法全称叫:对比度受限的自适应直方图均衡化CLAHE(Contrast Limited Adaptive Histogram Equalization)

自适应均衡化

# 自适应均衡化,参数可选
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img[:,:,0])

plt.imshow(np.hstack((img[:,:,0], equ, cl1)), cmap = 'gray')  # 并排显示
plt.show()
数字图像的基本运算_第5张图片

点运算

即对应元素的四则运算:

# 乘法
plt.imshow(np.hstack([img*i for i in range(1,4)])) 
plt.show()
数字图像的基本运算_第6张图片
output_17_0.png
# 除法
plt.imshow(np.hstack([img/i for i in [2, 5, 7]]).astype('B'))
plt.show()
数字图像的基本运算_第7张图片
output_18_0.png
# 加法
plt.imshow(np.hstack([img+i for i in [2, 30, 70]]))
plt.show()
数字图像的基本运算_第8张图片
output_19_0.png
# 减法
plt.imshow(np.hstack([img-i for i in [2, 50, 70]]).astype('B'))
plt.show()
数字图像的基本运算_第9张图片
output_20_0.png
# 组合运算
plt.imshow(np.hstack([img*i-i for i in [2, 50, 70]]).astype('B'))
plt.show()
数字图像的基本运算_第10张图片
output_21_0.png
#  指数运算
plt.imshow(np.hstack([np.exp(img*i + 1e-9) for i in [2, 50, 70]]).astype('B'))
plt.show()
数字图像的基本运算_第11张图片
output_22_0.png
# 对数运算
plt.imshow(np.hstack([np.log(img*i + 1e-9) for i in [2, 50, 70]]).astype('B'))
plt.show()
数字图像的基本运算_第12张图片
output_23_0.png
# 阈值处理
plt.imshow(np.hstack([255*(img < i).astype('B') for i in [50, 150, 200]]))
plt.show()
数字图像的基本运算_第13张图片
output_24_0.png

你可能感兴趣的:(数字图像的基本运算)