分享

老外讲解什么是直方图以及如何用opencv绘制直方图(译文)

 新用户0118F7lQ 2022-07-02 发布于湖北

1. 目标

  • Find histograms, using both OpenCV and Numpy functions 使用 OpenCV 和 Numpy 函数查找直方图

  • Plot histograms, using OpenCV and Matplotlib functions 使用 OpenCV 和 Matplotlib 函数绘制直方图

  • You will see these functions : 你会看到这些函数:cv.calcHist() cv.calcHist (), np.histogram() Np.histogram () etc. 等等

2. 理论

So what is histogram ? You can consider histogram as a graph or plot, which gives you an overall idea about the intensity distribution of an image. It is a plot with pixel values (ranging from 0 to 255, not always) in X-axis and corresponding number of pixels in the image on Y-axis.

那么什么是直方图呢?您可以将直方图看作一个图形或图表,它可以让您对图像的强度分布有一个全面的了解。它是一个以 x 轴为单位的像素值(范围从0到255,并非总是如此)和 y 轴上图像中相应的像素数的绘图。

It is just another way of understanding the image. By looking at the histogram of an image, you get intuition about contrast, brightness, intensity distribution etc of that image. Almost all image processing tools today, provides features on histogram. Below is an image from Cambridge in Color website, and I recommend you to visit the site for more details.

这只是理解图像的另一种方式。通过查看图像的直方图,你可以直观地了解图像的对比度、亮度、强度分布等等。现在几乎所有的图像处理工具都提供了直方图特征。下面是一张来自 Cambridge in Color 网站的图片,我建议你访问该网站了解更多细节。

图片

You can see the image and its histogram. (Remember, this histogram is drawn for grayscale image, not color image). Left region of histogram shows the amount of darker pixels in image and right region shows the amount of brighter pixels. From the histogram, you can see dark region is more than brighter region, and amount of midtones (pixel values in mid-range, say around 127) are very less.

你可以看到图像和它的直方图。(请记住,此直方图是为灰度图像绘制的,而不是为彩色图像绘制的)。直方图的左侧区域显示图像中较暗的像素数量,右侧区域显示较亮的像素数量。从直方图上,你可以看到黑色区域比亮色区域多,而中间色调的数量(像素值在中间范围,比如127左右)非常少。

3. 查找直方图

Now we have an idea on what is histogram, we can look into how to find this. Both OpenCV and Numpy come with in-built function for this. Before using those functions, we need to understand some terminologies related with histograms.

现在我们知道什么是直方图了,我们可以研究如何找到它。OpenCV 和 Numpy 都为此提供了内置功能。在使用这些函数之前,我们需要了解一些与直方图相关的术语。

BINS :The above histogram shows the number of pixels for every pixel value, ie from 0 to 255. ie you need 256 values to show the above histogram. But consider, what if you need not find the number of pixels for all pixel values separately, but number of pixels in a interval of pixel values? say for example, you need to find the number of pixels lying between 0 to 15, then 16 to 31, …, 240 to 255. You will need only 16 values to represent the histogram. And that is what is shown in example given in OpenCV Tutorials on histograms.

上面的直方图显示了每个像素值的像素数,即从0到255。即你需要256个值来显示上面的直方图。但是,考虑一下,如果您不需要为所有像素值单独找到像素数,而是需要以像素值间隔找到像素数呢?例如,你需要找到0到15之间的像素数,然后是16到31,… ,240到255。你只需要16个值来表示直方图。这就是在 OpenCV 的直方图教程中展示的例子。

Sowhat you do is simply split the whole histogram to 16 sub-parts and value of each sub-part is the sum of all pixel count in it. This each sub-part is called 'BIN'. In first case, number of bins were 256 (one for each pixel) while in second case, it is only 16. BINS is represented by the term histSize in OpenCV docs.

所以你要做的就是把整个直方图分成16个子部分,每个子部分的值就是其中所有像素数的总和。这个每个子部分称为“ BIN”。在第一种情况下,垃圾箱的数量是256个(每个像素一个) ,而在第二种情况下,垃圾箱的数量只有16个。在 OpenCV 文档中,术语 histSize 表示 bin。

DIMS : It is the number of parameters for which we collect the data. In this case, we collect data regarding only one thing, intensity value. So here it is 1.

DIMS: 它是我们收集数据的参数数目。在这种情况下,我们只收集关于一件事情的数据,强度值。这里是1。

RANGE : It is the range of intensity values you want to measure. Normally, it is [0,256], ie all intensity values.

范围: 这是你想测量的强度值的范围。通常,它是[0,256] ,即所有强度值。

3.1. OpenCV 中的直方图计算

So now we use cv.calcHist() function to find the histogram. Let's familiarize with the function and its parameters :

现在我们使用 cv.calcHist ()函数来查找直方图:

cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

  1. images : it is the source image of type uint8 or float32. it should be given in square brackets, ie, '[img]'. 图片: 它是 uint8或 float32类型的源图片。应该用方括号表示,例如”[ img ]”

  2. channels : it is also given in square brackets. It is the index of channel for which we calculate histogram. For example, if input is grayscale image, its value is [0]. For color image, you can pass [0], [1] or [2] to calculate histogram of blue, green or red channel respectively. 也可以用方括号来表示。它是我们计算直方图的信道指标。例如,如果输入是灰度图像,它的值是[0]。对于彩色图像,可以通过[0]、[1]或[2]分别计算蓝色、绿色或红色通道的直方图

  3. mask : mask image. To find histogram of full image, it is given as 'None'. But if you want to find histogram of particular region of image, you have to create a mask image for that and give it as mask. (I will show an example later.) 面具: 面具图像。为了查找完整图像的直方图,给出了“无”的表示。但是,如果你想找到图像的特定区域的直方图,你必须创建一个蒙版图像,并给它作为蒙版。(我稍后将展示一个例子)

  4. histSize : this represents our BIN count. Need to be given in square brackets. For full scale, we pass [256]. histSize: 这表示我们的 BIN 计数。需要在方括号中给出。对于完整规模,我们通过[256]

  5. ranges : this is our RANGE. Normally, it is [0,256]. 范围: 这是我们的范围。通常,它是[0,256]

So let's start with a sample image. Simply load an image in grayscale mode and find its full histogram.

让我们从一个样本图像开始,简单地加载一个图像在灰度模式下,找到它的完整直方图。

img = cv.imread('home.jpg',0)

hist = cv.calcHist([img],[0],None,[256],[0,256])

hist is a 256x1 array, each value corresponds to number of pixels in that image with its corresponding pixel value.

Hist 是一个256x1的数组,每个值对应于该图像中的像素数及其对应的像素值

2. Numpy 的直方图计算

Numpy also provides you a function, np.histogram(). So instead of calcHist() function, you can try below line :

Numpy 还提供了一个函数 np.histogram ():

hist,bins = np.histogram(img.ravel(),256,[0,256])

hist is same as we calculated before. But bins will have 257 elements, because Numpy calculates bins as 0-0.99, 1-1.99, 2-2.99 etc. So final range would be 255-255.99. To represent that, they also add 256 at end of bins. But we don't need that 256. Upto 255 is sufficient.

历史和我们之前计算的一样。但是箱子将有257个元素,因为 Numpy 将箱子计算为0-0.99、1-1.99、2-2.99等。所以最终的范围是255-255.99。为了表示这一点,他们还在垃圾箱的末尾加了256个。但我们不需要那256。高达255就足够了。

See also 参见

Numpy has another function, 还有另一个功能,np.bincount() Np.bincount () which is much faster than (around 10X) np.histogram(). So for one-dimensional histograms, you can better try that. Don't forget to set minlength = 256 in np.bincount. For example, hist = np.bincount(img.ravel(),minlength=256) 这比(大约10X) np.histogram ()快得多。所以对于一维直方图,你可以尝试一下。不要忘记将 minlength = 256设置为 np.bincount。例如,hist = np.bincount (img.ravel () ,minlength = 256)

Note 注意

OpenCV function is faster than (around 40X) than np.histogram(). So stick with OpenCV function. OpenCV 函数比 np.histogram ()快(大约40倍) ,所以坚持使用 OpenCV 函数

Now we should plot histograms, but how?

现在我们应该绘制直方图,但是如何绘制呢?

4. 绘制直方图

There are two ways for this,

有两种方法,

  1. Short Way : use Matplotlib plotting functions Short Way: 使用 Matplotlib 绘图函数

  2. Long Way : use OpenCV drawing functions 长途: 使用 OpenCV 绘图功能

4.1. 使用 Matplotlib

Matplotlib comes with a histogram plotting function : matplotlib.pyplot.hist()

Matplotlib 附带一个直方图绘制函数: Matplotlib.pyplot.hist ()

It directly finds the histogram and plot it. You need not use calcHist() or np.histogram() function to find the histogram. See the code below:

它直接找到直方图并绘制它。您不需要使用 calcHist ()或 np.histogram ()函数来查找直方图。参见下面的代码:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()

图片

Or you can use normal plot of matplotlib, which would be good for BGR plot. For that, you need to find the histogram data first. Try below code:

或者可以使用 matplotlib 的普通绘图,这对 BGR 绘图很有帮助。为此,您需要首先找到直方图数据。试试下面的代码:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
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()

图片

You can deduct from the above graph that, blue has some high value areas in the image (obviously it should be due to the sky)

你可以从上面的图表中推断出,蓝色在图像中有一些高值区域(显然这应该是由于天空)

5. 代码

#!usr/bin/env python
# -- coding:utf-8 _-
'''
@Copyright: Jihua Lab 2021.
@File Name : 1301-historgram.py
@Description:

@Create Time : 2021/1/7 0007 15:12
@Author : HaoWANG, Foshan,China
@Email : haowanghk@163.com

@Software : Pycharm
@Version: V1.0

'''

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

def plothistdemo(image):
'''
# 统计并绘制彩色BGR图像灰度值统计直方图
:param image: src img
:return: plt plot
'''
plt.hist(image.ravel( ), 256, [0, 256])
plt.show()

def imagehist(image):
'''
# 彩色图像RGB三通道的灰度直方图绘制
:param image: 彩色图像
:return: RGB三通道的灰度直方图
'''
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
hist = cv.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color = color)
plt.xlim([0, 256])
plt.show( )

def imagemask_plot(img):
'''
# 使用make切去ROI区域内的图像统计并绘制直方图
:param img: color image
:return: matplotlib plot.show()
'''

# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[50:200, 50:300] = 255
masked_img = cv.bitwise_and(img, img, mask = mask)
# Calculate histogram with mask and without mask
# Check third argument for mask
hist_full = cv.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv.calcHist([img], [0], mask, [256], [0, 256])

# cvt color space from OpenCV BGR to RGB
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
mask = cv.cvtColor(mask, cv.COLOR_BGR2RGB)
masked_img = cv.cvtColor(masked_img, cv.COLOR_BGR2RGB)

# matplotlib subplot src images and their histogram
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( )

def main():
print('————-Histogram Plot Python ————-')
src = cv.imread('../pictures/cat.jpg')
cv.namedWindow('input image', cv.WINDOW_AUTOSIZE)
cv.imshow('input image', src)
# gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) # color cvt BGR->gray
# plot_hist_demo(gray) # plot the source image histgram
# image_hist(src)
image_mask_plot(src) # Application of Mask
cv.waitKey(0)
cv.destroyAllWindows( ) # destroy all windows

if __name
== '__main
':
main( )

图片

5.1 BGR三通道灰度直方图

图片

5.2 灰度通道直方图

图片

图片

5.3 mask操作

图片


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多