今天,花了些时间研究了一下直方图和直方图均衡化的一些操作,对我这个小白来说,虽然是原理简单的知识,但在实操时却遇到很多问题,真实不太容易,所以这里记录一下。
主要完成了以下的实操:
下面详细来大概记录一下。
对于直方图的处理,有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得掌握了,虽然简单,但实际开发应用与简单得语法测试还是天差地别的,加油!