Описание
В этом уроке мы подключим Pi камеру к Raspberry Pi Zero W и разберёмся как использовать библиотеку opencv-python
для определения координат объектов выбранного цвета в кадре.
Машинное зрение — это применение компьютерного зрения для промышленности и производства, и в этом видео уроке мы рассмотрим частный случай такого зрения, в котором будем определять координаты положения яркого контрастного объекта в поле видимости камеры Распберри. Определение группы пикселей одного цвета не слишком сложная задача для компьютеров, поэтому для её осуществление возьмём Raspberry Pi Zero W с относительно не высокими вычислительными способностями.
Видео
Нам понадобится
- 1x Raspberry Pi Zero W
- 1x Pi камера
- 1x Шлейф камеры
- 1x microSD карта
- 1x Источник питания USB
- 1x Провод USB-microUSB
Подключение
Руководствуясь статьёй на нашей Wiki, настроим Raspberry на работу через VNC.
После настройки подключим камеру:
Подключим питание:
Далее подключимся к Raspberry через VNC, как в статье выше
Установка библиотек
Установим библиотеки для работы с компьютерным зрением.
Откроем эмулятор терминала
Для работы скрипта нам потребуются библиотеки opencv-python
, imutils
, numpy
и libatlas-base-dev
. Первые три мы установим при помощи pip, а последнюю при помощи apt.
Введём в окно терминала следующую строку и нажмём <enter>
на клавиатуре:
pip3 install opencv-python imutils numpy
Далее установим libatlas-base-dev
таким же образом, только после нажатия <enter>
потребуется ввести пароль суперпользователя (по умолчанию raspberry
, пароль никак не отображается во время ввода):
sudo apt install libatlas-base-dev
Cкрипт проекта
Откроем Thonny Python IDE и введём в него следующий скрипт.
import cv2 import numpy as np from imutils.video import VideoStream import imutils from time import sleep # название окна подстройки WINDOWNAME = "Настройка тона" # минимальный размер контуров пятна BLOBSIZE = 1500 # константы насыщенности и яркости S_MIN = 29 S_MAX = 255 V_MIN = 148 V_MAX = 255 # цвет прямоугольника (B, G, R) RECTCOLOR = (0, 255, 0) # толщина линии прямоугольника RTHICK = 2 # определяем функцию проверки размера пятна def checkSize(w, h): if w * h > BLOBSIZE: return True else: return False # определяем пустую функцию def empty(a): pass # определяем размеры кадра frameSize = (320, 240) # создаём объект видео потока vs = VideoStream(src=0, usePiCamera=True, resolution=frameSize, framerate=32).start() # ждём окончания инициализации видеопотока sleep(2) # создаём окно с ползунком cv2.namedWindow(WINDOWNAME) cv2.resizeWindow(WINDOWNAME, 500, 100) cv2.createTrackbar("Hue", WINDOWNAME, 0, 180, empty) while True: # получаем кадр изображения image = vs.read() # получаем максимальный и минимальный тон из значения ползунка h_min = cv2.getTrackbarPos("Hue", WINDOWNAME) - 10 h_max = cv2.getTrackbarPos("Hue", WINDOWNAME) + 10 # определяем границы цвета в HSV lower_range = np.array([h_min, S_MIN, V_MIN]) upper_range = np.array([h_max, S_MAX, V_MAX]) # конвертируем изображение в HSV hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # создаём маску выбранного цвета thresh = cv2.inRange(hsv, lower_range, upper_range) # побитово складываем оригинальную картинку и маску bitwise = cv2.bitwise_and(image, image, mask=thresh) # показываем картинку маски цвета cv2.imshow("bitwise", bitwise) # удаляем цвет из маски gray = cv2.cvtColor(bitwise, cv2.COLOR_BGR2GRAY) # ищем контуры в картинке contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # если контуры найдены... if len(contours) != 0: # выводим найденные контуры #cv2.drawContours(image, contours, -1, 255, 1) # находим контуры бОльшего размера c = max(contours, key = cv2.contourArea) # получаем координаты прямоугольника, в который они вписаны x,y,w,h = cv2.boundingRect(c) # если прямоугольник достаточного размера... if checkSize(w, h): # выводим его cv2.rectangle(image, (x, y), (x+w, y+h), RECTCOLOR, RTHICK) # Показываем картинку с квадратом выделения cv2.imshow("Image", image) # Если была нажата клавиша ESC k = cv2.waitKey(1) if k == 27: # прерываем выполнение цикла break # закрываем все окна cv2.destroyAllWindows() # останавливаем видео поток vs.stop()
Обсуждение