Автоматизированное визуальное отслеживание объектов на Raspberry Pi и OpenCV
Система панорамного/наклонного сервопривода, автоматически отслеживающая цветные объекты с помощью компьютерного зрения.
История
Введение
В предыдущем туториале мы научились управлять панорамно/наклонным сервоприводом для позиционирования камеры Raspberry Pi. Сегодня расширим эту установку, чтобы камера могла автономно отслеживать цветной объект.
Это мой первый практический опыт с OpenCV, и я уже влюбился в эту открытую библиотеку компьютерного зрения.
OpenCV бесплатен для академического и коммерческого использования, предлагает интерфейсы C++, C, Python, Java и работает на Windows, Linux, macOS, iOS, Android. В этой серии мы фокусируемся на Raspberry Pi (Raspbian) и Python, потому что OpenCV построен для вычислительной эффективности и приложений реального времени — именно то, что нужно для физических вычислительных проектов.
Шаг 1: BOM — Список материалов
Основные детали:
- Raspberry Pi V3 – US$ 32.00
- 5 MP 1080p OV5647 Mini Camera Video Module – US$ 13.00
- TowerPro SG90 9G 180-градусный микросервопривод (2 шт.) – US$ 4.00
- Мини панорамная/наклонная платформа для камеры с антивибрационным монтажом и 2 сервоприводами (*) – US$ 8.00
- Красный светодиод
- Резистор 220 Ом
- Резистор 1 кОм (2 шт.) — опционально
- Разное: металлические детали, резинки и т.д. (если собираете свой панорамный механизм)
(*) Можно купить готовую панорамную платформу с сервоприводами или собрать свою.
Шаг 2: Установка OpenCV 3
На Raspberry Pi V3 под актуальным Raspbian Stretch самым надёжным способом является следование туториалу Адриана Розброука (Raspbian Stretch: Install OpenCV 3 + Python on your Raspberry Pi). Он ведёт через сборку OpenCV из исходников и настройку выделенного виртуального окружения Python.
После завершения туториала активируйте виртуальное окружение и подтвердите установку:
source ~/.profile
workon cv
python
import cv2
print(cv2.__version__)
Должна появиться версия 3.3.0 или новее. Вывод подтверждает, что OpenCV готов к использованию внутри виртуального окружения cv.
Шаг 3: Проверка камеры
С установленным OpenCV проверьте, что PiCamera стримит корректно. Запустите следующий скрипт (или скачайте simpleCamTest.py):
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, -1) # Вертикальный флип при необходимости
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Нажмите q или Ctrl+C для выхода. Успешный запуск показывает цветной и grayscale потоки.
Шаг 4: Детекция цвета в Python с OpenCV
OpenCV работает в HSV (Hue, Saturation, Value) пространстве, лучше соответствующем человеческому восприятию цвета. Для детекции конкретного цвета сначала определите его BGR-значения, затем конвертируйте в HSV и установите нижние/верхние границы.
Пример: отслеживание жёлтого объекта. С помощью пипетки (например, PowerPoint) вы нашли BGR (71, 234, 213). Конвертируйте в HSV скриптом ниже (или скачайте bgr_hsv_converter.py):
import sys, numpy as np, cv2
blue, green, red = int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])
color = np.uint8([[[blue, green, red]]])
hsv = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)
hue = hsv[0][0][0]
print('Lower bound:', [hue-10, 100, 100])
print('Upper bound:', [hue+10, 255, 255])
Запуск python bgr_hsv_converter.py 71 234 213 печатает:
Lower bound: [24, 100, 100] Upper bound: [44, 255, 255]
Используйте эти границы для маскирования цвета на изображении:
import cv2, numpy as np
img = cv2.imread('yellow_object.JPG', 1)
img = cv2.resize(img, (0,0), fx=0.2, fy=0.2)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([24, 100, 100], dtype=np.uint8)
upper = np.array([44, 255, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('mask', mask)
cv2.imshow('image', img)
while True:
k = cv2.waitKey(0)
if k == 27:
break
cv2.destroyAllWindows()
Сохраните скрипт как colorDetection.py и запустите python colorDetection.py (убедитесь, что изображение в той же директории).
Шаг 5: Отслеживание движения объекта в реальном времени
Строя на маске, можно отслеживать центроид объекта кадр за кадром. Код ниже заимствован из Ball Tracking tutorial Адриана Розброука и включает HSV-границы, определённые ранее.
Сначала убедитесь, что библиотека imutils установлена:
pip install imutils
Затем запустите ball_tracking.py:
python ball_tracking.py
Скрипт флипит кадр вертикально (при необходимости) и применяет маску. При обнаружении объекта рисуются круг и центроид.
Шаг 6: Тестирование GPIO
Теперь добавим красный светодиод к Pi и подтвердим, что можем управлять им через GPIO.
Проводка: катод светодиода к GPIO 21, анод к земле через резистор 220 Ом.
Если RPi.GPIO ещё не установлен в окружении cv, установите:
pip install RPi.GPIO
Тестовый скрипт (LED_simple_test.py):
import sys, time, RPi.GPIO as GPIO
led = int(sys.argv[1])
freq = int(sys.argv[2])
GPIO.setmode(GPIO.BCM)
GPIO.setup(led, GPIO.OUT)
GPIO.setwarnings(False)
print(f'Blinking LED on GPIO {led} every {freq}s, 5 times.')
for _ in range(5):
GPIO.output(led, GPIO.LOW)
time.sleep(freq)
GPIO.output(led, GPIO.HIGH)
time.sleep(freq)
GPIO.cleanup()
Запустите python LED_simple_test.py 21 1 для мигания светодиода пять раз в секунду.
Шаг 7: Распознавание цвета и взаимодействие с GPIO
Объедините логику отслеживания с управлением GPIO так, чтобы светодиод загорался при обнаружении целевого цвета. Основные добавления:
import RPi.GPIO as GPIO
led = 21
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led, GPIO.OUT)
GPIO.output(led, GPIO.LOW)
ledOn = False
Внутри цикла детекции, после подтверждения валидного радиуса, добавьте:
if not ledOn:
GPIO.output(led, GPIO.HIGH)
ledOn = True
Полный скрипт: object_detection_LED.py. Запустите python object_detection_LED.py. Светодиод включается только когда цвет объекта попадает в HSV-границы.
Шаг 8: Панорамный/наклонный механизм
С работающим OpenCV и GPIO, подключите сервоприводы к внешнему 5-вольтовому источнику. Провода данных:
- GPIO 17 → Tilt Servo
- GPIO 27 → Pan Servo
Объедините землю Pi, сервоприводов и блока питания. Опционально поставьте резистор 1 кОм последовательно между GPIO Pi и data-пином сервопривода для защиты Pi от токовых скачков.
Тест управления сервоприводами через angleServoCtrl.py:
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
def setServoAngle(servo, angle):
pwm = GPIO.PWM(servo, 50)
pwm.start(8)
duty = angle / 18. + 3.
pwm.ChangeDutyCycle(duty)
sleep(0.3)
pwm.stop()
if __name__ == '__main__':
import sys
servo = int(sys.argv[1])
GPIO.setup(servo, GPIO.OUT)
setServoAngle(servo, int(sys.argv[2]))
GPIO.cleanup()
Пример: python angleServoCtrl.py 17 45 поворачивает tilt-сервопривод на 45°.
Шаг 9: Определение реального положения объекта
Для центрирования камеры на цели сначала нужны координаты центроида. Модифицируйте objectDetect_LED.py для печати x и y:
def mapObjectPosition(x, y):
print(f'[INFO] Object center at X={x}, Y={y}')
Координаты варьируются от 0–500 (слева направо) для x и 0–350 (сверху вниз) для y. Двигайте объект и наблюдайте живой вывод.
Шаг 10: Система отслеживания позиции объекта
Определите «центрированную» зону (например, 220 < x < 280 и 160 < y < 210). Если объект выходит за границы, скорректируйте панорамные и наклонные сервоприводы:
def mapServoPosition(x, y):
global panAngle, tiltAngle
if x < 220:
panAngle = min(panAngle + 10, 140)
positionServo(panServo, panAngle)
if x > 280:
panAngle = max(panAngle - 10, 40)
positionServo(panServo, panAngle)
if y < 160:
tiltAngle = min(tiltAngle + 10, 140)
positionServo(tiltServo, tiltAngle)
if y > 210:
tiltAngle = max(tiltAngle - 10, 40)
positionServo(tiltServo, tiltAngle)
Помощник positionServo(servo, angle) просто вызывает angleServoCtrl.py:
import os
def positionServo(servo, angle):
os.system(f'python angleServoCtrl.py {servo} {angle}')
print(f'[INFO] Positioning servo GPIO {servo} to {angle}°')
Все скрипты в одной директории; скачайте полную реализацию с objectDetectTrack.py.
Шаг 11: Заключение
Этот проект демонстрирует, как соединить OpenCV, Raspberry Pi GPIO и панорамно/наклонный сервопривод для создания автономной системы отслеживания цветных объектов. Экспериментируйте с разными цветами, формами и скоростями сервоприводов.
Полный код и дополнительные ресурсы доступны на GitHub и блоге MJRoBot.org.
Спасибо за чтение — увидимся в следующем туториале!
Производственный процесс
- Объектно-ориентированное программирование в Python: классы, наследование, инкапсуляция и полиморфизм
- Продвинутое отслеживание теннисного мяча на Raspberry Pi с OpenCV
- Speathe: коммуникация на основе дыхания для парализованных пользователей
- Распознавание лиц в реальном времени на Raspberry Pi — полное руководство
- Объектно-ориентированное программирование в Python: полное руководство
- Измерение точности динамического трекинга объектов в системах моشن-капчера
- Новый фильтр улучшает робототехническое зрение для точной 6D оценки позы
- Автоматические прессовые станки: принцип работы, преимущества и применение
- Автоматические кованые прессы: особенности, преимущества и применение
- Автоматические трубогибоны: функции, преимущества и применение