Подсчёт объектов (людей), пересекающих линию (People counting) Самый простейший путь при подсчёте объектов – это использование детектирования движений. Например, используя ту же функцию update_mhi из примеров OpenCV. Собственно решение напрашивается само – следить за выделяемыми областями движения, и как только происходит пересечение заданной линии, то увеличивать значение счётчика. Однако функция update_mhi не предназначена для слежения за объектами, поэтому эту часть придётся делать самостоятельно. На рисунке 1 показано обнаруженные центра движений (а), и изменения положений центров движений (б). Рис. 1. Центры движений в кадре (а), изменение движений (b) Красные центры – старое местоположение, чёрные – новое. Одной из красных точек не соответствует чёрной, т.к. объект остановился и не двигается. R – максимальное расстояние, на которое может сместиться объект за один кадр. Для наблюдения за объектами будет использоваться следующая структура: struct _OBJECT_ { int x,y; //Координаты центра объекта int w,h; //Ширина, высота объекта int timer; //Задержка, позволяющая следить за объектом после остановки int num; //Номер объекта int object;//Соответствие с новым объектом int inn; //Переменная, показывающая где находится объект относительно линии http://recog.ru Создание документа: 30 декабря 2011 (Кручинин Александр) пересечения }VObject[MAX_OBJECTS],BVObject[MAX_OBJECTS]; VObject – текущий массив объектов, BVObject – предыдущий массив объектом. При каждом анализе детектируемых зон, необходимо сначала сохранить предыдущий массив, например так: memcpy(BVObject,VObject,sizeof(_OBJECT_)*MAX_OBJECTS); Если в предыдущем массиве нет ни одного объекта, то при анализе детектируемых зон можно вызвать следующий листинг: if (all_object<MAX_OBJECTS){ VObject[all_object].num=end_object; VObject[all_object].timer=timer_1; VObject[all_object].x=xx; VObject[all_object].y=yy; VObject[all_object].w=comp_rect.width; VObject[all_object].h=comp_rect.height; VObject[all_object].object=-1; VObject[all_object].inn=2; cur_object=all_object; all_object++; end_object++; } Листинг 1 Здесь, end_object – глобальный счётчик номеров объектов (всегда увеличивается); timer_1 – максимальное время задержки, после которого объект, которому не соответствия движения, уничтожается; xx, yy – текущие координаты центра движения; comp_rect – размер зоны движения. Если от предыдущего кадра сохранились объекты, то необходимо проверять соответствие со старыми объектами: min=-1; for(j=0;j<local_all_object;j++) if (BVObject[j].object==-1) { dd=LengthLine(xx,yy,BVObject[j].x,BVObject[j].y); if (dd<maxdist && (min==-1 || dd1>dd)) http://recog.ru Создание документа: 30 декабря 2011 (Кручинин Александр) { min=j; dd1=dd; } } if (min==-1) { VObject[all_object].num=end_object; VObject[all_object].inn=2; end_object++; } else { VObject[all_object].num=BVObject[min].num; VObject[all_object].inn=BVObject[min].inn; BVObject[min].object=0; } VObject[all_object].timer=timer_1; VObject[all_object].x=xx; VObject[all_object].y=yy; VObject[all_object].w=comp_rect.width; VObject[all_object].h=comp_rect.height; VObject[all_object].object=-1; cur_object=all_object; all_object++; Листинг 2 Здесь, local_all_object – общее количество старых объектов. Если указатель ссылки на новый объект (BVObject[j].object) равен -1, то сравнивается его удалённость с текущим объектом, если она минимальна и меньше расстояния R, заданного переменной maxdist, то соответствие найдено. Если соответствие не было найдено, то создаётся новый объект, иначе текущему объекту присваиваются номера и положения относительно граничной линии старого объекта. Определение пересечения линии достаточно просто – необходимо сравнивать значения inn текущего и старого объекта. Определить inn относительно положения текущей линии можно по следующему листингу: float ang=MakePolarF(center.x-Center.x,center.y-Center.y); http://recog.ru Создание документа: 30 декабря 2011 (Кручинин Александр) byte inn=0; if ((ang>In_ && ang<In_+PI) || (In_>PI && ang<PI-In_)) { inn=1; } if (VObject[cur_object].inn==0 && inn==1) All_In++; if (VObject[cur_object].inn==1 && inn==0) { All_Out++; } VObject[cur_object].inn=inn; Листинг 3 Здесь, center – это центр области движения; Center – центр заданной нами линии; In_ - угол в радианах вектора из центра линии в одну из сторон линии. Этот метод прост и не лишён недостатков, возможно он не всегда работает http://recog.ru Создание документа: 30 декабря 2011 (Кручинин Александр)