使用OpenCV,Numpy计算直方图,Matplot绘制直方图及分析

1,031 阅读3分钟

使用OpenCV,Numpy计算直方图,Matplot绘制直方图及分析

这篇博客将介绍如何使用Python,OpenCV,Numpy函数计算直方图,并使用 OpenCV 和 Matplotlib 函数绘制直方图,并对直方图进行分析。

通过查看图像的直方图,可以直观地了解该图像的对比度、亮度、强度分布等。

1. 效果图

原始图如下:

在这里插入图片描述

灰度图直方图效果如下:

可以看到左侧区域显示图像中较暗像素的数量,右侧区域显示较亮像素的数量。从直方图中可以看到暗区、亮区均不多,并且中间色调(中间范围的像素值,例如 170/210 左右)的数量非常多。

在这里插入图片描述 BGR三通道的直方图效果图下: 在这里插入图片描述 原始图 VS Mask遮罩 VS Mask图像 VS 混合直方图如下: 在第4个直方图中,蓝线表示完整图像的直方图,红线表示遮罩区域的直方图。 在这里插入图片描述

2. 原理

直方图可以帮助全面了解图像的强度分布。 最基本的直方图是灰度图像直方图,在 X 轴上具有像素值(范围从 0 到 255)和 Y 轴上图像中相应像素数的图。

计算直方图的3种方式:

  • hist = cv2.calcHist([img],[0],None,[256],[0,256])
  • hist,bins = np.histogram(img.ravel(),256,[0,256])
  • np.bincount(img.ravel(),minlength=256)

其中cv2的方式比np.histogram快40倍; np.bincount比np.histogram快10倍,因此优先使用cv2.calHist()方式;

绘制直方图的2种方式:

  • matplot计算直方图并绘制:plt.hist(img.ravel(),256,[0,256]); plt.show()
  • matplot的简单绘制方式:histr = cv2.calcHist([img],[i],None,[256],[0,256]) plt.plot(histr,color = col) plt.xlim([0,256])

3. 源码

3.1 直方图3种计算方法和2种绘制方法

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

img = cv2.imread('ml.jpg', 0)

# cv计算直方图
# cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
# - img:要计算直方图的图像
# - channels:通道值,如果传入灰度图为0,彩色图[0][1][2]分别计算BGR通道
# - mask:蒙版,并非为整个图计算直方图
# - histSize:x轴分多少个范围
# - ranges: 值的范围,通常是[0,256]
hist = cv2.calcHist([img], [0], None, [256], [0, 256])

# numpy计算直方图
#  np.bincount() 比 np.histogram() 大概快10倍
#  cv2.calHist() 比 np.histogram() 大概快40倍
hist, bins = np.histogram(img.ravel(), 256, [0, 256])
hist = np.bincount(img.ravel(), minlength=256)

# 绘制直方图法1:matplot
img = cv2.imread('ml.jpg', 0)
plt.hist(img.ravel(), 256, [0, 256])
plt.show()

# 绘制直方图法2:matplot普通绘制方式
img = cv2.imread('ml.jpg')
color = ('b', 'g', 'r')
for i, col in enumerate(color):
    histr = cv2.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(histr, color=col)
    plt.xlim([0, 256])
plt.show()

3.2 Mask遮罩图像直方图

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

img = cv2.imread('ml.jpg', 0)

# 构造一个mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img, img, mask=mask)

# 计算整个图直方图以及mask的直方图
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.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, color='b'), plt.plot(hist_mask, color='r')
plt.xlim([0, 256])

plt.show()

参考