4.4 直方图的计算与显示
写在前面
当然也可以用NumPy和Matplotlib计算和绘制直方图
1.直方图的概念:
直方图其实就是一副图像的灰度级统计,设一副图像的灰度级为\[0,L-1\],则可以建立一个二维坐标系(x,y\),x取值\[0,L-1\],y取值为相应灰度级的像素数量。如果是归一化直方图,则y代表该灰度级在图像中的出现概率,且![](http://hi.csdn.net/attachment/201110/29/0_1319909647VzvY.gif)
2.函数原型
python调用Opencv直方图计算函数为:cv2.calcHist
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist
通过一例子了解函数中的参数:
#coding=utf-8
import cv2
import numpy as np
image = cv2.imread("D:/histTest.jpg", 0)
hist = cv2.calcHist([image],
[0], #使用的通道
None, #没有使用mask
[256], #HistSize
[0.0,255.0]) #直方图柱的范围
第一个参数,表述我们要处理的img,一定要用方括号括起来(实际处理的是矩阵);
第二个参数,用作计算直方图的通道,这里使用灰度图计算;
第三个参数,Mask;处理没有使用,用None表示;
- 第四个参数,用作表示我们将直方图分成几个直方柱表示
- 第五个参数,表示直方图各个像素的值,[0.0, 255.0]表示直方图能表示像素值从0.0到255的像素。
- 剩下两个参数,用的比较少。这里不做解释
3.计算和显示彩色图像不同通道的直方图
函数封装,便于使用:
def calcAndDrawHist(image, color):
hist= cv2.calcHist([image], [0], None, [256], [0.0,255.0])
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(hist)
histImg = np.zeros([256,256,3], np.uint8)
hpt = int(0.9* 256);
for h in range(256):
intensity = int(hist[h]*hpt/maxVal)
cv2.line(histImg,(h,256), (h,256-intensity), color)
return histImg;
源代码:
import cv2
import numpy as np
def calcAndDrawHist(image, color):
hist= cv2.calcHist([image], [0], None, [256], [0.0,255.0])
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(hist)
histImg = np.zeros([255,255,3], np.uint8)
hpt = int(0.9* 256);
for h in range(256):
intensity = int(hist[h]*hpt/maxVal)
cv2.line(histImg,(h,256), (h,256-intensity), color)
return histImg
if __name__ == '__main__':
img = cv2.imread("G:/python project/lena.jpg")
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()
重点理解:
函数返回的Hist参数以及后续处理;
如何调用Opencv画图实现树状图绘制
运行结果:
挂,另外一种画折线图:
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread('G:/python project/lena.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])
cv2.normalize(originHist, originHist,0,255*0.9,cv2.NORM_MINMAX)
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.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
CSDN作者sunny原文:
这里的for循环是对三个通道遍历一次,每次绘制相应通道的直方图的折线。for循环的第一行是计算对应通道的直方图,经过上面的介绍,应该很容易就能明白。
这里所不同的是没有手动的计算直方图的最大值再乘以一个系数,而是直接调用了OpenCV的归一化函数。该函数将直方图的范围限定在0-255×0.9之间,与之前的一样。下面的hist= np.int32(np.around(originHist))先将生成的原始直方图中的每个元素四舍六入五凑偶取整(cv2.calcHist函数得到的是float32类型的数组),接着将整数部分转成np.int32类型。即61.123先转成61.0,再转成61。注意,这里必须使用np.int32(...)进行转换,numpy的转换函数可以对数组中的每个元素都进行转换,而Python的int(...)只能转换一个元素,如果使用int(...),将导致only length-1 arrays can be converted to Python scalars错误。
下面的pts = np.column_stack((bins,hist))是将直方图中每个bin的值转成相应的坐标。比如hist[0] =3,...,hist[126] = 178,...,hist[255] = 5;而bins的值为[[0],[1],[2]...,[255]]。使用np.column_stack将其组合成[0, 3]、[126, 178]、[255, 5]这样的坐标作为元素组成的数组。
最后使用cv2.polylines函数根据这些点绘制出折线,第三个False参数指出这个折线不需要闭合。第四个参数指定了折线的颜色。
当所有完成后,别忘了用h = np.flipud(h)反转绘制好的直方图,因为绘制时,[0,0]在图像的左上角。这在直方图可视化一节中有说明。
原创自:http://blog.csdn.net/sunny2038/article/details/9097989(作者:sunny2038)