一起学opencv-python十二(图像直方图)

如何画图像直方图

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.html#histograms-getting-started

和https://www.bilibili.com/video/av24998616/?p=12

 

上面那张图更符合数学中的直方图,和图像中的直方图还是有很大差别的。

 

这个为什么要到256呢?我们上一讲曾经说过最右边的应该是闭区间啊。

 

上面的无是None,也就是没有mask。

这个0指的是flags=0,也就是以灰度模式读图像:

 

 

 

虽然我们不经常用np来计算直方图,不过还是了解一下输入参数位置。

 

 

 

 

 

 

 

我们真正用的在下面的三通道:

 

 

 

用opencv不就得自己画线吗?挺麻烦的,坐标刻度还要自己用putText加。下面就用matplotlib了:

 

我们用了一个枚举的函数enumerate,其实这个函数很简单。

 

就是把一个可迭代对象的每一个值和序号打包成一个元组,序号在前,序号的开始默认是0,当然也可以用start指定的,最后合成一个枚举类型,枚举类型是在c语言里也绝对学过的。我们用zip也能实现的。

 

img要加中括号是上面官方写的。plt.xlim就是限制x轴范围的,这个我感觉可以不要的。

 

这个plot里面按理说应该是要有x和y的,这里为什么可以只输入一个呢?这个和MATLAB里面应该是一样的,就是如果只输入一个参数,那么认为是y,而x自动取自然数,也就是0,1,2...,这正好和我们的需要符合,所以是可以的。1.jpg是下图:

 

看到bgr的波峰很靠近255,这是因为整张图都是偏白的。不要xlim其实影响不是特别大。不是正好贴边而已,不限制范围的话,matplotlib会自动给一个范围,这个范围都是留有余量的,也就是说最左边会比最小值再小一点,最大值大一点,所以不会贴边。

 

如果我改成了[0,255]会有比较大的变化,其实前面是没有变化的,只是纵坐标刻度不同而已,这个请注意一下。

 

出现这个问题的原因应该是这里每一个区间都是左闭右开,所以导致了最后的255没有画出来,我们稍微改动一下就能证明这点。没错255变成255.1,出来的就和原来的一样了。

 

不过这两个其实不太一样,因为范围是[0,256]的话,区间是[0,1),[1,2)一直到[255,256)一共256个,这个对应到0,1,...是没有问题的,因为我们的BGR就只有整数,如果是[0,255.1],各个区间就得是[0,255.1/256)....了,这对应自然数也没有问题。

 

 

 

虽然峰值都还是比较大的,但是看到还有一些峰值靠近左边了,毕竟这张图上有一些地方还是比较暗的或者如果有比较纯的颜色,比如纯蓝是(255,0,0)其它的通道的值就比较小了。

 

 

 

这个用了一个mask而已,我们只关注白色区域,就在calcHist的时候加入准备好的nask。

直方图均衡(HE)

 

 

 

 

关于直方图均衡的原理其实就是找一个对应函数f,y=f(x),y是均衡之后的灰度值,x是均衡之前的,让y的范围在[0,255]之内,并且是单调的,为什么单调其实很好理解,因为不单调岂不是乱套了吗?本来暗的地方均衡后搞得比原来亮的地方还亮。单调还有一个好处就是容易求出反函数。所以说,我们其实最主要的工作在于寻找T函数。我们如何找到这个函数呢?其实也不难:rmin对应0,而rmax对应255,我们也就只能确定两点,中间的值我们不知道,需要插值了,最简单的肯定是线性插值了,也就是说

 

当然最后要取整一下。不同的插值函数出来结果肯定是不一样的。不过

 

上图应该是纵坐标刻度不一样,因为变换前后,像素点总和不变,峰值对应的纵轴也不会变。

下面对比一下我自己编写的图像均衡和opencv自带的均衡函数出来的结果,这里要说一点,上面只是针对一个通道采用的方法,彩色通道的方法下面会有。

 

蓝色是原来的直方图,红色是均衡之后的直方图,1是原图,2是均衡之后的图,看到对比度明显增强了。这里还要说一点,plt.show()要放在两个cv2.imshow()之后,不然的话只有把直方图关掉,关掉是点x,1和2才能出来,这个原因在于plt.show()如果不点x,代码不会往下执行,这个和cv2.imshow有点相似,不同的是cv2.imshow除了点x,还能接受键盘事件或者设定时间。来试试opencv自带的函数:

 

 

 

官方用的是累积法,参考了https://www.cnblogs.com/wangguchangqing/p/7098213.html#autoid-1-1-0

 

这么累积就保证了一定是单调的,而且有一个好处就是会比较均匀,因为如果灰度值比较小的有很多的话,这些基本上再除以总数n之后会归为一个灰度值,虽然方法本身是单调的,但是由于取整就会出现多对1。

 

我用hstack把三张图拼接在一起了,看了一下,官方的对比确实比我的更好一些,官方的直方图看起来就是更分散。绿色的是官方均衡之后的结果。我下面就来把我原来的方法改成累积法试一试看看和官方的结果是不是一样的。

 

圈起来的就是实现累积和对应表转换的过程。出来的图像基本上和官方的一样,不过直方图略有区别,应该是因为取整方法不同的原因,有向上和向下取整,还有四舍五入。里面用到了一个cumsum。

 

实现的就是累积求和功能。

 

那么关于彩色图像呢?

 

来试试分别均衡并合并。

 

确实有很严重的色彩失真。再来试一试HSV。只对v通道做直方图均衡,结果:

 

有点太暗了。换一张图,这张效果还可以。

 

联合概率密度挺难搞的。转换函数用线性的效果还蛮好的:

 

我们上面用的都是全局直方图均衡算法,除此以外,还有局部直方图均衡算法

 

我们就先来看局部直方图均衡算法的一种实现方式:

 

 

 

CLAHE的原理,参考https://blog.csdn.net/piaoxuezhong/article/details/78271785

https://www.cnblogs.com/jsxyhelu/p/6435601.html?utm_source=debugrun&utm_medium=referral

和https://blog.csdn.net/piaoxuezhong/article/details/78271785

 

所谓的块效应,指的就是:

 

因为每一个矩形都是不重叠的,而且都是分开处理的。

 

其实就是设置一个阈值,如果选定矩形范围内的最大亮度和最小亮度大于这个阈值,那么就把高于的部分的亮度平均分到整个区间,这个时候肯定还会再超一部分,不过这部分就不管了。

 

关于插值方式:https://blog.csdn.net/xbinworld/article/details/65660665

https://blog.csdn.net/fengbingchun/article/details/17335477

 

 

 

 

 

目前,CLAHE算法在图像处理领域有较多的应用,典型的有图像去雾,水下图像处理,低照度图像处理还有医学图像处理等方面。当然具体到实际应用,算法是需要调参和优化的。

以上我们差不多就已经知道了数学原理了,下面是代码实现,我们就直接用opencv自带的函数了,说实话,我时间挺紧的,我还有太多东西要学,没时间一个一个去编程验证这些算法,而且编出来的效率不一定有opencv自带的高,但是我们需要知道函数每个参数的意义和如何调整参数。

 

clpLimit就是强度差阈值,tileGridSize就是矩形的大小。这里并没有输入数组参数。

 

apply就是把这个CLAHE方法应用到某一个数组上。

 

我们来试一试吧。

 

直方图:

 

CLAHE的看起来连续多了,而HE是比较离散的。来试一下对彩色的HSV格式的H格式来试一下吧。

 

 

 

CLAHE相比HE效果还是好一些。

 

绿色的峰值移动没有那么夸张。

 

减小这个cliplimit,对于这张图片来说效果会更好。

 

 

 

cliplimit的设置就是为了不要让结果的对比度改变那么大,如果cliplimit减小的话,那么对比度就改变得更小了,从上图也能看出来,绿色和蓝色相差不大。基于三个通道的联合概率密度方法的我还没有想好该怎么写程序,也没有找到很好的程序。

直方图规定化

https://www.cnblogs.com/wangguchangqing/p/7098213.html#autoid-2-1-0

从上面可以看出,直方图的均衡化自动地确定了变换函数,可以很方便的得到变换后的图像,但是在有些应用中这种自动的增强并不是最好的方法。有时候,需要图像具有某一特定的直方图形状(也就是灰度分布),而不是均匀分布的直方图,这时候可以使用直方图规定化
直方图规定化,也叫做直方图匹配,用于将图像变换为某一特定的灰度分布,也就是其目的的灰度直方图是已知的。这其实和均衡化很类似,均衡化后的灰度直方图也是已知的,是一个均匀分布的直方图;而规定化后的直方图可以随意的指定,也就是在执行规定化操作时,首先要知道变换后的灰度直方图,这样才能确定变换函数。规定化操作能够有目的的增强某个灰度区间,相比于,均衡化操作,规定化多了一个输入,但是其变换后的结果也更灵活。

 

 

 

 

 

映射关系也有两种:

 

还可以参考https://blog.csdn.net/majinlei121/article/details/46482615。

这个暂时没有代码演示,感觉其实不好编的。

直方图对比

有几种对比方式:Correlation,也就是相关系数,这个越接近1,说明两个正相关程度越高,越接近-1,说明负相关程度越高。第二chi-square是卡方检验。

 

 

 

感觉第三个不能作为距离的度量啊,第四个是巴氏距离。

 

用的是compareHist函数。

 

 

 

 

 

 

 

但是其实直方图一样也不代表图片一样,因为一张图片上的任意像素互换,直方图都不变。所以直方图其实并不能用来做图像比较。

 

比较两个图像是否一样可以直接用np.array_equal,结果为true代表一样,反之,不一样,判断两个图像相似度,最简单的办法就是用像素的差的绝对值的和了。最后我前面写过一个添加椒盐噪声的函数,其实有一点问题,就是最后一句应该改成a[r1,r2]=r3,也就是利用广播机制,这样就可以适用于各种通道的了而不仅仅是三通道。

 

最近开了一个一门数字图像处理是用MATLAB的,嗯,感觉其实用的原理都差不多,MATLAB就是RGB的,就很好。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值