OpenCV(24) --- Найти и нарисовать контуры

OpenCV
OpenCV(24) --- Найти и нарисовать контуры

Что такое контур изображения

В предыдущем обнаружении края, хотя мы можем обнаружить информацию о крае, край является прерывистым, и обнаруженный край не является целым. Контур изображения отвечает за соединение ребер в единое целое для последующих вычислений.

Следует отметить, что контур изображения является очень важной информацией об особенностях.Благодаря операции с контуром изображения мы можем получить такую ​​информацию, как размер, положение и направление целевого изображения.

Найдите контуры изображения

Контур на изображении соответствует ряду точек, которые в той или иной форме представляют собой кривую на изображении. В OpenCV он предоставляет нам функцию cv2.findContours() для поиска контуров изображения и может возвращать контуры определенного представления в соответствии с параметрами.

Полное определение функции выглядит следующим образом:

def findContours(image, mode, method, contours=None, hierarchy=None):

изображение: исходное изображение, все ненулевые значения обрабатываются как 1, а все 0 значений остаются неизменными

режим: режим поиска контура

параметр значение
cv2.RETR_EXTERNAL Обнаружение только внешних контуров
cv2.RETR_LIST Для обнаруженных контуров не устанавливается иерархическая связь
cv2.RETR_CCOMP Обнаружьте все контуры и организуйте их в двухуровневую иерархию. Верхний слой — это внешняя граница, а нижний слой — внутренняя граница отверстия. Если во внутреннем отверстии есть связанный объект, то граница этого объекта все еще находится на верхнем слое.
cv2.RETR_TREE Построить схему иерархической древовидной структуры

метод: метод аппроксимации контуров

параметр значение
cv2.CHAIN_APPROX_NONE Сохраните все точки контура, а разница в позициях пикселей между двумя соседними точками не превышает 1
cv2.CHAIN_APPROX_SIMPLE Сжимайте элементы в горизонтальном направлении, вертикальном направлении и направлении линии объекта и сохраняйте только координаты конечной точки в этом направлении. Например, в крайних случаях прямоугольнику нужно всего 4 точки для хранения информации о контуре.
cv2.CHAIN_APPROX_TC89_L1 Стиль алгоритма аппроксимации с использованием цепочки teh_Chinl
cv2.CHAIN_APPROX_TC89_KCOS Стиль алгоритма аппроксимации с использованием цепочки teh_Chinl

контуры: возвращенные контуры. Например, на изображении есть 3 непересекающихся фигуры: круг, прямоугольник и вперед и назад. Тогда это список длины 3, то есть контуров 3, контуры[i][j] — это j-я точка i-го контура.

Конечно, контуры изображения не обязательно непересекающиеся.Если контуры нескольких фигур пересекаются друг с другом, образуется связь родитель-потомок.Contours[i] использует четыре элемента для описания иерархической связи контуров.

  1. Next: Индекс следующего контура
  2. Предыдущий: Индекс предыдущего контура
  3. First_Child: порядковый номер первого дочернего контура
  4. Parent: порядковый номер родительского контура

Если все вышеуказанные параметры пусты, то есть случай, когда контуры фигур, упомянутых выше, не пересекаются. и значение "-1".

Особо отметим, что иерархическая структура контура определяется режимом параметров, то есть при использовании разных режимов получаются разные номера контуров, и иерархия тоже разная.

иерархия: информация о топологии изображения

Его возвращаемое значение — 3 параметра: изображение, контуры и иерархия. В версии OpenCV4.X функция возвращает только два значения: контуры, иерархия.

Далее мы сосредоточимся на режиме параметров.

режим параметра

(1) cv2.RETR_EXTERNAL (обнаружение только внешнего контура)

1

Если теперь у нас есть наше изображение, как показано выше, когда мы используем параметр cv2.RETR_EXTERNAL, информация о топологии иерархии будет следующей:

[[ [1 -1 -1 -1] [-1 0 -1 -1] ]]

[1 -1 -1 -1] Эти четыре параметра соответствуют четырем элементам контуров соответственно.

Next1: То есть это означает следующий контур, где следующий контур 0 равен 1

Предыдущий-1: 0-й контур не имеет предыдущего контура

First_Child-1: 0 не имеет дочерних контуров

Parent-1: 0 также не существует родительского контура

[-1 0 -1 -1] соответствует изображению 1 и имеет следующие значения:

-1 : 1 контур не существует следующий контур

0: 1-й контур имеет предыдущий 0-й контур, поэтому он равен 0

-1 : 1 не существует подконтуров

-1:1 родительский контур также не существует

Его топология выглядит следующим образом:

11

(2) cv2.RETR_LIST (не устанавливать иерархическую связь для обнаруженного контура)

2

Предположим, мы используем исходное изображение, как показано выше, тогда значение иерархии равно:

[[ [1 -1 -1 -1] [2 0 -1 -1] [-1 1 -1 -1] ]]

[1 -1 -1 -1] Значение:

1: Следующий контур нулевого контура равен 1, поэтому возвращаем 1

-1: 0-й контур не имеет предыдущего контура, поэтому -1

-1 : 0 не существует подконтуров

-1:0 также не существует родительского контура

[2 0 -1 -1] Значение:

Следующий контур контура 2:1 равен 2, поэтому возвращаем 2

0: Контур перед первым контуром равен 0, поэтому значение равно 0

-1 : 1 не существует подконтуров

-1:1 родительский контур также не существует

[-1 1 -1 -1] Значение:

Контур -1:2 не имеет следующего контура, поэтому возвращаем -1

1: передний контур второго контура равен 1, поэтому значение равно 1

-1 : 2 не существует подконтуров

-1:2 также не существует родительского контура

Топология этой связи такова:

22

(3) cv2.RETR_CCOMP (построить два уровня контуров)

3

Когда параметр режима равен cv2.RETR_CCOMP, исходное изображение выглядит так, как показано выше, и его иерархическое значение:

[[ [1 -1 -1 -1] [-1 0 2 -1] [-1 -1 -1 1] ]]

[1 -1 -1 -1] означает следующее:

Следующий контур контура 1:0 равен 1, поэтому возвращаем 1

-1: 0-й контур не имеет предыдущего контура, поэтому значение равно -1.

-1 : 0 не существует подконтуров

-1:0 также не существует родительского контура

[-1 0 2 -1] означает следующее:

-1: 1 контур не имеет следующего контура, поэтому возвращаем -1

0: Контур перед первым контуром равен 0, поэтому значение равно 0

2 : Подконтур 1-го контура равен 2, поэтому значение равно 2.

-1: 1-й контур также не имеет родительского контура

[-1 -1 -1 1] означает следующее:

Контур -1:2 не имеет следующего контура, поэтому возвращаем -1

-1: Контур не существует до 2-го контура, поэтому значение равно -1.

-1: 2-й контур также не имеет подконтуров

1: Родительский контур второго контура равен 1, поэтому значение равно 1.

Его топология выглядит следующим образом:

33

(4) cv2.RETR_TREE (построение схемы иерархической древовидной структуры)

Когда граф все еще (3) граф, его значение режима равно cv2.RETR_TREE, а возвращаемое значение иерархии:

[[ [1 -1 -1 -1] [-1 0 2 -1] [-1 -1 -1 1] ]]

[1 -1 -1 -1] означает следующее:

Контур 1:0 Следующий контур равен 1, поэтому возвращаем 1

-1: Контур не существует до 0-го контура, поэтому значение равно -1.

-1: 0-й контур также не имеет подконтуров

-1: 0-й контур также не имеет родительского контура

[-1 0 2 -1] означает следующее:

-1: 1 контур не имеет следующего контура, поэтому возвращаем -1

0: Контур перед первым контуром равен 0, поэтому значение равно 0

2: Первый контур имеет подконтур 2, поэтому значение равно 2.

-1: у первого контура нет родительского контура

[-1 -1 -1 1] означает следующее:

Контур -1:2 не имеет следующего контура, поэтому возвращаем -1

-1: 2-й контур не имеет переднего контура, поэтому значение равно -1.

-1: для 2-го контура не существует подконтуров

1: Второй контур имеет родительский контур 1, значение равно 1

Топология также является (3)-графом.

нарисовать контур изображения

В OpenCV он предоставляет нам cv2.drawContours() для рисования контуров изображения, и его полное определение выглядит следующим образом:

def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None):

image: изображение контура, который будет нарисован

контуры: контуры, которые нужно нарисовать

контурIdx: индекс края, который необходимо нарисовать, -1 означает рисовать все, 0 и положительное число означает рисовать соответствующий контур.

цвет: цвет для рисования

толщина: кисть для рисования контура, значение "-1" для рисования сплошного контура

lineType: тип линии для рисования контура

иерархия: соответствует иерархической информации, выводимой функцией cv2.findContours()

maxLevel: управляет глубиной нарисованного уровня контура, если значение равно 0, рисуется только 0-й слой.

offset: параметр смещения, который представляет собой смещение нарисованного контура в определенной позиции.

Далее, давайте нарисуем контур изображения на практике Конкретный код выглядит следующим образом:

import cv2

img = cv2.imread("24.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

result = cv2.drawContours(img, contours, -1, (0, 0, 255), 5)

cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()

После запуска эффект следующий:

5

Однако это не конечная цель, цель получения контура состоит в том, чтобы разделить изображение, то есть что мне теперь делать, чтобы получить единый подграф из этих трех контуров? Перейти непосредственно к коду.

import cv2
import numpy as np

img = cv2.imread("24.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

result = []
for i in range(len(contours)):
    temp = np.zeros(img.shape, dtype=np.uint8)
    result.append(temp)
    result[i] = cv2.drawContours(result[i], contours, i, (0, 0, 255), 5)
    cv2.imshow(str(i), result[i])

cv2.waitKey()
cv2.destroyAllWindows()

После запуска мы можем разделить отдельные графики.

555

Контур изображения в сочетании с побитовым И для получения объекта переднего плана изображения

Помимо выделения чистых контуров изображения для машинного обучения, мы также можем получить объекты переднего плана на изображении. Здесь нам просто нужно заменить изображение и изменить последние несколько строк кода.

Конкретный код выглядит следующим образом:

import cv2
import numpy as np

img = cv2.imread("4.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

mask = np.zeros(img.shape, dtype=np.uint8)
mask = cv2.drawContours(mask, contours, -1, (255, 255, 255), -1)
cv2.imshow("MASK",mask)
result=cv2.bitwise_and(img,mask)
cv2.imshow("result",result)

cv2.waitKey()
cv2.destroyAllWindows()

После запуска эффект следующий:

66

Крайний левый - исходное изображение

Посередине сплошной контур персонажа, полученный из исходного изображения.

Крайний справа — это извлеченный человек на переднем плане.