Kaptain.
Telegram /
LinkedIn /
Email /
GIT /
RSS /
GPG /
Заказ печатных плат

№ 8620 В разделе
Programming
от March 21st, 2018,
В подшивках: Computer Vision, OpenCV, Python
Встала задача отслеживания движения рядом с конкретной областью. Камера хоть и умеет сама детектить движение, но делает это очень топорно и в последствии теряя записи. Было принято решение написать программу, которая обрабатывает видео файлы и находит движение в указанных мной областях. Выбор пал на библиотеку OpenCV, позволяющую очень удобно работать с видео и графикой, она универсальная, имеет биндинг для python и работает под Linux и Windows.
В программу вложены функции установки тонких параметров: минимальная яркость передвигающегося элемента, количество найденных изменений после которых срабатывает тревога и количество пропущенных фреймов. Чем больше пропускаете фреймов, тем менее вероятно обнаружить движение ведь если объект передвигается слишком быстро он может попасть в неучитываемый отрезок времени. Тоже самое касается и минимальной яркости, чем больше, тем хуже. Также на обнаружение влияет и размер передвигающегося объекта, который напрямую влияет на количество измененных пикселов и чем выше это значение, тем крупее объект для обнаружения.
Здесь задается область обнаружения и параметры поиска. Координаты области задаются двумя точками [x1, y1, x2, y2] по которым вырезается прямоугольник. weightAlarm задает минимальный размер объекта, а lightingAlarm минимальную яркость в разности фреймов.
coord = [366, 790, 462, 884] weightAlarm = 250 lightingAlarm = 30 skipFrames = 6
Весь алгоритм строится на сравнении 3 изображений, хранящихся в t0, t1 и t2.
def findDifference(t0, t1, t2):
d1 = cv2.absdiff(t2, t1)
d2 = cv2.absdiff(t1, t0)
return cv2.bitwise_and(d1, d2)
Каждый следующий фрейм перемещается по переменным в поиске различий. Цикл проходит по всему видеофайлу фрейм за фреймом, попутно пропуская обработку ненужных фреймов и при нахождении различий сохраняя полностью фрейм в отдельный файл.
while(cap.isOpened()):
frameNum += 1
if frameNum >= framesCount:
break
else:
ret, frame = cap.read()
if frameSkip <= skipFrames:
frameSkip += 1
continue
else:
frameSkip = 0
imgROI = cropRegionOfInterest(frame, coord)
t0 = t1
t1 = t2
t2 = cv2.cvtColor(imgROI, cv2.COLOR_BGR2GRAY)
diffImage = findDifference(t0, t1, t2)
cv2.imshow('Movement', diffImage)
if getWeight(diffImage, lightingAlarm) > weightAlarm:
print('I found! Frame {}'.format(frameNum))
name = "out/frame%d.jpg" % frameNum
cv2.imwrite(name, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
Вызов imshow не обязателен и если его убрать это сохранит достаточно много процессорного времени. Обработка видео длительностью 2 часа 10 минут заняла чуть более 10 минут при размере области 96х94 пикселя со скважностью 6. Не знаю как вам, а я считаю результат неплохим и его можно улучшить.
Тестовое видео
Область обнаружения:
Результат:
weightAlarm = 250
lightingAlarm = 30
skipFrames = 6
UPDATE! Сегодня класс начал поддерживать несколько охранных зон.
Проход по 2 охранным зонам:
Processing: /media/Documents/tmp/detect_motion/20180320112608-20180320160500_2.mp4 FPS: 25 Frames count: 7848 Length: 00:05:14 Movement! Frame 856, time 00:00:34, zone zone 1 Movement! Frame 864, time 00:00:35, zone zone 1 Movement! Frame 872, time 00:00:35, zone zone 1 Movement! Frame 880, time 00:00:35, zone zone 1 Movement! Frame 888, time 00:00:36, zone zone 1 Movement! Frame 896, time 00:00:36, zone zone 1 Movement! Frame 904, time 00:00:36, zone zone 1 Movement! Frame 6632, time 00:04:25, zone zone 1 Movement! Frame 6640, time 00:04:26, zone zone 1 Movement! Frame 6648, time 00:04:26, zone zone 1 Movement! Frame 7840, time 00:05:14, zone zone 2 real 0m31,290s
А еще было бы круто распараллелить обработку на несколько ядер процессора, а не молотить все на одном.
Вот вам репозиторий с полным кодом https://git.blindage.org/21h/detect-motion
Fortune cookie: Hear about... the freshman coed who decided not to sign up for a course in sex education when she heard the final exam would be oral?
Leave a Reply