Пятница, 30 марта 2018 21:01

Автоматическое отслеживание объекта на Python

Оцените материал
(5 голосов)

В предыдущем уроке мы рассмотрели, как управлять сервоприводами Поворота / Наклона для размещения PiCam. Теперь мы будем использовать наше устройство, чтобы помочь камере автоматически отслеживать цветные объекты, как вы можете видеть ниже:

giphy (3)

Это мой первый опыт работы с OpenCV, и я должен признаться, я влюблен в эту фантастическую «библиотеку компьютерного зрения с открытым исходным кодом».

OpenCV бесплатный для академического и коммерческого использования. Он имеет интерфейсы C ++, C, Python и Java и поддерживает Windows, Linux, Mac OS, iOS и Android. В моей серии обучающих программ OpenCV мы сосредоточимся на Raspberry Pi (так, Raspbian как OS) и Python. OpenCV был разработан для вычислительной эффективности и с большим вниманием к приложениям реального времени. Таким образом, он идеально подходит для физических вычислений!

 

Шаг 1: Список деталей проекта

  1. Raspberry Pi V3 - US$ 32.00 / Raspberry Pi V3 - US$ 36.99
  2. 5 Megapixels 1080p Sensor OV5647 Mini Camera Video Module - US$ 13.00 / 5 Megapixels 1080p Sensor OV5647 Mini Camera Video Module - US$ 6.40
  3. TowerPro SG90 9G 180 degrees Micro Servo (2 X)- US$ 4.00 / TowerPro SG90 9G 180 degrees Micro Servo (2 X)- US$ 2.45
  4. Mini Pan/Tilt Camera Platform Anti-Vibration Camera Mount w/ 2 Servos (*) - US$ 8.00 / Mini Pan/Tilt Camera Platform Anti-Vibration Camera Mount w/ 2 Servos (*) - US$ 5.89
  5. Красный Светодиод
  6. Резистор 220 Ом
  7. Резистор 1 кОм (2) - Опционально
  8. Прочее: металлические детали, ленты и т. Д. (В случае, если вы создадите механизм Поворота / Наклона

(*) вы можете купить полную платформу Поворота / Наклона с сервоприводами или построить свой собственный.

 

Шаг 2: Установка пакета OpenCV 3

FEENSMWJDEUHJKY.LARGE

Я использую Raspberry Pi V3, обновленный до последней версии Raspbian (Stretch), поэтому лучший способ установить OpenCV - следовать отличному учебному пособию, разработанному Адрианом Розброком: Raspbian Stretch: Установка OpenCV 3 + Python на Raspberry Pi V3.

Я попробовал несколько разных руководств по установке OpenCV на моем Pi. Учебник Адриана - лучший. Я советую вам сделать то же самое, следуя его указаниям шаг за шагом.

После того, как вы закончите установку по учебнику Адриана, у Вас должна быть виртуальная среда OpenCV, готовая запускать наш эксперимент на Raspberry Pi.

Перейдем к нашей виртуальной среде и убедитесь, что OpenCV 3 правильно установлен.

Адриан рекомендует запускать команду «источник» каждый раз, когда вы открываете новый терминал, чтобы обеспечить правильную настройку системных переменных.

source ~/.profile

Затем перейдем к нашей виртуальной среде:

workon cv

Если вы видите текст (cv), предшествующий вашему запросу, то вы находитесь в виртуальной среде cv:

(cv) pi@raspberry:~$

Адриан обращает внимание, что виртуальная среда cv Python полностью независима и секвестрирована из стандартной версии Python, включенной в загрузку Raspbian Stretch. Таким образом, любые пакеты Python в каталоге глобальных пакетов сайтов не будут доступны для виртуальной среды cv. Аналогично, любые пакеты Python, установленные в сайтах-пакетах cv, не будут доступны для глобальной установки Python.

Теперь введите интерпретатор Python:

Python

и убедитесь, что вы используете версию 3.5 (или выше)

Внутри интерпретатора (появится «>>>») импортируйте библиотеку OpenCV:

import cv2

Если сообщений об ошибках не выходят, значит OpenCV правильно установлен на ВАШЕЙ PYTHON ВИРТУАЛЬНОЙ СРЕДЕ.

Вы также можете проверить какая версия OpenCV установлена:

cv2.__version__

Должен появиться 3.3.0 (или более высокая версия, которая может быть выпущена в будущем). Вышеупомянутый терминал PrintScreen показывает предыдущие шаги.

 

Шаг 3: Тестирование Вашей Камеры

FW2WCVWJDEUHKG7.LARGE

Как только вы установите OpenCV в свой RPi, давайте проверим, работает ли ваша камера правильно.

Я предполагаю, что у вас есть PiCam, уже установленный на вашем Raspberry Pi.

Введите ниже код Python в вашу среду IDE:


import numpy as np
import cv2

cap = cv2.VideoCapture(0)
 
while(True):
    ret, frame = cap.read()
    frame = cv2.flip(frame, -1) # Flip camera vertically
    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()

Вышеприведенный код будет захватывать видеопоток, который будет создан вашим PiCam, и отображать его как в цвете BGR, так и в режиме Gray.

Обратите внимание, что я повернул камеру по вертикали из-за того, что она собрана. Если это не ваше дело, прокомментируйте или удалите командную строку «flip».

Вы также можете загрузить код из GitHub: simpleCamTest.py

Для выполнения введите команду:

python simpleCamTest.py

Чтобы завершить программу, вы должны нажать клавишу [q] tor [Ctrl] + [C] на клавиатуре

На рисунке показан результат.

Чтобы узнать больше о OpenCV, вы можете изучить за учебник: -video-python-opencv-tutorial

 

Шаг 4: Обнаружение цвета в Python с OpenCV

F9YMVK0JDEUHNJ1.LARGE

FGLV96UJDEUHOXY.LARGE

Одна вещь, которую мы попытаемся выполнить, будет - обнаружение и отслеживание определенного цветового объекта. Для этого нам нужно понять немного больше о том, как OpenCV интерпретирует цвета.

Анри Данг написал отличный учебник по распознаванию цвета в Python с OpenCV.

Обычно наша камера будет работать с цветовым режимом RGB, что можно понять, думая об этом как о всех возможных цветах, которые могут быть сделаны из трех цветных огней красного, зеленого и синего. Мы будем работать здесь с BGR (синий, зеленый, красный).

Как описано выше, с BGR пиксель представлен тремя параметрами: синим, зеленым и красным. Каждый параметр обычно имеет значение от 0 до 255 (или от 0 до FF в шестнадцатеричном формате). Например, чистый синий пиксель на экране вашего компьютера будет иметь значение B 255, значение G 0 и значение R 0.

1024px RGB Cube Show lowgamma cutout a

OpenCV работает с цветовой моделью HSV (Hue, Saturation, Value), что является альтернативным представлением цветовой модели RGB, разработанной в 1970-х годах исследователями компьютерной графики, чтобы в большей степени соответствовать тому, как человеческое видение воспринимает цветовые атрибуты:

1024px HSV color solid cylinder alpha lowgamma

Отлично. Итак, если вы хотите отслеживать определенный цвет с помощью OpenCV, Вы должны определить его с помощью модели HSV.

Предположим, что я должен отследить желтый объект, как пластиковый кубик, показанный выше картинки. Легкость в том, чтобы найти его элементы BGR. Вы можете использовать любую конструкторскую программу для ее поиска (я использовал PowerPoint). В моем случае я обнаружил:

  • Синий: 71
  • Зеленый: 234
  • Красный: 213

Затем мы должны преобразовать модель BGR (71, 234, 213) в модель HSV, которая будет определена с верхними и нижними границами диапазона. Для этого давайте запустим следующий код:


import sys
import numpy as np
import cv2
 
blue = sys.argv[1]
green = sys.argv[2]
red = sys.argv[3]  
 
color = np.uint8([[[blue, green, red]]])
hsv_color = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)
 
hue = hsv_color[0][0][0]
 
print("Lower bound is :"),
print("[" + str(hue-10) + ", 100, 100]\n")
 
print("Upper bound is :"),
print("[" + str(hue + 10) + ", 255, 255]")

Вы также можете скачать код из GitHub: bgr_hsv_converter.py

Для выполнения введите команду ниже, имеющую в качестве параметров значения BGR, найденные ранее:

python bgr_hsv_converter.py 71 234 213

Программа напечатает верхнюю и нижнюю границы цвета нашего объекта.

В этом случае:

lower bound: [24, 100, 100]

и

upper bound: [44, 255, 255]

Терминал PrintScreen покажет результат.

Последнее, но не финал, давайте посмотрим, как OpenCV может «mask» наш объект, как только мы определили его цвет:


import cv2
import numpy as np

# Read the picure - The 1 means we want the image in BGR
img = cv2.imread('yellow_object.JPG', 1) 

# resize imag to 20% in each axis
img = cv2.resize(img, (0,0), fx=0.2, fy=0.2)
# convert BGR image to a HSV image
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 

# NumPy to create arrays to hold lower and upper range 
# The “dtype = np.uint8” means that data type is an 8 bit integer

lower_range = np.array([24, 100, 100], dtype=np.uint8) 
upper_range = np.array([44, 255, 255], dtype=np.uint8)

# create a mask for image
mask = cv2.inRange(hsv, lower_range, upper_range)

# display both the mask and the image side-by-side
cv2.imshow('mask',mask)
cv2.imshow('image', img)

# wait to user to press [ ESC ]
while(1):
  k = cv2.waitKey(0)
  if(k == 27):
    break
 
cv2.destroyAllWindows()

Вы также можете загрузить код из GitHub: colorDetection.py

Для выполнения введите следующую команду, имеющую в вашем каталоге фотографию с вашим целевым объектом (в моем случае: yellow_object.JPG):

python colorDetection.py

На приведенном выше рисунке будет отображаться исходное изображение («image») и как будет отображаться объект («mask») после применения маски.

 

Шаг 5: Отслеживание движения объекта

Теперь, когда мы знаем, как «выбрать» наш объект с помощью маски, давайте проследим его движение в реальном времени с помощью камеры. Для этого я написал код на основе Adrian Rosebrock's Ball Tracking with OpenCV.

Я настоятельно рекомендую вам подробно прочитать учебник Адриана.

Сначала проверьте, установлена ли библиотека imutils. Это коллекция удобных функций OpenCV от Adrian, чтобы сделать несколько основных задач (например, изменение размера или переворот-экрана) намного проще. Если библиотека не установлена, введите команду ниже, чтобы установить библиотеку в среду Virtual Python:

pip install imutils

Затем загрузите код ball_tracking.py из GitHub и выполните его с помощью команды:

python ball_traking.py

В результате вы увидите нечто похожее на gif ниже:

giphy (1)

В принципе, это тот же код, что и Adrian's, если только «вертикальный вертикальный поворот», который я получил со строчкой:

frame = imutils.rotate(frame, angle=180)

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

 

Шаг 6: Тестирование GPIO

FVNAITBJDF2DA7W.LARGE

F5JZDP3JDF2DA89.LARGE

Теперь, когда мы поиграли с основами OpenCV, давайте установим светодиод на наш RPi и начнем взаимодействовать с нашими GPIO.

Следуйте приведенной выше электрической схеме: катод светодиода будет подключен к GPIO 21 и анод к GND через 220-омный резистор.

Давайте проверим наш светодиод внутри нашей виртуальной среды Python.

Помните, что возможно, что RPi. GPIO не установлен в вашей виртуальной среде Python! Чтобы устранить эту проблему, как только вы зашли (не забудьте подтвердить, что (cv) находится в вашем терминале), вам нужно использовать pip для его установки в вашу виртуальную среду:

pip install RPi.GPIO

Давайте используем скрипт python для выполнения простого теста:


import sys
import time
import RPi.GPIO as GPIO

# initialize GPIO and variables
redLed = int(sys.argv[1])
freq = int(sys.argv[2])
GPIO.setmode(GPIO.BCM)
GPIO.setup(redLed, GPIO.OUT)
GPIO.setwarnings(False)

print("\n [INFO] Blinking LED (5 times) connected at GPIO {0} at every {1} second(s)".format(redLed, freq))
for i in range(5):
    GPIO.output(redLed, GPIO.LOW)
    time.sleep(freq)
    GPIO.output(redLed, GPIO.HIGH)
    time.sleep(freq)

# do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff \n")
GPIO.cleanup()

Этот код будет принимать в качестве аргумента номер GPIO и частоту в секундах, которые должен мигать нашим светодиодом. Светодиод будет мигать 5 раз, и программа будет прекращена. Обратите внимание: перед завершением мы освободим GPIO.

Итак, чтобы выполнить скрипт, вы должны ввести параметры, светодиод 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:

import RPi.GPIO as GPIO 
redLed = 21
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(redLed, 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

Вот результат. Обратите внимание, что светодиод (левый нижний угол) горит каждый раз, когда объект обнаружен:

giphy (2)

Попробуйте использовать разные объекты (цвет и формат). Вы увидите, что как только цвет будет соответствовать границам маски, светодиод будет включен.

Видео, приведенное ниже, показывает некоторые варианты. Обратите внимание, что будут обнаружены только желтые объекты, которые остаются внутри цветового диапазона, включив светодиод. Объекты с иными цветами игнорируются.

Мы используем только светодиод здесь, как объяснено на последнем шаге. У меня был уже собрана поворотно / наклонная площадка, когда я сделал видео, так что игнорировать его. В следующем шаге мы будем работать с механизмом Поворота / Наклона.

 

Шаг 8: Механизм Поворота / Наклона

F4D3S0JJDF24UJY.LARGE

FF8XOHCJD4UKY55.LARGE

FSKBN4OJDF24UL3.LARGE

Теперь, когда мы поэкспериментировали с основами OpenCV и GPIO, давайте установим наш механизм Поворота / Наклона.

Для получения дополнительной информации ознакомитесь с уроком: ПОВОРОТНО-НАКЛОННАЯ ПЛАТФОРМА НА RASPBERRY PI И PYTHON.

Сервоприводы должны быть подключены к внешнему источнику питания 5 В, имеющему свой Контакт данных (в моем случае, их желтая проводка) подключаться к Raspberry Pi GPIO, как показано ниже:

  • GPIO 17 ==> Tilt Servo
  • GPIO 27 ==> Pan Servo

Не забудьте соединить GND вместе ==> Raspberry Pi - Серводвигатели - внешний источник питания)

Опционально у вас может быть, резистор 1 кОм, между Raspberry Pi GPIO и выводом ввода данных сервера. Это защитит ваш RPi в случае проблемы с сервомеханизмом.

Давайте также воспользуемся возможностью и протестируем наши сервомоторы внутри нашей виртуальной среды Python.

Давайте используем скрипт Python для выполнения некоторых тестов с нашими драйверами:


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)
	dutyCycle = angle / 18. + 3.
	pwm.ChangeDutyCycle(dutyCycle)
	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()

Ядром приведенного выше кода является функция setServoAngle (servo, angle). Эта функция принимает в качестве аргументов, номер GPIO сервопривода и значение угла, в котором должен быть установлен сервопривод. Когда вход этой функции является «углом», мы должны преобразовать его в эквивалентный рабочий цикл.

Чтобы выполнить сценарий, вы должны ввести в качестве параметров, сервопривод GPIO и angle.

Например:

python angleServoCtrl.py 17 45

Вышеуказанная команда будет позиционировать сервопривод, подключенный к GPIO 17 («наклон») с 45 градусами в «высоте». Аналогичную команду можно использовать для управления поворотного привода (положение до 45 градусов в «азимуте»:

python angleServoCtrl.py 27 45

Файл angleServoCtrl.py можно загрузить с GitHub.

 

Шаг 9: Поиск позиции объекта в реальном времени

FO69IBUJDF2E26P.LARGE

FZKQ6H5JDF2DZY9.LARGE

F4806UZJDF2E3L1.LARGE

Идея здесь состоит в том, чтобы поместить объект в середину экрана с помощью механизма Поворота / Наклона. Плохая новость заключается в том, что для начала мы должны знать, где объект находится в реальном времени. Но хорошая новость в том, что это очень легко, как только мы узнаем координаты центра объекта.

Во-первых, давайте возьмем использованный ранее код «object_detect_LED» и изменим его, чтобы распечатать координаты x, y основанного объекта.

Загрузите с GitHub код: objectDetectCoord.py

«Ядро» кода - это часть, где мы находим объект и наносим на него круг с красной точкой в центре.


# only proceed if the radius meets a minimum size
if radius > 10:
	# draw the circle and centroid on the frame,
	# then update the list of tracked points
	cv2.circle(frame, (int(x), int(y)), int(radius),
		(0, 255, 255), 2)
	cv2.circle(frame, center, 5, (0, 0, 255), -1)
			
	# print center of circle coordinates
	mapObjectPosition(int(x), int(y))
			
	# if the led is not already on, turn the LED on
	if not ledOn:
		GPIO.output(redLed, GPIO.HIGH)
		ledOn = True

Давайте будем «экспортировать» координаты центра для функции mapObjectPosition (int (x), int (y)) для печати своих координат. Ниже функция:

def mapObjectPosition (x, y): 
print ("[INFO] Object Center coordenates at X0 = {0} and Y0 = {1}".format(x, y)

Запустив программу, мы увидим на нашем терминале координаты положения (x, y), как показано выше. Переместите объект и наблюдайте за координатами. Мы поймем, что x идет от 0 до 500 (слева направо), а y идет от o до 350 (сверху вниз). См. Приведенные выше снимки.

Отлично! Теперь мы должны использовать эти координаты в качестве отправной точки для нашей системы отслеживания Поворота / Наклона.

 

Шаг 10: Система отслеживания местоположения объекта

F0RVWMJJDKKDN9Y.LARGE

Мы хотим, чтобы наш объект всегда находился на экране. Итак, давайте определим, например, что наш объект будет «центрирован», если:

220 < x < 280

И

160 < y < 210

Вне этих границ мы должны переместить наш механизм Поворота / Наклона, чтобы компенсировать отклонения. Исходя из этого, мы можем построить функцию mapServoPosition (x, y), как показано ниже. Обратите внимание, что «x» и «y», используемые в качестве параметров в этой функции, те же, что мы использовали ранее для печати центрального положения:


# position servos to present object at center of the frame
def 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
        if panAngle < 40:
            panAngle = 40
        positionServo (panServo, panAngle)

    if (y < 160):
        tiltAngle += 10
        if tiltAngle > 140:
            tiltAngle = 140
        positionServo (tiltServo, tiltAngle)
 
    if (y > 210):
        tiltAngle -= 10
        if tiltAngle < 40:
            tiltAngle = 40
        positionServo (tiltServo, tiltAngle)
		

На основе координат (x, y) генерируются команды сервопозиции, используя функцию positionServo (servo, angle). Например, предположим, что y-позиция равна «50», что означает, что наш объект находится почти в верхней части экрана, что можно перевести, что «взгляд камеры» направлен вниз (скажем, угол наклона 120 градусов) Таким образом, мы должны «уменьшить» угол наклона (скажем, до 100 градусов), поэтому «взгляд камеры» будет двигаться «вверх», и объект будет перемещаться «вниз» на экране (у увеличится, скажем, 190). На приведенной выше диаграмме показан пример с точки зрения геометрии.

Подумайте, как будет работать камера Наклона. обратите внимание, что экран не заркалит, что означает, что, если вы переместите объект в «лево», он будет перемещаться по экрану «справа», когда вы находитесь в оппозиции к камере.

Функция positionServo (servo, angle) может быть записана как:


def positionServo (servo, angle):
    os.system("python angleServoCtrl.py " + str(servo) + " " + str(angle))
    print("[INFO] Positioning servo at GPIO {0} to {1} degrees\n".format(servo, angle))

Мы будем вызывать скрипт, показанный ранее, для позиционирования сервопривода.

Обратите внимание, что angleServoCtrl.py должен находиться в том же каталоге, что и objectDetectTrac.py

Полный код можно скачать с GitHub: objectDetectTrack.py

Ниже gif показан пример работы нашего проекта:

giphy (3)

Шаг 11: Вывод

Как всегда, я надеюсь, что этот проект поможет другим найти свой путь в захватывающий мир электроники!

Подробнее и окончательный код, пожалуйста, посетите депозитарий GitHub: OpenCV-Object-Face-Tracking

На следующем уроке, мы рассмотрим «Распознавание лица»:

giphy (4)

Источник

Author

Bender

Я поделюсь с тобой всеми знаниями, которые доступны мне.

Комментарии (3)

This comment was minimized by the moderator on the site

У Вас код написан для веб камеры, а как сделать что бы работало с pi камерой то есть с родной камерой для raspberry.

 
This comment was minimized by the moderator on the site

Вышеприведенный код будет захватывать видеопоток, который будет создан вашим PiCam, и отображать его как в цвете BGR, так и в режиме Gray.


Данный код написан для камеры PiCam (родная камера от Rasberry)
У Вас возникли с запуском данного кода?

 
This comment was minimized by the moderator on the site

У меня этот код работал с веб камерой, сейчас уже знаю как подключить PiCam, с ней тоже работает. Спасибо.

 
There are no comments posted here yet

Оставьте свой комментарий

  1. Posting comment as a guest. Sign up or login to your account.
Вложения (0 / 3)
Share Your Location

О нас

Основой деятельностью портала является показ и объяснение что представляет собой выражени "Робот", "Робототехника", "Законы робототехники", "Мехатроника", "Искусственный интеллект(ИИ)". 

 Если у Вас есть интересная информация по тематике сайта и Вы готовы ей поделиться, - обращайтесь на емайл через форму обратной связи. И мы опубликуем Вашу статью

Мы используем файлы cookie для улучшения нашего веб-сайта. Продолжая использовать этот веб-сайт, вы даете согласие на использование файлов cookie. More details…