© Fu Xianjun. All Rights Reserved
从统计的角度讲,直方图是图像内灰度值的统计特性与图像灰度值之间的函数,直方图统计图像内各个灰度级的次数。从直方图的图形上观察,横坐标是图像中各像素点的灰度级,纵坐标是具有该灰度级(像素值)的像素个数.
Python的模块matplotlib.pyplot中的hist()函数能够方便地绘制直方图,我们通常采用该函数直接绘制直方图。除次之外,OpenCV中的cv2.calcHist()函数能够计算统计直方图,还可以在此基础上绘制图像的直方图。
语法格式: matplotlib.pyplot.hist(X,BINS)
·X: 数据源,必须是一维的。图像通常是二维的,需要使用ravel()函数(b = a.ravel)将图像处理为一维数据源以后,再作为参数使用。
·BINS: BINS的具体值,表示灰度级的分组情况。
代码如下:
import cv2
import matplotlib.pyplot as plt
img1=cv2.imread("hj.jpg",0)
cv2.imshow("img1",img1)
plt.hist(img1.ravel(),256,facecolor='yellowgreen')
cv2.waitKey()
cv2.destroyAllWindows()
2.1使用cv2.calcHist()函数统计图像直方图
语法格式:
hist = cv2.calcHist(image,channels,mask,histSize,ranges,accumulate)
·image: 原始图像,该图像需要使用“ [ ] ”括起来。
·channels: 指定通道编号。通道编号需要用“ [ ] ”括起来,如果输入图像是单通道灰度图像,该参数的值就是[0]。对于彩色图像,它的值可以是[0]、[1]、[2],分别对应通道B、G、R。
·mask: 掩码图像,当统计整幅图像的直方图时,将这个值设置为None。当统计图像某一部分的直方图时,需要用到掩码图像。
·histSize: BINS的值,该值需要用“ [ ] ”括起来。
·ranges: 即像素范围。
·accumulate: 累积标识,默认值为False。
代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread("bd.jpg")
hist = cv2.calcHist([img],[0],None,[256],[0,255])
plt.plot(hist,color='b')
2.2绘制彩色直方图
代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread("bd.jpg")
histb = cv2.calcHist([img],[0],None,[256],[0,255])
histg = cv2.calcHist([img],[1],None,[256],[0,255])
histr = cv2.calcHist([img],[2],None,[256],[0,255])
plt.plot(histb,color='b')
plt.plot(histg,color='g')
plt.plot(histr,color='r')
import cv2
import numpy as np
from matplotlib import pyplot as plt
def image_hist(image):
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
hist = cv2.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
img=cv2.imread("bd.jpg")
image_hist(img)
在函数cv2.calcHist()中,参数mask用于标识是否使用掩码图像。当使用掩码图像获取直方图时,仅获取掩码参数mask指定区域的直方图。
代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread("hj.jpg",0)
w,h=img.shape
mask=np.zeros([w,h],np.uint8)
mask[(w-200):w,0:200]=255
hist = cv2.calcHist([img],[0],None,[256],[0,255])
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,255])
# cv2.imshow('mask',mask)
plt.plot(hist,color='b')
plt.plot(hist_mask,color='g')
cv2.waitKey()
cv2.destroyAllWindows()
直方图均衡化的主要目的是将原始图像的灰度级均匀地映射到整个灰度级范围内,得到一个灰度级分布均匀的图像。这种均衡化,即实现了灰度值统计上的概率均衡,也实现了人类视觉系统上的视觉均衡。
4.1直方图均衡化原理
直方图均衡化的算法主要包括两个步骤:
(1)计算累积直方图
(2)对累积直方图进行区间转换
在此基础上,再利用人眼视觉达到直方图均衡化的目的。
4.2直方图均衡化处理
语法格式: dst = cv2.equalizeHist(scr)
式中,scr是8位单通道原始图像。
代码如下:
import cv2
import numpy as np
img=cv2.imread("hj.jpg",0)
equ=cv2.equalizeHist(b)
hist = cv2.calcHist([equ],[0],None,[256],[0,255])
plt.plot(hist,color='b')
cv2.imshow("equ",equ)
cv2.waitKey()
cv2.destroyAllWindows()
import cv2
import numpy as np
img=cv2.imread("qb.jpg")
b,g,r=cv2.split(img)
equb=cv2.equalizeHist(b)
equg=cv2.equalizeHist(g)
equr=cv2.equalizeHist(r)
img_new=cv2.merge([equb,equg,equr])
histb = cv2.calcHist([img_new],[0],None,[256],[0,255])
histg = cv2.calcHist([img_new],[1],None,[256],[0,255])
histr = cv2.calcHist([img_new],[2],None,[256],[0,255])
plt.plot(histb,color='b')
plt.plot(histg,color='g')
plt.plot(histr,color='r')
cv2.imshow("img",img)
cv2.imshow("img_new",img_new)
cv2.waitKey()
cv2.destroyAllWindows()
import cv2
import numpy as np
img=cv2.imread("qb.jpg")
b,g,r=cv2.split(img)
clah=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
equb=clah.apply(b)
equg=clah.apply(g)
equr=clah.apply(r)
img_new=cv2.merge([equb,equg,equr])
histb = cv2.calcHist([img_new],[0],None,[256],[0,255])
histg = cv2.calcHist([img_new],[1],None,[256],[0,255])
histr = cv2.calcHist([img_new],[2],None,[256],[0,255])
plt.plot(histb,color='b')
plt.plot(histg,color='g')
plt.plot(histr,color='r')
cv2.imshow("img",img)
cv2.imshow("img_new",img_new)
cv2.waitKey()
cv2.destroyAllWindows()
代码如下:
import cv2
import numpy as np
def create_rgb_hist(image):
h, w, c = image.shape
rgbhist = np.zeros([16 * 16 * 16, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
index = int(b / bsize) * 16 * 16 + int(g / bsize) * 16 + int(r / bsize)
rgbhist[int(index), 0] += 1
return rgbhist
def hist_compare(image1, image2):
hist1 = create_rgb_hist(image1)
hist2 = create_rgb_hist(image2)
match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA)
match2 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
match3 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)
print("巴氏距离:%s, 相关性:%s, 卡方:%s" %(match1, match2, match3))
img1 = cv2.imread("dog1.jpg")
cv2.imshow("dog1", img1)
img2 = cv2.imread("dog3.jpg")
cv2.imshow("dog3", img2)
hist_compare(img1, img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
def create_rgb_hist(image):
""""创建 RGB 三通道直方图(直方图矩阵)"""
h, w, c = image.shape
# 创建一个(16*16*16,1)的初始矩阵,作为直方图矩阵
# 16*16*16的意思为三通道每通道有16个bins
rgbhist = np.zeros([16 * 16 * 16, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
# 人为构建直方图矩阵的索引,该索引是通过每一个像素点的三通道值进行构建
index = int(b / bsize) * 16 * 16 + int(g / bsize) * 16 + int(r / bsize)
# 该处形成的矩阵即为直方图矩阵
rgbhist[int(index), 0] += 1
return rgbhist
def hist_compare(image1, image2):
"""直方图比较函数"""
# 创建第一幅图的rgb三通道直方图(直方图矩阵)
hist1 = create_rgb_hist(image1)
# 创建第二幅图的rgb三通道直方图(直方图矩阵)
hist2 = create_rgb_hist(image2)
# 进行三种方式的直方图比较
match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA)
match2 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
match3 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)
print("巴氏距离:%s, 相关性:%s, 卡方:%s" %(match1, match2, match3))
img1 = cv2.imread("dog1.jpg")
cv2.imshow("dog1", img1)
img2 = cv2.imread("dog2.png")
cv2.imshow("dog2", img2)
hist_compare(img1, img2)
img3 = cv2.imread("dog3.jpg")
cv2.imshow("dog3", img3)
hist_compare(img1, img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码如下:
import cv2
import numpy as np
#计算灰度直方图
def calcGrayHist(grayimage):
#灰度图像矩阵的高,宽
rows, cols = grayimage.shape
print(grayimage.shape)
#存储灰度直方图
grayHist = np.zeros([256],np.uint64)
for r in range(rows):
for c in range(cols):
grayHist[grayimage[r][c]] += 1
return grayHist
#阈值分割:直方图阈值法
def threshTwoPeaks(image):
if len(image.shape) == 2:
gray = image
else:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
print(666666)
#计算灰度直方图
histogram = calcGrayHist(gray)
#寻找灰度直方图的最大峰值对应的灰度值
maxLoc = np.where(histogram==np.max(histogram))
firstPeak = maxLoc[0][0]
#寻找灰度直方图的第二个峰值对应的灰度值
measureDists = np.zeros([256],np.float32)
for k in range(256):
measureDists[k] = pow(k-firstPeak,2)*histogram[k]
maxLoc2 = np.where(measureDists==np.max(measureDists))
secondPeak = maxLoc2[0][0]
#找到两个峰值之间的最小值对应的灰度值,作为阈值
thresh = 0
if firstPeak > secondPeak:#第一个峰值再第二个峰值的右侧
temp = histogram[int(secondPeak):int(firstPeak)]
minloc = np.where(temp == np.min(temp))
thresh = secondPeak + minloc[0][0] + 1
else:#第一个峰值再第二个峰值的左侧
temp = histogram[int(firstPeak):int(secondPeak)]
minloc = np.where(temp == np.min(temp))
thresh =firstPeak + minloc[0][0] + 1
#找到阈值之后进行阈值处理,得到二值图
threshImage_out = gray.copy()
#大于阈值的都设置为255
threshImage_out[threshImage_out > thresh] = 255
threshImage_out[threshImage_out <= thresh] = 0
return thresh, threshImage_out
if __name__ == "__main__":
img = cv2.imread('dog2.png')
thresh,threshImage_out = threshTwoPeaks(img)
print(thresh)
cv2.imshow('threshImage_out',threshImage_out)
cv2.waitKey(0)
cv2.destroyAllWindows()
画直方图要用到matplotlib库,如果不导入matplotlib的包,代码将运行不了。