介绍

不熟悉摄影,“Try-X 是完美的”“背光获胜”“世界的三分之一”“不允许山核桃”“顶空是敌人”我只有有偏见的知识。
这就是为什么几年前我买了一台稍贵的数码相机时,我不知道液晶显示屏上显示的图形是什么的原因。
但是现在我已经在 OpenCV 中使用图像处理获得了很多乐趣,我知道。这是一个亮度直方图。

在 Python 中创建直方图

直方图不是专门用于图像处理的技术。它被广泛用作统计方法之一,并以七大质量控制工具之一而闻名。
在 Python 中,OpenCV 和 numpy 具有获取直方图的功能。

在统计界,有关于条形图的个数和宽度的讨论,但如果是图像亮度的直方图,则是“256个类别,从0到255(包括255),宽度为1”。将是正常的

这次的图像是 Rena 小姐,她的 RGB 是适度偏向的。

莲娜.png
OpenCVとNumPyでヒストグラムを作成する

开放式CV

在 OpenCV 中cv2.calcHist()利用。只写所需的参数

hist = cv2.calcHist(images, channels, mask, histSize, ranges)

变成。从参数名称imageschannels 可以看出,它们指定了列表。元组也是可能的。

争论

  • 图像 输入图像列表。指定为 [image] 和元素 1 的列表。除了np.uint8np.float32也可以。
  • channels 颜色通道。为灰度图像指定 [0],为 BGR 指定 [0][1][2]
  • 蒙版蒙版图像。如果未指定,请使用None。我希望这是可选的。
  • histSize 间隔数。亦称仓。如果要单独计算 256 个渐变,请使用 [256]。
  • ranges 要计数的值范围。对图像的所有亮度执行时设置为 [0, 256]。不是 [0, 255]。

输出

  • hist 直方图。当图像数量为 1 时,返回一个 2D numpy 数组,例如 [[0.000e+00], [0.000e+00], …]。每个元素都是一个 float32。

就这个返回值而言,即使images是一个列表,似乎也不可能一次指定多张图片并获取多个直方图。

样本

为 RGB 图像的每个颜色通道创建直方图的示例。
请注意,颜色序列是 BGR,因为它是 OpenCV。

import cv2 
import matplotlib.pyplot as plt

filename = "lenna.png"
image = cv2.imread(filename)
COLORS = ["blue","green","red"]

for i, color in enumerate(COLORS):
    hist = cv2.calcHist([image], [i], None, [256], [0, 256])
    plt.plot(hist, color=color)

plt.show()

结果,确认莉娜图像偏红。
OpenCVとNumPyでヒストグラムを作成する

数字货币

在 numpy 中np.histogram()利用。

hist, bin_edges = np.histogram(a, bins=10, range=None, normed=None, weights=None, density=None)

如何使用。

论据(仅部分)

  • 一个输入矩阵。预先进行一维化的情况很多,但实际上在计算过程中一维化。
  • bins 箱数。可选,默认为 10。它可以是数字、列表或元组(任何东西都可以是字符串)。
  • 范围 Bin 范围。可以省略,初始值为a的最小值到最大值。

输出

  • 直方图。一维 numpy 数组,其中每个元素都是整数。
  • bin_edges Bin 范围。

样本 1 省略范围

尝试使用指定的bins 和未指定的range 进行绘图。

for i, color in enumerate(COLORS):
    hist, bin_edges = np.histogram(image[:, :, i], bins=256)
    plt.plot(hist, color=color)
仅指定 np.histogram() bins cv2.calcHist()
OpenCVとNumPyでヒストグラムを作成する OpenCVとNumPyでヒストグラムを作成する

注意红色。 Lena图像整体呈现强烈的红色,应该没有亮度小于等于50的点,但是在这个图中,正常图中50到255的范围已经扩大到0到25​​5。这是“如果省略范围,则从最小值到最大值”的结果。
图被切碎的原因是当将“从最小值到最大值”扩展到“从0到255的256个类”时,会出现“从100.1到100.9”这样的不完整范围。这被认为是因为由于亮度是整数值,因此“从 100.1 到 100.9”范围内的点数为 0。

示例 2 指定范围

接下来,尝试指定binsrange

for i, color in enumerate(COLORS):
    hist, bin_edges = np.histogram(image[:, :, i], bins=256, range=(0, 256))
    plt.plot(hist, color=color)
指定 np.histogram() binsrange cv2.calcHist()
OpenCVとNumPyでヒストグラムを作成する OpenCVとNumPyでヒストグラムを作成する

原以为还有很长的路要走,但我能画出几乎一样的图表。
这真的正确吗?

检查正确性

Lena 图像大小为 512x512,像素为 262144。如果您采用直方图,则频率总和应为 262144,无论箱数如何。
此外,在此图像中,红色强度 = 255 的像素是

np.sum(image[:, :, 2]==255)    # 112

事实证明,其中有 112 个。

示例 1 范围 =(0, 254)

让我们指定range=(0, 254) 作为一个明显不正确的例子。垃圾箱的数量无关紧要,因此请将其保留为默认值。

hist, bin_edges = np.histogram(image[:, :, 2], range=(0, 254))
len(hist)        # 10 ビン数(デフォ値)
sum(hist)        # 262032 度数の合計

这里出现的 262032 是总像素数 262144 减去亮度为 255、112 的像素数。这意味着不计算亮度为 255 的像素。

示例 2 bins=256, range=(0, 255)

接下来,让我们指定bins=256, range=(0, 255)

hist, bin_edges = np.histogram(image[:, :, 2], bins=256, range=(0, 255))
len(hist)        # 256 ビン数
sum(hist)        # 262144 度数の合計
len(bin_edges)   # 257 bin_edgesの数
bin_edges
[  0.           0.99609375   1.9921875    2.98828125   3.984375
   4.98046875   5.9765625    6.97265625   7.96875      8.96484375
    中略
 249.0234375  250.01953125 251.015625   252.01171875 253.0078125
 254.00390625 255.        ]

可以看出,频率之和等于像素数,所有像素都被计算在内。

顺便说一句, bin_edges 有 (length(hist)+1) 元素。
0 开头,255 结尾。最后一个是第 257 个,而不是第 256 个。虽然它被 256 个 bin 分隔,但亮度 255 属于它之外的第 257 个簇。情况不妙。
另外,我不喜欢每个类都是一个不可分割的数字,而不是一个精确的间隔。

示例 3 bins=256, range=(0, 256)

接下来,让我们指定bins=256, range=(0, 256)

hist, bin_edges = np.histogram(image[:, :, 2], bins=256, range=(0, 256))
len(hist)        # 256 ビン数
sum(hist)        # 262144 度数の合計
len(bin_edges)   # 257 bin_edgesの数
bin_edges
[  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.
  14.  15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.
    中略
 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251.
 252. 253. 254. 255. 256.]

现在值 255 最终属于第 256 个集群。我们还确认每个类的宽度为 1。

这周围这个网站最好关注一下

比较 OpenCV 直方图和 Numpy 直方图

cv2.calcHist() 没有在 np.histogram() 中的bin_edges 的输出。让我们看看这两个直方图是否完美匹配。
输出的 dtype 和 shape 再次表示如下。

cv2.calcHist() np.histogram() 统一格式
类型 dtype('float32') dtype('int64') 使它成为 dtype('float32')
形状 (256, 1) (256,) 设置为 (256,)

让我们统一这个区域,检查内容是否完全匹配。还要检查处理时间。
似乎有一种更复杂的方式来编写处理时间测量部分,但它离题了,所以我在这里写得很扎实。

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

COLORS = ["blue","green","red"]
filename = "lenna.png"
image = cv2.imread(filename)

for i, color in enumerate(COLORS):
    print("-" * 20)
    print(color)

    # cv2.calcHist() リストでなくタプルで指示してみる 良い子は真似するな
    start_time = time.time()
    hist_cv = cv2.calcHist((image,), (i,), None, histSize=(256,), ranges=(0, 256))
    end_time = time.time()
    print("cv2.calcHist()", end_time - start_time)

    # np.histogram() rangeをリストで指示してみる
    start_time = time.time()
    hist_np, bin_edges = np.histogram(image[:, :, i], bins=256, range=[0, 256])
    end_time = time.time()
    print("np.histogram()", end_time - start_time)

    hist_cv_sameformat = hist_cv.flatten()                      # (256, 1) -> (256,)
    hist_np_sameformat = hist_np.astype(np.float32)             # int64 -> float32
    if np.array_equal(hist_cv_sameformat, hist_np_sameformat):  # 本当はarray_equalはdtypeを揃える必要はない
        print("完全一致")    
    else:
        print("不一致あり")   

这是结果。

--------------------
blue
cv2.calcHist() 0.0020308494567871094
np.histogram() 0.005982637405395508
完全一致
--------------------
green
cv2.calcHist() 0.000997781753540039
np.histogram() 0.003998756408691406
完全一致
--------------------
red
cv2.calcHist() 0.0010008811950683594
np.histogram() 0.003998994827270508
完全一致

我能够使用 OpenCV 和 numpy 获得相同的结果。我还发现 OpenCV 要快得多。
发现参数,无论其名称如何,都以几乎相同的方式使用。如果一个是 (0, 255) 而另一个是 [0, 256] 或类似的东西,你甚至不能看它。

在最后

我打算省略 np.histogram() 的bin_edges 的解释,但通过提及这一点,我现在可以理解范围不合适时的行为。这是你无法学习的东西,除非你自己做。


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308627088.html

相关文章:

  • 2022-12-23
  • 2022-01-31
  • 2021-12-20
  • 2022-12-23
  • 2021-12-17
  • 2021-04-09
  • 2022-12-23
  • 2021-11-20
猜你喜欢
  • 2021-06-26
  • 2022-12-23
  • 2022-12-23
  • 2021-09-04
  • 2021-08-06
  • 2022-01-26
  • 2021-10-30
相关资源
相似解决方案