b, g, r = cv2.split(img) >>#按通道划分图像histImgB = calcAndDrawHist(b, [255, 0, 0])
histImgG = calcAndDrawHist(g, [0, 255, 0])
histImgR = calcAndDrawHist(r, [0, 0, 255])
cv2.imshow("histImgB", histImgB)
cv2.imshow("histImgG", histImgG)
cv2.imshow("histImgR", histImgR)
cv2.imshow("Img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中函数minMaxLoc()在C++下表⽰为:
void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = 0,
Point * minLoc = 0,
Point * maxLoc = 0,
InputArray mask = noArray()
)
参数解释
src: 输⼊的单通道数组
minVal: double类型指针,⽤于返回最⼩值的指针,如果不需要返回则设置为NULL
maxVal: double类型的指针,⽤于返回最⼤值指针,如果不需要返回则设置为NULL
minLoc: 返回最⼩值位置指针(2D的情况下),如果不需要则设置为NULL
maxLoc: 返回最⼤位置指针(2D情况下),如果不需要则设置为NULL
mask: 可选掩模板。
表⽰成折线图:
import cv2
import numpy as np
img = cv2.imread('scene.jpg')
h = np.zeros((256,256,3)) #创建⽤于绘制直⽅图的全0图像
bins = np.arange(256).reshape(256,1) #直⽅图中各bin的顶点位置
color = [ (255,0,0),(0,255,0),(0,0,255) ] #BGR三种颜⾊
for ch, col in enumerate(color):
originHist = cv2.calcHist([img],[ch],None,[256],[0,256])
hist=np.int32(np.around(originHist))
pts = np.column_stack((bins,hist))
cv2.polylines(h,[pts],False,col)
h=np.flipud(h)
cv2.imshow('colorhist',h)
cv2.waitKey(0)
主要⽤到的函数包括alize()、np.column_stack(),、含义如下:
void cv::normalize ( InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray()
)
参数解释
src: 输⼊数组
dst: 输出数组,与src有相同的尺⼨
alpha: 将数组归⼀化范围的最⼤值,有默认值1
beta: 归⼀化的最⼩值,有默认值0
norm_type: 归⼀化⽅式,可以查看NormTypes()函数查看详细信息,有默认值NORM_L2
dtype: 当该值取负数时,输出数组与src有相同类型,否则,与src有相同的通道并且深度为CV_MAT_DEPTH(dtype)
mask: 可选的掩膜版
三、Gamma变换
背景⾥的暗部细节是⾮常弱的时候,⼀个常⽤⽅法是考虑⽤Gamma变换来提升暗部细节。Gamma变换是矫正相机直接成像和⼈眼感受图像差别的⼀种常⽤⼿段,简单来说就是通过⾮线性变换让图像从对曝光强度的线性响应变得更接近⼈眼感受到的响应。具体的定义和实现,还是接着上⾯代码中读取的图⽚,执⾏计算直⽅图和Gamma变换的代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
img = cv2.imread('scene.jpg')
# 分通道计算每个通道的直⽅图
hist_b = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img], [1], None, [256], [0, 256])
hist_r = cv2.calcHist([img], [2], None, [256], [0, 256])
# 定义Gamma矫正的函数
def gamma_trans(img, gamma):
# 具体做法是先归⼀化到1,然后gamma作为指数值求出新的像素值再还原
gamma_table = [np.power(x/255.0, gamma)*255.0 for x in range(256)]
gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
# 实现这个映射⽤的是OpenCV的查表函数
return cv2.LUT(img, gamma_table)
# 执⾏Gamma矫正,⼩于1的值让暗部细节⼤量提升,同时亮部细节少量提升
dst指数img_corrected = gamma_trans(img, 0.5)
cv2.imwrite('gamma_corrected.jpg', img_corrected)
# 分通道计算Gamma矫正后的直⽅图
hist_b_corrected = cv2.calcHist([img_corrected], [0], None, [256], [0, 256])
hist_g_corrected = cv2.calcHist([img_corrected], [1], None, [256], [0, 256])
hist_r_corrected = cv2.calcHist([img_corrected], [2], None, [256], [0, 256])
fig = plt.figure()
pix_hists = [
[hist_b, hist_g, hist_r],
[hist_b_corrected, hist_g_corrected, hist_r_corrected]
]
pix_vals = range(256)
for sub_plt, pix_hist in zip([121, 122], pix_hists):
ax = fig.add_subplot(sub_plt, projection='3d')
for c, z, channel_hist in zip(['b', 'g', 'r'], [20, 10, 0], pix_hist):
cs = [c] * 256
#ax.bar(pix_vals, channel_hist, zs=z, zdir='y', color=cs, alpha=0.618, edgecolor='none', lw=0)
ax.plot3D(pix_vals, channel_hist, zs=z,zdir='y',color=c)
ax.set_xlabel('Pixel Values')
ax.set_xlim([0, 256])
ax.set_ylabel('Channels')
ax.set_zlabel('Counts')
plt.show()
直⽅图 原图 gamma变换之后