Описание
В этом уроке мы научим Raspberry Pi Zero W определять форму и цвет объектов в кадре
Видео
Нам понадобится
- 1x Raspberry Pi Zero W
- 1x Pi камера
- 1x Шлейф камеры
- 1x microSD карта
- 1x Источник питания USB
- 1x Провод USB-microUSB
Подключение
Для подробного пояснения подключения и установки библиотек обратитесь к предыдущему уроку
Cкрипт проекта
Откроем Thonny Python IDE и введём в него следующий скрипт.
# Импортируем библиотеки from PIL import ImageDraw, ImageFont, Image import numpy as np from imutils.video import VideoStream import imutils import cv2 from time import sleep # Загружаем шрифт FONT = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSansBold.ttf", 16) # минимальный размер пятна BLOBSIZE = 1000 # константы насыщенности и яркости S_MIN = 29 S_MAX = 255 V_MIN = 148 V_MAX = 255 # примерные значения тона для фильтров HUES = { "оранжевый": 10, "жёлтый": 40, "зелёный": 55, "синий": 100, "фиолетовый" : 130, "красный": 165, } # цвет подсвечивания контуров (красный, зелёный, синий) CONTCOLOR = (0, 255, 0) # толщина линии контура CTHICK = 2 # определяем размеры кадра FRAMESIZE = (640, 480) # создаём объект видео потока vs = VideoStream(src=0, usePiCamera=True, resolution=FRAMESIZE, framerate=32).start() # ждём окончания инициализации видеопотока sleep(2) # определяем функцию проверки углов контура def shapeDetect(c): # инициируем переменную названия фигуры и приблизительный контур shape = "" peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.04 * peri, True) # если 3 вершины - фигура треугольник if len(approx) == 3: shape = "треугольник" # если 4 - прямоугольник elif len(approx) == 4: # вычисляем прямоугольник в который вписывается фигура # и его отношение сторон (x, y, w, h) = cv2.boundingRect(approx) ar = w / float(h) # если отношение сторон не 1 - значит прямоугольник shape = "квадрат" if ar >= 0.95 and ar <= 1.05 else "прямоугольник" # иначе - круг else: shape = "круг" # возвращаем название фигуры return shape # входим в бесконечный цикл while True: # считываем кадр из потока image = vs.read() # создаём его копию для вывода img_copy = image.copy() # уменьшаем изображение для ускорения вычислений resized = imutils.resize(image, width=300) # вычисляем отношение оригинального изображения к уменьшенному ratio = image.shape[0] / float(resized.shape[0]) # проходим по всем тонам for hue in HUES: # вычисляем порог тона h_min = HUES[hue] - 10 h_max = HUES[hue] + 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(resized, cv2.COLOR_BGR2HSV) # создаём маску из границ цвета thres = cv2.inRange(hsv, lower_range, upper_range) thres = cv2.GaussianBlur(thres, (5, 5), 0) # вывод масок всех цветов #cv2.imshow(hue, thres) # раскомментируйте для вывода # находим контуры cnts = cv2.findContours( thres.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) cnts = imutils.grab_contours(cnts) # Следующие два цикла можно объединить в один если # нет необходимости выводить текст кириллицей. Для # вывода латиницы используйте cv2.putText() # проходим по всем контурам for c in cnts: # если площадь текущего контура мала... if cv2.contourArea(c) < BLOBSIZE: # переходим к следующему continue # приводим размеры контуров к исходным c = c.astype("float") c *= ratio c = c.astype("int") # выводим контуры на копию изображения cv2.drawContours(img_copy, [c], -1, CONTCOLOR, CTHICK) # Следующие манипуляции нужны для вывода текста кириллицей. # Конвертируем изображение из BGR в RGB img = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB) # создаём объект изображения PIL из массива пикселей im_pil = Image.fromarray(img) # создаём объект рисования draw = ImageDraw.Draw(im_pil) # проходим по всем контурам for c in cnts: # если площадь текущего контура мала... if cv2.contourArea(c) < BLOBSIZE: # переходим к следующему continue # получаем моменты изображения контура M = cv2.moments(c) cX = 0 cY = 0 # вычисляем из моментов координаты if M["m00"] != 0: cX = int((M["m10"] / M["m00"]) * ratio) cY = int((M["m01"] / M["m00"]) * ratio) # вычисляем название фигуры shapename = shapeDetect(c) shapename = hue + " " + shapename # выводим название фигуры draw.text((cX, cY), shapename, font=FONT) # конвертируем объект изображения PIL обратно в массив пикселей img_copy = np.asarray(im_pil) # конвертируем изображение из RGB в BGR img_copy = cv2.cvtColor(img_copy, cv2.COLOR_BGR2RGB) # выводим изображение cv2.imshow("Image", img_copy) # Если была нажата клавиша ESC k = cv2.waitKey(1) if k == 27: # прерываем выполнение цикла break # закрываем все окна cv2.destroyAllWindows() # останавливаем видео поток vs.stop()
Ссылки
- Машинное зрение на Raspberry Pi определение координат объектов выбранного цвета в кадре
- Raspberry Pi Zero W
- Pi камера
- Шлейф камеры
- microSD карта
- Источник питания USB
- Провод USB-microUSB
- Wiki: Установка и настройка Raspberry Pi
- Wiki: Raspberry Pi, настройка для работы в режиме Headless
- Wiki: Камера для Raspberry Pi
- Wiki: становка и использование модулей (библиотек) Python
Обсуждение