OpenCV-Histograms

像素值在整幅图像中的分布情况是该图像的一个重要属性。

计算图像直方图

直方图是一个简单的表格, 表示一个图像(有时是一组图像) 中具有某个值的像素的数量。
也可以把直方图归一化, 即所有箱子的累加和等于1。
这时每个箱子的数值表示对应的像素数量占总数的百分比。

1.使用cv.calHist()

使用cv.calHist()计算每个颜色通道的直方图
cv.calcHist函数。 是一个通用的直方图计算函数, 可处理包含任何值类型和范围的多通道图像。
calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
参数列表:

  • images: source image of type uint8 or float32,given in “[img]”
  • channels:the index of channel for which we calculate histogram.
    grayscale: [0], color image: [0] or [1] or [2]
  • mask:To find histogram of full image, it is given as “None”.
    find histogram of particular region of image,given as mask
  • histSize:BIN count,For full scale, we pass [256].
  • ranges:[0,256]
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

# 载入图像并显示
src_img = cv.imread("test.png")
hist_result0 = cv.calcHist([src_img], [0], None, [256], [0, 256])
hist_result1 = cv.calcHist([src_img], [1], None, [256], [0, 256])
hist_result2 = cv.calcHist([src_img], [2], None, [256], [0, 256])
plt.figure(figsize=(10, 4))
plt.subplot(1, 3, 1)
plt.title("Blue channel")
plt.plot(hist_result0)
plt.subplot(1, 3, 2)
plt.title("Green channel")
plt.plot(hist_result1)
plt.subplot(1, 3, 3)
plt.title("Red channel")
plt.plot(hist_result2)
plt.show()

在这里插入图片描述

2.使用np.histogram()

使用np.histogram()计算每个颜色通道的直方图

np.histogram()是一个生成直方图的函数

np.histogram() 默认地使用10个相同大小的区间(箱),边界的数量比分箱数多一个.

histogram(a, bins=10, range=None, normed=None, weights=None, density=None)

parameter:

  • a:Input data. The histogram is computed over the flattened array.
  • bins:int or sequence of scalars or str int: defines the number of equal-width bins in the given range sequence: defines a monotonically increasing array of bin edges, including the rightmost edge.
  • range: (float, float), optional. The lower and upper range of the bins. Values outside the range are ignored. If not provided, range is simply (a.min(), a.max()).
  • density: bool, optional (False default) True:the result is the value of the probability False:the result will contain the number of samples in each bin.

return:

  • hist:array, The values of the histogram.
  • bin_edges: array, bin edges ,(length(hist)+1).
np_hist, bin_edges = np.histogram(src_img.ravel(), 256)
# 自动进行转换,直接使用src_img效果相同。
# ravel和flatten都是将多维数组转换为一维数组
# numpy.flatten()返回一份拷贝,对拷贝所做的修改不会影响原始矩阵
# 而numpy.ravel()返回的是视图,会影响原始矩阵。
plt.title("numpy histogram")
plt.plot(np_hist)
plt.show()

在这里插入图片描述

3.使用np.bincount()

Count number of occurrences of each value in array of non-negative ints. faster than (around 10X) np.histogram().

bincount(x, weights=None, minlength=0)

Parameters:

  • x : array_like, 1 dimension, nonnegative ints
  • weights : array_like, optional Weights, array of the same shape as x.
  • minlength : int, optional A minimum number of bins for the output array.

Returns :

  • out : ndarray of ints The result of binning the input array. The length of out is equal to np.amax(x)+1.
np_hist= np.bincount(src_img.ravel(), minlength=256)
plt.title("numpy bincount")
plt.plot(np_hist)
plt.show()

在这里插入图片描述

图像均衡化

若一个图象中的像素值仅限于某些特定值范围,其图像的对比度就会很差。一个好的图像中的像素值范围应该覆盖所有的亮度值。这就是直方图均衡化并且这通常会提高图像的对比度。

函数的输入只能是灰度图像,输出为均衡化后的图像。

gray_img = cv.cvtColor(src_img, cv.COLOR_BGR2GRAY)
equ_img = cv.equalizeHist(gray_img)
np_hist, _ = np.histogram(gray_img.ravel(), 256, [0, 256])
equ_hist, _ = np.histogram(equ_img.ravel(), 256, [0, 256])
plt.figure(figsize=(8,5))
plt.subplot(1,2,1)
plt.title("src histogram")
plt.plot(np_hist)
plt.subplot(1,2,2)
plt.title("equ_hist histogram")
plt.plot(equ_hist)
plt.show()

在这里插入图片描述

二维图像直方图(colorHistograms)

在二维直方图中,需要考虑两个特征,每个像素的色调和饱和度值。 函数的输入只能是HSV图像,因此需要先将图像转换为HSV格式。

1.使用numpy.histogram2d()

Compute the bi-dimensional histogram of two data samples.

histogram2d(x, y, bins=10, range=None, normed=None, weights=None, density=None)

Parameters:

  • x : array_like, shape (N,)
  • y : array_like, shape (N,)
  • bins : int or array_like or [int, int] or [array, array], optional
  • range : array_like, shape(2,2), optional
    • The leftmost and rightmost edges of the bins along each dimension

Returns:

  • H : ndarray, shape(nx, ny) The bi-dimensional histogram of samples x and y.
    • Values in x are histogrammed along the first dimension
    • values in y are histogrammed along the second dimension.
  • xedges : ndarray, shape(nx+1,) The bin edges along the first dimension.
  • yedges : ndarray, shape(ny+1,) The bin edges along the second dimension.
hsv_img = cv.cvtColor(src_img, cv.COLOR_BGR2HSV)
hue, sat, _ = cv.split(hsv_img)
hist, xbins, ybins = np.histogram2d(hue.ravel(), sat.ravel(), [180, 256], [[0, 180], [0, 256]])
plt.imshow(hist)
plt.show()

在这里插入图片描述

2.使用重载的cv.calcHist()

For color histograms, we need to convert the image from BGR to HSV.

For 1D histogram, we converted from BGR to Grayscale.

For 2D histograms, its parameters will be modified as follows:

channels = [0,1], because we need to process both H and S plane.

bins = [180,256], 180 for H plane and 256 for S plane.

range = [0,180,0,256] , Hue value lies between 0 and 180 Saturation lies between 0 and 256.

hsv_img = cv.cvtColor(src_img, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv_img], [0, 1], None, [180, 256], [0, 180, 0, 256])
plt.imshow(hist)
plt.show()

在这里插入图片描述

图像直方图反向投影

反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的特征。
反向投影在某一位置的值就是原图对应位置像素值在原图像中的总数目,即反向投影矩阵中某点的值就是它对应的原图像中的点所在区间的灰度直方图值。

OpenCV提供了一个内置函数cv.calcBackProject(),参数几乎与cv.calcHist()函数相同。
先求出原图像的直方图,再由直方图得到反向投影矩阵。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt


roi_img = cv.imread('mask.png')
hsv_roi = cv.cvtColor(roi_img, cv.COLOR_BGR2HSV)
src_img = cv.imread('lena.jpg')
hsv_src = cv.cvtColor(src_img, cv.COLOR_BGR2HSV)

# 计算二维直方图
roi_hist = cv.calcHist([hsv_roi], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 均一化
# 归一化就是把数据转换到一定范围内,
# 使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系
# (src, dst, alpha=None, beta=None, norm_type=None, dtype=None, mask=None)
# alpha:范围的下限,beta:范围的上限
roi_hist = cv.normalize(roi_hist, 0, 255, cv.NORM_MINMAX)

# 计算反向投影矩阵
back_project_mat = cv.calcBackProject([hsv_src], [0, 1], roi_hist, [0, 180, 0, 256], 1)

# 生成结构化元素
# cv.getStructuringElement返回指定形状和尺寸的结构元素
# 第一个参数表示内核的形状
# 第二和第三个参数分别是内核的尺寸以及锚点的位置
# 对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))

# 使用生成的椭圆元素对反向矩阵进行卷积
res_back_project_mat = cv.filter2D(back_project_mat, -1, disc)

# threshold 
ret, thresh = cv.threshold(res_back_project_mat, 50, 255, 0)
thresh = cv.merge((thresh, thresh, thresh))
# 与原图求与,获取原图中的像素值
res = cv.bitwise_and(src_img, thresh)
cv.imshow('res mat', res)
key = cv.waitKey()
if key == 27:
    cv.destroyAllWindows()

threshold(res_back_project_mat, 50, 255, 0)
thresh = cv.merge((thresh, thresh, thresh))
# 与原图求与,获取原图中的像素值
res = cv.bitwise_and(src_img, thresh)
cv.imshow('res mat', res)
key = cv.waitKey()
if key == 27:
    cv.destroyAllWindows()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值