一、直接使用直方图
1 import matplotlib.pyplot as plt 2 import cv2 as cv 3 def plot_demo(image): 4 print(image.ravel()) ##ravel将图像3维转一维数组,便于统计频率 5 # 统计为256个bin,直方图显示[0,256]所有的bin,意思是全部显示,我们可以设置只显示一部分[0,200]也可以 6 plt.hist(image.ravel(), 256, [0, 256]) 7 plt.show() 8 src = cv.imread('1.jpg') 9 cv.imshow('inputimage',src) 10 plot_demo(src) 11 cv.waitKey(0) 12 cv.destroyAllWindows()
hist是256x1数组,每个值对应于该图像中其像素数与其相应像素值的数量。
二、使用opencv直方图
calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None):
推文:直方图
images:输入图像,必须用[ ]括起来
channels:需要统计直方图的第几通道,用于计算直方图的通道,使用灰度图计算直方图是,就直接用[0]
mask:掩膜,不使用的话写None
histSize:指的是直方图分成多少个区间,就是 bin的个数,表示这个直方图分成多少份(即多少个直方柱)
ranges: 统计像素值得区间,表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
hist:输出的直方图数组
最后是两个可选参数,由于直方图作为函数结果返回了,所以第六个hist就没有意义了(待确定)
最后一个accumulate是一个布尔值,用来表示直方图是否叠加。
accumulate=false:在多个图像时,是否累计计算像素值得个数
1 import cv2 as cv 2 import matplotlib.pyplot as plt 3 def hist_image(image): 4 colors = ('blue','green','red') 5 for i,color in enumerate(colors): 6 hist = cv.calcHist([image],[i],None,[256],[0,256]) 7 plt.plot(hist,color=color) 8 plt.xlim([0,256]) 9 plt.show() 10 img = cv.imread('1.jpg') 11 cv.imshow('img',img) 12 hist_image(img) 13 cv.waitKey(0) 14 cv.destroyAllWindows()
根据直方图的波峰可以判断图像的主要特征,可以用于图像的分割,根据各个波峰
四、直方图应用(均衡化和图像比较)
OpenCV直方图均衡化都是基于灰度图像
1、全局直方图均衡化(对比度增强)equalizeHist
函数equalizeHist的作用:直方图均衡化,提高图像质量。
直方图均衡化:如果一副图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。 它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像元取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
全局直方图均衡化可能得到是一种全局意义上的均衡化,但是有的时候这种操作并不是很好,会把某些不该调整的部分给调整了。 Opencv中还有一种直方图均衡化,它是一种局部直方图均衡化,也就是是说把整个图像分成许多小块(比如按10*10作为一个小块),那么对每个小块进行均衡化。
全局的对比度太强
1 import cv2 as cv 2 import matplotlib.pyplot as plt 3 4 img = cv.imread('1.jpg') #OpenCV直方图均衡化都是基于灰度图像 5 gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 6 cv.imshow('gray',gray) 7 dst = cv.equalizeHist(gray) #直方图均衡化,对比度增强 8 cv.imshow('equalizehist',dst) 9 cv.waitKey(0) 10 cv.destroyAllWindows()
2、自适应的局部的直方图均衡化createCLAHE
createCLAHE([, clipLimit[, tileGridSize]]) -> retval
clipLimit参数表示对比度的大小。
tileGridSize参数表示每次处理块的大小 。
1 img = cv.imread('1.jpg') #OpenCV直方图均衡化都是基于灰度图像 2 gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 3 cv.imshow('gray',gray) 4 clahe = cv.createCLAHE(clipLimit=2.0,tileGridSize=(8,8)) 5 dst = clahe.apply(gray) #将灰度图像和局部直方图相关联,把直方图均衡化应用到灰度图 这两行必须搭配起来使用才可以 6 cv.imshow('dis',dst) 7 cv.waitKey(0) 8 cv.destroyAllWindows()
五、直方图比较
1 def create_rag_hist(image): 2 h,w,c = image.shape 3 rgbHist = np.zeros([16*16*16,1],np.float32) #注意,np.array二维以上的,每个元素是一个数组 4 bsize = 256/16 #间隔是16 5 for row in range(h): 6 for col in range(w): 7 b = image[row,col,0] 8 g = image[row,col,1] 9 r = image[row,col,2] 10 index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize) 11 rgbHist[np.int(index),0] = rgbHist[np.int(index),0] + 1 #二维的,所以是rgbhist[n,0]只不过每个数组只有一个元素,所以用0 12 return rgbHist 13 14 def hist_compare(image1,image2): 15 hist1 = create_rag_hist(image1) 16 hist2 = create_rag_hist(image2)
##注意:compareHist里面的hist1和hist2必须是np.float32 17 match1 = cv.compareHist(hist1,hist2,cv.HISTCMP_BHATTACHARYYA) #巴氏距离比较,越小越相似 18 match2 = cv.compareHist(hist1,hist2,cv.HISTCMP_CORREL) #相关性比较(最大为1):越接近1越相似 19 match3 = cv.compareHist(hist1,hist2,cv.HISTCMP_CHISQR) #卡方比较,越小越相似 20 print("巴氏:%s 相关性:%s 卡方:%s"%(match1,match2,match3))
hist_compare(src,src) #当我们使用两张一样的图像比较
巴氏:0.0 相关性:1.0 卡方:0.0
六、直方图反向投影
1、直方图反向投影方法
2、二维直方图表示(就是x,y坐标有编辑)
(1)直接显示(不炫酷)
hsv = cv.cvtColor(image,cv.COLOR_BGR2HSV) hist = cv.calcHist([image],[0,1],None,[289,286],[0,289,0,286]) #横坐标289个,范围是[0,289],纵坐标是286个,范围是[0,286] cv.imshow("hist2D",hist)
(2)、使用matplotlib
hsv = cv.cvtColor(image,cv.COLOR_BGR2HSV) hist = cv.calcHist([image],[0,1],None,[289,286],[0,289,0,286]) plt.imshow(hist,interpolation="nearest") #插值方式,临近点差值,显示的会很漂亮 plt.title("2D Histogram") plt.show()
3、直方图反向映射
def back_projection_demo(): sample = cv.imread("./s2.png") target = cv.imread("./b.png") roi_hsv = cv.cvtColor(sample,cv.COLOR_BGR2HSV) tar_hsv = cv.cvtColor(target,cv.COLOR_BGR2HSV) cv.imshow("sample",sample) cv.imshow("target",target) roihist = cv.calcHist([roi_hsv], [0, 1], None, [324, 356], [0, 324, 0, 356]) #加红部分越小,匹配越放松,匹配越全面,若是bsize值越大,则要求得越精细,越不易匹配,所以导致匹配出来的比较小 cv.normalize(roihist,roihist,0,255,cv.NORM_MINMAX) #规划到0-255之间 dst = cv.calcBackProject([tar_hsv],[0,1],roihist,[0,324,0,356],1) #直方图反向投影 cv.imshow("back_projection_demo",dst)
roihist = cv.calcHist([roi_hsv], [0, 1], None, [32, 32], [0, 324, 0, 356]) #这是两个通道,bsize变少了,但是他的匹配更加广了(对于匹配的局限放宽了),小的话,效果越好
normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]) -> dst
归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。
src参数表示输入数组。
dst参数表示输出与src相同大小的数组,支持原地运算。
alpha参数表示range normalization模式的最小值。
beta参数表示range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
norm_type参数表示归一化的类型。
norm_type参数可以有以下的取值:
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF:归一化数组的C-范数(绝对值的最大值)。
NORM_L1 :归一化数组的L1-范数(绝对值的和)。
NORM_L2 :归一化数组的(欧几里德)L2-范数。
calcBackProject(images, channels, hist, ranges, scale[, dst]) -> dst
函数cv2.calcBackProject用来计算直方图反向投影。
反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
images参数表示输入图像(是HSV图像)。传入时应该用中括号[ ]括起来。目标图像
channels参数表示用于计算反向投影的通道列表,通道数必须与直方图维度相匹配。直方图维度
hist参数表示输入的模板图像直方图。sample直方图
ranges参数表示直方图中每个维度bin的取值范围 (即每个维度有多少个bin)。
scale参数表示可选输出反向投影的比例因子,一般取1(按照原样大小输出)。