Главная Новости

OpenCV на python: выделение контуров

Опубликовано: 27.08.2018

видео OpenCV на python: выделение контуров

Open CV contour Testing

Освоив работу с цветовыми фильтрами приступим к изучению ещё одного важного инструмента машинного зрения — функции выделения контуров.



Контур объекта — это его видимый край, который отделяет объект от фона. В действительности, большинство методов анализа изображений работают именно с контурами, а не с пикселями как таковыми. Совокупность методов работы с контурами называется контурным анализом .

Возьмём в качестве подопытного изображения что-нибудь такое, где есть ярко выраженные вложенные контуры, какой-нибудь диск. И попробуем применить к нему стандартные функции OpenCV для поиска и визуализации контуров объектов.


Компьютерное зрение

1. Функция OpenCV для поиска контуров findContours

В OpenCV для поиска контуров имеется функцией findContours , которая имеет вид:

findContours( кадр, режим_группировки, метод_упаковки [, контуры[, иерархия[, сдвиг]]])

кадр — должным образом подготовленная для анализа картинка. Это должно быть 8-битное изображение. Поиск контуров использует для работы монохромное изображение, так что все пиксели картинки с ненулевым цветом будут интерпретироваться как 1, а все нулевые останутся нулями. На уроке про  поиск цветных объектов  была точно такая же ситуация.


Распознование объектов по шаблону OpenCV 2.4 (Raspberry Pi)

режим_группировки — один из четырех режимов группировки найденных контуров:

CV_RETR_LIST — выдаёт все контуры без группировки; CV_RETR_EXTERNAL — выдаёт только крайние внешние контуры. Например, если в кадре будет пончик, то функция вернет его внешнюю границу без дырки. CV_RETR_CCOMP — группирует контуры в двухуровневую иерархию. На верхнем уровне — внешние контуры объекта. На втором уровне — контуры отверстий, если таковые имеются. Все остальные контуры попадают на верхний уровень. CV_RETR_TREE — группирует контуры в многоуровневую иерархию.

метод_упаковки — один из трёх методов упаковки контуров:

CV_CHAIN_APPROX_NONE — упаковка отсутствует и все контуры хранятся в виде отрезков, состоящих из двух пикселей. CV_CHAIN_APPROX_SIMPLE — склеивает все горизонтальные, вертикальные и диагональные контуры. CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS — применяет к контурам метод упаковки (аппроксимации) Teh-Chin.

контуры  — список всех найденных контуров, представленных в виде векторов;

иерархия — информация о топологии контуров. Каждый элемент иерархии представляет собой сборку из четырех индексов, которая соответствует контуру[i]:

иерархия[i][0] — индекс следующего контура на текущем слое; иерархия[i][1] — индекс предыдущего контура на текущем слое: иерархия[i][2] — индекс первого контура на вложенном слое; иерархия[i][3] — индекс родительского контура.

сдвиг — величина смещения точек контура.

2. Функция OpenCV для отображения контуров drawContours

Полученные с помощью функции  findContours контуры хорошо бы каким-то образом нарисовать в кадре. Машине это не нужно, зато нам это поможет лучше понять как выглядят найденные алгоритмом контуры. Поможет в этом ещё одна полезная функция — drawContours .

drawContours( кадр, контуры, индекс, цвет[, толщина[, тип_линии[, иерархия[, макс_слой[, сдвиг]]]]])

кадр  — кадр, поверх которого мы будем отрисовывать контуры;

контуры — те самые контуры, найденные функцией findContours;

индекс — индекс контура, который следует отобразить. -1 — если нужно отобразить все контуры;

цвет — цвет контура;

толщина — толщина линии контура;

тип_линии — тип соединения точек вектора;

иерархия — информация об иерархии контуров;

макс_слой — индекс слоя, который следует отображать. Если параметр равен 0, то будет отображен только выбранный контур. Если параметр равен 1, то отобразится выбранный контур и все его дочерние контуры. Если параметр равен 2, то отобразится выбранный контур, все его дочерние и дочерние дочерних! И так далее.

сдвиг  — величина смещения точек контура.

3. Программа поиска и отображения контуров

Теперь напишем программу, которая будет искать контуры предметов в кадре с пончиком. Прежде всего, следует подготовить изображение. Помним, что функция findContours  работает с монохромной картинкой, и нам потребуется обработать наш пончик цветовым фильтром , чтобы сам пончик стал абсолютно белым, а фон — чёрным.

import sys import numpy as np import cv2 as cv # параметры цветового фильтра hsv_min = np.array((2, 28, 65), np.uint8) hsv_max = np.array((26, 238, 255), np.uint8) if __name__ == '__main__': print(__doc__) fn = 'image.jpg' # путь к файлу с картинкой img = cv.imread(fn) hsv = cv.cvtColor( img, cv.COLOR_BGR2HSV ) # меняем цветовую модель с BGR на HSV thresh = cv.inRange( hsv, hsv_min, hsv_max ) # применяем цветовой фильтр # ищем контуры и складируем их в переменную contours _, contours, hierarchy = cv.findContours( thresh.copy(), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # отображаем контуры поверх изображения cv.drawContours( img, contours, -1, (255,0,0), 3, cv.LINE_AA, hierarchy, 1 ) cv.imshow('contours', img) # выводим итоговое изображение в окно cv.waitKey() cv.destroyAllWindows()

В результате работы программы мы получим пончики с выделенными внешними и вложенными границами.

Теперь разберёмся как параметры кадр и макс_слой влияют на отображаемые контуры.

Алгоритм  findContours нашел у пончиков четыре замкнутых контура. Если вывести иерархию в консоль с помощью обычного print, то мы увидим следующую таблицу:

[ 2 -1 1 -1] - внешний контур первого бублика [-1 -1 -1 0] - дырка первого бублика [-1 0 3 -1] - внешний контур второго бублика [-1 -1 -1 2] - дырка второго бублика

На верхнем уровне иерархии имеется два контура. Эти контуры легко вычислить по значению четвертой величины = -1, которая отвечает за указатель на родительский контур. Также имеются два вложенных контура. Один вложен в первый внешний контур, а второй вложен во второй внешний контур.

В программе параметр  контур = -1 , следовательно drawContours должна вывести все четыре найденных контура. Но есть ещё второй параметр макс_слой , как он будет влиять на вывод? Посмотрим его поведение на анимации:

Примечание! На верхнем бегунке contour = 0, хотя мы почему-то говорим про -1.  Это не ошибка! На самом деле в этом положении бегунка в функцию поступает параметр контур = -1 . Это несоответствие возникло из-за особенностей бегунка в OpenCV — он не может принимать отрицательные значения, поэтому в программе из значения бегунка contour каждый раз принудительно вычитается единица.

Вернёмся к параметрам.

При  макс_слой = 0 отображается первый попавшийся контур на верхнем уровне иерархии. Такая комбинация параметров вообще нетипичная  и бесполезная, она эквивалентна комбинации контур = 0 , макс_слой=0 .

При макс_слой = 1 отобразятся все контуры на самом верхнем уровне иерархии — это уже полезно. Так мы сможем увидеть все бублики в кадре.

Наконец, при  макс_слой = 2  отобразятся контуры на верхнем уровне и все контуры на следующем уровне — то есть дырки.

Теперь наоборот, зафиксируем  макс_слой = 0 , и будем менять контур  в диапазоне от 0 до 3.

Тут опять видна путающая всех первая комбинация: контур = -1, макс_слой = 0, игнорируем её. Но затем всё становится логично. Как и ожидалось, мы просто перебираем контуры на всех слоях, внутренних и внешних.

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

import sys import numpy as np import cv2 as cv hsv_min = np.array((2, 28, 65), np.uint8) hsv_max = np.array((26, 238, 255), np.uint8) if __name__ == '__main__': fn = 'donuts.jpg' img = cv.imread(fn) hsv = cv.cvtColor( img, cv.COLOR_BGR2HSV ) thresh = cv.inRange( hsv, hsv_min, hsv_max ) _, contours0, hierarchy = cv.findContours( thresh.copy(), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) index = 0 layer = 0 def update(): vis = img.copy() cv.drawContours( vis, contours0, index, (255,0,0), 2, cv.LINE_AA, hierarchy, layer ) cv.imshow('contours', vis) def update_index(v): global index index = v-1 update() def update_layer(v): global layer layer = v update() update_index(0) update_layer(0) cv.createTrackbar( "contour", "contours", 0, 7, update_index ) cv.createTrackbar( "layers", "contours", 0, 7, update_layer ) cv.waitKey() cv.destroyAllWindows()

Заключение

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

На следующем уроке начнем с простого — займемся поиском прямоугольников в кадре и вычислением угла их наклона.

Рекомендации по покупке авто
рунета
Автомобильные чехлы по индивидуальному заказу
rss