本文使用python实现
图像直方图
图像直方图是不同像素值范围的像素个数统计图:
# matplotlib.pyplot.hist()函数
def hist(x: Any, # 输入的数据
bins: Any = None, # 条形数
range: Any = None, # x轴的范围,范围之外的将被舍弃,数组元组类型(起,终)
density: bool = False, # 是否以密度形式显示
weights: Any = None,
cumulative: bool = False,
bottom: Any = None, # y轴的起始位置
histtype: str = 'bar', # 线条类型:‘bar’,方形;“barstacked”:柱形,“step”:“未填充线条”;“stepfilled”:“填充线条”
align: str = 'mid',
orientation: str = 'vertical',
rwidth: Any = None,
log: bool = False,
color: Any = None,
label: Any = None,
stacked: bool = False,
*,
data: Any = None,
**kwargs: Any) -> Any
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def plot_demo(image):
plt.hist(image.ravel(), 256, [0, 256]) # #ravel功能是将多维数组降为一维数组
plt.title("image1")
plt.show()
src = cv.imread("C:/Users/admin/Desktop/14.jpg") # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 设置图片尺寸,自动
cv.imshow("input image", src) # 显示图像
plot_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
opencv里面函数如下
# OpenCV中函数
cv2.cv2 def calcHist(images: Any, # 输入的图像或数组,必须用方括号括起来
channels: Any, # 用于计算直方图的通道
mask: Any, #
histSize: Any,
ranges: Any, # 这个直方图分成多少份(即多少个直方柱)
hist: Any = None, # 表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
accumulate: Any = None) # 一个布尔值,用来表示直方图是否叠加
示例代码
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def image_hist(image):
color = ('blue', 'green', 'red')
for i, color in enumerate(color): # 这是python语法
hist = cv.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.title("image2")
plt.show()
src = cv.imread("C:/Users/admin/Desktop/14.jpg") # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 设置图片尺寸,自动
cv.imshow("input image", src) # 显示图像
image_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()
直方图均衡化
import cv2 as cv
import numpy as np
def equal_hist_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # 转成灰度
dst = cv.equalizeHist(gray) # 将灰度图像进行直方图均衡化,是图像增强的一个手段
cv.imshow("equal_hist_demo image", dst)
src = cv.imread("C:/Users/admin/Desktop/6.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
equal_hist_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
这种方法可以提高图像的亮度:
局部直方图均衡化,可以调节参数来改变效果
def clahe_demo(image): # 局部直方图均衡化
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
dst = clahe.apply(gray)
cv.imshow("clahe_demo image", dst)
直方图比较,将以上两张米粒的图片拿来作直方图比较:
def create_rgb_hist(image): # 创建rgb直方图
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 = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
return rgbHist
def hist_compare(image1, image2): # 直方图比较
hist1 = create_rgb_hist(image1) # 创建直方图
hist2 = create_rgb_hist(image2)
match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA) # 巴氏距离
match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL) # 相关性,越大越相似
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR) # 卡方,越大越不相似
print("巴氏距离:%s,相关性:%s,卡方:%s"%(match1, match2, match3))
结果
巴氏距离:0.2635654174726917,相关性:0.9962298431258823,卡方:91208.7069553576
直方图反向投影
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def hist2d_demo(image):
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# [0, 1]表示两个通道:0通道和1通道
# [180, 256]0通道180,1通道256
# [0, 180, 0, 256]0通道范围[0, 180],1通道范围[0, 256]
'''
def calcHist(images: Any, # 必须用方括号括起来
channels: Any, # 用于计算直方图的通道
mask: Any, # 没有使用
histSize: Any, # 表示这个直方图分成多少份(即多少个直方柱)
ranges: Any, # 表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
hist: Any = None,
accumulate: Any = None)
'''
plt.imshow(hist, interpolation='nearest')
plt.title("2D Histogram")
plt.show()
src = cv.imread("C:/Users/admin/Desktop/14.jpg") # 打开一张图片
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 设置图片尺寸,自动
cv.imshow("input image", src) # 显示图像
hist2d_demo(src)
back_projection_demo()
cv.waitKey(0)
cv.destroyAllWindows()
直方图反向投影
def back_projection_demo(): # 直方图反向投影
sample = cv.imread("C:/Users/admin/Desktop/sample.jpg")
target = cv.imread("C:/Users/admin/Desktop/14.jpg")
roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV) # 转换为hsv
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
cv.imshow("sample", sample) # 显示图片
cv.imshow("target", target)
roiHist = cv.calcHist([roi_hsv], [0, 1], None, [32, 32], [0, 180, 0, 256]) # 可通过调节[32, 32]来调节输出效果
cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX) # 归一化
'''
def normalize(src: Any, # 输入数据
dst: Any, # 输出数据
alpha: Any = None, # range normalization模式的最小值
beta: Any = None, # range normalization模式的最大值
norm_type: Any = None, # 归一化的类型
dtype: Any = None, # dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask: Any = None) -> None # 操作掩膜,用于指示函数是否仅仅对指定的元素进行操作
'''
dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
'''
def calcBackProject(images: Any, # 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
channels: Any, # 通道
hist: Any, # 输入的直方图
ranges: Any, # 直方图中每个维度bin的取值范围
scale: Any, # 可选输出反向投影的比例因子
dst: Any = None) -> None
'''
cv.imshow("back_projection_demo", dst)
其中cv.normalize()函数中归一化类型norm_type有如下取值:
NORM_MINMAX: 数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF: 此类型的定义没有查到,根据OpenCV1的对应项,可能是归一化数组的C - 范数(绝对值的最大值)
NORM_L1: 归一化数组的L1 - 范数(绝对值的和)
NORM_L2: 归一化数组的(欧几里德)L2 - 范数