opencv-python 小白笔记(17)

第十七节:直方图与直方图均衡化

  • (一)画出图像直方图
  • (二)同时绘制多通道(BGR)的直方图
  • (三)直方图均衡化与自适应均衡化
  • (四)结语

opencv中的直方图可以帮助我们更直观的获取图像像素的分布信息,也可以帮助我们更好的提取图像的特征信息。直方图是对数据进行统计的一种方法,图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。这种直方图中,横坐标的左侧为较暗的区域,而右侧为较亮的区域。

(一)画出图像直方图

需要用到函数cv2.calcHist对图像信息进行统计,然后用matplotlib对图像进行绘制

cv2.calcHist(images,channels,mask,histSize,ranges)

参数 解释
images 原图像。当传入函数时应该用中括号 [] 括起来,例如:[img]。
channels 如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
mask 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
histSize BIN 的数目。也应该用中括号括起来,例如:[256]。你也可以把它理解为设置直方图的组距
ranges 像素值范围,通常为 [0,256]

下面我们将先用cv2.calcHist对图像信息进行统计,然后使用matplotlib里的plt.plot函数对统计信息以折线图图的方式进行绘制
示例:


import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('lambo.PNG',0)

cv2.imshow('original', img)#显示原图
cv2.waitKey(0)


hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.plot(hist)
plt.grid(linestyle='--',alpha=1)
plt.show()


还有一种方法就是直接使用matplotlib的直方图绘制函数plt.hist

import numpy as np
import cv2
from matplotlib import pyplot as plt


img = cv2.imread('lambo.PNG',0)
cv2.imshow('img',img)
plt.hist(img.ravel(),256,[0,256])#img.ravel()是将图片的多维数组转换为一维数组
plt.show()


这时可能就有小伙伴们问,难道没有什么方法只是用opencv的函数将cv2.calcHist统计的到的信息画出来吗(意思是只用opencv的函数将直方图画出来)。当然有,但是相比上面两种方法,会复杂一点,且统计出的数据并不直观。具体怎么做,这里就不写了,下面是使用方法的链接

传送门

(二)同时绘制多通道(BGR)的直方图

下面先用cv2.calcHist函数对图像信息进行统计,然后用matplotlib对统计得到数据以折线图的形式显示出来

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('lambo.PNG') 
cv2.imshow('img',img)
color = ('b','g','r')
for i,col in enumerate(color): #这里是枚举操作
    hist = cv2.calcHist([img],[i],None,[256],[0,256])
    plt.plot(hist,color = col)
    plt.grid(linestyle='--', alpha=1)
plt.show()

(三)直方图均衡化与自适应均衡化

“直方图均衡化”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在更广泛灰度范围内的分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。

看了这段解释你可能还不是十分明白,我们来直接看一下效果

import numpy as np
import cv2
from matplotlib import pyplot as plt

plt.figure(figsize=(11,10),facecolor='green')#创建figure
plt.rcParams['font.sans-serif']='STXINWEI'#设置中文字体为华文新魏

img = cv2.imread('lambo.PNG',0)

plt.subplot(2,2,1)
plt.title('均衡化之前的直方图')
plt.hist(img.ravel(),256,[0,256])#img.ravel()是将图片的多维数组转换为一维数组

plt.subplot(2,2,2)
plt.title('均衡化之后直方图')
equ = cv2.equalizeHist(img) #均衡化操作,只需将待处理的图片传入cv2.equalizeHist
plt.hist(equ.ravel(),256)

plt.subplot(2,2,3)
plt.title('均衡化之前图像')
plt.imshow(img,'gray')

plt.subplot(2,2,4)
plt.title('均衡化之后图像')
plt.imshow(equ,'gray')

plt.show()

opencv-python 小白笔记(17)_第1张图片

由上面的左右直方图的对比可以看出,原先高瘦的直方图变成了矮胖的直方图。由上面的左右图片对比可以看出图像的对比度变大,清晰度变大,所以能有效增强图像。

但是这种图像均衡化会让图片的某些部分的细节丢失,小伙伴们可能不难发现图中小车的左侧车门在图像均衡化后直接变黑了。其实想一想出现这种情况的原因也不难理解,因为对图像整体均衡化,部分的细节肯定会丢失一些。那么下面我们就来解决这问题

图像自适应均衡化

自适应的直方图均衡将整幅图像分成很多小块,然后再对每一个小块分别进行直方图均衡化,最后进行拼接。

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
上面这个函数先设置对比度限制(clipLimit=2.0),对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把 其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。它是为了防止噪音被放大。 tileGridSize=(8,8)它是设置均衡化小块的大小,默认为8*8。在均衡化好后,将返回值传入下面的函数
out_put = clahe.apply(img)

import numpy as np
import cv2
from matplotlib import pyplot as plt

plt.figure(figsize=(11,10),facecolor='green')#创建figure
plt.rcParams['font.sans-serif']='STXINWEI'#设置中文字体为华文新魏

img = cv2.imread('lambo.PNG',0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
out_put = clahe.apply(img)

plt.subplot(2,2,1)
plt.title('均衡化之前的直方图')
plt.hist(img.ravel(),256,[0,256])#img.ravel()是将图片的多维数组转换为一维数组

plt.subplot(2,2,2)
plt.title('自适应均衡化之后直方图')
plt.hist(out_put.ravel(),256)

plt.subplot(2,2,3)
plt.title('均衡化之前图像')
plt.imshow(img,'gray')

plt.subplot(2,2,4)
plt.title('自适应均衡化之后图像')
plt.imshow(out_put,'gray')

plt.show()


这里小伙伴可以与上面的全局均衡化进行对比,这里可以明显看出小车的左侧车门的细节要比全局均衡化要好,但自适应均衡化相比于全局均衡化在保留图像的细节部分确实要好些,但并不代表自适应均衡化一定要比全局均衡化要好,以为自适应均衡化可能会放到局部的噪音,所以还得具体情况具体对待。

(四)结语

学习opencv有很多的方法,我的建议是你可以加一些群,可以充分利用B站,CSDN,和百度。

在我的博客中,我不会讲解opencv的算法实现(当然我也不太会),我只会讲解一些函数的调用,不理解就多改一些参数,多尝试尝试,慢慢你就理解来。相信你总有一天可以说opencv不过“Ctrl+C,Crtl+V”

PS:如果有什么错误的地方,还请大家批评指正,不过错了也没啥关系,反正也没什么人看
最后,希望小伙伴们都能有所收获。码字不易,喜欢的话,关注一波在走吧

你可能感兴趣的:(opencv-python笔记)