Когда я начал работать над магистерской диссертацией на тему «Анализ пространственной структуры динамических изображений», то столкнулся с проблемой, что очень трудной найти какие-то готовые примеры алгоритмов распознавания образов и движущихся объектов. Везде, и в литературе, и в Интернете одна только голая теория. Цель написания данной статьи как раз восполнить данный пробел.

Итак, для проведения эксперимента я снял из окна квартиры короткий видеоролик, разбил его на кадры и сохранил парочку кадров в виде картинок:





Для определения факта движения я решил пока пойти простым путем: превратить изображения в матрицу, из второй матрицы вычесть первую (поэлементно). Вот код на C#, выполняющий данную обработку:

        /// <summary>
        /// Создать матрицу
        /// </summary>
        /// <param name="file_name">Имя открываемого файла</param>
        private ImageMatrix crate_matrix(string file_name)
        {
            Bitmap picture = new Bitmap(file_name);
            ImageMatrix res = new ImageMatrix();
 
            using (var wrapper = new ImageWrapper(picture,true))
            {
                res.matrix = new int[wrapper.Width, wrapper.Height];
                for (int i = 0; i < wrapper.Width; i++)
                {
                    for (int j = 0; j < wrapper.Height; j++)
                    {
                        Color color = wrapper[i, j];
                        res.matrix[i, j] = (color.R + color.G + color.B) / 
3;
                    }
                }
                res.height = wrapper.Height;
                res.width = wrapper.Width;
                res.picture = picture;
            }     
 
            return res;
        }
 
        private void tsmiDifference_Click(object sender, EventArgs e)
        {
            ImageMatrix matrix1 = crate_matrix("D:\\3\\1.png");
            ImageMatrix matrix2 = crate_matrix("D:\\3\\2.png");
 
            Bitmap picture = new Bitmap(matrix1.picture);
 
            using (var wrapper = new ImageWrapper(picture, true))
            {
                
                for (int i = 0; i < wrapper.Width; i++)
                {
                    for (int j = 1; j < wrapper.Height; j++)
                    {
                        int light1 = matrix1.matrix[i, j];
                        int light2 = matrix2.matrix[i, j];
                        int light = Math.Abs(light2-light1);
                        wrapper[i, j] = Color.FromArgb(light, light, light);
                    }
                }
                pbImage.Image = picture;
            }
        }

И вот что получилось в ходе выполнения данного алгоритма:



На полученной матрице мы видим пропечатанный контур автомобиля и еще какие то контуры на заднем плане, которые, скорее всего, возникли из-за дрожания руки и из за шедшего в момент съемки дождя. На фотографии дождь не виден, но на видео его хорошо заметно.

Для того, чтобы улучшить качество распознавания, можно ввести в программу некое пороговое значение:

if (light < 50) light = 0; else light = 255;

Результат тогда будет совсем другой:



Как видим, при помощи простого вычитания матриц и использования порогового значения мы смогли определить на динамической картинке движущийся объект. Что делать с полученными данным дальше? По сути, что мы имеем сейчас, это бинарная картинка. В ней есть некоторые пятна, которые определяют движущийся объект. Шумы, как видим, наш алгоритм отсек. В дальнейшем, можно определить координаты обнаруженных областей движения. Правда, у нас движущихся объектов получилось несколько — каждое пятно при попытке определить его координаты б��дет отдельным объектов. Но если мы таким образом обработаем несколько матриц, то мы можем заметить, что несколько объектов движутся синхронного, что позволяет нам отнести их к единому объекту.

Однако, приведенный здесь алгоритм не единственный способ определить движение. Если вам понравиться моя статья, то я продолжу тему и расскажу о других алгоритмах распознавания движения и распознавания образов.