Участник:MariaAleshina/Поиск устойчивых зависимостей в движении транспортных потоков города Москвы
Материал из MachineLearning.
(→Обработка исходных данных) |
|||
(53 промежуточные версии не показаны) | |||
Строка 1: | Строка 1: | ||
{{Tip|На странице изложена примерная структура будущей статьи посвященной исследованию задачи поиска устойчивых зависимостей в движении транспортных средств города Москвы студенткой [[Участник:MariaAleshina|Марией Алёшиной]] в рамках работы над дипломом}} | {{Tip|На странице изложена примерная структура будущей статьи посвященной исследованию задачи поиска устойчивых зависимостей в движении транспортных средств города Москвы студенткой [[Участник:MariaAleshina|Марией Алёшиной]] в рамках работы над дипломом}} | ||
== Предпосылки == | == Предпосылки == | ||
+ | В связи с большим увеличением числа транспортных средств в городе Москве возникла проблема образования большого числа пробок, участились случаи аварий. Авария на одной дороге может повлечь за собой образование пробок на близлежащих трассах. Кроме того, каждое утро и каждый вечер буднего дня возникает невероятное число заторов, связанных с тем, что люди едут на работу или с работы. Это все примеры того, что многие ситуации на дорогах не случайны. | ||
+ | |||
+ | В движении транспортных потоков внутри одного города существуют устойчивые зависимости, обнаружение которых и является главной (окончательной) задачей этой работы. | ||
+ | |||
== Постановка задачи == | == Постановка задачи == | ||
Работа состоит в анализе данных (в частности в поиске некоторых зависимостей) движения транспортного потока города Москвы на основе данных, полученных с видеокамер сервиса Яндекс.Карты. | Работа состоит в анализе данных (в частности в поиске некоторых зависимостей) движения транспортного потока города Москвы на основе данных, полученных с видеокамер сервиса Яндекс.Карты. | ||
Конкретнее, можно разделить задачу на несколько этапов. Для начала требуется скопировать видео с Яндкс.Карт и сохранить его в формате, удобном для дальнейшей обработки. Далее следует этап обработки видео. В результате требуется по видео определить такой набор параметров, как количество полос дороги, скорость потока, плотность потока и некоторые другие. Поскольку эти параметры, очевидно, не постоянны, в результате для оценки каждого парамера по данным с одной камеры можно построить временной ряд. Следующая задача состоит в одновременном (ну или почти одновременном) сборе данных с нескольких камер и построении для них временных рядов. Анализируя эти временные ряды для различных камер, появляется возможность установить некоторые закономерности в движении по Москве ("графу дорог"). Например возможно спрогнозировать образование пробок, заторов и других ситуаций в различных частях Москвы. | Конкретнее, можно разделить задачу на несколько этапов. Для начала требуется скопировать видео с Яндкс.Карт и сохранить его в формате, удобном для дальнейшей обработки. Далее следует этап обработки видео. В результате требуется по видео определить такой набор параметров, как количество полос дороги, скорость потока, плотность потока и некоторые другие. Поскольку эти параметры, очевидно, не постоянны, в результате для оценки каждого парамера по данным с одной камеры можно построить временной ряд. Следующая задача состоит в одновременном (ну или почти одновременном) сборе данных с нескольких камер и построении для них временных рядов. Анализируя эти временные ряды для различных камер, появляется возможность установить некоторые закономерности в движении по Москве ("графу дорог"). Например возможно спрогнозировать образование пробок, заторов и других ситуаций в различных частях Москвы. | ||
- | |||
- | |||
== Этапы решения задачи == | == Этапы решения задачи == | ||
Решение задачи делится на несколько этапов: <br /> | Решение задачи делится на несколько этапов: <br /> | ||
- | 1 | + | 1. Получение данных с одной из камер на сайте Яндекс |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | === Получение | + | : Выкачивание видео с сервиса Яндекс.Карты и сохранение его в формате, удобном для дальнейшей обработки (например .avi). Объем информации (длительность видео) должен быть достаточно велик. |
+ | |||
+ | 2. Обработка исходных данных | ||
+ | |||
+ | : Покадровая обработка полученного видео-файла. Нужно попробовать несколько вариантов обработки - вычитание кадров, медиана, вычитание фона и т.п. Приведение изображений к бинарному виду. Создание последовательности кадров, на основе которой можно производить непосредственно анализ и/или вычисление необходимых параметров. | ||
+ | |||
+ | 3. Выделение одного и того же движущегося объекта на разных кадрах | ||
+ | |||
+ | : Решение задачи слежения | ||
+ | |||
+ | 4. Получение необходимой информации из видео-файла и построение временных рядов | ||
+ | |||
+ | : Оценка параметров движения потока в каждый момент времени. Например плотность потока, скорость потока и другие. Возможно необходимо оценить эти параметры отдельно для каждой полосы дороги. Оценка количества полос на дороге. Построение временных рядов, характеризующих изменение вышеописанных параметров на протяжении длительного периода времени. Анализ этих временных рядов, выявление закономерностей, связанных с изменением времени суток, дней недели. Это зависит от объема информации, которую придется обрабатывать | ||
+ | |||
+ | 5. Подсчет параметров объектов на "плохих" видеозаписях и при плотных потоках | ||
+ | : Здесь мы сталкиваемся с проблемой: разработанный выше алгоритм работает не всегда. Поэтому теперь нашей задачей является разработка и реализация альтернативного алгоритма. Это параметрический алгоритм, работающий с временным рядом яркости. Основная задача - найти оптимальные параметры. | ||
+ | |||
+ | 6. Реализация удобного пользовательского интерфейса. | ||
+ | : Организовать работу пользователя с видеозаписью | ||
+ | |||
+ | 7. Сбор информации с нескольких камер | ||
+ | |||
+ | : Возможно единовременно | ||
+ | |||
+ | 8. Комплексный анализ ситуации на дорогах Москвы на основе информации с различных камер | ||
+ | |||
+ | : Например прогнозирование дорожной ситуации в какой-то конкретной точке Москвы на основе информации с близлежащих камер. | ||
+ | |||
+ | === Получение видео-ряда с одной камеры === | ||
+ | Перед тем, как начать обработку данных, необходимо их получить. Изначальный видео поток, который необходимо обрабатывать, находится на серверах Яндекса. Найти или получить прямой ссылки на поток не удалось, поэтому было принято решение сохранять видео с помощью видео грабберов. Среди множества программ, была выбрана Camtasia Studio, которая позволяет не только снимать определенную часть экрана, но и сохранять видео в различных форматах. | ||
+ | Существует так же одна небольшая проблема. Для того, чтобы не перегружать сервер, ровно раз в минуту видео поток на Яндекс.Картах останавливается, появляется стрелочка с надписью "Смотреть дальше". Так как для полноценного анализа данных требуется обрабатывать видео большой длины (сильно больше, чем минута), то появляется необходимость раз в минуту программно нажимать на эту стрелочку. В недрах интернета была найдена программа Сlickermann, которая позволяет программно управлять мышью. С помощью этой программы были сделаны следующие действия: раз в минуту происходит нажатие на стрелочку, после чего курсор мыши сразу отодвигается в другую часть экрана, чтобы не попадать в видеозапись. Все необходимые координаты задаются в ручную. | ||
+ | В результате с помощью все той же Camtasia Studio видео сохраняется в формате .AVI, как в самом удобном для обработки. | ||
+ | Пока примерная длина видео составляет 20 минут. Для полноценного анализа движения транспортных средств в Москве необходимо будет "снять" видео на пару часов. | ||
+ | |||
+ | Здесь есть несколько неприятностей. Видеопоток имеет очень плохое качество, скорость загрузки с сервера оставляет желать лучшего. Поэтому fps получаемого .AVI файла иногда слишком мало. | ||
+ | В идеале хотелось бы получить ссылку непосредственно на поток, тогде проблемы с зависанием видео решились бы. Но пока непонятно, как это сделать. | ||
=== Обработка исходных данных === | === Обработка исходных данных === | ||
+ | Следующим этапом после формировки .AVI файла является его обработка. Уже давно написано множество алгоритмов, библиотек и даже целых систем по обработке изображений в целом и видео в частности. Так что есть множество путей решения поставленной задачи. Был выбран следующий путь. | ||
- | = | + | Для обработки видео была написана программа в среде Visual Studio 6.0 на языке С++ c использованием библиотеки OpenCV (CV = Computer Vision). Это довольно большая разрабатываемая библиотека, в которой реализовано множество алгоритмов обработки изображений, удобно сделана работа с видео и даже представлена пара алгоритмов по Machine Learning. |
- | = Построение временных рядов для | + | |
+ | В данной работе производится обработка не самого .AVI файла, а кадров, из которых он состоит. С помощью программы VirtualDub на основе .AVI файла формируется последовательность фреймов (картинок в .BMP формате), дальнейшая обработка производится уже с ними. | ||
+ | |||
+ | Итак, первичная задача обработки видео состояла в выделении движущихся объектов. Вот несколько способов решения этой маленькой подзадачи. | ||
+ | * '''Покадровая разность''' | ||
+ | [[Изображение:Razn.PNG|thumb|Разность первого и второго кадров]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Fr2.PNG|thumb|Второй кадр]]</div> | ||
+ | <div class="tright" style="clear:none">[[Изображение:Fr1.PNG|thumb|Первый кадр]]</div> | ||
+ | : Самый примитивный алгоритм, использующийся для выделения движущихся объектов на видео - это покадровая разность. Рассматриваются 2 соседних кадра (в принципе можно брать кадры через один или даже через два), на основе которых формируется третье изображение, как попиксельная разность первых двух. Специфика видео, используемого в данной работе такова, что цвет одно и того же пикселя фона может немного отличаться от кадра к кадру, соответственно в результирующем изображении цвет этого пикселя не будет нулем. Поэтому кроме вычитания, необходимо сделать изображение монохромным с некоторым порогом. Все пиксели, цвет которых выше этого порога, становятся черными, все остальные - белыми. Порог - это тоже параметр, который необходимо подобрать так, чтобы движущиеся объекты были довольно четкими, но при этом чтобы было как можно меньше шумов. Задачу удаления шумов также можно решить различными другими алгоритмами, например медианным сглаживанием. | ||
+ | |||
+ | : Из-за плохого качества и медленной работы видео существует несколько проблем. Во-первых, очень много шума. Но с этим можно успешно бороться. Во-вторых, из-за того, что видео поток на Яндексе подгружается часто очень медленно, мы получаем несколько подряд идущих одинаковых кадров, что значит, что их разность - это пустой кадр. | ||
+ | |||
+ | * '''Вычитание фона''' | ||
+ | [[Изображение:Bkg.PNG|thumb|Исходный файл без фона, монохромный]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Source.PNG|thumb|Исходный кадр]]</div> | ||
+ | : Другая, более "умная" стратегия - сформировать фон, а потом вычесть этот фон из каждого кадра, в результате останутся только движущиеся объекты, не принадлежащий фону. | ||
+ | : Фон формируется на основе некоторого набора кадров. Количество кадров - параметр. | ||
+ | : Было реализовано два алгоритма выделения фона. | ||
+ | : Первый и самый простой можно кратко описать так: данный пиксель изображения считать фоном, если он не изменялся (а точнее изменялся в заданном небольшом диапазоне) на протяжении нескольких кадров. Параметром данного алгоритма является не только количество кадров, но и порог, определяющий допустимый диапазон изменения цвета пикселя. | ||
+ | |||
+ | : Далее приводится второй более "умный" алгоритм. | ||
+ | : Формируем изображение-разность первого и второго кадра. Считаем его изначально фоном. Но на этом изображении естественно будут пятна от движущихся машин. Получили своеобразную маску, которую накладываем на первый кадр. Далее берем разность второго и третьего кадров. На получившемся изображении тоже будут пятна от переместившихся машин, но эти пятна будут уже в другом месте. После этого, делаем попиксельную логическую операцию "И" или умножение для двух изображений-разностей. В результате получаем новую маску. В результате такого последовательного добавления точек, получаем фон. Далее фон последовательно вычитается из каждого кадра, таким образом выделяются движущиеся объекты. | ||
+ | |||
+ | (вставить картинки) | ||
+ | |||
+ | * '''Медианная фильтрация''' | ||
+ | [[Изображение:Med3.PNG|thumb|Результат применения медианного фильтра с окном 3]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Bkg.PNG|thumb|Исходный кадр без фона]]</div> | ||
+ | |||
+ | [[Изображение:Med7.PNG|thumb|Результат применения медианного фильтра с окном 7]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Med5.PNG|thumb|Результат применения медианного фильтра с окном 5]]</div> | ||
+ | : Естественно, полученное таким образом изображение содержит множество шумов. Кроме того, движущиеся объекты состоят из некоторого числа связных пятен. А для дальнейшей обработки желательно, чтобы каждая машина была представлена на изображении в виде одно связного пятна. Для решения этих двух проблем одновременно была применена медианная фильтрация. | ||
+ | : Опишем алгоритм работы медианного фильтра. Требуемое изображение загружается в память, далее производится проход по всем его пикселям с каким-то окном. Ширина окна - параметр фильтра. Обычно берут окно размера 3х3, 5х5 или 7х7 (для данной задачи как показала практика, нет смысла брать окно больше). Далее для каждого такого набора из 9ти, 25ти или 49ти пикселей вычисляется среднее значение цвета. Этим цветом заливается весь квадрат. В результате происходит эффективное удаление шума, а связные пятна, находящиеся на маленьком расстоянии друг от друга (то есть которые с большой вероятностью принадлежат одной машине) сливаются. Но здесь опять же возникает проблема. Машины, которые проезжают близко друг к другу (например по разным полосам), с большой вероятностью сливаются в одно связное пятно. Кроме того, машины, которые находятся еще далеко, распознаются как шум и удаляются. Но если для подсчета параметров потока поставить отсечку ближе к нижнему левому углу, то это перестает быть проблемой. | ||
+ | |||
+ | * '''Алгоритм FloodFill(заливки)''' | ||
+ | [[Изображение:Flf.PNG|thumb|Результат работы функции FloodFill]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Med5flf.PNG|thumb|Кадр]]</div> | ||
+ | : Следующая стадия обработки видео - выделение отдельных связных пятен (машин, движущихся объектов). Эта задача была решена с помощью простой функции FloodFill, реализованной в OpenCV. Принцип работы этой функции прост. Работа происходит с монохромным изображением. Белые пиксели обозначают фон, черные пиксели принадлежат движущимся объектам (машинам). Производится проход по пикселям изображения, пока не попадется черный пиксель. Вызываем функцию FloodFill, передавая ей как параметр координаты черного пикселя. Функция производит заливку связной области, содержащей заданный пиксель заданным цветом (отличным от черного). Таким образом в результате формируется изображение, на котором все связные пятна (машины) раскрашены в разные цвета. | ||
+ | |||
+ | === Выделение одного и того же движущегося объекта на разных кадрах === | ||
+ | После того, как проведена первичная обработка и на каждом кадре выделены движущиеся объекты, необходимо решить задачу поиска одного и того же объекта на каждом кадре. | ||
+ | |||
+ | Вот несколько возможных методов решения этой задачи. | ||
+ | |||
+ | * Можно воспользоваться тем, что по мере движения очертания машины меняются с точностью до размеров. Соответственно можно отдельно сохранить область изображения, соответствующую одной машине, пропорционально увеличивать или уменьшать ее и наложением искать совпадения на последующих (или предыдущих) кадрах. | ||
+ | |||
+ | * Другой способ основан на том, что для данного видео ряда есть возможность указать вектор движения потока (или несколько, если дорога с двусторонним движением или большим числом полос). Кроме того, можно вычислить, как изменяются размеры объекты при приближении и удалении от камеры. Соответственно на каждом кадре есть возможность для каждого связного пятна (машины) указать область изображения, в котором с большой вероятностью окажется машина на следующем кадре. После выделения такой области, переходим к следующему кадру и смотрим, какую часть зоны занимает пятно (машина). С помощью параметра-порога определяем, принадлежат ли пятна на первом и втором кадрах одной и той же машине. | ||
+ | |||
+ | Наконец-то эта задача решена! Было реализовано несколько алгоритмов. | ||
+ | ====Решение 1. По точечное сравнение объектов==== | ||
+ | Перед тем как решать задачу необходимо составить некоторое признаковое описание каждого пятна. Поэтому на первом кадре каждому черному пятну (движущемуся объекту) ставится в соответствие структура. | ||
+ | <pre> | ||
+ | struct Spot | ||
+ | { | ||
+ | int* x; //абсциссы точек, составляющих пятно | ||
+ | int* y; //ординаты точек, составляющих пятно | ||
+ | CvScalar color; // цвет пятна | ||
+ | int pixelnum; // количество точек в пятне | ||
+ | int* speed; // скорость пятна при переходе от кадра к кадру | ||
+ | bool up; // параметр, показывающий, с какой стороны от разделительной полосы находится пятно | ||
+ | bool out; // вышло ли пятно за кадр (true, если машина уехала из кадра) | ||
+ | bool counted; // посчитали ли мы уже эту машину? параметр, необходимый при подсчете количества машин | ||
+ | double wholespeed; // средняя скорость машины на видеозаписи | ||
+ | }; | ||
+ | </pre> | ||
+ | Некоторые параметры введены для удобства и не понадобились при решении дальнейших задач. | ||
+ | На основе такой структуры проводится анализ видеоряда. | ||
+ | |||
+ | Задача решена при помощи следующего алгоритма: | ||
+ | * Для первого кадры видео последовательности: | ||
+ | ** С помощью функции FloodFill закрасить все отдельные пятна разными цветами | ||
+ | ** Создать список существующих пятен. Каждое пятно имеет довольно большой список параметров. Основные из них - список координат точек, составляющих данное пятно, и цвет. | ||
+ | * Цикл. Для каждого следующего кадра | ||
+ | ** Найти черное пятно | ||
+ | ** В списке существующих пятен найти кандидата на совпадение. Далее возможны 2 ситуации. | ||
+ | *** Если кандидат найден, то обновляются данные о соответствующем пятне в списке. Цвет рассматриваемого пятна равен цвету кандидата. | ||
+ | *** Если кандидат не найден, то формируется новый элемент списка пятен. Пятну присваиваем новый цвет (вычисляется случайным образом) | ||
+ | ** Окрашиваем рассмотренное пятно в установленный цвет. | ||
+ | ** Переходим к следующему черному пятну и повторяем цикл | ||
+ | ** После просмотра всех пятен, смотрим, есть ли объекты, для которых на новом кадру не нашлось совпадений. Такие объекты считаются машинами, уехавшими из кадра. Они исключаются из дальнейшего рассмотрения. | ||
+ | <br\> | ||
+ | Теперь рассмотрим самый важный вопрос. Как сравнивать пятна? <br\> | ||
+ | В реализованном алгоритме пятна сравниваются по точечно. Примем несколько гипотез: | ||
+ | # За время между двумя кадрами машина не может сдвинуться больше, чем на ''определенное число'' пикселей. | ||
+ | # Для каждого отдельного видеоряда мы можем и должны вручную найти разделительную полосу на дороге и определить вектора движения машин в обе стороны. | ||
+ | <br\> | ||
+ | В соответствии с этими гипотезами, делаем следующее. <br\> | ||
+ | Сначала для каждого видеоряда необходимо вручную найти функцию (это линейная функция), описывающую разделительную полосу дороги, а так же указать, в какую сторону движутся машину по одну и по другую сторону от разделительной полосы.<br\> | ||
+ | Далее приступаем к непосредственному сравнению пятен. Рассматриваем 2 пятна. Одно классифицируемое (назовем его для краткости "Пятно1") и одно уже занесенное в список пятен, а значит присутствующее на предыдущем кадре ("Пятно2"). Наша задача определить, является ли "Пятно1" на текущем кадре тем же движущимся объектом, что и "Пятно2" на предыдущем кадре. "Пятно2" попиксельно сдвигается на вектора длин 0, 3, 6, 9, 12, 15. Все они имеют одно и то же направление. Это направление движения потока. Данный вектор заранее рассчитан для данного видеоряда. После сдвига происходит по точечное сравнение "Пятна2" (сдвинутого) и "Пятна1". Вычисляется величина, определяющая степень схожести объектов по формуле:<br\><br\> | ||
+ | <tex>Quality = \frac{hits}{(pixelnum1+pixelnum2)/2}</tex>,<br\><br\> | ||
+ | где hits - число совпавших точек, | ||
+ | pixelnum1 и pixelnum2 - число точек в сравниваемых пятнах. | ||
+ | <br\> | ||
+ | Если среди полученных величин самая большая превосходит заранее заданный порог ε = 0.85, то совпадение найдено. Иначе начинаем обработку следующего пятна.<br\> | ||
+ | Так же важно то, что в кандидаты мы выбираем только те пятна, который находят с той же стороны от разделительной полосы, что и классифицируемое пятно. При большом количестве движущихся объектов это помогает значительно сократить время работы алгоритма. | ||
+ | |||
+ | '''''Достоинства''''' | ||
+ | * Данный алгоритм довольно прост в реализации | ||
+ | * На "хороших" видеозаписях он показывает довольно неплохие результаты. Их можно оценить в следующих разделах, когда речь пойдет о подсчете параметров движения потока. | ||
+ | '''''Недостатки''''' | ||
+ | * Учитывая огромный объем обрабатываемой информации, данный алгоритм не в состоянии решить задачу за реальное время. | ||
+ | |||
+ | ====Решение 2. Построение матриц схожести==== | ||
+ | Данный алгоритм отличается от предыдущего способом сравнения пятен. Самый главный недостаток по точечного сравнения объектов - очень невысокая скорость обработки данных. Алгоритм, который мы рассмотрим в этом разделе, должен помочь решить эту проблему.<br\> | ||
+ | |||
+ | Построим для каждой пары кадров матрицу схожести движущихся объектов, в которой число строк - количество пятен на первом кадре, а число столбцов - количество выделенных объектов на втором кадре. В каждой ячейке такой матрицы запишем величину, характеризующую схожесть соответствующих объектов. Но проблема в том, что сравнивать объекты можно по абсолютно разным параметрам - по размеру, по форме, по местоположению и т.д. Выбрать какой-то один из этих критериев невозможно. Поэтому было принято решение отобрать самые информативные для данной задачи критерии схожести объектов и рассмотреть их суперпозицию. Схожесть m-ого объекта из первого кадра и n-ого объекта из второго определяется по формуле:<br\><br\> | ||
+ | <tex>a_{mn} = w_1 Square + w_2 Vector + w_3 Length</tex><br\><br\> | ||
+ | Здесь Square - величина, определяющая соответствие по площади(предположение: размер машины от кадра к кадру не должен значительно изменяться), Vector - по направлению (предположение: машины должны двигаться параллельно разделительной полосе), Length - по длине вектора (предположение: за время между двумя кадрами машина не может уехать на большое расстояние), <tex>w_1, w_2, w_3</tex> - веса, причем <tex>\sum_{i = 1}^3 {w_i} = 1</tex><br\> | ||
+ | Кроме того, величины Square, Vector, Length имеют тип double и лежат в промежутке [0, 1], где значение 1 - объекты полностью совпадают по данному критерию.<br\> | ||
+ | Параметры <tex>w_1, w_2, w_3</tex> необходимо некоторым образом настраивать. Сделать это можно, использовав два одинаковых кадра. При решении такой задачи заранее известен ответ. Максимум по каждой строке должен содержаться на диагонали матрицы. Исходя из этого настройку весов можно провести с использованием нейронной сети.<br\> | ||
+ | После того, как матрица сравнений построена, необходимо на ее основе решить поставленную задачу. В таблице в каждой строке выбирается максимальное число. То есть для каждого существующего объекта-машины на старом кадре выбирается наиболее похожий объект на новом кадре. <br\> | ||
+ | Здесь возможен ряд проблем:<br\> | ||
+ | * В строке нет максимума (2 и более чисел имеют одинаковые и при этом максимальные значения). | ||
+ | * Все числа в строке близки к 0 (ни один кандидат не подходит) | ||
+ | После проведения нескольких экспериментов, было выяснено, что такие проблемы на "хороших" видеозаписях возникают крайне редко. Обычно они связаны с очень плохим качеством видео. | ||
+ | |||
+ | === Сбор информации о потоке и построение временных рядов для различных параметров движения === | ||
+ | Следующий этап работы - расчет параметров потока для одной видеозаписи. Рассчитываются такие параметры, как количество проехавших машин и средняя скорость потока. | ||
+ | ==== Привязка к реальному времени ==== | ||
+ | Для расчета скорости необходима привязка видеозаписи к реальному времени. На некоторых видеозаписях на Яндекс.Картах в правом верхнем углу выводится реальное время. Но считывать цифры с видеозаписи - довольно трудоемкая отдельная задача. Кроме того, время есть не на всех камерах. Поэтому предлагается другой способ привязки кадров к реальному времени. Используется следующая особенность видеозаписей: ровно через каждые 2 минуты видеозапись прерывается, пользователю предлагается нажать на кнопку, чтобы продолжить просмотр. Значит, существует возможность посчитать количество кадров за 2 минуты. Если это число разделить на 120 (количество секунд в двух минутах), то мы получим количество кадров в одной секунде. Среди этих кадров будут повторяющиеся (т.к. качество видеозаписи не самое лучшее). | ||
+ | ==== Подсчет количества транспортных средств==== | ||
+ | Перейдем к непосредственному решению поставленной задачи, а именно к подсчету параметров потока. Для начала, рассмотрим алгоритм, с помощью которого был реализован подсчет количества машин. | ||
+ | [[Изображение:Area.PNG|thumb|Кадр, на котором обозначена разделительная полоса и отсечки для каждой области дороги]] | ||
+ | Каждая видеозапись содержит изображение дороги с двусторонним движением. На предыдущем этапе была выделена разделительная полоса. Теперь на каждой части дороги необходимо обозначить область, в которой транспортные средства с помощью нашего алгоритма выделяются лучше всего, а следовательно область, в которой их можно посчитать. Практически на любой видеозаписи границы областей удобно определять горизонтальными линиями. То есть другими словами, просто ставится отсечка и считается число машин, прошедших через эту отсечку. | ||
+ | <br\> | ||
+ | Теперь начнем подсчет. Если движущийся объект попал в область (хотя бы одна его точка оказалась внутри области), то прибавляем к счетчику машин единицу и устанавливаем флаг counted в значение true. Теперь, если на следующем шаге мы обнаружим ту же самую машину в заданной области, то просто не будем ее считать.<br\> | ||
+ | Теперь оценим, на сколько наш алгоритм ошибается. Вот данные, полученные при обработке одной видеозаписи, продолжительность которой 17 минут. В таблице приведены значения, полученные программно и посчитанные вручную. Внизу отображен график, показывающий различия между реальными и программно полученными данными.<br\> | ||
+ | Количество машин на видео Количество машин, посчитанных в программе<br\> | ||
+ | 22,00 24,00<br\> | ||
+ | 25,00 27,00<br\> | ||
+ | 19,00 21,00<br\> | ||
+ | 20,00 21,00<br\> | ||
+ | 18,00 20,00<br\> | ||
+ | 15,00 15,00<br\> | ||
+ | 21,00 21,00<br\> | ||
+ | 23,00 24,00<br\> | ||
+ | 20,00 21,00<br\> | ||
+ | 16,00 17,00<br\> | ||
+ | 22,00 24,00<br\> | ||
+ | 24,00 24,00<br\> | ||
+ | 23,00 23,00<br\> | ||
+ | 26,00 28,00<br\> | ||
+ | 25,00 25,00<br\> | ||
+ | 20,00 20,00<br\> | ||
+ | 24,00 26,00<br\> | ||
+ | <br\> | ||
+ | [[Изображение:Cars.PNG|Диаграмма количества машин по минутам]]<br\> | ||
+ | Легко видеть, что данные программы всегда немного выше, чем реальные. Это связано с тем, что выделенные транспортные средства, представленные в виде пятен, разваливаются, либо склеиваются, следовательно появляется один, а то и два новых объекта, которых на самом деле нет. Но также можно заметить, что ошибка эта систематическая и весьма небольшая, а следовательно с ней можно бороться и без улучшения алгоритма. Можно просто немного подкорректировать данные с учетом такой систематической ошибки.<br\> | ||
+ | Вычислим эту ошибку для данной видеозаписи:<br\> | ||
+ | Всего проехало машин – 363. Посчитано 381. <br\> | ||
+ | Ошибка = 381-363/381 = 0.047.<br\> | ||
+ | |||
+ | ==== Подсчет средней скорости потока ==== | ||
+ | Для подсчета средней скорости потока, ведется учет длин векторов, на которые смещается данной транспортное средство от кадра к кадру. В результате для каждого объекта вычисляется среднее значение среди всех длин. Это и есть средняя скорость транспортного средства. Для вычисления средней скорости потока необходимо всего лишь сложить средние скорости транспортных средств (движущихся в одну сторону!) и поделить на количество машин, полученное в предыдущем разделе. <br\> | ||
+ | Но скорость лучше вычислить в м/с или км/ч. Для этого необходимо обозначить на записи некоторую область, размер которой мы знаем или можем вычислить (например на Яндекс.Картах существует такая возможность, можно посчитать расстояние в метрах). Так же, учитывая то, что у нас есть привязка к реальному времени, появляется возможность посчитать, за какое время (в секундах) транспортное средство преодолевает выбранный нами путь. Отсюда получаем скорость в м/с. Перевести скорость в км/ч не представляет труда. | ||
+ | |||
+ | === Основные сложности === | ||
+ | После того, как такая большая работа была проведена с одной видеозаписью, были предприняты попытки применить описанный алгоритм для других видеозаписей.<br\> | ||
+ | [[Изображение:Jam_vc.PNG|thumb|Исходный кадр после применения описанного алгоритма выделения движущихся объектов]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Jam.PNG|thumb|Исходный кадр]]</div> | ||
+ | Сразу возникло множество проблем. Оказывается, что если видеозапись "хорошая" (то есть транспортный средства движутся с достаточно большими скоростями и расстояние между ними составляет несколько корпусов), то алгоритм работает приемлемо и даже хорошо. <br\> | ||
+ | Но часто на видеозаписи машины стоят в пробке или очень медленно движутся. И тогда проблемы возникают уже на стадии выделения движущихся объектов. | ||
+ | На рисунках, представленных справа, видно, что описанный алгоритм не может выделить движущиеся объекты. Он выдает набор разрозненных пятен, некоторые из которых на самом деле относятся к одной и той же машине. Работать с таким материалом дальше не представляется возможным.<br\><br\><br\><br\><br\> | ||
+ | ==== Вычитание фона, задающегося вручную ==== | ||
+ | [[Изображение:Jam_bkg.PNG|thumb|Исходный кадр после вычитания фона, заданного вручную]] | ||
+ | <div class="tright" style="clear:none">[[Изображение:Jam.PNG|thumb|Исходный кадр]]</div> | ||
+ | Для решения этой проблемы было предложено следующее: так как во время пробки машины стоят, и выделить фон программно не всегда представляется возможным, можно попробовать выделить фон вручную. То есть пользователь сам мышкой выбирает некоторое количество (10 - 20) точек, которые действительно принадлежат фону. Далее в программе анализируется яркость этих точек по каждому из каналов, определяются максимум и минимум яркости. То есть строится допустимый диапазон яркостей, в который должна попадать точка, чтобы быть фоном. Далее просто анализируются все точки изображения. Если яркость точки по каждому каналу попала в полученную область, то такая точка считается принадлежащей фону и вычитается из изображения. К сожалению, данная идея тоже дала плохие результаты. | ||
+ | |||
+ | == Альтернативный алгоритм. Обработка массива яркостей. == | ||
+ | В данной главе сделана попытка проанализировать плотные транспортные потоки. Основная проблема состоит в том, что стандартные разностные методы обработки изображений (выделения движущихся объектов на последовательности кадров) не работают в рассматриваемом случае. А значит, необходимо придумать альтернативные алгоритмы. Идея алгоритма, реализованного в данной задаче, была взята из книги «Цифровая обработка видеоизображений». | ||
+ | |||
+ | === Основные этапы разработки алгоритма === | ||
+ | Среди основных этапов можно выделить: | ||
+ | *Получение видеозаписей. Необходимо «скачать» нужные видеозаписи с сервиса «Яндекс.Карты» | ||
+ | *Расстановка рубежей. На каждой видеозаписи необходимо вручную поставить рубеж (линию), а далее считать число проехавших через нее машин. Чаще всего рубеж соответствует одной полосе на дороге. | ||
+ | *Реализация параметрического алгоритма подсчета машин для одного рубежа. | ||
+ | *Построение таблиц зависимости результатов работы алгоритма от значений параметров. | ||
+ | *Подсчет реального числа машин (вручную) и построение таблиц ошибок, | ||
+ | *Анализ таблиц ошибок и определение значений параметров. | ||
+ | |||
+ | === Описание алгоритма === | ||
+ | [[Изображение:Rub.png|thumb|Пример расстановки рубежей на кадре]] | ||
+ | Для начала, необходимо вручную задать рубеж/рубежи для данной видеозаписи. Обычно рубеж занимает одну полосу движения. (картинка с примером расстановки рубежей). После чего происходит построение массива значений яркостей на этом рубеже на каждом кадре. Далее на основе этого массива необходимо определить количество проехавших машин. Предполагается, что значение яркости фона (дороги) незначительно колеблется относительно некоторой величины. В качестве такой величины берем медианной значение нашего массива (обозначим как mediana), а в качестве параметра разброса – величину p1. | ||
+ | P1 – параметр, отвечающий за допустимое изменение яркости фона. | ||
+ | После этого, на основе полученного массива строится бинарный массив по следующим правилам: если значение яркости некоторого элемента массива находится в пределах [mediana-p1, mediana+p1], то относим такое значение к фону, т.е. заменяем на 0. Если описанное выше условие не выполняется, то считаем, что данный элемент соответствует наличию на рубеже машины, т.е. заменяем значение данного элемента массива на 1. | ||
+ | После этого, вводится второй параметр р2. Этот параметр имеет смысл расстояния между машинами в кадрах. По-другому, это минимальное число нулей, которое должно быть между совокупностями единиц для того, чтобы отделить две машины. То есть, если после совокупности единиц идет >=p2 нулей, то к уже посчитанному количеству машин прибавляется единица. | ||
+ | |||
+ | === Построение таблиц === | ||
+ | Для определения оптимальных значений параметров р1 и р2 применен следующий простой подход. Пусть значение р1 изменяются в пределах от 7 до 20, а значения р2 от 1 до 15. (Такие рамки были подобраны в ходе проведения экспериментов. Абсолютно верные результаты алгоритм выдает, когда параметры находятся именно в этих промежутках.) Для каждой пары (р1, р2) запускается описанный выше алгоритм. Результаты записываются в таблицу. Пример такой таблицы приведен ниже.<br /> | ||
+ | [[Изображение:Table1.png|Таблица результатов работы программы для разных значений параметров]]<br /> | ||
+ | Вручную посчитано, что на записи проехало 8 машин. Значения работы алгоритма приведены в таблице. Можно заметить, что верный ответ алгоритм выдает при значениях р1 = 15, 16, 17 и р2 = 1, 2, 3, 4, 5. | ||
+ | Далее для каждой такой таблицы посчитаны соответствующие таблицы ошибок. Вот пример одной из таких таблиц:<br /> | ||
+ | [[Изображение:Table2.png|Таблица ошибок]]<br /> | ||
+ | Ошибки считаются, как модуль разности между реальным количество проехавших машин и посчитанным в программе. | ||
+ | Очевидно, что на основе работы алгоритма на одном рубеже одной видеозаписи, невозможно оценить значения параметров р1 и р2. Поэтому было проведено множество экспериментов для различных видеозаписей. | ||
+ | |||
+ | ===Результаты и выводы === | ||
+ | Результаты приведены в таблице суммарной ошибки по большому количеству экспериментов.<br /> | ||
+ | |||
+ | [[Изображение:Table3.png|Таблица результатов]]<br /> | ||
+ | |||
+ | Выделенные значения соответствуют оптимальному соотношению параметров р1 и р2. Это те значения, при которых ошибка минимальна. (в данном случае минимальная ошибка – это ошибка в 7 машин из 111 действительно проехавших). <br /> | ||
+ | |||
+ | Заметим, что параметр р2 имеет смысл плотности потока. То есть изменяя р2, можно адаптировать данный алгоритм для потоков различной плотности. Но учитывая то, что для потоков с хорошо отделимыми транспортными средствами, у нас уже есть реализованный хорошо работающий алгоритм, в данном алгоритме р2 будем брать достаточно малым. | ||
+ | |||
+ | == Разработка пользовательского интерфейса == | ||
+ | Все описанные выше алгоритмы уже реализованы на практике. Из них уже отобраны наиболее эффективные. Следующая задача состоит в том, чтобы объединить все модули в одно целое. <br /> | ||
+ | В результате разработана небольшая программка, объединяющая все описанные выше реализованные алгоритмы. | ||
+ | Для работы с этой программой для начала необходимо загрузить .bmp файл с каким-либо кадром той видеозаписи, на основе которой будет вестись подсчет. Далее на кадре нужно отметить области и разделительную полосу для работы разностного алгоритма, а также рубежи для работы параметрического алгоритма. Все данные, вводимые пользователем сохраняются в текстовые файлы. Все модули программы общаются с помощью текстовых файлов. После нажатия кнопки "Подсчет машин", происходит подсчет количества и скорости машин на данной видеозаписи. В каждый момент времени программно выбирается алгоритм для подсчета. Если машин на дороге мало (на разности двух соседних кадров мало "черного"), то запускается разностный алгоритм. Но если поток достаточно плотный, то подсчет осуществляется с помощью параметрического алгоритма. Все результаты разбиваются по минутам. Иначе говоря, мы получаем временной ряд для количества проехавших машин и скорости потока. | ||
+ | Заметим, что программа обрабатывает данные в пакетном режиме. Т.е. расчет ведется на основе всех .bmp файлов, находящихся в выбранной папке. | ||
== Текущие результаты == | == Текущие результаты == | ||
- | + | На данный момент сделано все вплоть до создания общей программы, включающей в себя все разработанные ранее модули. Кроме того, проведен эксперимент по сбору данных с двух согласованных камер. Результаты обработаны и представлены в виде графиков. Но надо еще придумать им интерпретацию. | |
+ | Параллельно ведется поиск и обзор аналогов. | ||
+ | |||
== Ссылки на литературу == | == Ссылки на литературу == | ||
+ | * Р. Гонсалес, Р. Вудс, «Цифровая обработка изображений» | ||
+ | * O'Reilly «Learning OpenCV: Computer Vision with the OpenCV Library» | ||
+ | * http://opencv.willowgarage.com/documentation/cpp/index.html |
Текущая версия
![]() | На странице изложена примерная структура будущей статьи посвященной исследованию задачи поиска устойчивых зависимостей в движении транспортных средств города Москвы студенткой Марией Алёшиной в рамках работы над дипломом |
Предпосылки
В связи с большим увеличением числа транспортных средств в городе Москве возникла проблема образования большого числа пробок, участились случаи аварий. Авария на одной дороге может повлечь за собой образование пробок на близлежащих трассах. Кроме того, каждое утро и каждый вечер буднего дня возникает невероятное число заторов, связанных с тем, что люди едут на работу или с работы. Это все примеры того, что многие ситуации на дорогах не случайны.
В движении транспортных потоков внутри одного города существуют устойчивые зависимости, обнаружение которых и является главной (окончательной) задачей этой работы.
Постановка задачи
Работа состоит в анализе данных (в частности в поиске некоторых зависимостей) движения транспортного потока города Москвы на основе данных, полученных с видеокамер сервиса Яндекс.Карты. Конкретнее, можно разделить задачу на несколько этапов. Для начала требуется скопировать видео с Яндкс.Карт и сохранить его в формате, удобном для дальнейшей обработки. Далее следует этап обработки видео. В результате требуется по видео определить такой набор параметров, как количество полос дороги, скорость потока, плотность потока и некоторые другие. Поскольку эти параметры, очевидно, не постоянны, в результате для оценки каждого парамера по данным с одной камеры можно построить временной ряд. Следующая задача состоит в одновременном (ну или почти одновременном) сборе данных с нескольких камер и построении для них временных рядов. Анализируя эти временные ряды для различных камер, появляется возможность установить некоторые закономерности в движении по Москве ("графу дорог"). Например возможно спрогнозировать образование пробок, заторов и других ситуаций в различных частях Москвы.
Этапы решения задачи
Решение задачи делится на несколько этапов:
1. Получение данных с одной из камер на сайте Яндекс
- Выкачивание видео с сервиса Яндекс.Карты и сохранение его в формате, удобном для дальнейшей обработки (например .avi). Объем информации (длительность видео) должен быть достаточно велик.
2. Обработка исходных данных
- Покадровая обработка полученного видео-файла. Нужно попробовать несколько вариантов обработки - вычитание кадров, медиана, вычитание фона и т.п. Приведение изображений к бинарному виду. Создание последовательности кадров, на основе которой можно производить непосредственно анализ и/или вычисление необходимых параметров.
3. Выделение одного и того же движущегося объекта на разных кадрах
- Решение задачи слежения
4. Получение необходимой информации из видео-файла и построение временных рядов
- Оценка параметров движения потока в каждый момент времени. Например плотность потока, скорость потока и другие. Возможно необходимо оценить эти параметры отдельно для каждой полосы дороги. Оценка количества полос на дороге. Построение временных рядов, характеризующих изменение вышеописанных параметров на протяжении длительного периода времени. Анализ этих временных рядов, выявление закономерностей, связанных с изменением времени суток, дней недели. Это зависит от объема информации, которую придется обрабатывать
5. Подсчет параметров объектов на "плохих" видеозаписях и при плотных потоках
- Здесь мы сталкиваемся с проблемой: разработанный выше алгоритм работает не всегда. Поэтому теперь нашей задачей является разработка и реализация альтернативного алгоритма. Это параметрический алгоритм, работающий с временным рядом яркости. Основная задача - найти оптимальные параметры.
6. Реализация удобного пользовательского интерфейса.
- Организовать работу пользователя с видеозаписью
7. Сбор информации с нескольких камер
- Возможно единовременно
8. Комплексный анализ ситуации на дорогах Москвы на основе информации с различных камер
- Например прогнозирование дорожной ситуации в какой-то конкретной точке Москвы на основе информации с близлежащих камер.
Получение видео-ряда с одной камеры
Перед тем, как начать обработку данных, необходимо их получить. Изначальный видео поток, который необходимо обрабатывать, находится на серверах Яндекса. Найти или получить прямой ссылки на поток не удалось, поэтому было принято решение сохранять видео с помощью видео грабберов. Среди множества программ, была выбрана Camtasia Studio, которая позволяет не только снимать определенную часть экрана, но и сохранять видео в различных форматах. Существует так же одна небольшая проблема. Для того, чтобы не перегружать сервер, ровно раз в минуту видео поток на Яндекс.Картах останавливается, появляется стрелочка с надписью "Смотреть дальше". Так как для полноценного анализа данных требуется обрабатывать видео большой длины (сильно больше, чем минута), то появляется необходимость раз в минуту программно нажимать на эту стрелочку. В недрах интернета была найдена программа Сlickermann, которая позволяет программно управлять мышью. С помощью этой программы были сделаны следующие действия: раз в минуту происходит нажатие на стрелочку, после чего курсор мыши сразу отодвигается в другую часть экрана, чтобы не попадать в видеозапись. Все необходимые координаты задаются в ручную. В результате с помощью все той же Camtasia Studio видео сохраняется в формате .AVI, как в самом удобном для обработки. Пока примерная длина видео составляет 20 минут. Для полноценного анализа движения транспортных средств в Москве необходимо будет "снять" видео на пару часов.
Здесь есть несколько неприятностей. Видеопоток имеет очень плохое качество, скорость загрузки с сервера оставляет желать лучшего. Поэтому fps получаемого .AVI файла иногда слишком мало. В идеале хотелось бы получить ссылку непосредственно на поток, тогде проблемы с зависанием видео решились бы. Но пока непонятно, как это сделать.
Обработка исходных данных
Следующим этапом после формировки .AVI файла является его обработка. Уже давно написано множество алгоритмов, библиотек и даже целых систем по обработке изображений в целом и видео в частности. Так что есть множество путей решения поставленной задачи. Был выбран следующий путь.
Для обработки видео была написана программа в среде Visual Studio 6.0 на языке С++ c использованием библиотеки OpenCV (CV = Computer Vision). Это довольно большая разрабатываемая библиотека, в которой реализовано множество алгоритмов обработки изображений, удобно сделана работа с видео и даже представлена пара алгоритмов по Machine Learning.
В данной работе производится обработка не самого .AVI файла, а кадров, из которых он состоит. С помощью программы VirtualDub на основе .AVI файла формируется последовательность фреймов (картинок в .BMP формате), дальнейшая обработка производится уже с ними.
Итак, первичная задача обработки видео состояла в выделении движущихся объектов. Вот несколько способов решения этой маленькой подзадачи.
- Покадровая разность
- Самый примитивный алгоритм, использующийся для выделения движущихся объектов на видео - это покадровая разность. Рассматриваются 2 соседних кадра (в принципе можно брать кадры через один или даже через два), на основе которых формируется третье изображение, как попиксельная разность первых двух. Специфика видео, используемого в данной работе такова, что цвет одно и того же пикселя фона может немного отличаться от кадра к кадру, соответственно в результирующем изображении цвет этого пикселя не будет нулем. Поэтому кроме вычитания, необходимо сделать изображение монохромным с некоторым порогом. Все пиксели, цвет которых выше этого порога, становятся черными, все остальные - белыми. Порог - это тоже параметр, который необходимо подобрать так, чтобы движущиеся объекты были довольно четкими, но при этом чтобы было как можно меньше шумов. Задачу удаления шумов также можно решить различными другими алгоритмами, например медианным сглаживанием.
- Из-за плохого качества и медленной работы видео существует несколько проблем. Во-первых, очень много шума. Но с этим можно успешно бороться. Во-вторых, из-за того, что видео поток на Яндексе подгружается часто очень медленно, мы получаем несколько подряд идущих одинаковых кадров, что значит, что их разность - это пустой кадр.
- Вычитание фона
- Другая, более "умная" стратегия - сформировать фон, а потом вычесть этот фон из каждого кадра, в результате останутся только движущиеся объекты, не принадлежащий фону.
- Фон формируется на основе некоторого набора кадров. Количество кадров - параметр.
- Было реализовано два алгоритма выделения фона.
- Первый и самый простой можно кратко описать так: данный пиксель изображения считать фоном, если он не изменялся (а точнее изменялся в заданном небольшом диапазоне) на протяжении нескольких кадров. Параметром данного алгоритма является не только количество кадров, но и порог, определяющий допустимый диапазон изменения цвета пикселя.
- Далее приводится второй более "умный" алгоритм.
- Формируем изображение-разность первого и второго кадра. Считаем его изначально фоном. Но на этом изображении естественно будут пятна от движущихся машин. Получили своеобразную маску, которую накладываем на первый кадр. Далее берем разность второго и третьего кадров. На получившемся изображении тоже будут пятна от переместившихся машин, но эти пятна будут уже в другом месте. После этого, делаем попиксельную логическую операцию "И" или умножение для двух изображений-разностей. В результате получаем новую маску. В результате такого последовательного добавления точек, получаем фон. Далее фон последовательно вычитается из каждого кадра, таким образом выделяются движущиеся объекты.
(вставить картинки)
- Медианная фильтрация
- Естественно, полученное таким образом изображение содержит множество шумов. Кроме того, движущиеся объекты состоят из некоторого числа связных пятен. А для дальнейшей обработки желательно, чтобы каждая машина была представлена на изображении в виде одно связного пятна. Для решения этих двух проблем одновременно была применена медианная фильтрация.
- Опишем алгоритм работы медианного фильтра. Требуемое изображение загружается в память, далее производится проход по всем его пикселям с каким-то окном. Ширина окна - параметр фильтра. Обычно берут окно размера 3х3, 5х5 или 7х7 (для данной задачи как показала практика, нет смысла брать окно больше). Далее для каждого такого набора из 9ти, 25ти или 49ти пикселей вычисляется среднее значение цвета. Этим цветом заливается весь квадрат. В результате происходит эффективное удаление шума, а связные пятна, находящиеся на маленьком расстоянии друг от друга (то есть которые с большой вероятностью принадлежат одной машине) сливаются. Но здесь опять же возникает проблема. Машины, которые проезжают близко друг к другу (например по разным полосам), с большой вероятностью сливаются в одно связное пятно. Кроме того, машины, которые находятся еще далеко, распознаются как шум и удаляются. Но если для подсчета параметров потока поставить отсечку ближе к нижнему левому углу, то это перестает быть проблемой.
- Алгоритм FloodFill(заливки)
- Следующая стадия обработки видео - выделение отдельных связных пятен (машин, движущихся объектов). Эта задача была решена с помощью простой функции FloodFill, реализованной в OpenCV. Принцип работы этой функции прост. Работа происходит с монохромным изображением. Белые пиксели обозначают фон, черные пиксели принадлежат движущимся объектам (машинам). Производится проход по пикселям изображения, пока не попадется черный пиксель. Вызываем функцию FloodFill, передавая ей как параметр координаты черного пикселя. Функция производит заливку связной области, содержащей заданный пиксель заданным цветом (отличным от черного). Таким образом в результате формируется изображение, на котором все связные пятна (машины) раскрашены в разные цвета.
Выделение одного и того же движущегося объекта на разных кадрах
После того, как проведена первичная обработка и на каждом кадре выделены движущиеся объекты, необходимо решить задачу поиска одного и того же объекта на каждом кадре.
Вот несколько возможных методов решения этой задачи.
- Можно воспользоваться тем, что по мере движения очертания машины меняются с точностью до размеров. Соответственно можно отдельно сохранить область изображения, соответствующую одной машине, пропорционально увеличивать или уменьшать ее и наложением искать совпадения на последующих (или предыдущих) кадрах.
- Другой способ основан на том, что для данного видео ряда есть возможность указать вектор движения потока (или несколько, если дорога с двусторонним движением или большим числом полос). Кроме того, можно вычислить, как изменяются размеры объекты при приближении и удалении от камеры. Соответственно на каждом кадре есть возможность для каждого связного пятна (машины) указать область изображения, в котором с большой вероятностью окажется машина на следующем кадре. После выделения такой области, переходим к следующему кадру и смотрим, какую часть зоны занимает пятно (машина). С помощью параметра-порога определяем, принадлежат ли пятна на первом и втором кадрах одной и той же машине.
Наконец-то эта задача решена! Было реализовано несколько алгоритмов.
Решение 1. По точечное сравнение объектов
Перед тем как решать задачу необходимо составить некоторое признаковое описание каждого пятна. Поэтому на первом кадре каждому черному пятну (движущемуся объекту) ставится в соответствие структура.
struct Spot { int* x; //абсциссы точек, составляющих пятно int* y; //ординаты точек, составляющих пятно CvScalar color; // цвет пятна int pixelnum; // количество точек в пятне int* speed; // скорость пятна при переходе от кадра к кадру bool up; // параметр, показывающий, с какой стороны от разделительной полосы находится пятно bool out; // вышло ли пятно за кадр (true, если машина уехала из кадра) bool counted; // посчитали ли мы уже эту машину? параметр, необходимый при подсчете количества машин double wholespeed; // средняя скорость машины на видеозаписи };
Некоторые параметры введены для удобства и не понадобились при решении дальнейших задач. На основе такой структуры проводится анализ видеоряда.
Задача решена при помощи следующего алгоритма:
- Для первого кадры видео последовательности:
- С помощью функции FloodFill закрасить все отдельные пятна разными цветами
- Создать список существующих пятен. Каждое пятно имеет довольно большой список параметров. Основные из них - список координат точек, составляющих данное пятно, и цвет.
- Цикл. Для каждого следующего кадра
- Найти черное пятно
- В списке существующих пятен найти кандидата на совпадение. Далее возможны 2 ситуации.
- Если кандидат найден, то обновляются данные о соответствующем пятне в списке. Цвет рассматриваемого пятна равен цвету кандидата.
- Если кандидат не найден, то формируется новый элемент списка пятен. Пятну присваиваем новый цвет (вычисляется случайным образом)
- Окрашиваем рассмотренное пятно в установленный цвет.
- Переходим к следующему черному пятну и повторяем цикл
- После просмотра всех пятен, смотрим, есть ли объекты, для которых на новом кадру не нашлось совпадений. Такие объекты считаются машинами, уехавшими из кадра. Они исключаются из дальнейшего рассмотрения.
Теперь рассмотрим самый важный вопрос. Как сравнивать пятна?
В реализованном алгоритме пятна сравниваются по точечно. Примем несколько гипотез:
- За время между двумя кадрами машина не может сдвинуться больше, чем на определенное число пикселей.
- Для каждого отдельного видеоряда мы можем и должны вручную найти разделительную полосу на дороге и определить вектора движения машин в обе стороны.
В соответствии с этими гипотезами, делаем следующее.
Сначала для каждого видеоряда необходимо вручную найти функцию (это линейная функция), описывающую разделительную полосу дороги, а так же указать, в какую сторону движутся машину по одну и по другую сторону от разделительной полосы.
Далее приступаем к непосредственному сравнению пятен. Рассматриваем 2 пятна. Одно классифицируемое (назовем его для краткости "Пятно1") и одно уже занесенное в список пятен, а значит присутствующее на предыдущем кадре ("Пятно2"). Наша задача определить, является ли "Пятно1" на текущем кадре тем же движущимся объектом, что и "Пятно2" на предыдущем кадре. "Пятно2" попиксельно сдвигается на вектора длин 0, 3, 6, 9, 12, 15. Все они имеют одно и то же направление. Это направление движения потока. Данный вектор заранее рассчитан для данного видеоряда. После сдвига происходит по точечное сравнение "Пятна2" (сдвинутого) и "Пятна1". Вычисляется величина, определяющая степень схожести объектов по формуле:
,
где hits - число совпавших точек,
pixelnum1 и pixelnum2 - число точек в сравниваемых пятнах.
Если среди полученных величин самая большая превосходит заранее заданный порог ε = 0.85, то совпадение найдено. Иначе начинаем обработку следующего пятна.
Так же важно то, что в кандидаты мы выбираем только те пятна, который находят с той же стороны от разделительной полосы, что и классифицируемое пятно. При большом количестве движущихся объектов это помогает значительно сократить время работы алгоритма.
Достоинства
- Данный алгоритм довольно прост в реализации
- На "хороших" видеозаписях он показывает довольно неплохие результаты. Их можно оценить в следующих разделах, когда речь пойдет о подсчете параметров движения потока.
Недостатки
- Учитывая огромный объем обрабатываемой информации, данный алгоритм не в состоянии решить задачу за реальное время.
Решение 2. Построение матриц схожести
Данный алгоритм отличается от предыдущего способом сравнения пятен. Самый главный недостаток по точечного сравнения объектов - очень невысокая скорость обработки данных. Алгоритм, который мы рассмотрим в этом разделе, должен помочь решить эту проблему.
Построим для каждой пары кадров матрицу схожести движущихся объектов, в которой число строк - количество пятен на первом кадре, а число столбцов - количество выделенных объектов на втором кадре. В каждой ячейке такой матрицы запишем величину, характеризующую схожесть соответствующих объектов. Но проблема в том, что сравнивать объекты можно по абсолютно разным параметрам - по размеру, по форме, по местоположению и т.д. Выбрать какой-то один из этих критериев невозможно. Поэтому было принято решение отобрать самые информативные для данной задачи критерии схожести объектов и рассмотреть их суперпозицию. Схожесть m-ого объекта из первого кадра и n-ого объекта из второго определяется по формуле:
Здесь Square - величина, определяющая соответствие по площади(предположение: размер машины от кадра к кадру не должен значительно изменяться), Vector - по направлению (предположение: машины должны двигаться параллельно разделительной полосе), Length - по длине вектора (предположение: за время между двумя кадрами машина не может уехать на большое расстояние), - веса, причем
Кроме того, величины Square, Vector, Length имеют тип double и лежат в промежутке [0, 1], где значение 1 - объекты полностью совпадают по данному критерию.
Параметры необходимо некоторым образом настраивать. Сделать это можно, использовав два одинаковых кадра. При решении такой задачи заранее известен ответ. Максимум по каждой строке должен содержаться на диагонали матрицы. Исходя из этого настройку весов можно провести с использованием нейронной сети.
После того, как матрица сравнений построена, необходимо на ее основе решить поставленную задачу. В таблице в каждой строке выбирается максимальное число. То есть для каждого существующего объекта-машины на старом кадре выбирается наиболее похожий объект на новом кадре.
Здесь возможен ряд проблем:
- В строке нет максимума (2 и более чисел имеют одинаковые и при этом максимальные значения).
- Все числа в строке близки к 0 (ни один кандидат не подходит)
После проведения нескольких экспериментов, было выяснено, что такие проблемы на "хороших" видеозаписях возникают крайне редко. Обычно они связаны с очень плохим качеством видео.
Сбор информации о потоке и построение временных рядов для различных параметров движения
Следующий этап работы - расчет параметров потока для одной видеозаписи. Рассчитываются такие параметры, как количество проехавших машин и средняя скорость потока.
Привязка к реальному времени
Для расчета скорости необходима привязка видеозаписи к реальному времени. На некоторых видеозаписях на Яндекс.Картах в правом верхнем углу выводится реальное время. Но считывать цифры с видеозаписи - довольно трудоемкая отдельная задача. Кроме того, время есть не на всех камерах. Поэтому предлагается другой способ привязки кадров к реальному времени. Используется следующая особенность видеозаписей: ровно через каждые 2 минуты видеозапись прерывается, пользователю предлагается нажать на кнопку, чтобы продолжить просмотр. Значит, существует возможность посчитать количество кадров за 2 минуты. Если это число разделить на 120 (количество секунд в двух минутах), то мы получим количество кадров в одной секунде. Среди этих кадров будут повторяющиеся (т.к. качество видеозаписи не самое лучшее).
Подсчет количества транспортных средств
Перейдем к непосредственному решению поставленной задачи, а именно к подсчету параметров потока. Для начала, рассмотрим алгоритм, с помощью которого был реализован подсчет количества машин.
Каждая видеозапись содержит изображение дороги с двусторонним движением. На предыдущем этапе была выделена разделительная полоса. Теперь на каждой части дороги необходимо обозначить область, в которой транспортные средства с помощью нашего алгоритма выделяются лучше всего, а следовательно область, в которой их можно посчитать. Практически на любой видеозаписи границы областей удобно определять горизонтальными линиями. То есть другими словами, просто ставится отсечка и считается число машин, прошедших через эту отсечку.
Теперь начнем подсчет. Если движущийся объект попал в область (хотя бы одна его точка оказалась внутри области), то прибавляем к счетчику машин единицу и устанавливаем флаг counted в значение true. Теперь, если на следующем шаге мы обнаружим ту же самую машину в заданной области, то просто не будем ее считать.
Теперь оценим, на сколько наш алгоритм ошибается. Вот данные, полученные при обработке одной видеозаписи, продолжительность которой 17 минут. В таблице приведены значения, полученные программно и посчитанные вручную. Внизу отображен график, показывающий различия между реальными и программно полученными данными.
Количество машин на видео Количество машин, посчитанных в программе
22,00 24,00
25,00 27,00
19,00 21,00
20,00 21,00
18,00 20,00
15,00 15,00
21,00 21,00
23,00 24,00
20,00 21,00
16,00 17,00
22,00 24,00
24,00 24,00
23,00 23,00
26,00 28,00
25,00 25,00
20,00 20,00
24,00 26,00
Легко видеть, что данные программы всегда немного выше, чем реальные. Это связано с тем, что выделенные транспортные средства, представленные в виде пятен, разваливаются, либо склеиваются, следовательно появляется один, а то и два новых объекта, которых на самом деле нет. Но также можно заметить, что ошибка эта систематическая и весьма небольшая, а следовательно с ней можно бороться и без улучшения алгоритма. Можно просто немного подкорректировать данные с учетом такой систематической ошибки.
Вычислим эту ошибку для данной видеозаписи:
Всего проехало машин – 363. Посчитано 381.
Ошибка = 381-363/381 = 0.047.
Подсчет средней скорости потока
Для подсчета средней скорости потока, ведется учет длин векторов, на которые смещается данной транспортное средство от кадра к кадру. В результате для каждого объекта вычисляется среднее значение среди всех длин. Это и есть средняя скорость транспортного средства. Для вычисления средней скорости потока необходимо всего лишь сложить средние скорости транспортных средств (движущихся в одну сторону!) и поделить на количество машин, полученное в предыдущем разделе.
Но скорость лучше вычислить в м/с или км/ч. Для этого необходимо обозначить на записи некоторую область, размер которой мы знаем или можем вычислить (например на Яндекс.Картах существует такая возможность, можно посчитать расстояние в метрах). Так же, учитывая то, что у нас есть привязка к реальному времени, появляется возможность посчитать, за какое время (в секундах) транспортное средство преодолевает выбранный нами путь. Отсюда получаем скорость в м/с. Перевести скорость в км/ч не представляет труда.
Основные сложности
После того, как такая большая работа была проведена с одной видеозаписью, были предприняты попытки применить описанный алгоритм для других видеозаписей.
Сразу возникло множество проблем. Оказывается, что если видеозапись "хорошая" (то есть транспортный средства движутся с достаточно большими скоростями и расстояние между ними составляет несколько корпусов), то алгоритм работает приемлемо и даже хорошо.
Но часто на видеозаписи машины стоят в пробке или очень медленно движутся. И тогда проблемы возникают уже на стадии выделения движущихся объектов.
На рисунках, представленных справа, видно, что описанный алгоритм не может выделить движущиеся объекты. Он выдает набор разрозненных пятен, некоторые из которых на самом деле относятся к одной и той же машине. Работать с таким материалом дальше не представляется возможным.
Вычитание фона, задающегося вручную
Для решения этой проблемы было предложено следующее: так как во время пробки машины стоят, и выделить фон программно не всегда представляется возможным, можно попробовать выделить фон вручную. То есть пользователь сам мышкой выбирает некоторое количество (10 - 20) точек, которые действительно принадлежат фону. Далее в программе анализируется яркость этих точек по каждому из каналов, определяются максимум и минимум яркости. То есть строится допустимый диапазон яркостей, в который должна попадать точка, чтобы быть фоном. Далее просто анализируются все точки изображения. Если яркость точки по каждому каналу попала в полученную область, то такая точка считается принадлежащей фону и вычитается из изображения. К сожалению, данная идея тоже дала плохие результаты.
Альтернативный алгоритм. Обработка массива яркостей.
В данной главе сделана попытка проанализировать плотные транспортные потоки. Основная проблема состоит в том, что стандартные разностные методы обработки изображений (выделения движущихся объектов на последовательности кадров) не работают в рассматриваемом случае. А значит, необходимо придумать альтернативные алгоритмы. Идея алгоритма, реализованного в данной задаче, была взята из книги «Цифровая обработка видеоизображений».
Основные этапы разработки алгоритма
Среди основных этапов можно выделить:
- Получение видеозаписей. Необходимо «скачать» нужные видеозаписи с сервиса «Яндекс.Карты»
- Расстановка рубежей. На каждой видеозаписи необходимо вручную поставить рубеж (линию), а далее считать число проехавших через нее машин. Чаще всего рубеж соответствует одной полосе на дороге.
- Реализация параметрического алгоритма подсчета машин для одного рубежа.
- Построение таблиц зависимости результатов работы алгоритма от значений параметров.
- Подсчет реального числа машин (вручную) и построение таблиц ошибок,
- Анализ таблиц ошибок и определение значений параметров.
Описание алгоритма
Для начала, необходимо вручную задать рубеж/рубежи для данной видеозаписи. Обычно рубеж занимает одну полосу движения. (картинка с примером расстановки рубежей). После чего происходит построение массива значений яркостей на этом рубеже на каждом кадре. Далее на основе этого массива необходимо определить количество проехавших машин. Предполагается, что значение яркости фона (дороги) незначительно колеблется относительно некоторой величины. В качестве такой величины берем медианной значение нашего массива (обозначим как mediana), а в качестве параметра разброса – величину p1. P1 – параметр, отвечающий за допустимое изменение яркости фона. После этого, на основе полученного массива строится бинарный массив по следующим правилам: если значение яркости некоторого элемента массива находится в пределах [mediana-p1, mediana+p1], то относим такое значение к фону, т.е. заменяем на 0. Если описанное выше условие не выполняется, то считаем, что данный элемент соответствует наличию на рубеже машины, т.е. заменяем значение данного элемента массива на 1. После этого, вводится второй параметр р2. Этот параметр имеет смысл расстояния между машинами в кадрах. По-другому, это минимальное число нулей, которое должно быть между совокупностями единиц для того, чтобы отделить две машины. То есть, если после совокупности единиц идет >=p2 нулей, то к уже посчитанному количеству машин прибавляется единица.
Построение таблиц
Для определения оптимальных значений параметров р1 и р2 применен следующий простой подход. Пусть значение р1 изменяются в пределах от 7 до 20, а значения р2 от 1 до 15. (Такие рамки были подобраны в ходе проведения экспериментов. Абсолютно верные результаты алгоритм выдает, когда параметры находятся именно в этих промежутках.) Для каждой пары (р1, р2) запускается описанный выше алгоритм. Результаты записываются в таблицу. Пример такой таблицы приведен ниже.
Вручную посчитано, что на записи проехало 8 машин. Значения работы алгоритма приведены в таблице. Можно заметить, что верный ответ алгоритм выдает при значениях р1 = 15, 16, 17 и р2 = 1, 2, 3, 4, 5.
Далее для каждой такой таблицы посчитаны соответствующие таблицы ошибок. Вот пример одной из таких таблиц:
Ошибки считаются, как модуль разности между реальным количество проехавших машин и посчитанным в программе.
Очевидно, что на основе работы алгоритма на одном рубеже одной видеозаписи, невозможно оценить значения параметров р1 и р2. Поэтому было проведено множество экспериментов для различных видеозаписей.
Результаты и выводы
Результаты приведены в таблице суммарной ошибки по большому количеству экспериментов.
Выделенные значения соответствуют оптимальному соотношению параметров р1 и р2. Это те значения, при которых ошибка минимальна. (в данном случае минимальная ошибка – это ошибка в 7 машин из 111 действительно проехавших).
Заметим, что параметр р2 имеет смысл плотности потока. То есть изменяя р2, можно адаптировать данный алгоритм для потоков различной плотности. Но учитывая то, что для потоков с хорошо отделимыми транспортными средствами, у нас уже есть реализованный хорошо работающий алгоритм, в данном алгоритме р2 будем брать достаточно малым.
Разработка пользовательского интерфейса
Все описанные выше алгоритмы уже реализованы на практике. Из них уже отобраны наиболее эффективные. Следующая задача состоит в том, чтобы объединить все модули в одно целое.
В результате разработана небольшая программка, объединяющая все описанные выше реализованные алгоритмы.
Для работы с этой программой для начала необходимо загрузить .bmp файл с каким-либо кадром той видеозаписи, на основе которой будет вестись подсчет. Далее на кадре нужно отметить области и разделительную полосу для работы разностного алгоритма, а также рубежи для работы параметрического алгоритма. Все данные, вводимые пользователем сохраняются в текстовые файлы. Все модули программы общаются с помощью текстовых файлов. После нажатия кнопки "Подсчет машин", происходит подсчет количества и скорости машин на данной видеозаписи. В каждый момент времени программно выбирается алгоритм для подсчета. Если машин на дороге мало (на разности двух соседних кадров мало "черного"), то запускается разностный алгоритм. Но если поток достаточно плотный, то подсчет осуществляется с помощью параметрического алгоритма. Все результаты разбиваются по минутам. Иначе говоря, мы получаем временной ряд для количества проехавших машин и скорости потока.
Заметим, что программа обрабатывает данные в пакетном режиме. Т.е. расчет ведется на основе всех .bmp файлов, находящихся в выбранной папке.
Текущие результаты
На данный момент сделано все вплоть до создания общей программы, включающей в себя все разработанные ранее модули. Кроме того, проведен эксперимент по сбору данных с двух согласованных камер. Результаты обработаны и представлены в виде графиков. Но надо еще придумать им интерпретацию. Параллельно ведется поиск и обзор аналогов.
Ссылки на литературу
- Р. Гонсалес, Р. Вудс, «Цифровая обработка изображений»
- O'Reilly «Learning OpenCV: Computer Vision with the OpenCV Library»
- http://opencv.willowgarage.com/documentation/cpp/index.html