使用 OpenCV 进行图像轮廓分析

作者:微信公众号:【架构师老卢】
5-4 14:38
65

概述:“轮廓图像”意味着生成边界,这些边界将具有相似颜色或强度的连续区域包围起来。在计算机科学中,等值线通常由定义这些边界_的点列表_表示。轮廓广泛用于计算机视觉应用,包括对象检测;图像分割;以及形状描述符(如面积和质心)的计算。在这个_快速成功数据科学_项目中,我们将使用世界上最流行的计算机视觉库 OpenCV 在月球图像上生成轮廓。我们的目标是创造一些有趣的艺术,但相同的一般过程用于更复杂的应用程序。安装库对于此项目,我们将使用 NumPy、Matplotlib 和 OpenCV 库。OpenCV 在很大程度上依赖于 NumPy 数组,我们可以使用 Matplotlib 作为一种快速简单的方法来

“轮廓图像”意味着生成边界,这些边界将具有相似颜色或强度的连续区域包围起来。在计算机科学中,等值线通常由定义这些边界_的点列表_表示。

轮廓广泛用于计算机视觉应用,包括对象检测;图像分割;以及形状描述符(如面积和质心)的计算。

在这个_快速成功数据科学_项目中,我们将使用世界上最流行的计算机视觉库 OpenCV 在月球图像上生成轮廓。我们的目标是创造一些有趣的艺术,但相同的一般过程用于更复杂的应用程序。

安装库

对于此项目,我们将使用 NumPyMatplotlib 和 OpenCV 库。OpenCV 在很大程度上依赖于 NumPy 数组,我们可以使用 Matplotlib 作为一种快速简单的方法来可视化轮廓图像(尽管 OpenCV 确实包含直接可视化图像的方法)。

您可以在前面的链接中找到 NumPy 和 Matplotlib 的安装说明,并在此处找到 OpenCV 的安装说明。

作为 Anaconda 用户,我一直很难使用 conda 安装 OpenCV。它似乎安装正确,但是当我尝试将库导入脚本时,我总是遇到错误。为了避免这种情况,我创建了一个新的 conda 环境,使用 conda 安装除了 OpenCV _之外_的所有内容,然后,作为最后一步,使用 pip 安装 OpenCV:

pip install opencv-python

注意:如果您对将 conda 与 pip 混合使用感到好奇,请参阅我文章末尾的附录,介绍 Conda 环境

月球图像

这是我们将使用的月球图像。这是来自 Unsplash 的公共图像,我稍微旋转了一下。我还使用Microsoft的Paint 3D照片编辑器将黑色背景替换为白色。

要使用该图像,请右键单击它并选择 。将其命名为“moon.jpg”并将其保存在包含笔记本或 Python 脚本的文件夹中,这样我们就不必处理路径名了。Save image as

守则

以下代码是在 JupyterLab 的单个单元格中编写的。它加载图像,将其转换为灰度,平滑,生成轮廓,然后在原始图像的透明版本上绘制轮廓。

导入库并处理图像

在检测轮廓之前,通常最好进行一些预处理以增强特征并减少噪声。最常见的步骤是将彩色图像转换为_灰度_,并使用高斯模糊等滤镜平滑生成的图像。幸运的是,OpenCV 提供了执行这些任务的方法。

下面是预处理代码。详细解释如下。

import numpy as np  
import matplotlib.pyplot as plt  
import cv2 as cv  
  
# Use these constants to tune your results:  
SMOOTHING_KERNEL = (11, 11)  # Must be odd numbers.  
NUM_CONTOURS = 8  
ALPHA = 0.6    
  
# Load the moon image:  
IMG_GRAY = cv.imread('moon.jpg', cv.IMREAD\_GRAYSCALE)  
  
# Smooth the image using Gaussian blur:  
smoothed_img = cv.GaussianBlur(IMG_GRAY,   
                               SMOOTHING_KERNEL,   
                               sigmaX=0)

导入库后,我们分配三个常量来“调整”轮廓和最终图像。第一个 ,表示 OpenCV 类的输入。SMOOTHING_KERNELGaussianBlur()

_模糊_会降低图像的清晰度。此过程使用由称为_内核_的方阵组成的过滤器。该内核在图像中逐渐滑动,并针对其中的所有像素计算其强度值的加权平均值。然后,它将矩阵中中心像素的值替换为此平均值。这将删除极值并创建“更平滑”的图像。

内核参数是宽度和高度的元组,以像素为单位。由于平均值位于内核_的中心_像素中,因此内核维度应始终为正数和_奇数_。所以,有效,但没有。(要了解有关图像平滑的更多信息,请访问此 OpenCV 网站)。(5, 5)(2, 2)

下一个常量 NUM_CONTOURS 表示 OpenCV 方法的_级别数_参数,我们稍后将对此进行讨论。contour()

该参数指定用于定义等值线的强度级别。如果输入单个值,例如 8,OpenCV 会自动将图像的强度范围划分为 8 个间隔。levels

您也可以手动指定间隔。您可以将值作为参数传递,而不是像我们在这里所做的那样使用常量值。例如,将导致在强度级别 50、100 和 150 下绘制轮廓。levels=[50, 100, 150]

最终常数 ,决定了将在其上绘制轮廓的初始图像的透明度。该值越低,图像越透明。ALPHA

如前所述,如果结果看起来太嘈杂或太稀疏,您可以使用这三个常量来“微调”结果。

接下来,我们使用 OpenCV 的方法和参数以灰度加载图像。然后,我们使用类对其进行平滑处理,向其传递图像、内核大小和标准差值 ()。使用 for 最后一个参数告诉 OpenCV 自动估计该值。imread()IMREAD_GRAYSCALEGuassianBlur()sigmaX0

绘制图像

现在我们已准备好生成轮廓图像并使用 Matplotlib 绘制它。

# Create a 2D Matplotlib figure:  
fig, ax = plt.subplots()  
  
# Set the contour levels:  
contour_levels = np.linspace(0, 255, NUM_CONTOURS)  
  
# Create the contour plot:  
contour_plot = ax.contour(smoothed_img,   
                          levels=contour_levels,   
                          colors='black')  
  
# Add the smoothed image:  
ax.imshow(smoothed_img,   
          cmap='gray',   
          alpha=ALPHA)  
  
# Customize the plot settings:  
ax.set_title('Smoothed Moon Image with Contours')  
ax.set_axis_off()  
  
# fig.savefig('moon_contour_medium.png', dpi=500)  
plt.show()

首先,我们创建 Matplotlib 和对象来保存绘图。接下来,我们确定用于每个轮廓的阈值。为此,我们调用 NumPy 的方法,该方法返回一个 NumPy 数组,其最大可能强度范围 (0–255) 细分为 8 个值,由 NUM_CONTOURS 常量指定。figure axes linspace()

然后,我们在对象上调用 OpenCV 方法,向其传递平滑图像、数组和线条颜色。在这一点上,我们只有一个带有黑色轮廓的白色显示器。为了赋予它一些生命,我们调用 Matplotlib 方法 ,向它传递平滑图像、Matplotlib 颜色图 () 和一个参数以防止它压倒轮廓。contour()axcontour_levelsimshow()axcmap='gray'alpha

最后,我们添加一个标题并关闭 x 轴和 y 轴。结果如下:

增加内核大小将使图像更加平滑,并产生更简单的轮廓图案。以下是使用 23 x 23 像素 () 的内核的结果,并且:SMOOTHING_KERNEL = (23, 23)ALPHA=0.7

用 23x23 内核平滑的轮廓月球图像(作者提供)

色彩图的乐趣

我们的“月球素描”让我想起了《星球大战:行星和卫星基本指南》一书中的插图。事实上,通过更改底层的颜色图,您可以轻松地将月球变成一个有趣的科幻或幻想世界。下面是一个示例,我们将方法中的参数从cmap imshow()grayterrain.

带有地形彩色地图和黑色背景的轮廓月亮(作者)

月球上的深灰色区域被称为_maria_(拉丁语为“海洋”),因为古人认为它们类似于充满水的盆地。通过更改代码中的单个参数,我们可以想象如果玛丽亚真的是海洋,而月球是一个类似于地球的活生生的世界,月球会是什么样子。

通过使用反转的颜色贴图,我们可以创建一个像阿拉基斯或塔图因一样的沙漠世界:Reds

Matplotlib 带有数十种有趣的颜色映射。您可以在此站点上找到它们。

说到沙漠行星,您可以在火星上使用轮廓。这是根据美国国家航空航天局(NASA在公共领域的图像拍摄的著名的水手谷(Mariner Valley)的视图。

当然,任何图像都可以被勾勒出来(尽管并不总是很好)。你认识这个家伙吗:

局限性

轮廓算法最适合高质量图像,其中物体的边缘被清晰定义。当背景繁忙且前景和背景对象(或重叠对象)具有相似的值时,它们往往会失败或返回不令人满意的结果。

预处理技术,如灰度转换和模糊,可以改善结果,但它们只能到此为止。幸运的是,OpenCV 和其他 Python 库提供了额外的工作流程来处理低对比度图像等问题。虽然这些超出了本文的讨论范围,但您可以在此处查看示例工作流。

OpenCV 还包含对轮廓图像_进行后_处理的功能。这包括提取和平滑轮廓以及删除包围小区域的轮廓的方法。

在本文中,我们研究了一种使用 Python 最流行的计算机视觉库 OpenCV 来勾勒图像轮廓的简单快速方法。这些等值线代表了不同强度区域之间的边界。

为了放置这些等值线,我们选择了称为“等值线级别”的阈值,方法是指定最终图像中我们想要_的等值线数量_,并让算法选择强度值。或者,我们可以提供一个特定强度值_的列表_,我们想要在其中放置轮廓。

图像轮廓是计算机视觉中一个非常重要的过程,我们几乎没有触及表面。我们在这里使用等高线来“勾勒”月球和火星,并创造想象世界的愿景。但应用范围更远,从识别肿瘤到识别人脸,再到实现自动驾驶汽车。