Лабораторная #4 - OpenCV и начала анализа изображений и видео


 e107    27 Mar 2018 : 22:55
 None    Misc

.

  Лабораторная №4 представляет собой комбинационное упражнение в области начал компьютерного зрения.
 
 Исходные данные:

 - софт: Visual Studio (если windows), Python 3, OpenCV. Все является свободным (имеет свободные версии) и доступно на соответствующих сайтах. (В интернете есть мануалы и для более простых сред программирования, нежели Visual Studio. Если вам она в дальнейшем не нужна, то вы можете использовать что-нибудь попроще. Напимер Codeblocks (Инструкция Codeblocks + OpenCV), но инструкция на английском + вам ещё нужно будет поставить пакет MinGW. Более сложная установка, но удобнее в будущем, если собираетесь программировать, т.к. Codeblocks работает не только под Windows)
 - информация по установке OpenCV в Windows (руководство) ->>>> Руководство
 - исходные коды 2 программ-примеров (в тексте лабораторной работы, но лучше скачайте в оригинале, ато опять с отступами будете косячить ->>> Исходные коды программ-примеров)
 - полезные ссылки

 Задание:

 1) установить OpenCV на Windows/Linux, выполнить тестовую программу из руководства (приложение 1), убедившись тем самым в работоспособности вашей установки. 


Если выполняется на Linux, то установить OpenCV и Python можно следующими командами:
$ sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install libgtk-3-dev
$ sudo apt-get install python2.7-dev python3.5-dev 
$ sudo apt-get install python-opencv

 2) Выполнить примеры, выложенные ниже, внимательно просмотреть исходные коды, прочитать аннотации.


 3) На базе существующих примеров сделать детектор объектов не только на картинке, как в примере, а в видеопотоке в режиме реального времени.

 Для этого вам понадобится совместить тексты этих двух программ. Удобнее всего делать это на базе video_player.py, постепенно добавляя строчки из второго примера. Главная идея состоит в использовании переменной frame в video_player.py во всех "махинациях", происходящих во втором примере. В конце, не забудьте, что вы хотите отдать пользователю необработанное изображение, поверх которого вы просто хотите нарисовать рамки найденного объекта. Для этого в конце программы в рисовании линии и выводе на экран также используйте frame. Я проделал совмещение и могу с уверенностью сказать, что это занимает 30 секунд и не требует добавления ни одной сложной "программистской" строчки - только копирование и пару коррекций. :)
  Для того, чтобы протестировать вашу программу, когда она начнет запускаться можно поступить следующим образом. Используйте скриншот вашей сцены - например, если вы сидите перед компьютером и хотите показать ему чайник на детекцию - просто откройте вебкамеру и сделайте скриншоты. Выбрав наиболее удачный скриншот, где ваш объект не засвечен, вырежьте его в любом редакторе и сохраните в файл template.png. Лучше всего, если это будет PNG, так как это наиболее поддерживаемый формат в мире программирования. Этот файл вы будете использовать в качестве паттерна для поиска. Учитывайте, что поиск в самом глупом алгоритме, поэтому следите, чтобы объект был не очень сложный и вписывался в вырезанную картинку, чтобы через него не просвечивался фон. Это ухудшит или сделает невозможным поиск - сами понимаете, это не самый лучший помощник на стадии тестирования. Я выбрал объект, который сильно отличается от окружающих и имеет удобную для выделения в шаблон квадратную форму - паспорт в яркой обложке. Как видите, детекция происходит успешно.

Рис. 1. Желаемый результат

Замечание:

Если у вас нет веб-камеры, то задание можно выполнить следующим образом. Вы берете любой видеоролик, где есть объект, почти неизменно присутствующий в кадре некоторое время. Делаете снимок экрана с ним, вырезаете его в качестве паттерна. Сам фильм будет считываться программой, если  cap = cv2.VideoCapture(0) вы замените на  cap = cv2.VideoCapture("video.mp4").

 Программа вывода видео из файла/с вебкамеры (video_player.py)

#заголовки, которые подключают OpenCV-модуль и numpy(вспомогательная библиотека) к нашей "сессии"
import numpy as np
import cv2

#обращение к веб-камере (или файлу) через переменную cap. Далее мы будем общаться с устройством или файлом через эту переменную.
cap = cv2.VideoCapture(0)

while(True):
 #кадр за кадром забираем изображения в переменную frame
 ret, frame = cap.read()

 #Т.к. детекцию выгодно делать по бесцветному каналу, мы переводим все в градации серого и записываем результат в gray
 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

 #Отображение на экране. В imshow первый агрумент это имя окна, второй аргумент - это массив, который мы хотим визуализировать
 cv2.imshow('frame',gray)

 #Если здесь ничего не будет, то мы не сможем покинуть программу. Здесь программа делает микропаузу и проверяет нажатие клавиши q для осуществления выхода
 if cv2.waitKey(1) & 0xFF == ord('q'):
 break

# Правила хорошего тона - освободить занятые устройства и файлы, уничтожить все окна. Это можно не делать, но тогда вы программист-варвар и вас не будут любить(
cap.release()
cv2.destroyAllWindows()

 Программа поиска объекта на картинке (detect.py)

#заголовки, которые подключают OpenCV-модуль и numpy(вспомогательная библиотека) к нашей "сессии"
import cv2
import numpy as np

#читаем изображение в переменную img_rgb
img_rgb = cv2.imread('test.png')

#переводим в градации серого
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

#читаем темплейт (искомый образ) в переменную template
template = cv2.imread('wallet.png', 0)
#запоминаем в переменных w и h параметры темплейта (надо для организации отрисовки - см. ниже)
w, h = template.shape[::-1]

#вызов функции сравнения обесцвеченного образа(img_gray) и шаблона(template). Если вас не устраивают результаты, то можете попробовать другие алгоритмы сравнения (меняем TM_CCOEFF_NORMED) - гуглите!
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)

#выставление уровня похожести. 80% - стартовое значение. Если не устраивают результаты, то можете понижать уровень. Если программа считает чайник за телефон, значит вы достигли дна и пора всплывать.
threshold = 0.8

#по результатам сравнения порога res с выставленным нами в loc записываются координаты объекта (если он есть). Если объект не найден, то loc пустой.
loc = np.where( res >= threshold)

#по loc мы рисуем красные линии детекции поверх ОРИГИНАЛЬНОГО кадра img_rgb. Если loc пустой, то ничего страшного не произойдет, просто будет кадр без отрисовки. Так и надо.
for pt in zip(*loc[::-1]):
 cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)

#запись результата в файл
cv2.imwrite('wallet.png', img_rgb)

 

 4) Расширенное задание (необязательно, но будет + в карму и вообще).

Для тех, кому это не показалось интересным, вызывающим, не удовлетворило внутреннего кодера есть дальнейшее интересное развитие задачи. Предлагаю сделать множественные паттерны различных объектов (или людей) и "говорить" на экране, что именно система видит сейчас в кадре.

Рис. 2. Желаемый результат для расширенного задания (нарисовано, т.к. я сам это не делал)

templateN = cv2.imread('N.png', 0)
wN, hN = templateN.shape[::-1]

Для выполнения расширенного пункта 4 вам, помимо введения новых переменных по шаблону. N - это место под число, можете сделать к примеру 5 файлов с объектами 1.png, ...5.png и в программе в начале собрать

template1 = cv2.imread('1.png', 0)       # пульт от телевизора
w1, h1 = template1.shape[::-1]
.....
.....
template5 = cv2.imread('5.png', 0)       # мобильный телефон
w5, h5 = template5.shape[::-1]

а далее, в конце программы последовательно делать matchTemplate c каждым по отдельности, сохраняя в разные переменные resN для того, чтобы потом нанести поверх оригинального кадра

res1 = cv2.matchTemplate(img_gray, template1, cv2.TM_CCOEFF_NORMED)

 Для целей лучшего различия вы можете разным объектам на этапе отрисовки дать разные цвета. Это очень легко делается в следующей строчке путем  изменения (0,0,255). Это, напоминаю, матрица цвета RGB в перевернутом варианте - BGR. В примере рамка красная, поэтому интенсивность R максимальная, а другие на нуле. Вы можете варьировать все числа в диапазоне 0...255, получая новые цвета. 

for pt in zip(*loc[::-1]): cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)


Кроме того, для качественной реализации понадобится сразу за рисованием рамок добавить на экран текст. Это очень легко можно найти в интернете, но добавлю здесь.
В функции putText используется следующая информация

  • 'Это мобильный телефон' -- Сам текст
  • (10, 500)  -- координаты, где будет расположен текст. Удобно сделать с некоторым смещением под рамкой, как на изображении-задании выше
  • font  -- переменная, в которой содержится шрифт. Можно оставить как есть.
  • 4 -- размер шрифта
  • (255,255,255), 2, cv2.LINE_AA   ---  цвет, толщина, тип линии. Тоже можно оставить как есть.
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, <span class="stringliteral">'Это мобильный телефон'</span>, (10, 500), font, 4, (255,255,255), 2, cv2.LINE_AA)


Полезные ссылки

1) Программа не работает. Что делать?

2) OpenCV-Python Tutorials (для тех, кто хочет в этом направлении двигаться, понимать, что можно сделать и как --  очень интересная страница)

3) Интуит: Начало работы с библиотекой OpenCV








This news item is from Видеоинформационные системы (СПБГЭТУ "ЛЭТИ")
http://rusvision.com/news.php?extend.11