Введение


Сегодня я расскажу о том как распознать контур нужного цвета с помощью python/ opencv такая задача часто встречается в робототехнике, и всяких автоматизациях.

С помощью предложенного решения можно например различать контур линии за которую не должен выезжать робот, или обьект для коптера. Такая задача может возникнуть если нужно например увидеть что в корзину положили апельсин.

image

Чему научимся


Изначально я предполагаю что у человека есть python ide(подойдет практически любое) и базовое знание питона.

Установим библиотеку OpenCV с помощью следующей команды:

pip install opencv-python

И numpy:

pip install numpy

Код


Добавим необходимые библиотеки:

import cv2
import numpy as np

Создадим обьект cup куда будет идти видео. 0 — камера дефолтная, 1 — кастомная.

cap = cv2.VideoCapture(0)

_, frame = cap.read()

считывает кадр. вместо _ может быть rate — туда пойдет fps камеры, но в данном случае я этим не пользуюсь.

А теперь давайте обработаем кадр для дальнейшего удобства. Уменьшим:


    frameresized = cv2.resize(frame, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # первеод в цветовой формат BGR2HSV
    hsv = cv2.blur(hsv, (5, 5))  # наложение  маски 
    mask = cv2.inRange(hsv, (89, 124, 73), (255, 255, 255))
    #кадр уже с маской
    lower_blue = np.array([38, 86, 0])
#нижняя граница необходимого цвета (в нашем случае голубого)

Рассмотрим подробнее функцию resize:

frame - кадр которой передается
fx - фактор размера по оси Х
fy - фактор размера по оси Y
interpolation - INTER_NEAREST - интерполяция до ближайшего соседа
INTER_LINEAR - билинейная интерполяция (используется по дефолту)
INTER_AREA - повторная выборка с использованием отношения площади пикселя. Это может быть предпочтительный метод для прореживания изображений  а когда изображение увеличина дает результат похожий на INTER_NEAREST method.
INTER_CUBIC - бикубическая интерполяция 4x4 клеток пикселей
INTER_LANCZOS4 - интерполяция Ланкоза  8x8 клеток пикселей

А теперь давайте на обработанном кадре распознаем контуры и отсортируем их:

 contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    counturs = sorted(contours, key=cv2.contourArea, reverse=True)

А теперь давайте рассмотрим findContours подробнее:

 cv.CHAIN_APPROX_NONE - найдет все точки границы контура(если контур сложный может неплохо так нагрузить комп)
cv.CHAIN_APPROX_SIMPLE - найдет точки границ линии - хорошо для распознования геометрии(знаков и тд)
cv.RETR_TREE - по сути просто извлекает точки  и не строит между ними никаких отношений
cv.RETR_EXTERNAL  - возвращает только самые старшие контуры в иерахии
cv.RETR_CCOMP - сторит 2 уровневую иерархию, те если у нас контур в контуре то он покажет то стариший будет на 1 , а младший на втором 
cv2.RETR_TREE - вернет дерево всех конутуров

Визуализация RETR_CCOMP:

image

Визуализация RETR_TREE:
image

И теперь нарисуем контуры которые нашли:

or contour in counturs:

        cv2.drawContours(frame, counturs[0], -1, (255, 0, 255), 3)
        cv2.imshow("Counturs", frame)  # рисует рокно с конурами
        #cv2.imshow("Mask", mask)
       # cv2.imshow("ret",ret)
        #cv2.imshow("blur",blurred_frame)
    key = cv2.waitKey(1) #ждем нажатия ESC 
    if key == 27:
          break

И по нажатию кнопки останавливаем чтение камеры и закрываем все окна:

cap.release()
cv2.destroyAllWindows()

Репозиторий


Спасибо за прочтение статьи.

Буду признателен если вы подпишитесь на мой канал в

телеграм


Upd — забавно что статья набрала примерно в 8 раз меньше просмотров чем ожидалось, но при этом примерно расчетное количество " добавлено в закладки" всего в два раза больше. Так и живем.