使用OpenCV和Python计算图像的“色彩”

2020-09-29 10:34:00 浏览数 (1)

本文翻译自光头哥哥的博客:

【Computing image “colorfulness” with OpenCV and Python】,仅做学习分享。

原文链接:

代码语言:javascript复制
https://www.pyimagesearch.com/2017/06/05/computing-image-colorfulness-with-opencv-and-python/

本文灵感来自读者提问:是否见过用Python实现测量自然图像的色彩?我想使用它作为一个图像搜索引擎。通过给每个图像一个“色彩”量,使我可以根据它们的颜色对图像进行排序。

图像色彩有许多实际用途,包括评估压缩算法,评估给定相机传感器模块对色彩的敏感性,计算图像的“色彩品质”,或简单地创建一个批量图像可视化,以显示色彩斑斓的数据集的光谱图像。

今天我们将学习如何计算图像的色彩,然后,我们将使用OpenCV和Python实现色彩度量。 在实现了色彩度量之后,我们将根据颜色对给定的数据集进行排序,并使用我们上周创建的图像蒙太奇工具显示结果。

今天的博客文章有三个核心部分: 首先,我们将学习Hasler和Susstrunk论文中描述的色彩度量方法。

代码语言:javascript复制
https://infoscience.epfl.ch/record/33994/files/HaslerS03.pdf

然后,我们将在Python和OpenCV中实现图像色彩计算。

最后,我将演示如何将色彩度量标准应用到一组图像,并根据图像的“色彩”大小对其进行排序。我们将使用我们方便的图像蒙太奇示例进行可视化。

测量图象的色彩

在他们的论文中,Hasler和Susstrunk首先让20名非专业的参与者按照1-7的色彩等级给图片打分。这项调查是在一组84张图片上进行的。打分值为:

  • 1:不是彩色的
  • 2:稍微有色彩
  • 3:有色彩
  • 4:接近丰富多彩
  • 5:丰富多彩
  • 6:非常丰富多彩
  • 7:色彩斑斓炫目的

为了设定一个基线,作者给参与者提供了4张示例图像和它们对应的色彩值,从1到7。

通过一系列的实验计算,他们得出了一个与志愿者评估的结果相近的简单度量标准。 他们通过这些实验发现,用一个简单的对位色空间表示对数据集进行颜色计算,结果的平均值和标准差与调查数据的相似度达95.3%。

代码语言:javascript复制
https://engineering.purdue.edu/~bouman/ece637/notes/pdf/Opponent.pdf

我们现在推出他们的图像色彩度度量:

以上两个方程表示了对位色空间表示,其中R为红色,G为绿色,B为蓝色。在第一个方程中,rg是红色通道和绿色通道的差值。在第二个方程中,yb是代表红色和绿色通道和的一半减去蓝色通道。

接下来,在计算最终的色彩度量C之前,计算标准偏差和平均值。

我们将发现,这是计算图像色彩的一种非常有效和实用的方法。 接下来,我们将使用Python和OpenCV代码实现这个算法。

在OpenCV中实现图像色彩度量

现在我们对色彩度度量有了基本的了解,让我们使用OpenCV和NumPy来计算它。 在本节中,我们将:

  • 导入必要的Python包。
  • 解析命令行参数。
  • 循环我们数据集中的所有图像,并计算相应的色彩度量。
  • 根据色彩对图像进行排序。
  • 以蒙太奇的方式显示“色彩最丰富”和“色彩最差”的图像。

首先,创建一个名为colorfulness.py的新文件,并插入以下代码:

代码语言:javascript复制
# import the necessary packages
from imutils import build_montages
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2

接下来,我们将定义一个新函数image_colorfullness:

代码语言:javascript复制
def image_colorfulness(image):
  # split the image into its respective RGB components
  (B, G, R) = cv2.split(image.astype("float"))
  # compute rg = R - G
  rg = np.absolute(R - G)
  # compute yb = 0.5 * (R   G) - B
  yb = np.absolute(0.5 * (R   G) - B)
  # compute the mean and standard deviation of both `rg` and `yb`
  (rbMean, rbStd) = (np.mean(rg), np.std(rg))
  (ybMean, ybStd) = (np.mean(yb), np.std(yb))
  # combine the mean and standard deviations
  stdRoot = np.sqrt((rbStd ** 2)   (ybStd ** 2))
  meanRoot = np.sqrt((rbMean ** 2)   (ybMean ** 2))
  # derive the "colorfulness" metric and return it
  return stdRoot   (0.3 * meanRoot)

第1行定义image_colorfulness函数,它接受一个图像作为唯一的参数,并返回上面一节中描述的色彩度量。 注意:第3、6和9行使用了颜色空间,这超出了本文的范围。如果你有兴趣学习更多关于色彩空间的知识,请参考实用Python和OpenCV以及PyImageSearch Gurus课程。 为了将图像分解为红、绿、蓝(RGB)通道,我们调用cv2。在第3行分开。该函数以BGR顺序返回一个元组,因为这是图像的表示方式。

接下来我们使用一个非常简单的对位色彩空间。 在参考文献中,我们在第6行计算红-绿对手rg。这就是红色通道减去蓝色通道。 类似地,我们在第9行计算黄蓝色对手。在这个计算中,我们取红色 绿色通道和的一半,然后减去蓝色通道。这就产生了我们想要的对手yb。

在第12和13行,我们计算rg和yb的均值和标准偏差,并将它们存储在各自的元组中。 接下来,我们在第16行上合并rbStd(红蓝标准差)和ybStd(黄蓝标准差)。我们将每个数的平方相加,然后取平方根,将其存储为stdRoot。 类似地,我们通过将rbMean和ybMean分别平方,相加,然后在第17行取平方根来合并rbMean和ybMean。我们将这个值存储为meanRoot。 计算图像色彩的最后一步是添加stdRoot和1/3 meanRoot,然后返回值。

代码语言:javascript复制
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", required=True,
  help="path to input directory of images")
args = vars(ap.parse_args())

这里我们只需要一个命令行参数——images,它是驻留在您的计算机上的映像目录的路径。 现在让我们对数据集中的每一张图像进行循环,并计算出相应的色彩度量:

代码语言:javascript复制
# initialize the results list
print("[INFO] computing colorfulness metric for dataset...")
results = []
# loop over the image paths
for imagePath in paths.list_images(args["images"]):
  # load the image, resize it (to speed up computation), and
  # compute the colorfulness metric for the image
  image = cv2.imread(imagePath)
  image = imutils.resize(image, width=250)
  C = image_colorfulness(image)
  # display the colorfulness score on the image
  cv2.putText(image, "{:.2f}".format(C), (40, 40), 
    cv2.FONT_HERSHEY_SIMPLEX, 1.4, (0, 255, 0), 3)
  # add the image and colorfulness metric to the results list
  results.append((image, C))

第3行初始化一个列表results,它包含一个包含图像路径和图像相应颜色的2元组。

我们开始对数据集中的图像进行循环,这些图像是由命令行参数——第5行中的images指定的。

在循环中,我们首先在第8行加载图像,然后在第9行将图像调整为宽度=250像素,保持高宽比。

我们的image_colorfulness函数调用是在第10行进行的,其中我们提供了唯一的参数image,在C中存储了相应的colorfulness度量。

在第12和13行,我们使用cv2.putText在图像上绘制颜色度量。要了解这个函数的更多参数,请参阅OpenCV文档(2.4,3.0)。 在for循环的最后一行中,我们将元组(imagePath, C)附加到结果列表(第15行)。

如果你用这个作为图片搜索引擎,你可能想要显示你的结果。

这正是我们下一步要做的,我们将:

  • 根据图像对应的色彩度量对图像进行排序。
  • 确定25幅色彩最丰富和25幅色彩最差的图像。
  • 显示我们的结果在蒙太奇。

让我们现在开始处理这三个任务:

代码语言:javascript复制
# sort the results with more colorful images at the front of the
# list, then build the lists of the *most colorful* and *least
# colorful* images
print("[INFO] displaying results...")
results = sorted(results, key=lambda x: x[1], reverse=True)
mostColor = [r[0] for r in results[:25]]
leastColor = [r[0] for r in results[-25:]][::-1]

在第5行,我们使用Python Lambda表达式对结果进行逆序排序(根据颜色度量)。 然后在第6行,我们将25幅色彩最丰富的图像存储到一个列表中。 类似地,在第7行,我们加载颜色最差的图像,也就是结果列表中的最后25个图像。我们将这个列表反向,以便图像按升序显示。我们将这些图像存储为最低颜色。 现在,我们可以使用上周学过的build_montages函数来可视化mostColor和least astcolor图像。

代码语言:javascript复制
# construct the montages for the two sets of images
mostColorMontage = build_montages(mostColor, (128, 128), (5, 5))
leastColorMontage = build_montages(leastColor, (128, 128), (5, 5))

在第2行和第3行上分别构建了色彩最丰富和最不丰富的蒙太奇。这里我们指出,蒙太奇中的所有图像将被调整为128 x 128,图像将有5列5行。 现在我们已经组装好了蒙太奇,我们将在屏幕上显示每个蒙太奇。

代码语言:javascript复制
# display the images
cv2.imshow("Most Colorful", mostColorMontage[0])
cv2.imshow("Least Colorful", leastColorMontage[0])
cv2.waitKey(0)

在第2和3行,我们在一个单独的窗口中显示每个蒙太奇。

图像色彩计算结果

现在让我们让这个脚本工作并查看结果。今天我们将使用一个样本(1000张图像)的流行的UKBench数据集,一个包含日常对象的图像集合。

我们的目标是将图像按色彩最丰富和最不丰富进行排序。 要运行该脚本,启动一个终端并执行以下命令:

代码语言:javascript复制
$ python colorfulness.py --images ukbench_sample

请注意,我们的图像色彩度量是如何很好地将基本上是黑白的非彩色图像(左)与充满活力的“彩色”图像(右)分离开来的。

THE END

在今天的博客文章中,我们学习了如何使用Hasler和Susstrunk在2003年的论文《测量自然图像的色彩》中详细介绍的方法来计算图像的“色彩”。 他们的方法是基于对手颜色空间中像素强度值的均值和标准差。这个指标是通过检验实验指标和参与者在他们的研究中分配给图像的色彩之间的相关性而得出的。 然后,我们实现了图像色彩度量,并应用到UKBench数据集,进行结果展示。

0 人点赞