Това с проследяването на бройка обекти се оказва голяма забава.
В общи линии "простите" начини се оказват два - и двата се базират на вероятности. Първият одеве го споменах - базиран на хистограми и хистограмни backprojection-и. В общи линии проследяваме движещият се обект на базата на на това в кой регион от изображението имаме хистограмен баланс най-близък до вече сметнатия за обекта. Тъй като използваме HSV colorspace е относително достатъчно да ползваме само H и S хистограми, 3D хистограмите се оказват лоша идея заради широките вариации между кадрите. Добра илюстрация на подхода е това:
https://www.youtube.com/watch?v=zXI2wOFaQ7QПредимствата на този метод са че е много бърз и че осветлението не играе огромна роля - ако обектът попадне в сянка, съотношенията между bin-овете в хистограмата ще се запазят сравнително добре (в някакви рамки) CAMShift е адаптивен алгоритъм и добре се нагажда и към промяна на ориентация и размер на обекта. Недостатъците обаче са много - първият е че в сцената може да имаме друг обект, който по-добре да пасва на моделната хистограма. При което почваме да следим грешния обект. Другият огромен проблем (който винаги е проблем, но тук е ужасно голям проблем) - колизия на два обекта води до "загубване" на дирята на единия от тях. Това е понеже в точката на колидиране, хистограмите на "общия" обект са едни и същи и в двата случая почваме да клоним към "общия обект" след не много итерации. Това не е огромен проблем ако камерата ни е разположена точно над главата и нямаме "презастъпване". Но случаят обикновено не е такъв. Другият проблем е че тези изпълнения са изключително чувствителни към клатенето на камерата. Друг проблем е че когато обектът се вижда под различен ъгъл, хистограмата му може да е съвсем различна, бруталният пример би бил с кубче което се върти и всяка страна му е с различен цвят. Ще го загубим в момента в който се извърти така че не виждаме вече страната за която сме смятали хистограмите.
Евентуални подобрения са възможни (аз си играх) - примерно през няколко кадъра да преизчисляваме хистограмата-модел, но това не е много надеждно. Решението на проблема с проследяване на грешни обекти се минимизира чрез използване на побитови маски (при които чертаем маска малко по-голяма от текущия размер на обекта и залагаме на хипотезата че обектът няма рязко да си смени позицията и размера - ако го направи, ще го изгубим). Решаването на проблема с презастъпването е ужасно сложно (чисто математически). Решенията са хакове - можем да приемем че временно губим обекта при колизия, използваме калманов филтър за да "предскажем" позицията му след колизията и ако нещата пасват, обявяваме новооткрития обект за стария изгубен такъв. Това е ужасно чекиджийска история и лично на мен не ми харесва.
Сега втория метод - т.наречения "optical flow". Тук идеята е по-различна - вместо хистограми (вероятности някои стойности на пикселите да се срещат по-често от други), ползваме т.нар "features". Такива обикновено са ръбовете на обектите, разглеждаме ги като матрици където feature-а е центъра на матрицата и съотношението между централната стойност и съседите й трябва да стоят в някакви тесни рамки. В следващите кадри търсим същите features. Тук има много подходи при селектиране на началните features и откриването им в следващите кадри. Включително гореспоменатия SIFT, който върши добра работа ако по обекта има някаква текстура, примерно фирмено лого, което да следим (и не особено добра работа иначе). Аз си харесах Harris детектора, използван от Shi-Tomasi findGoodFeaturesToTrack(). Крайният резултат от това (засега):
https://www.youtube.com/watch?v=05ALOtdvOeQТакава сцена е убиец за всякакви CAMShift и като цяло за всякакви ползващи хистограмни вероятности подходи. Просто ще ги задави много лошо - имаме обекти с доста варираща големина под кофти ъгъл с ужасно много презастъпване. Тук обаче optical flow / feature tracking подходите работят далеч по-добре.
Предимства: доста по-добре отреагираме на случаи в които обектът се вижда под друг ъгъл и има съвсем различен вид от въпросния ъгъл. Доста по-добре се проследяват обекти, които колидират. Доста по-трудно се бъркаме с други обекти. Доста по-толерантно на клатене на камерата. Относително бързо.
Недостатъци: алгоритъмът (Lucas-Kanade, апропо пълна изродия, изобщо не мога да схвана как нещо работи след няколко прочита) е много чувствителен на промяна на осветеността на търсения обект. Влезе ли в сянка примерно, всичко отива по дяволите. Алгоритъмът не е перфектен и чат-пат някой feature се "открива" на случайно място в кадъра. С цел да минимизирам последното, ползвам два трика: първият е "обратна проверка" - на всеки кадър проследявам feature-ите в двете посоки - от предишен към следващ и от следващ към предишен и вземам само тези features, които се откриват в двата случая. Така се отсяват огромна част от случайните false positives. Другият номер е по-забавен - използвам функцията findHomography() за да открия трансформацията в перспективата между двата кадъра и да отсея "грешните" features - с други думи намираме модел при който всичките features променят координатите си между двата кадъра като тези, които не се вписват във въпросната трансформация ги изхвърляме. Не особено добра илюстрация на това:

Всички features които не се вписват във въпросната трансформация (горе из облаците има няколко такива) ги разкарваме.
Проблемът е че след няколко кадъра след тези агресивни проверки, не ни остават features за проследяване, затова динамично търсим нови такива. Другия проблем е че дори и тези агресивни проверки не отсяват грешките на 100% (както се вижда във видеото). Третият проблем е с откриването на центъра на движещият се обект - геометричният център на всички открити features не ни върши работа (прекалено много шум и вариации - дори Калманов филтър не може да се справи с тях). Та тук използвах друг фокус добре познат от статистиката - K means clustering. Идеята е да търсим точка, където имаме "клъстерирани" възможно най-голям брой открити features и тези дето са прекалено далеч от "клъстера" ги отсвирваме за сметките за центъра. Само на тези, които пасват, търсим геометричния център. За илюстрация това:

Тук имаме цели три центъра на клъстери, но нас ни интересува случаят когато имаме един "изявен такъв". Този център ползваме за център на открития обект. Когато смятаме траекторията на движещите се обекти, минаваме на всеки кадър координатите на центъра през Калманов филтър, за да "изгладим" траекторията от излишен "шум". Това както се вижда работи добре.
Големият проблем - вече не знаем реалният размер и форма на търсения обект. Можем да гадаем де, но не е точно. Много добре се вижда как смятаме за движещ се обект само краката или главата на човека. Това е резултата от homography филтъра - защото при движението си, главата на човека може да се движи в една посока, ръцете и краката в други, но ние вземаме предвид единствено "доминиращата" тенденция. Та нямаме красивите очертаващи рамки от Camshift алгоритъма.
Крайното решение? Вероятно някакво хибридно такова. Обаче още не мога да измисля как да стане. Двата подхода са радикално различни и е доста трудно да се обединят

Защо проследяването на обекти е забавно нещо иначе - защото има доста практични приложения в крайна сметка. Като изключим видеонаблюдението, където бихме искали да получаваме аларми когато някой обект примерно навлезе в забранена зона, доста интересни приложения има за следене на интензивност на трафика, откриване на задръствания, проследяване на потока от пазаруващи в някой мол или супермаркет, откриване на пътни нарушения или "утилизиране" на паркинги, всякакви такива неща.
А, другото забавно нещо което открих покрай тези експерименти е че мога да махам с ръце пред камерата и да го използвам като mouse pointer, хаха. Само дето кликането не знам как трябва да стане. Но е забавно донякъде, напомня ми за разни sci-fi филми дето разни хора махат с ръце и отварят местят и затварят разни джамове