OpenCV颜色直方图与直方图自定义可视化

·  阅读 578
OpenCV颜色直方图与直方图自定义可视化

「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战

颜色直方图

《灰度直方图详解》中,我们知道 OpenCV 中使用 cv2.calcHist() 函数来计算一个或多个数组的直方图,并详细介绍如何使用该函数绘制灰度图像的直方图。接下来,我们将了解如何计算颜色直方图。

在多通道图像中,计算颜色直方图的实质上是计算每个通道的直方图,因此我们需要创建函数来计算多个通道的直方图:

def hist_color_img(img):
    histr = []
    histr.append(cv2.calcHist([img], [0], None, [256], [0, 256]))
    histr.append(cv2.calcHist([img], [1], None, [256], [0, 256]))
    histr.append(cv2.calcHist([img], [2], None, [256], [0, 256]))
    return histr
复制代码

我们也可以创建一个 for 循环或类似的方法来调用 cv2.calcHist() 函数三次。

接下来需要调用 hist_color_img() 函数计算图像的颜色直方图:

# 加载图像
image = cv2.imread('example.png')
# 计算图像的颜色直方图
hist_color = hist_color_img(image)
# 可视化
show_img_with_matplotlib(image, "image", 1)
# 可视化颜色直方图函数
def show_hist_with_matplotlib_rgb(hist, title, pos, color):
    ax = plt.subplot(2, 3, pos)
    plt.xlabel("bins")
    plt.ylabel("number of pixels")
    plt.xlim([0, 256])
    for (h, c) in zip(hist, color):
        plt.plot(h, color=c)
show_hist_with_matplotlib_rgb(hist_color, "color histogram", 4, ['b', 'g', 'r'])
复制代码

同样,使用 cv2.add()cv2.subtract() 来修改加载的 BGR 图像的亮度(原始 BGR 图像的每个像素值添加/减去 10),并查看直方图的变化情况:

M = np.ones(image.shape, dtype="uint8") * 10
# 原始 BGR 图像的每个像素值添加 10
added_image = cv2.add(image, M)
hist_color_added_image = hist_color_img(added_image)

# 原始 BGR 图像的每个像素值减去 10
subtracted_image = cv2.subtract(image, M)
hist_color_subtracted_image = hist_color_img(subtracted_image)

# 可视化
show_img_with_matplotlib(added_image, "image lighter", 2)
show_hist_with_matplotlib_rgb(hist_color_added_image, "color histogram", 5, ['b', 'g', 'r'])
show_img_with_matplotlib(subtracted_image, "image darker", 3)
show_hist_with_matplotlib_rgb(hist_color_subtracted_image, "color histogram", 6, ['b', 'g', 'r'])
复制代码

颜色直方图

直方图的自定义可视化

为了可视化直方图,我们调用了 plt.plot() 函数,这是由于没有 OpenCV 函数可以用来直接绘制直方图。因此,如果我们想要使用 OpenCV 绘制直方图,必须利用 OpenCV 原语(例如 cv2.polylines()cv2.rectangle() 等)来绘制直方图。

我们创建实现此功能的 plot_hist() 函数,此函数创建一个 BGR 彩色图像,并在其中绘制直方图。该函数的代码如下:

def plot_hist(hist_items, color):
    # 出于可视化目的,我们添加了一些偏移
    offset_down = 10
    offset_up = 10
    # 这将用于创建要可视化的点(x坐标)
    x_values = np.arange(256).reshape(256, 1)
    # 创建画布
    canvas = np.ones((300, 256, 3), dtype='uint8') * 256

    for hist_item, col in zip(hist_items, color):
        # 在适当的可视化范围内进行规范化
        cv2.normalize(hist_item, hist_item, 0 + offset_down, 300 - offset_up, cv2.NORM_MINMAX)
        # 将值强制转换为int
        around = np.around(hist_item)
        # 数据类型转换
        hist = np.int32(around)
        # 使用直方图和x坐标创建点
        pts = np.column_stack((x_values, hist))
        # 绘制点
        cv2.polylines(canvas, [pts], False, col, 2)
        # 绘制一个矩形
        cv2.rectangle(canvas, (0, 0), (255, 298), (0, 0, 0), 1)
    
    # 沿上/下方向翻转图像
    res = np.flipud(canvas)
    return res
复制代码

此函数接收直方图并为直方图的每个元素构建 (x, y)pts,其中 y 值表示直方图 x 元素的频率。这些点 pts 是通过使用 cv2.polylines() 函数绘制的,该函数根据 pts 数组绘制曲线。最后,图像需要垂直翻转,因为 y 值颠倒了。最后使用 plt.plot() 和自定义函数的直方图绘制函数进行比较:

# 读取图像
image = cv2.imread('example.png')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 使用 plt.plot() 绘制的灰度直方图
hist = cv2.calcHist([gray_image], [0], None, [256], [0, 256])

# 使用 plt.plot() 绘制的颜色直方图
hist_color = hist_color_img(image)

# 自定义灰度直方图
gray_plot = plot_hist([hist], [(255, 0, 255)])

# 自定义颜色直方图
color_plot = plot_hist(hist_color, [(255, 0, 0), (0, 255, 0), (0, 0, 255)])

# 可视化
show_img_with_matplotlib(cv2.cvtColor(gray_image, cv2.COLOR_GRAY2BGR), "gray", 1)
show_img_with_matplotlib(image, "image", 4)
show_hist_with_matplotlib_gray(hist, "grayscale histogram (matplotlib)", 2, 'm')
show_hist_with_matplotlib_rgb(hist_color, "color histogram (matplotlib)", 3, ['b', 'g', 'r'])
show_img_with_matplotlib(gray_plot, "grayscale histogram (custom)", 5)
show_img_with_matplotlib(color_plot, "color histogram (custom)", 6)
复制代码

直方图的自定义可视化

相关链接

OpenCV直方图基本概念

OpenCV灰度直方图详解

收藏成功!
已添加到「」, 点击更改