Разработка приложения с использованием метода Лукаса-Канаде

Особенности и методы построения приложений с технологией оптического потока. Простые функции для преобразования изображений. Примитивные типы данных в OpenCV. Выбор языка программирования. Разработка приложения с использованием алгоритма Лукаса-Канаде.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 07.08.2018
Размер файла 1,1 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Для повышения производительности работы Java-программ были разработаны "JustinTime" (JIT) компиляторы, но универсального решения этой проблемы не существует.

На первый взгляд, полуинтерпретируемая природа Java-программ обеспечивает выполнение принципа "скомпилированный однажды код выполняется везде". Однажды скомпилированная в байт-код Java-программа может выполняться на любой платформе, для которой доступна JVM. На практике же, это не всегда так из-за отличий в реализациях разных JVM и из-за необходимости иногда наряду с Java-программами использовать родной, не-Java код, обычно написанный на C или C++.

Но разве использование платформенно-независимого байт-кода является верным подходом в создании кросс-платформенных приложений? С хорошим кросс-платформенным инструментарием, наподобие Qt, и хорошими компиляторами для различных платформ программисты могут достичь почти той же цели компиляцией своего исходного кода один раз для каждой из платформ: "написанный однажды код компилируется везде". Можно возразить, что для этого разработчикам потребуется доступ ко всем поддерживаемым платформам, в то время, как с Java, теоретически, разработчикам необходим доступ только к одной из платформ, имеющей средства разработки для Java и JVM. На практике же ни один из ответственных производителей программного обеспечения не будет сертифицировать свои программные продукты для платформ без предварительного их тестирования, поэтому в любом случае производителям будет необходим доступ ко всем поддерживаемым платформам.

Возникает вопрос, зачем использовать программную реализацию виртуальной машины Java, если такую же функциональность можно получить с помощью аппаратной реализации? Именно так рассуждали разработчики при создании языка Java; они предполагали, что вопрос низкой производительности будет решен, когда станет доступной аппаратная реализация JVM в виде Java-процессоров. Однако даже по прошествии пяти лет Java-процессоры не получили широкого распространения. Существуют проектные экземпляры и даже работающие прототипы Java-процессоров, однако понадобится еще немало времени, чтобы стало возможным их приобрести.

Java и C++ используют различные подходы в управлении памятью.ВC++ управление памятью полностью осуществляется программистом, т.е. по мере необходимости распределение и освобождение памяти должно выполняться программистом. Если программист забывает освободить ранее полученную память, возникает "утечка памяти". Если во время работы приложения произойдет лишь одна такая утечка, проблем не возникнет, так как после завершения работы приложения операционная система освободит всю ранее использованную им память. Но если утечки памяти будут происходить постоянно (например, если пользователь будет периодически выполнять определенные действия), использование памяти приложением будет расти вплоть до полного ее расхода с последующим возможным отказом системы.

Java обеспечивает автоматическое освобождение неиспользуемой памяти. Наряду с распределением памяти программистом JVM ведет учет всех используемых блоков памяти и указателей на них. Если блок памяти больше не используется, он может быть освобожден. Это обеспечивает процесс, который называется "сборкой мусора". Он периодически вызывается JVM, проверяет все используемые блоки памяти и освобождает те из них, на которые отсутствуют указатели.

Сборка мусора очень удобна, но за ее использование приходится расплачиваться большим потреблением памяти и низкой произодительностью. Программисты C++ могут (и должны) освобождать блоки памяти сразу после того, как они перестали быть нужны. С Java блоки не освобождаются до очередного вызова сборщика мусора, периодичность работы которого зависит от использумой реализации JVM. Вдобавок к большому расходу памяти процесс сборки мусора требует дополнительной процессорной мощности, которая в результате становится недоступной приложению, и это приводит к замедлению его работы. Поэтому периодическая работа сборщика мусора может приводить к "замораживанию" Java-программы на несколько секунд. Лучшие реализации JVM минимизируют такие замораживания, но не устраняют их полностью.

При работе с внешними программами и устройствами, например, во время ввода/вывода или при взаимодействии с базой данных, желательно закрыть файл или соединение с базой данных сразу же после того, как они перестали быть нужны. Благодаря деструкторам C++ это происходит сразу после вызова delete. В Java закрытие произойдет лишь во время следующего цикла работы сборщика мусора. В лучшем случае это может привести к излишней блокировке ресурсов, в худшем - к нарушению целостности открытых ресурсов.

Тот факт, что Java-программы используют блоки памяти большие, чем необходимо, является особенно критичным для встраиваемых устройств, объемы памяти которых невелики. Неслучайно, что до сих пор (на время написания этой статьи) не существует полной реализации Java-платформы для встраиваемых устройств, а лишь ее частичные реализации.

Главная причина, по которой сборка мусора является более дорогостоящей, чем непосредственное управление памятью программистом, - это утрата информации. В C++ программе программист знает и местонахождение своих блоков памяти (сохраняя указатели на них), и когда они перестанут быть ему нужными. В Java-программе последняя информация недоступна для JVM (даже если она известна программисту), поэтому JVM должна перебирать все блоки на предмет отсутствующих указателей. Для того, чтобы вызвать сборку мусора вручную, Java-программист может удалить все указатели на больше ненужные ему блоки памяти. Но со стороны программиста это потребует больше усилий, чем непосредственное управление памятью в C++; и тем не менее, во время сборки мусора JVM все равно придется проверить все блоки памяти, чтобы освободить неиспользуемые.

С технической точки зрения, нет ничего такого, что бы мешало реализовать сборку мусора в C++ программах. Существуют обеспечивающие это коммерческие программы и библиотеки. Но из-за перечисленных выше недостатков немногие C++ программисты используют их. Инструментарий Qt использует более эффективный подход для упрощения задачи управления памятью: при удалении объекта все зависящие от него объекты также автоматически удаляются. Подход Qt не мешает программистам по желанию самостоятельно удалять объекты.

Так как управление памятью в C и C++ обременительно для программиста, созданное с помощью этих языков программное обеспечение обвиняется в нестабильной работе и подверженности ошибкам. Хотя некорректная работа с памятью в C и C++ может привести к более критичным ошибкам (обычно приводящим к аварийному завершению программы), хорошие знания, инструментарий и опыт могут значительно уменьшить связанный с этим риск. Изучению управления памятью должно уделяться достаточно внимания. Также существует большое число коммерческих и свободных инструментов, позволяющих программистам обеспечить отсутствие в программах ошибок при работе с памятью; например, ParasoftInsure++, RationalPurify и ElectricFence. Гибкая система управления памятью в C++ делает возможным создавать адаптированные для любого типа приложений профилировщики памяти.

В результате этого обсуждения мы убедились в том, что при сравнимой продуктивности программирования C++ обеспечивает приложениям гораздо лучшие, чем Java, производительность работы и эффективность использования памяти.

Java-платформа предлагает внушительное число пакетов, насчитывающих сотни классов для любых задач, включая пользовательский графический интерфейс, безопасность, поддержку сети и прочие.Это несомненное преимущество Java-платформы. Любому Java-пакету соответствует, как минимум, одна C++ библиотека, хотя иногда бывает очень трудно собрать в одном C++ проекте множество библиотек и заставить их вместе правильно работать.

Однако это преимущество Java является также ее недостатком. Разобраться в огромномAPI программисту становится все сложнее. Можете быть наверняка уверены, что для любой задачи всегда найдется уже готовое решение или, по крайней мере, решение, облегчающее выполнение этой задачи. Но найти пригодный для этого пакет и класс становится все труднее. Также с увеличением числа пакетов стремительно растет размер Java-платформы. В результате стали возникать ее "урезанные" версии, утратившие преимущества готовых решений. Таким образом, размер Java-платформы делает практически невозможным создание Java-систем небольшими производителями независимо от создателя JavaSunMicrosystems, что ослабляет конкуренцию.

Если преимущества Java заключаются в доступных библиотеках, то явные преимущества C++ - в имеющихся средствах разработки. За все время существования семейства языков C и C++ было создано огромное количество самых разнообразных средств разработки, включая инструменты для дизайна, отладки и профилирования. Имеющиеся средства разработки для Java часто уступают по возможностям своим C++ -аналогам. Это справедливо даже для инструментов от одного производителя; например, сравните Java и C/C++ -версии профилировщика RationalQuantify.

Самым важным инструментом для любого разработчика, использующего компилируемые языки, является компилятор. Основным достоинством компиляторов C++ является скорость работы. Для обеспечения кросс-платформенности своих компиляторов (и других средств разработки) производители Java-инструментов часто сами используют Java, со всеми вытекающими отсюда проблемами производительности и эффективности использования памяти. Иногда встречаются Java-компиляторы, написанные на C/C++ (например, IBMJikes), но это редкость.

Проведя анализ языков, выбор остановился на языке C++.

4.2 Реализация алгоритма с использованием библиотеки OpenCV

Результатом исследования стала реализация алгоритма Лукаса-Канаде, с использованием библиотеки OpenCV. На данный момент программа обладает следующим функционалом:

· Определение объекта

· Реализация захвата видео с камеры и обработка кадров с целью выделения руки в кадре.

Рассмотрим подробнее реализацию данного программного продукта на примере отрывка кода.

int main(intargc, char** argv)

{

VideoCapturecap("Pryamougolnik2.avi"); //capture the video from web cam

if (!cap.isOpened()) // if not success, exit program

{

cout<< "Cannot open the web cam" <<endl;

return -1;

}

double fps = cap.get(CV_CAP_PROP_FPS);

double period = 1. / fps;

cout<< fps <<endl;

namedWindow("Control", CV_WINDOW_AUTOSIZE); //create a window called "Control"

intiLowH = 0;

intiHighH = 179;

intiLowS = 0;

intiHighS = 255;

intiLowV = 0;

intiHighV = 0;

//Create trackbars in "Control" window

cvCreateTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)

cvCreateTrackbar("HighH", "Control", &iHighH, 179);

cvCreateTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255)

cvCreateTrackbar("HighS", "Control", &iHighS, 255);

cvCreateTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)

cvCreateTrackbar("HighV", "Control", &iHighV, 255);

intprevX = 0, prevY = 0;

int frame = 0;

doublesummVelocity = 0;

intmarginTextTop = 10;

Mat imageText(600, 800, CV_8UC3, Scalar::all(0));

string text;

boolisFindContour = false;

constintTimeFrame = fps;

Ptr<BackgroundSubtractor>pMOG; //MOG Background subtractor

Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor

Ptr<BackgroundSubtractorGMG>pGMG; //MOG2 Background subtractor

pMOG = new BackgroundSubtractorMOG();

Mat resizeF;

Mat fgMaskMOG; //fg mask generated by MOG method

doublecurrentDist = 0;

while (true)

{

Mat imgOriginal;

boolbSuccess = cap.read(imgOriginal); // read a new frame from video

if (!bSuccess) //if not success, break loop

{

cout<< "Cannot read a frame from video stream" <<endl;

break;

}

resize(imgOriginal, resizeF, Size(imgOriginal.size().width / 4, imgOriginal.size().height / 4));

pMOG->operator()(resizeF, fgMaskMOG);

Mat imgHSV;

std::vector<std::vector<cv::Point>> contours;

std::vector<cv::Vec4i> hierarchy;

cv::findContours(fgMaskMOG,

contours,

hierarchy,

CV_RETR_TREE,

CV_CHAIN_APPROX_SIMPLE,

cv::Point(0, 0));

std::vector<std::vector<cv::Point>>contours_poly(contours.size());

std::vector<cv::Rect>boundRect(contours.size());

for (inti = 0; i<contours.size(); i++)

{

cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);

boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i]));

}

if (boundRect.size())

{

cv::Rectrect = *boundRect.begin();

if (isFindContour)

{

doubledistX = rect.br().x - prevX, distY = rect.br().y - prevY;

doubledist = std::sqrt(distX*distX + distY*distY);

currentDist += dist;

cout<<distX<< " " <<distY<<endl;

}

prevX = rect.br().x, prevY = rect.br().y;

isFindContour = true;

}

else

{

isFindContour = false;

}

// then put the text itself

putText(imgOriginal, text, textOrg, fontFace, fontScale,

Scalar::all(255), thickness, 8);

imshow("Original", imgOriginal); //show the original image

if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop

{

cout<< "esc key is pressed by user" <<endl;

break;

}

frame++;

}

return 0;

} int radius = 1;

int radius_max=10;

//

// функция-обработчик ползунка -

// радиусядра

void myTrackbarRadius(int pos) {

radius = pos;

}

int iterations = 1;

int iterations_max = 10;

if (frame % TimeFrame == 0)

{

std::ostringstreamstrs;

strs<<currentDist;

text = strs.str() + " pixels per second";

currentDist = 0;

cout<< text <<endl;

}

intfontFace = FONT_HERSHEY_DUPLEX;

doublefontScale = 1;

int thickness = 1;

int baseline = 0;

Size textSize = getTextSize(text, fontFace,

fontScale, thickness, &baseline);

baseline += thickness;

// center the text

Point textOrg(10, textSize.height + marginTextTop);

// then put the text itself

putText(imgOriginal, text, textOrg, fontFace, fontScale,

Scalar::all(255), thickness, 8);

imshow("Original", imgOriginal); //show the original image

if (waitKey(30) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop

{

cout<< "esc key is pressed by user" <<endl;

break;

}

frame++;

}

return 0;

}

Рассмотрим подробнее определение конструктора.

VideoCapturecap(""); Данной командой мы указываем источник видеопоследовательности, на данный момент это видеофайл, который мы в итоге получаем из видеопоследовательности онлайн-камеры.

Далее мы с помощью команды doublefps происходит расчет частоты кадров, путем считывания количества кадров в переменную за интервал времени. Данная процедура необходима для получения интервала времени, в будущем необходимого для расчета скорости объекта.

namedWindow("Control", CV_WINDOW_AUTOSIZE)необходима для создания рабочего окна, в которое будет происходить вывод видеопоследовательности и результатов измерений Рабочее окно будет автоматически подстраиваться под возможности экрана пользователя.

Необходимо обрабатывать каждый полученный кадр, используя функцию cvCreateTrackbar, которая позволяет преобразовывать кадры и хранить их в переменной imgOriginal. Благодаря этому процессу мы сможем сравнивать последующие кадры друг с другом, для нахождения объекта.

Функция pMOG = newBackgroundSubtractorMOG() позволяет преобразовывать многоканальное изображение в одноканальное, для упрощения поиска объекта. Учитывая, что преобразованное изображение требуется только для вывода на исходном изображении расчетов, вся дальнейшая работа с кадром будет происходить в переменной fgMaskMOG.

После того как кадр был обработан, оригинал изображения транслируется на экран, а программа при помощи boolbSuccess = cap.read(imgOriginal); начинает работу со следующим кадром. Вся работа над видеопоследовательностью происходит в режиме реального времени.

Команда MatimgHSV позволит использовать функцию вычитания фона. Принцип работы: из исходного изображения, содержащее фон и объект, вычитается изображение, содержащее только фон, затем получившееся изображение обрабатывается для удаления шумов. Требуется два кадра: изображение с объектом и изображение без объекта. В результате получаем маску, которая очень точно повторяет объект на исходном изображении. Действительно точных результатов можно добиться лишь при совпадающем фоне, но так как у нас сплошной фон черного цвета, то проблем с вычитанием с использованием функции не наблюдается.

Функция td::vector<std::vector<cv::Point>>contours_poly(contours.size()); позволяет искать замкнутый контур в маске. Если такого контура не нашлось, то программа перестает обработку кадра и переходит к следующему. Ниже приведен код для поиска контура и объекта :

import numpy as np

import cv2

cap = cv2.VideoCapture('slow.flv')

# params for ShiTomasi corner detection

feature_params = dict( maxCorners = 100,

qualityLevel = 0.3,

minDistance = 7,

blockSize = 7 )

# Parameters for lucas kanade optical flow

lk_params = dict( winSize = (15,15),

maxLevel = 2,

criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# Create some random colors

color = np.random.randint(0,255,(100,3))

# Take first frame and find corners in it

ret, old_frame = cap.read()

old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)

# Create a mask image for drawing purposes

mask = np.zeros_like(old_frame)

while(1):

ret,frame = cap.read()

frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# calculate optical flow

p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

# Select good points

good_new = p1[st==1]

good_old = p0[st==1]

# draw the tracks

for i,(new,old) in enumerate(zip(good_new,good_old)):

a,b = new.ravel()

c,d = old.ravel()

mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)

frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)

img = cv2.add(frame,mask)

cv2.imshow('frame',img)

k = cv2.waitKey(30) & 0xff

if k == 27:

break

# Now update the previous frame and previous points

old_gray = frame_gray.copy()

p0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()

cap.release()

Ниже приведен и описан результат работы программы.

Для дальнейшей работы с изображением используется принцип бинаризации - неизменный фон становится черным, а меняющийся объект, в данном случае рука - становится белым (рис 3.1).

Рис. 3.1 - Бинаризация изображения

После процесса бинаризации, достаточно легко определить объект на изображениии в дальнейшем его не терять, если не будет резких смен кадров.(рис. 3.2).

Рис. 3.2 - Определение объекта и его вершин

Заключение

В результате проделанной работы было разработано приложение с использованием алгоритма Лукаса-Канаде, реализованного на основе библиотеки OpenCV.

Для достижения поставленной цели были решены следующие задачи:

• Рассмотрено понятие оптический поток;

• Подготовлена среда разработки языка С++;

• Разработано приложение;

• Проведен анализ разработанного приложения

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

Список использованных источников

1. Шилдт Г. C++. Базовый курс [Текст]/ Шилдт Г. М.: «Вильямс», 2008. - 624 с.

2. Щупак Ю. C/C++. Структурное и объектно-ориентированное программирование: практикум [Текст]/ Щупак Ю., Павловская Т. - СПб.: «Питер», 2010. - 436 с.

3. Bradski G. Learning OpenCV: Computer Vision with the OpenCV Library [Текст]/ Bradski G., Kaehler A. - «O'Reilly Media», 2008. - 123 с.

4. Рао С. Освой самостоятельно C++ за 21 день[Текст]/ М.: «Вильямс», 2015. - 699 с.

5. Подбельский В.В. Язык C++. Учебное пособие [Текст] / В.В. Подбельский - Москва: Финансы и статистика, 1994 - 560с.

6. Седжвик Р. Алгоритмы на C++ [Текст]/ Седжвик Р. М.: «Вильямс», 2011. - 1056 с.

7. Литвиненко Н. А. - Технология программирования на С++ [Текст]/ Гуревич С -М.: БХВ-Петербург, 2010. - 281 с.

8. Ирэ Пол. Объектно-ориентированное программирование с использованием C++ / Пол. Ирэ; пер. с англ. - Киев: НИИПФ ДиаСофт Лтд, 1996 - 480с.

9. Форсайт Д. Компьютерное зрение. Современный подход / Форсайт Д., Понс Ж. // М: Издательский дом" Вильямс. - 2004. 314с.

10. Грузман И.С. Цифровая обработка изображений в информационных системах: Учебное пособие / И.С. Грузман, В.С. Киричук, В.П. Косых и др. - Новосибирск: Изд-во НГТУ, 2002. - 352 c.

11. OpenCV documentation [Electronic resource]//OpenCV documentation. 2014. URL: ttp://docs.opencv.org/ (access date 24.02.2015)

Приложение А

Программный код

import cv2

import numpy as np

cap = cv2.VideoCapture("vtest.avi")

ret, frame1 = cap.read()

prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)

hsv = np.zeros_like(frame1)

hsv[...,1] = 255

while(1):

ret, frame2 = cap.read()

next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)

flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)

mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])

hsv[...,0] = ang*180/np.pi/2

hsv[...,2] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX)

bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)

cv2.imshow('frame2',bgr)

k = cv2.waitKey(30) & 0xff

if k == 27:

break

elif k == ord('s'):

cv2.imwrite('opticalfb.png',frame2)

cv2.imwrite('opticalhsv.png',bgr)

prvs = next

cap.release()

cv2.destroyAllWindows()

importnumpyasnp

Продолжение приложения А

import cv2

cap = cv2.VideoCapture('slow.flv')

# params for ShiTomasi corner detection

feature_params = dict( maxCorners = 100,

qualityLevel = 0.3,

minDistance = 7,

blockSize = 7 )

# Parameters for lucas kanade optical flow

lk_params = dict( winSize = (15,15),

maxLevel = 2,

criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# Create some random colors

color = np.random.randint(0,255,(100,3))

# Take first frame and find corners in it

ret, old_frame = cap.read()

old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)

# Create a mask image for drawing purposes

mask = np.zeros_like(old_frame)

while(1):

ret,frame = cap.read()

frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# calculate optical flow

p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

# Select good points

good_new = p1[st==1]

Продолжение приложения А

good_old = p0[st==1]

# draw the tracks

for i,(new,old) in enumerate(zip(good_new,good_old)):

a,b = new.ravel()

c,d = old.ravel()

mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)

frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)

img = cv2.add(frame,mask)

cv2.imshow('frame',img)

k = cv2.waitKey(30) & 0xff

if k == 27:

break

# Now update the previous frame and previous points

old_gray = frame_gray.copy()

p0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()

cap.release()

import numpy as np

import cv2

cap = cv2.VideoCapture('slow.flv')

# params for ShiTomasi corner detection

feature_params = dict( maxCorners = 100,

qualityLevel = 0.3,

minDistance = 7,

blockSize = 7 )

# Parameters for lucas kanade optical flow

lk_params = dict(winSize = (15,15),

Продолжение приложения А

maxLevel = 2,

criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# Create some random colors

color = np.random.randint(0,255,(100,3))

# Take first frame and find corners in it

ret, old_frame = cap.read()

old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)

# Create a mask image for drawing purposes

mask = np.zeros_like(old_frame)

while(1):

ret,frame = cap.read()

frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# calculate optical flow

p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

# Select good points

good_new = p1[st==1]

good_old = p0[st==1]

# draw the tracks

for i,(new,old) in enumerate(zip(good_new,good_old)):

a,b = new.ravel()

c,d = old.ravel()

mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)

frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)

img = cv2.add(frame,mask)

cv2.imshow('frame',img)

Продолжение приложения А

k = cv2.waitKey(30) & 0xff

if k == 27:

break

# Now update the previous frame and previous points

old_gray = frame_gray.copy()

p0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()

cap.release()

Приложение Б

Презентационный материал

Размещено на Allbest.ur

...

Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.