OpenCV 中的图像分割

Manav Narula 2023年1月30日
  1. 在 Python 中使用 opencv 进行图像分割
  2. 使用 GrabCut 算法使用 opencv 进行图像分割
  3. 使用 opencv 进行图像分割的颜色检测
  4. 结论
OpenCV 中的图像分割

图像处理是计算机视觉任务中的关键步骤。在 Python 中,我们可以使用 opencv 库来实现使用不同对象和方法的多种图像处理技术。

本教程将演示如何在 Python 中使用 opencv 执行图像分割。

在 Python 中使用 opencv 进行图像分割

图像分割是指将给定图像分成若干部分的过程。

我们添加了连接沿分段部分边界的点的曲线。这些曲线称为等高线。

图像分割在计算机视觉中非常有用,并且有许多现实生活中的应用。我们可以使用这种技术来分割图像的各个部分以对各种对象进行分类。

几种可用的方法可用于在 Python 中使用 opencv 进行图像分割。

每种图像分割技术不同的主要方法通常是基于分割图像的标准。我们可以基于检测一些颜色、预定义算法(如分水岭算法)、边缘检测,甚至根据用户输入选择分割部分来进行图像分割。

我们将在以下部分讨论其中一些方法。

使用 GrabCut 算法使用 opencv 进行图像分割

此方法需要用户使用鼠标和键盘进行交互。内置的 opencv 库具有可以从鼠标和键盘读取用户输入的对象和方法。

GrabCut 算法是一种非常简单且有用的图像分割工具。在这种技术中,我们使用用户输入来选择给定图像的某个区域。

该算法自动检测分割部分的前景和背景,我们可以将它们显示出来。

我们可以使用 opencv 库中的 grabCut() 函数来实现该算法。我们将在此函数中将图像与所选区域的框一起传递以进行图像分割。

有关示例,请参见以下代码。

import cv2
import numpy as np


def algo_grabcut(img, bounding_box):
    seg = np.zeros(img.shape[:2], np.uint8)
    x, y, width, height = bounding_box
    seg[y : y + height, x : x + width] = 1
    background_mdl = np.zeros((1, 65), np.float64)
    foreground_mdl = np.zeros((1, 65), np.float64)

    cv2.grabCut(
        img, seg, bounding_box, background_mdl, foreground_mdl, 5, cv2.GC_INIT_WITH_RECT
    )

    mask_new = np.where((seg == 2) | (seg == 0), 0, 1).astype("uint8")
    img = img * mask_new[:, :, np.newaxis]
    cv2.imshow("Output", img)


def box_draw(click, x, y, flag_param, parameters):
    global x_pt, y_pt, drawing, topleft_pt, bottomright_pt, img

    if click == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        x_pt, y_pt = x, y

    elif click == cv2.EVENT_MOUSEMOVE:
        if drawing:
            topleft_pt, bottomright_pt = (x_pt, y_pt), (x, y)
            image[y_pt:y, x_pt:x] = 255 - img[y_pt:y, x_pt:x]
            cv2.rectangle(image, topleft_pt, bottomright_pt, (0, 255, 0), 2)

    elif click == cv2.EVENT_LBUTTONUP:
        drawing = False
        topleft_pt, bottomright_pt = (x_pt, y_pt), (x, y)
        image[y_pt:y, x_pt:x] = 255 - image[y_pt:y, x_pt:x]
        cv2.rectangle(image, topleft_pt, bottomright_pt, (0, 255, 0), 2)
        bounding_box = (x_pt, y_pt, x - x_pt, y - y_pt)

        algo_grabcut(img, bounding_box)


drawing = False
topleft_pt, bottomright_pt = (-1, -1), (-1, -1)

img = cv2.imread("img4.jpg")
img = cv2.resize(img, (500, 500))
image = img.copy()
cv2.namedWindow("Frame")
cv2.setMouseCallback("Frame", box_draw)

while True:
    cv2.imshow("Frame", image)
    ch = cv2.waitKey(1)
    if ch == 32:
        break

cv2.destroyAllWindows()

输出:

抓取算法的选定区域

使用 GrabCut 算法分割图像

让我们了解上面示例中发生的情况。

box_draw() 函数读取用户与鼠标的交互以选择图像分割区域。盒子和图像被传递给 algo_grabcut() 函数,该函数获取图像并为分割图像创建二进制掩码。

我们使用这个掩码并显示分段部分的前景。

使用 opencv 进行图像分割的颜色检测

在 Python 中,我们可以使用 opencv 进行颜色检测。图像有不同的颜色空间来表示其颜色。

对于我们的例子,我们将使用 HSV 颜色空间来确定给定颜色的范围。

我们将使用不同的颜色进行图像分割。我们为给定颜色创建一个范围,并使用 opencv 库中的 inRange() 函数来检测与该颜色匹配的对象。

这将返回一个二进制掩码。然后我们细化这个掩码并将轮廓添加到这个检测到的部分。

如前所述,轮廓是分段部分边界上的曲线。我们将使用 findContours() 函数使用创建的蒙版查找边界,然后使用 drawContours() 函数绘制这些轮廓。

请参阅下面的代码。

import cv2
import numpy as np

img = cv2.imread("img4.jpg")
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
bound_lower = np.array([36, 25, 25])
bound_upper = np.array([70, 255, 255])

mask_green = cv2.inRange(hsv_img, bound_lower, bound_upper)
kernel = np.ones((7, 7), np.uint8)

mask_green = cv2.morphologyEx(mask_green, cv2.MORPH_CLOSE, kernel)
mask_green = cv2.morphologyEx(mask_green, cv2.MORPH_OPEN, kernel)

seg_img = cv2.bitwise_and(img, img, mask=mask_green)
contours, hier = cv2.findContours(
    mask_green.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
output = cv2.drawContours(seg_img, contours, -1, (0, 0, 255), 3)

cv2.imshow("Result", seg_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

输出:

使用颜色检测进行图像分割

在上面的代码中,我们从给定的图像中分割出绿色对象。首先,我们使用 cvtColor 函数将图像转换为 HSV 颜色空间。

然后我们继续创建存储检测到的颜色的蒙版。我们也从这个面具中删除了任何不需要的噪音。

然后我们将轮廓绘制到检测到的段并显示它。waitKey() 函数可防止图像窗口自动关闭。

它等待用户按下某个键然后关闭它。

结论

在本教程中,我们讨论了使用 Python 的 opencv 库进行图像分割。我们还为此实施了一些技术,尽管还有更多可能。

我们讨论了图像分割背后的基础知识,以及每种方法的方法和最终结果。

我们详细讨论了两种方法。首先,我们实现了 GrabCut 算法。

在该算法中,用户选择他想要用于分割的区域。从这部分,我们检测前景对象并显示它们。

在第二种技术中,我们使用了颜色检测。我们检测到绿色物体。

在这种类型的分割中,我们将图像转换为给定的颜色空间,并使用该模型的颜色范围来使用 inRange() 函数检测颜色。我们使用这个掩码进行图像分割并在边缘周围绘制轮廓。

作者: Manav Narula
Manav Narula avatar Manav Narula avatar

Manav is a IT Professional who has a lot of experience as a core developer in many live projects. He is an avid learner who enjoys learning new things and sharing his findings whenever possible.

LinkedIn