今天,花了些时间研究了一下直方图和直方图均衡化的一些操作,对我这个小白来说,虽然是原理简单的知识,但在实操时却遇到很多问题,真实不太容易,所以这里记录一下。
主要完成了以下的实操:
- 直方图的处理
- cv2处理直方图(灰度图和彩图)
- pyplot处理直方图(灰度图和彩图)
- 直方图均衡化
- 灰度图均衡化
- 彩图均衡化
- 均衡化自实现,并于cv结果比较
下面详细来大概记录一下。
直方图展示(灰度图和彩图)
对于直方图的处理,有cv2和pyplot2种常用的方式,接口定义分别为
cv2.calcHist()和plt.Hist(),这部分就是理解现有接口定义,直接调用即可,直接上代码。
''' calcHist—计算图像直方图 函数原型:calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None) images:图像矩阵,例如:[image] channels:通道数,例如:0 mask:掩膜,一般为:None histSize:直方图大小,一般等于灰度级数 ranges:横轴范围 ''' import cv2 import matplotlib.pyplot as plt color = cv2.imread("..//..//dataset//lena.png", 1) cv2.imshow('color', color) gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY) cv2.imshow('gray', gray) img_Gray = cv2.imread('..//..//dataset//lena.png', cv2.IMREAD_GRAYSCALE) # cv2.cvtColor(img) cv2.imshow('lenaGray', img_Gray) '''cv2操作直方图''' # 这里注意,全部的参数,都要[]形式,否则数据不正确 # cv2 灰度直方图 cv2_hist = cv2.calcHist([img_Gray], [0], None, [256], [0, 255]) plt.plot(cv2_hist) plt.show() # cv2 各通道彩色直方图 color_hist0 = cv2.calcHist([color], [0], None, [256], [0, 255]) color_hist1 = cv2.calcHist([color], [1], None, [256], [0, 255]) color_hist2 = cv2.calcHist([color], [2], None, [256], [0, 255]) plt.plot(color_hist0) plt.plot(color_hist1) plt.plot(color_hist2) plt.show() '''plt直接显示直方图''' # 灰度直方图 plt.hist(img_Gray.ravel(), 256) plt.show() # 彩色直方图 # 彩色直方图 plt.hist(color[:, :, 0].ravel(), 256) plt.hist(color[:, :, 1].ravel(), 256) plt.hist(color[:, :, 2].ravel(), 256) plt.show() cv2.waitKey(0) cv2.destroyAllWindows()
这里需要特别注意一下的是,calcHist的参数,所有的参数都以[]形式进行传递,当mask为None时,直接以None替代,否则,结果不正确。
上面只是使用pyplot简单展示了数据,关于pyplot的使用,其实可以做到很多好看的样式,有需要的同学可以去学习一下。
然后,主要说一下直方图均衡化的操作,因为在实际运用种,均衡化是用的较多的。
操作其实也简单,直接调用接口即可,上代码看一下
img = cv2.imread('..//..//dataset//lena.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # gray图像均衡化 dst = cv2.equalizeHist(gray) hist_src = cv2.calcHist([gray], [0], None, [256], [0, 255]) hist_dst = cv2.calcHist([dst], [0], None, [256], [0, 255]) # plt.plot(hist_dst) # plt.show() # print(type(hist_src)) cv2.imshow('hist_origin_Equalization', np.hstack([gray, dst])) # 多通道图像均衡化 # 注意该方法只能对单通道图像进行处理,因此,对多通道图像需要先split进行处理,之后再merge进行合并 (sb, sg, sr) = cv2.split(img) db = cv2.equalizeHist(sb) dg = cv2.equalizeHist(sg) dr = cv2.equalizeHist(sr) dstImg = cv2.merge((db, dg, dr)) cv2.imshow('EqualizationImage', np.hstack([img, dstImg])) # cv2.waitKey(0) # cv2.destroyAllWindows()
这里我们提一下,均衡化操作,对应的都是单通道数据,因此,如果是彩色图片进行处理时,我们可以通过split()函数先将其拆分,处理完成后,再通过merge()函数将其合并即可。
这里,附上结果图看一下,可以看到,效果还是蛮明显的。
到这里后,需要想要详细理解均衡化的原理,可以试着自己实现一下均衡化操作。
下面,是我自己实现的均衡化操作,过程种的变量是随意定义的,可以根据流程理解一下
# 自实现均衡化 # 排序-求对应数量-求累计数量-计算结果-生成目标图像 def histEqualization(img): points = list(img.flatten()) sets = list(set(points)) sets.sort() # 默认升序 point_count = [points.count(i) for i in sets] sum = [np.sum(point_count[0:i]) for i in range(len(point_count))] level = [i / len(points) for i in sum] # 很多推导公式,这里显示是(比例*256)-1,这样会得到很多的负值情况,但我认为直接*256即可,因为其取值范围已经是256个了。 dp = [int(l * 256) for l in level] dst = [dp[sets.index(i)] for i in points] dstImg = np.array(dst,np.uint8).reshape((img.shape[0], img.shape[1])) return dstImg # 自实现均衡化方法 dstCustom=histEqualization(gray) cv2.imshow('customEqualization',dstCustom) # 从比较结果可以看出自实现的效果和cv的效果还是有很大差别的。 print(np.sum(dstCustom==dst)) print(np.sum(dstCustom.flatten()==dst.flatten())) # 彩色图像分开调用多次即可
这里的话,提2点:
1.通过我自定义的方法实现的结果与cv的结果有较大的却别,图像只有200多点相同(应该是cv做了一些优化操作),但整体效果看着几乎没差别。
2.在实际使用时,推荐使用cv方法直接处理。
3.关于list的sort操作,其sort是针对自身list进行,可以排序后赋值给其他变量,但不能将排序直接赋值给新变量,这样返回为None
a=[1,2,3,4,5] a.sort(reverse=Ture) c=a # 此时,c与a相同,均为[5,4,3,2,1] b=a.sort() # 此时,b为None,不能直接赋值
以上即今天的全部内容,感觉对基础不熟悉,在实操时影响真的很大,还是得注重平时多练习,也得加强一下对python得掌握了,虽然简单,但实际开发应用与简单得语法测试还是天差地别的,加油!