直方图
原文链接:http://www.woshicver.com/FifthSection/
使用opencv和matplotlib绘制直方图,使用的绘制直方图函数cv.calcHist(), np.histogram()等。
直方图可以总体了解图像的强度分布,x轴具有像素值,Y轴表示图像中想要像素的数量。可以只管的了解图像的对比度、亮度和强度分布。
查找、绘制和分析
OpenCV中的直方图计算
#OpenCV中的直方图计算
import cv2 as cv
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg',0)
hist = cv.calcHist([img],[0],None,[256],[0,256])
#numpy的直方图计算
import numpy as np
hist,bins = np.histogram(img.ravel(),256,[0,256])
备注:opencv函数比numpy快40倍,因此尽量使用opencv。
绘制直方图
#使用matplotlib绘制直方图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg',0)
plt.hist(img.ravel(),256,[0,256])
plt.show()
#使用matplotlib绘制BGR直方图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg')
color = ('b','g','r')
for i,col in enumerate(color):
histr = cv.calcHist(img,[i],None,[256],[0,256])
plt.plot(histr,color=col)
plt.xlim([0,256])
plt.show()
掩码的应用
如果需要找到图像在某一个区域的直方图,需要创建一个掩码图像,在要找的直方图为白色,都在为黑色,然后把这个作为掩码传递。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg')
mask = np.zeros(img.shape[:2],np.uint8)
mask[100:300,100:400]=255
masked_img = cv.bitwise_and(img,img,mask=mask)
#计算掩码区域和非掩码区域的直方图
#检查作为掩码的第三个参数
hist_full = cv.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask,'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()
直方图均衡
利用直方图均衡来提高图像的对比度。
#直方图均衡化的numpy实现
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg')
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf*float(hist.max())/cdf.max()
plt.plot(cdf_normalized,color='b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
#利用掩码数组进行直方图均衡化
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')
img2=cdf[img]
opencv中的直方图均衡
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg',0)
equ = cv.equalizeHist(img)
res = np.hstack((img,equ))
cv.imshow("images",res)
cv.waitKey(0)
cv.destroyAllWindows()
备注:图像均衡化可以在不同的光照条件下拍摄不同的图像,对其进行均衡并检查结果。
CLAHE(对比度受限的自适应直方图均衡)
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Desktop\\empire.jpeg',0)
clahe = cv.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv.imshow("images",cl1)
cv.waitKey(0)
cv.destroyAllWindows()
二维直方图
使用cv.calcHist()进行计算,对于颜色直方图需要将颜色从BGR转换成HSV。
channel = [0,1],因为我们需要同时处理H和S平面。
bins = [180,256] 对于H平面为180,对于S平面为256。
range = [0,180,0,256] 色相值介于0和180之间,饱和度介于0和256之间。
#opencv中的二维直方图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Yan.Dong5\\Desktop\\empire.jpeg',0)
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv],[0,1],None,[180,256],[0,180,0,256])
cv.imshow('image',hist)
cv.waitKey(0)
cv.destroyAllWindows()
#numpy中的二维直方图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:\\Users\\Yan.Dong5\\Desktop\\empire.jpeg',0)
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist,xbins,ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
plt.imshow(hist,interpolation='nearest')
plt.show()
直方图反投影
直方图反投影用于图像分割或者在图像中查找感兴趣的对象。输出图像与输入图像大小相同,且在可能有对象的区域具有更多的白色值;
直方图反投影和camshift算法配合使用。
opencv中的反投影
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
#roi是我们需要找到的对象或者对象区域
roi = cv.imread('C:\\Users\\Desktop\\empire.jpeg')
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
#目标是我们搜索的图像
target = cv.imread('C:\\Users\\Desktop\\empire.jpeg')
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
#使用calcHist查找直方图
roihist = cv.calcHist([hsv],[0,1],None,[180,256],[0,180,0,256])
#直方图归一化并利用反传算法
cv.normalize(roihist,roihist,0,255,cv.NORM_MINMAX)
dst = cv.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
#现在对圆盘应用卷积,其中D是圆盘内核
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
cv.filter2D(dst,-1,disc,dst)
#应用阈值操作
ret, thresh = cv.threshold(dst,50,255,0)
thresh = cv.merge((thresh,thresh,thresh))
res = cv.bitwise_and(target,thresh)
res = np.vstack((target,thresh,res))
cv.imshow("image",res)
cv.waitKey(0)
cv.destroyAllWindows()