WinAPI FAQs
Posted on September 2nd, 2007кльовий FAQ по Win32 API із прикладами на С++
http://faqs.org.ru/progr/windows/win32api.htm
http://sources.ru/cpp/faqs/index.htm
і на десерт Перехват API-функций в Windows NT/2000/XP
персональний IT блог
кльовий FAQ по Win32 API із прикладами на С++
http://faqs.org.ru/progr/windows/win32api.htm
http://sources.ru/cpp/faqs/index.htm
і на десерт Перехват API-функций в Windows NT/2000/XP
В цій статті я хочу описати простий алгоритм, який дозволяє розділити рухомий об’єкт і статичний фон в послідовності кадрів. Маємо вхідний файл. Наша задача знайти статичний фон і прибрати рухомий об’єкт.
Середовище. На мою думку, найоптимальнішим середовищем для подібних експериметів є Virtual Dub. Він має дуже простий інтерфейс для створення власних фільтрів. На кожній ітерації фільтр отримує вхідний і вихідний буфери і їх характеристики. Піксел має формат RGB32, але ефективними є тільки 24 біта (по 8 біт на канал). Для створення фільтру необхідно мати Virtual Dub filter SDK (http://www.virtualdub.org/filtersdk) і будь яку сучасну версію Visual C++ (хоча я не впевнений стосовно VS Express Edition).
Шуми. Шуми невід’ємна частина відеоданих. Спричинені вони недосконалістю знімальної техніки а також компресією, що у випадку із відео дуже рідко буває без втрат якості. Тому навіть у нерухомої частини зображення конкретний піксел не може бути стабільним. Тому я вирішив поділити зображення на сегменти розміром 5х5 пікселів. Такий розмір сегменту в нашому випадку достатній для того щоб випадкові відхилення окремого піксела не сильно впливали на оцінку сегменту вцілому, крім того розмір відеофайлів зазвичай кратний 5-ти як по вертикалі так і по горизонталі.
Оцінка сегменту і маска кадру. Для оцінки сегменту я використовую структуру RGB48 (по 16 біт на канал). Ітеруючи по всім пікселам сегменту я знаходжу суму для кожної з компонент:
RGB48 val;
//....
val.r += u16((ln[pixel] & RED32) >>16);
val.g += u16((ln[pixel] & GREEN32)>>8);
val.b += u16((ln[pixel] & BLUE32) >>0);
u16 тут 16-бітне беззнакове ціле. Маскою кадру я називаю матрицю оцінок сегментів.
Відстань між сегментами і кадрами. Відстань між сегментами це оцінка того наскільки сильно відрізняються два сегменти. Як оцінку я використовую суму різниць кожного з компонентів:
u32 Distance(RGB48 v1, RGB48 v2){
u32 ret = 0;
ret += abs(v1.r - v2.r);
ret += abs(v1.g - v2.g);
ret += abs(v1.b - v2.b);
return ret;
}
Якщо відстань двох сегментів перевищує поріг то вважається що сегменти відрізняються. Як оцінку відстані між кадрами я використовую кількість сегментів що відрізняються. Ось візуалізація різниці між масками першого кадру і теперішнього
Червоні сегменти - це сплільна область, сині сегменти показують різницю між кадрами. Дивлячись на це я прийшов до висновку: перший кадр можна поділити на 2 області - фон і об’єкт. Оскільки в наступних кадрах об’єкт рухається, то можна зібрати статистику по стабільності різниці першого кадру із наступними. Робиться це наступним чином: якщо цей сегмент відрізняється від аналогічного в першому кадрі, то +1 в матрицю на відповідні кординати.
void UpdateSegmentStability(const RGB48 *new_frame_mask){
u32 sz = MaskWidth()*MaskHeight();
for (u32 i = 0; i < sz; i++)
{
m_pSegStability[i] += Far( m_pFirstFrameMask[i], new_frame_mask[i]) ? 1 : 0;
}
}
Ось що з цього вийшло:
Далі задача зводиться до наступного: потрібно знайти кадр із високою відстанню від першого і об’єднати їхні сегмети що відносяться до фону. Я цей процес зробив ітеративним: спочатку беремо перший кадр із відстанню більше нуля і зберігаємо його, а потім як тільки знаходимо кадр із більшою відстанню, то робимо заміну на нього. Ось що вийшло:
Код(VC++ 2005) плагіну можна завантажити тут: mv_det.rar
Скомпілений плагін тут: mv_det.vdf
Тестовий відеофайл тут: mouse.avi
Прокоментувати статтю можна тут