比如说,数据集中在000处(左侧)的图像全体会偏暗,数据集中在255255255处(右侧)的图像会偏亮。
如果直方图有所偏向,那么其动态范围( dynamic range )就会较低。
为了使人能更清楚地看见图片,让直方图归一化、平坦化是十分必要的。
这种归一化直方图的操作被称作灰度变换(Grayscale Transformation)。像素点取值范围从[c,d][c,d][c,d]转换到[a,b][a,b][a,b]的过程由下式定义。这回我们将imori_dark.jpg
的灰度扩展到[0,255][0, 255][0,255]范围:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def hist_normalization(img, a=0, b=255):
c = img.min()
d = img.max()
out = img.copy()
# normalization
out = (b - a) / (d - c) * (out - c) + a
out[out < a] = a
out[out > b] = b
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("imori_dark.jpg").astype(np.float)
H, W, C = img.shape
# histogram normalization
out = hist_normalization(img)
# Display histogram
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.savefig("out_his.png")
plt.show()
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
输入:
输出:
直方图:
API
cv2.normalize(src, dst, alpha, beta, norm_type, dtype, mask)
详细
:
src-输入数组
dst-输出数组,支持原地运算
alpha-range normalization模式的最小值
beta-range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
normType-归一化的类型,可以有以下的取值:
1. NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
2. NORM_INF: 此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
3.NORM_L1 : 归一化数组的L1-范数(绝对值的和)
4.NORM_L2: 归一化数组的(欧几里德)L2-范数
dtype-dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask-操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
适用于:灰度级主要在0 ~ 150之间,造成图像对比度较低,可用直方图归一化将图像灰度级拉伸到0~255,使其更清晰。
import cv2
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
src = cv2.imread("child.jpg", cv2.IMREAD_ANYCOLOR)
dst = np.zeros_like(src)
cv2.normalize(src, dst, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
#计算灰度直方图
grayHist = cv2.calcHist([src], [0], None, [256], [0, 256])
grayHist1 = cv2.calcHist([dst], [0], None, [256], [0, 256])
#画出直方图
x_range = range(256)
plt.plot(x_range, grayHist, 'r', linewidth=1.5, c='black')
plt.plot(x_range, grayHist1, 'r', linewidth=1.5, c='b')
#设置坐标轴的范围
y_maxValue = np.max(grayHist)
plt.axis([0, 255, 0, y_maxValue]) #画图范围
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
plt.show()
cv2.imshow("src", src)
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyWindow()