Автоматическое отслеживание объекта обзора
Сервоустройство панорамирования / наклона, помогающее камера для автоматического отслеживания цветных объектов с помощью зрения.
История
Введение
В моем последнем руководстве мы изучили, как управлять сервоприводом панорамирования / наклона для позиционирования PiCam. Теперь мы будем использовать наше устройство, чтобы помочь камере автоматически отслеживать цветные объекты
Это мой первый опыт работы с OpenCV, и я должен признаться, я влюблен в эту фантастическую «Библиотеку компьютерного зрения с открытым исходным кодом».
OpenCV бесплатен как для академического, так и для коммерческого использования. Он имеет интерфейсы C ++, C, Python и Java и поддерживает Windows, Linux, Mac OS, iOS и Android. В моей серии руководств по OpenCV мы сосредоточимся на Raspberry Pi (то есть Raspbian как ОС) и Python. OpenCV был разработан для вычислительной эффективности и с упором на приложения реального времени. Итак, он идеально подходит для проектов физических вычислений!
Шаг 1. Спецификация - Спецификация
Основные части:
- Raspberry Pi V3 - 32 доллара США.
- 5-мегапиксельный сенсор 1080p, мини-видеокамера OV5647 - 13 долларов США.
- TowerPro SG90 9G 180 градусов Micro Servo (2 X) - 4 доллара США.
- Антивибрационное крепление для миниатюрной платформы панорамирования / наклона камеры с 2 сервоприводами (*) - 8 долларов США.
- Красный светодиод
- Резистор 220 Ом
- Резистор 1 кОм (2X) - опционально
- Разное:металлические детали, ленты и т. д. (на случай, если вы создадите свой механизм панорамирования / наклона).
(*) вы можете купить полную платформу панорамирования / наклона с сервоприводами или построить свою собственную.
Шаг 2. Установка пакета OpenCV 3
Я использую Raspberry Pi V3, обновленный до последней версии Raspbian (Stretch), поэтому лучший способ установить OpenCV - это следовать отличному руководству, разработанному Адрианом Роузброком:Raspbian Stretch:Install OpenCV 3 + Python на Raspberry Pi.
Я пробовал несколько разных руководств по установке OpenCV на свой Pi. Учебник Адриана - лучший. Я советую вам сделать то же самое, шаг за шагом следуя его указаниям.
После того, как вы закончите обучение Адриана, у вас должна быть виртуальная среда OpenCV, готовая для проведения наших экспериментов на вашем Pi.
Перейдем в нашу виртуальную среду и убедимся, что OpenCV 3 установлен правильно.
Адриан рекомендует запускать команду «source» каждый раз, когда вы открываете новый терминал, чтобы убедиться, что ваши системные переменные настроены правильно.
исходный текст ~ / .profile
Теперь давайте войдем в нашу виртуальную среду:
работа на резюме
Если вы видите текст (cv) перед подсказкой, значит, вы находитесь в cv virtual окружающая среда:
(cv) pi @ raspberry:~ $
Адриан обращает внимание на то, что виртуальная среда cv Python полностью независим и отделен от версии Python по умолчанию, включенной в загрузку Raspbian Stretch. Таким образом, любые пакеты Python в глобальном каталоге site-packages не будут доступны для виртуальной среды cv. Точно так же любые пакеты Python, установленные в пакетах сайтов cv, не будут доступны для глобальной установки Python.
Теперь введите в свой интерпретатор Python:
питон
и убедитесь, что вы используете версию 3.5 (или выше)
Внутри интерпретатора (появится значок «>>>») импортируйте библиотеку OpenCV:
импортировать cv2
Если сообщения об ошибках не появляются, OpenCV правильно установлен В ВАШЕЙ ВИРТУАЛЬНОЙ СРЕДЕ PYTHON.
Вы также можете проверить установленную версию OpenCV:
cv2 .__ version__
Должна появиться 3.3.0 (или улучшенная версия, которая может быть выпущена в будущем). На приведенном выше экране PrintScreen терминала показаны предыдущие шаги.
Шаг 3. Тестирование камеры
После установки OpenCV в RPi давайте проверим, правильно ли работает ваша камера.
Я предполагаю, что на вашем Raspberry Pi уже установлена PiCam.
Введите указанный ниже код Python в своей среде IDE:
import numpy as npimport cv2cap =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 ('серый', серый) if cv2.waitKey (1) &0xFF ==ord ('q'):breakcap.release () cv2.destroyAllWindows ()
Приведенный выше код захватит видеопоток, который будет сгенерирован вашей камерой PiCam, и отобразит его как в цвете BGR, так и в сером режиме.
Обратите внимание, что я повернул камеру вертикально из-за того, как она собрана. Если это не ваш случай, прокомментируйте или удалите командную строку «перевернуть».
Вы также можете загрузить код с моего GitHub:simpleCamTest.py
Для выполнения введите команду:
python simpleCamTest.py
Чтобы завершить программу, вы должны нажать клавишу [q] или [Ctrl] + [C] на клавиатуре
На картинке показан результат.
Чтобы узнать больше об OpenCV, вы можете следовать руководству:loading -video-python-opencv-tutorial
я> Шаг 4. Определение цвета в Python с помощью OpenCV
Одна вещь, которую мы попытаемся выполнить, - это обнаружение и отслеживание объекта определенного цвета. Для этого мы должны немного больше понять, как OpenCV интерпретирует цвета.
Анри Данг написал отличное руководство по обнаружению цвета в Python с помощью OpenCV.
Обычно наша камера будет работать с цветовым режимом RGB, который можно понять, если представить себе все возможные цвета, которые можно создать из трех цветных источников света:красного, зеленого и синего. Вместо этого мы будем работать с BGR (синий, зеленый, красный).
Как описано выше, с BGR пиксель представлен тремя параметрами:синим, зеленым и красным. Каждый параметр обычно имеет значение от 0 до 255 (или от O до FF в шестнадцатеричном формате). Например, чистый синий пиксель на экране вашего компьютера будет иметь значение B, равное 255, значение G, равное 0, и значение R, равное 0.
OpenCV работает с цветовой моделью HSV (оттенок, насыщенность, значение), которая является альтернативным представлением цветовой модели RGB, разработанной в 1970-х годах исследователями компьютерной графики для более точного соответствия с человеческой зрение воспринимает цветообразующие атрибуты:
Отлично. Итак, если вы хотите отслеживать определенный цвет с помощью OpenCV, вы должны определить его с помощью модели HSV.
Пример
Допустим, я должен отслеживать желтый объект, как показано на пластиковом поле, показанном на картинке выше. Часть легкости - найти его элементы BGR. Вы можете использовать любую дизайнерскую программу, чтобы найти его (я использовал PowerPoint).
В моем случае я обнаружил:
- Синий:71
- Зеленый:234
- Красный:213
Затем мы должны преобразовать модель BGR (71, 234, 213) в модель HSV, которая будет определена с верхними и нижними границами диапазона. Для этого запустим следующий код:
импортировать sysimport numpy как npimport cv2blue =sys.argv [1] зеленый =sys.argv [2] красный =sys.argv [3] color =np.uint8 ([[[синий, зеленый , красный]]]) hsv_color =cv2.cvtColor (color, cv2.COLOR_BGR2HSV) hue =hsv_color [0] [0] [0] print ("Нижняя граница:"), print ("[" + str (hue- 10) + ", 100, 100] \ n") print ("Верхняя граница:"), print ("[" + str (hue + 10) + ", 255, 255]")
Вы также можете загрузить код с моего GitHub:bgr_hsv_converter.py
Для выполнения введите следующую команду, имеющую в качестве параметров значения BGR, найденные ранее:
python bgr_hsv_converter.py 71234213
Программа распечатает верхнюю и нижнюю границы цвета нашего объекта.
В этом случае:
нижняя граница:[24, 100, 100]
и
верхняя граница:[44, 255, 255]
Экран печати терминала показывает результат.
И последнее, но не менее важное:давайте посмотрим, как OpenCV может «замаскировать» наш объект после того, как мы определили его цвет:
import cv2import numpy as np # Прочтите картинку - 1 означает, что нам нужно изображение в BGRimg =cv2.imread ('yellow_object.JPG', 1) # изменить размер изображения до 20% в каждой осиimg =cv2.resize (img, (0,0), fx =0.2, fy =0.2) # преобразовать изображение BGR в изображение HSV hsv =cv2.cvtColor (img, cv2.COLOR_BGR2HSV) # NumPy для создания массивов для хранения нижнего и верхнего range # «dtype =np.uint8» означает, что тип данных является 8-битным целым числом lower_range =np.array ([24, 100, 100], dtype =np.uint8) upper_range =np.array ([44, 255, 255 ], dtype =np.uint8) # создать маску для imagemask =cv2.inRange (hsv, lower_range, upper_range) # отобразить маску и изображение рядом cv2.imshow ('mask', mask) cv2.imshow ('image', img) # ждем, пока пользователь нажмет [ESC] while (1):k =cv2.waitKey (0) if (k ==27):breakcv2.destroyAllWindows ()
Вы также можете загрузить код с моего GitHub:colorDetection.py
Для выполнения введите следующую команду, имеющую в вашем каталоге фотографию с вашим целевым объектом (в моем случае:yellow_object.JPG):
python colorDetection.py
На приведенном выше рисунке показано исходное изображение («изображение») и то, как объект будет выглядеть («маска») после применения маски.
Шаг 5. Отслеживание движения объекта
Теперь, когда мы знаем, как «выбирать» наш объект с помощью маски, давайте отследим его движение в реальном времени с помощью камеры. Для этого я основал свой код на учебнике Адриана Роузброка по отслеживанию мяча с помощью OpenCV.
Я настоятельно рекомендую вам подробно прочитать руководство Адриана.
Сначала убедитесь, что у вас есть библиотека imutils установлен. это коллекция удобных функций OpenCV, созданная Адрианом, чтобы упростить несколько основных задач (например, изменение размера или переворачивание экрана). Если нет, введите команду ниже, чтобы установить библиотеку в вашу виртуальную среду Python:
pip install imutils
Затем загрузите код ball_tracking.py с моего GitHub и выполните его с помощью команды:
python ball_traking.py
По сути, это тот же код, что и у Адриана, за исключением «вертикального поворота видео», который я получил со строкой:
frame =imutils.rotate (frame, angle =180)
Также обратите внимание, что использованные границы маски были теми, которые мы получили на предыдущем шаге.
Шаг 6. Тестирование GPIO
Теперь, когда мы познакомились с основами OpenCV, давайте установим светодиод на наш RPi и начнем взаимодействовать с нашими GPIO.
Следуйте приведенной выше электрической схеме:катод светодиода будет подключен к GPIO 21, а его анод - к GND через резистор 220 Ом.
Давайте протестируем наш светодиод в нашей виртуальной среде Python.
Помните, что вполне возможно, что RPi.GPIO не установлен в вашей виртуальной среде Python! Чтобы решить эту проблему, как только вы окажетесь там (не забудьте подтвердить, что (cv) находится в вашем терминале), вам необходимо использовать pip для его установки в вашу виртуальную среду:
pip install RPi.GPIO
Давайте воспользуемся скриптом Python для выполнения простого теста:
import sysimport timeimport RPi.GPIO as GPIO # инициализируйте GPIO и переменные redLed =int (sys.argv [1]) freq =int (sys.argv [2]) GPIO.setmode (GPIO.BCM ) GPIO.setup (redLed, GPIO.OUT) GPIO.setwarnings (False) print ("\ n [ИНФОРМАЦИЯ] Мигающий светодиод (5 раз) подключен к GPIO {0} каждые {1} секунды». Format ( redLed, freq)) для i в диапазоне (5):GPIO.output (redLed, GPIO.LOW) time.sleep (freq) GPIO.output (redLed, GPIO.HIGH) time.sleep (freq) # немного cleanupprint ("\ n [INFO] Выход из программы и очистка \ n") GPIO.cleanup ()
Этот код получит в качестве аргументов номер GPIO и частоту мигания нашего светодиода в секундах. Светодиод мигнет 5 раз, и программа будет завершена. Обратите внимание, что перед завершением мы освободим GPIO.
Итак, чтобы выполнить сценарий, вы должны ввести в качестве параметров LED GPIO и частота .
Например:
python LED_simple_test.py 21 1
Приведенная выше команда будет мигать 5 раз красным светодиодом, подключенным к «GPIO 21», каждую «1» секунду.
Файл GPIO_LED_test.py можно загрузить с моего GitHub
На приведенном выше экране печати терминала показан результат (и, конечно же, вы должны убедиться, что индикатор мигает.
Теперь давайте поработаем с OpenCV и некоторыми базовыми функциями GPIO.
Шаг 7. Распознавание цветов и взаимодействия GPIO
Давайте начнем интегрировать наши коды OpenCV с взаимодействием GPIO. Мы начнем с последнего кода OpenCV и интегрируем в него библиотеку GPIO-RPI, поэтому мы будем включать красный светодиод в любое время, когда наш цветной объект будет обнаружен камерой. Код, использованный на этом этапе, был основан на отличном учебнике Адриана OpenCV, RPi.GPIO и GPIO Zero на Raspberry Pi:
Первое, что нужно сделать, - это «создать» наш светодиод, подключив его к конкретному GPIO:
импортировать RPi.GPIO как GPIOredLed =21GPIO.setmode (GPIO.BCM) GPIO.setwarnings (False) GPIO.setup (красный светодиод, GPIO.OUT)
Во-вторых, мы должны инициализировать наш светодиод (выключен):
GPIO.output (redLed, GPIO.LOW) ledOn =False
Теперь внутри цикла, где создается «круг», когда объект найден, мы включим светодиод:
GPIO.output (redLed, GPIO.HIGH) ledOn =True
Давайте загрузим полный код с моего GitHub:object_detection_LED.py
Запустите код с помощью команды:
python object_detection_LED.py
Попробуйте использовать разные объекты (цвет и формат). Вы увидите, что после совпадения цветов внутри границ маски включается светодиод.
На видео ниже показан некоторый опыт. Обратите внимание, что при включении светодиода будут обнаружены только желтые объекты, которые остаются в пределах цветового диапазона. Объекты разного цвета игнорируются.
Мы используем здесь только светодиод, как описано на последнем шаге. Когда я снимал видео, у меня уже был собран Pan Tilt, так что не обращайте на него внимания. На следующем шаге мы рассмотрим механизм PAN / TILT.
Шаг 8. Механизм панорамирования и наклона
Теперь, когда мы познакомились с основами OpenCV и GPIO, давайте установим наш механизм панорамирования / наклона.
Для получения подробной информации, пожалуйста, посетите мой учебник:Pan-Tilt-Multi-Servo-Control
Сервоприводы должны быть подключены к внешнему источнику питания 5 В, а их вывод данных (в моем случае - желтая проводка) должен быть подключен к Raspberry Pi GPIO, как показано ниже:
- GPIO 17 ==> Сервопривод наклона
- GPIO 27 ==> Сервопривод панорамирования
Не забудьте соединить GND вместе ==> Raspberry Pi - Сервоприводы - Внешний источник питания)
В качестве опции вы можете установить резистор на 1 кОм последовательно между Raspberry Pi GPIO и контактом ввода данных сервера. Это защитит ваш RPi в случае неисправности сервопривода.
Давайте также воспользуемся возможностью и протестируем наши сервоприводы в нашей виртуальной среде Python.
Давайте воспользуемся скриптом Python для выполнения некоторых тестов с нашими драйверами:
из time import sleepimport RPi.GPIO as GPIOGPIO.setmode (GPIO.BCM) GPIO.setwarnings (False) def setServoAngle (servo, angle):pwm =GPIO.PWM (servo, 50) pwm .start (8) dutyCycle =angle / 18. + 3. pwm.ChangeDutyCycle (dutyCycle) sleep (0.3) pwm.stop () if __name__ =='__main__':import sys servo =int (sys.argv [1]) GPIO.setup (серво, GPIO.OUT) setServoAngle (серво, int (sys.argv [2])) GPIO.cleanup ()
Ядром приведенного выше кода является функция setServoAngle (servo, angle). Эта функция принимает в качестве аргументов номер GPIO сервопривода и значение угла, в котором сервопривод должен быть расположен. После того, как эта функция введена как «угол», мы должны преобразовать его в эквивалентный рабочий цикл.
Чтобы выполнить сценарий, вы должны ввести в качестве параметров servo GPIO и угол .
Например:
python angleServoCtrl.py 17 45
Приведенная выше команда разместит сервопривод, подключенный к GPIO 17 («наклон»), под углом 45 градусов «по высоте».
Файл angleServoCtrl.py можно загрузить с моего GitHub
Шаг 9. Определение положения объекта в реальном времени
Идея состоит в том, чтобы расположить объект посередине экрана с помощью механизма панорамирования / наклона. Плохая новость в том, что для начала мы должны знать, где находится объект в реальном времени. Но хорошая новость в том, что это очень просто, если у нас уже есть координаты центра объекта.
Во-первых, давайте возьмем код «object_detect_LED», который использовался ранее, и изменим его, чтобы вывести координаты x, y найденного объекта.
Загрузите с моего GitHub код:objectDetectCoord.py
«Ядро» кода - это часть, где мы находим объект и рисуем на нем круг с красной точкой в центре.
# продолжаем, только если радиус соответствует минимальному размеру if radius> 10:# рисуем круг и центроид на кадре, # затем обновляем список отслеживаемых точек cv2.circle (frame, (int ( x), int (y)), int (radius), (0, 255, 255), 2) cv2.circle (frame, center, 5, (0, 0, 255), -1) # печать центра круга координаты mapObjectPosition (int (x), int (y)) # если светодиод еще не горит, включить светодиод, если не ledOn:GPIO.output (redLed, GPIO.HIGH) ledOn =True
Давайте «экспортируем» координаты центра в mapObjectPosition (int (x), int (y)) функция, чтобы распечатать его координаты. Ниже функции:
def mapObjectPosition (x, y):print ("[INFO] Центр объектов имеет координаты X0 ={0} и Y0 ={1}". format (x, y))
Запустив программу, мы увидим на нашем терминале координаты положения (x, y), как показано выше. Переместите объект и наблюдайте за координатами. Мы поймем, что x изменяется от 0 до 500 (слева направо), а y изменяется от o до 350 (сверху вниз). См. Изображения выше.
Отлично! Теперь мы должны использовать эти координаты в качестве отправной точки для нашей системы отслеживания поворота / наклона
Шаг 10. Система отслеживания положения объекта
Мы хотим, чтобы наш объект всегда оставался в центре экрана. Итак, давайте определим, например, что мы будем считать наш объект «центрированным», если:
- 220
- 160
За эти границы мы должны переместить наш механизм панорамирования / наклона, чтобы компенсировать отклонение. Исходя из этого, мы можем построить функцию mapServoPosition (x, y) как показано ниже. Обратите внимание, что «x» и «y», используемые в качестве параметров в этой функции, те же самые, что мы использовали ранее для печати центральной позиции:
# позиционируем сервоприводы для отображения объекта в центре кадра. mapServoPosition (x, y):global panAngle global tiltAngle if (x <220):panAngle + =10 if panAngle> 140:panAngle =140 positionServo (panServo, panAngle) if (x> 280):panAngle - =10, если panAngle <40:panAngle =40 positionServo (panServo, panAngle) if (y <160):tiltAngle + =10, если tiltAngle> 140:tiltAngle =140 positionServo (tiltServo, tiltAngle) if (y> 210):tiltAngle - =10 if tiltAngle <40:tiltAngle =40 positionServo (tiltServo, tiltAngle)
На основе координат (x, y) генерируются команды положения сервопривода с использованием функции positionServo (сервопривод, угол). Например, предположим, что положение y равно «50», что означает, что наш объект находится почти в верхней части экрана, что можно перевести как «низкий угол обзора камеры» (скажем, угол наклона 120 градусов). Поэтому мы должны «уменьшить» угол наклона (скажем, до 100 градусов), чтобы прицел камеры был «вверх», а объект опускался «вниз» на экране (y увеличится, скажем, до 190).
На диаграмме выше показан пример с точки зрения геометрии.
Подумайте, как будет работать панорамная камера. обратите внимание, что экран не является зеркальным. Это означает, что если вы переместите объект «влево», он будет перемещаться на экране «вправо», как только вы окажетесь напротив камеры.
Функция positionServo (серво, угол) может быть записана как:
def positionServo (servo, angle):os.system ("python angleServoCtrl.py" + str (servo) + "" + str (angle)) print ("[INFO] Сервопривод позиционирования на GPIO {0} в {1} градусы \ n ".format (серво, угол))
Мы будем вызывать показанный ранее скрипт для позиционирования сервопривода.
Обратите внимание, что angleServoCtrl.py должен находиться в том же каталоге, что и objectDetectTrac.py
Полный код можно загрузить с моего GitHub:objectDetectTrack.py
Шаг 11:Заключение
Как всегда, я надеюсь, что этот проект поможет другим найти свой путь в захватывающий мир электроники!
Для получения подробной информации и окончательного кода посетите мой депозитарий GitHub:OpenCV-Object-Face-Tracking
Чтобы узнать о других проектах, посетите мой блог:MJRoBot.org
Салудо с юга мира!
Увидимся в моем следующем руководстве!
Спасибо,
Источник: Автоматическое слежение за объектами зрения
Производственный процесс
- Объектно-ориентированное программирование Python
- Отслеживание Raspberry Pi Ball
- Speathe
- Распознавание лиц в реальном времени:сквозной проект
- Python — объектно-ориентированный
- Определение точности отслеживания динамических объектов
- Фильтр улучшает зрение робота при оценке положения в 6D
- Что такое автоматический пресс?
- Что такое автоматический силовой пресс?
- Что такое автоматический трубогиб?