Использование M2M для распознавания дорожных знаков

автор админ

9 Июл 2013

Будущее рынка программного обеспечения и мобильных приложений в частности тесно связано с прикладным использованием M2M-технологий, позволяющих реализовывать новые интересные идеи и внедрять более совершенные решения в самых различных областях: безопасности, удаленного видеонаблюдения, автоматизации производства, потребительской электроники и других.

В 2014 Apple планирует запустить iOS in the Car — мобильную платформу, позволяющую использовать iOS-устройства через интерфейс автомобиля, и сейчас наша команда работает над созданием прототипа приложения-помощника водителя для iOS-устройств.

Обзор проекта

Идея проекта — добавить к возможностям iOS-устройств функции штурмана, «умного видеорегистратора». Задача текущего этапа — разработать приложение-прототип, которое не только ведет запись дорожных событий, как обычный регистратор, но и распознает встречающиеся дорожные знаки, предупреждая о них водителя. Функция предупреждения важна, т. к. зачастую водители не успевают заметить знак или быстро забывают, какой последний знак или последовательность знаков они проехали.

Разрабатывая прототип, мы ограничились лишь запрещающими знаками — знаками круглой формы с красной каймой на белом фоне. В дальнейшем планируем добавить остальные знаки, реализовать постоянно пополняемую базу данных о дорогах и дорожных знаках, общую для всех устройств, использующих приложение, и многое другое.

Принцип работы приложения: видеокамера телефона захватывает видеопоток с разрешением 1920×1080, полученные кадры анализируются и распознаются, когда знак распознан, запускается определенное событие: подать предупреждающий сигнал водителю, добавить информацию в базу данных о дорогах и т. д.

Задачу можно условно разбить на два этапа:

  • Цветовая сегментация изображения
  • Распознавание знака

Этап 1. Цветовая сегментация изображения

Захват изображения. Поиск красного и белого цветов

Уникальной характеристикой запрещающих знаков является круг с преобладанием белого цвета и красным контуром, позволяющий идентифицировать эти знаки на изображениях. После того, как мы получили кадр с камеры в формате RGB, мы вырезаем изображение размером 512 на 512 (Рис. 1) и выделяем на нем красный и белый цвета, отбрасывая все остальные.

Для цветовой локализации — определения элементов конкретного цвета — формат RGB очень неудобен, потому что чистый красный цвет в природе встречается очень редко, но почти всегда идет с примесями других цветов. Кроме того, цвет изменяет оттенок и яркость в зависимости от освещения. Так, например, на восходе и закате солнца все предметы приобретаю красный оттенок; сумерки и полумрак тоже дают свои оттенки.

Рис. 1. Изображение в формате RGB размером 512 х 512, поступающее на вход алгоритма.

Тем не менее, сначала мы попробовали решить задачу, используя исходный RGB-формат. Чтобы выделить красный цвет, мы устанавливали верхний и нижний пороги: R > 0,7, а G и B < 0,2. Но модель оказалась не очень удобной, т.к. значения цветовых каналов сильно зависели от освещенности и времени суток. Например, значения каналов RGB красного цвета в солнечный и пасмурный дни сильно отличаются.

Поэтому модель RGB мы перевели в цветовую модель HSV/B, в которой координатами цвета являются: цветовой тон (Hue), насыщенность (Saturation) и яркость (Value / Brightness).

Модель HSV/B обычно представляют цветовым цилиндром (Рис. 2). Она удобна тем, что оттенки цвета в ней являются лишь инвариантами различных типов освещения и теней, что естественным образом упрощает задачу выделения необходимого цвета на изображении вне зависимости от условий, таких как время суток, погода, тень, расположение солнца и др.

Код шейдера для перехода от RGB к HSV/B:

varying highp vec2 textureCoordinate;
precision highp float;

uniform sampler2D Source;

void main()
{
    vec4 RGB = texture2D(Source, textureCoordinate);
    
    vec3 HSV = vec3(0);
    float M = min(RGB.r, min(RGB.g, RGB.b));
    HSV.z = max(RGB.r, max(RGB.g, RGB.b));
    float C = HSV.z — M;
    if (C != 0.0)
    {
        HSV.y = C / HSV.z;
        vec3 D = vec3((((HSV.z — RGB) / 6.0) + (C / 2.0)) / C);
        if (RGB.r == HSV.z)
            HSV.x = D.b — D.g;
        else if (RGB.g == HSV.z)
            HSV.x = (1.0/3.0) + D.r — D.b;
        else if (RGB.b == HSV.z)
            HSV.x = (2.0/3.0) + D.g — D.r;
        if ( HSV.x < 0.0 ) { HSV.x += 1.0; }
        if ( HSV.x > 1.0 ) { HSV.x -= 1.0; }
    }

     gl_FragColor = vec4(HSV, 1);
}


Рис. 2
. Цветовой цилиндр HSV/B.

Для выделения красного цвета мы строим три пересекающиеся плоскости, которые образуют область в цветовом цилиндре HSV/B, соответствующую красному цвету. Задача выделения белого цвета является более простой, т.к. белый цвет расположен в центральной части цилиндра и нам достаточно указать порог по радиусу (ось S) и высоте (ось V) цилиндра, которые образуют область, соответствующую белому цвету.

Код шейдера, выполняющий эту операцию:

varying highp vec2 textureCoordinate;
precision highp float;

uniform sampler2D Source;

//parameters that define plane
const float v12_1 = 0.7500;
const float s21_1 = 0.2800;
const float sv_1 = -0.3700;

const float v12_2 = 0.1400;
const float s21_2 = 0.6000;
const float sv_2 = -0.2060;

const float v12_w1 = -0.6;
const float s21_w1 = 0.07;
const float sv_w1 = 0.0260;

const float v12_w2 = -0.3;
const float s21_w2 = 0.0900;
const float sv_w2 = -0.0090;

void main()
{
    vec4 valueHSV = texture2D(Source, textureCoordinate);
    
    float H = valueHSV.r;
    float S = valueHSV.g;
    float V = valueHSV.b;
    
    bool fR=(((H>=0.75 && -0.81*H-0.225*S+0.8325 <= 0.0) || (H <= 0.045 && -0.81*H+0.045*V-0.0045 >= 0.0)) && (v12_1*S + s21_1*V + sv_1 >= 0.0 && v12_2*S + s21_2*V + sv_2 >= 0.0));
    float R = float(fR);
    float B = float(!fR && v12_w1*S + s21_w1*V + sv_w1 >= 0.0 && v12_w2*S + s21_w2*V + sv_w2 >= 0.0);
    
    gl_FragColor = vec4(R, 0.0, B, 1.0);
}

Результат работы шейдера, выделяющего красный и белый цвет на изображении 512 х 512, приведен на Рис. 2. Однако, как показали вычислительные эксперименты, для дальнейшей работы полезно понижать разрешение изображения до 256 на 256, т.к. это повышает производительность и практически не влияет на качество локализации знаков.

Рис. 3. Красно-белое изображение.

Поиск окружностей на изображении

Большинство методов поиска окружностей работают с бинарными изображениями. Поэтому, полученное на предыдущем шаге красно-белое изображение нужно преобразовать в бинарный вид. В нашей работе мы опирались на то, что на запрещающих знаках белый цвет фона граничит с красным контуром знака, и разработали алгоритм для шейдера, который ищет такие границы на красно-белом изображении и отмечает граничные пиксели как 1, а не граничные — 0.

Работа алгоритма заключается в следующем:

  • сканируются соседние пиксели каждого красного пикселя изображения;
  • если находится хоть один пиксел белого цвета, то исходный красный пиксел помечается как граничный.

Таким образом, у нас получается черно-белое изображение (256 х 256), в котором фон залит черным цветом, а предполагаемые окружности — белым (Рис. 4а).

Рис. 4а. Бинарное изображение, отображающее границы красного и белого цветов.

Для уменьшения количества ложных точек полезно применить морфологию (Рис. 4б).

Рис. 4б. То же изображение, но после применения морфологии.

Далее, на полученном бинарном изображении необходимо найти окружности. Сначала, мы решили использовать метод Хаффа для поиска окружностей (Hough Circles Transform), реализованный на CPU в библиотеке OpenCV. К сожалению, как показали вычислительные эксперименты, данный метод слишком нагружает CPU и снижает производительность до неприемлемого уровня.

Логичным выходом из данной ситуации служил бы перенос алгоритма на шейдеры GPU, однако, как и другие методы поиска окружностей на изображениях, метод Хаффа плохо соответствует парадигме шейдеров (shader-approach). Таким образом, нам пришлось обратиться к более экзотическому методу поисков окружностей — методу быстрого поиск кругов при помощи градиентных пар (Fast Circle Detection Using Gradient Pair Vectors) [1], который показывает более высокую производительность на CPU.

Основные этапы данного метода следующие:

1. Для каждого пикселя бинарного изображения определяется вектор, характеризующий направление градиента яркости в данной точке. Данные вычисления выполняет шейдер, реализующий оператор Собеля (Sobel operator):

varying highp vec2 textureCoordinate;
precision highp float;

uniform sampler2D Source;
uniform float Offset;

void main()
{
    vec4 center = texture2D(Source, textureCoordinate);
    
    vec4 NE = texture2D(Source, textureCoordinate + vec2(Offset, Offset));
    vec4 SW = texture2D(Source, textureCoordinate + vec2(-Offset, -Offset));
    vec4 NW = texture2D(Source, textureCoordinate + vec2(-Offset, Offset));
    vec4 SE = texture2D(Source, textureCoordinate + vec2(Offset, -Offset));
    vec4 S = texture2D(Source, textureCoordinate + vec2(0, -Offset));
    vec4 N = texture2D(Source, textureCoordinate + vec2(0, Offset));
    vec4 E = texture2D(Source, textureCoordinate + vec2(Offset, 0));
    vec4 W = texture2D(Source, textureCoordinate + vec2(-Offset, 0));
    
    vec2 gradient;
    gradient.x = NE.r + 2.0*E.r + SE.r — NW.r — 2.0*W.r — SW.r;
    gradient.y = SW.r + 2.0*S.r + SE.r — NW.r — 2.0*N.r — NE.r;

    float gradMagnitude = length(gradient);
    float gradX = (gradient.x+4.0)/255.0;
    float gradY = (gradient.y+4.0)/255.0;

    gl_FragColor = vec4(gradMagnitude, gradX, gradY, 1.0);
}

Все ненулевые векторы группируются по направлениям. В силу дискретности бинарного изображения всего получается 48 направлений, т. е. 48 групп.

2. В группах ищутся пары противоположно направленных векторов V1 и V2, например, 45 градусов и 225. Для каждой найденной пары проверяются условия (Рис. 5):

  • угол бета меньше некоторого порога
  • расстояние между точками P1 и P2 меньше заданного максимального диаметра окружности и больше минимального.

Если данные условия выполняются, то считается, что точка С, являющаяся серединой отрезка P1P2, является предполагаемым центром окружности. Далее эта точка C помещается, в так называемый, аккумулятор.

3. Аккумулятор представляет собой трехмерный массив размером 256 x 256 x 80. Первые два измерения (256 x 256 — высота и ширина бинарного изображения) соответствуют предполагаемым центрам окружностей, а третье измерение (80) представляет возможные радиусы окружностей (максимальный — 80 пикселей). Таким образом, каждая градиентная пара накапливает отклик в некоторой точке, соответствующей предполагаемому центру окружности с некоторым радиусом.


Рис. 5. Пара векторов V1-V2 и предполагаемый центр окружности C.

4. Далее, в аккумуляторе ищутся центры, в которых дали отклик как минимум 4 пары векторов с различными направлениями, например, пары 0 и 180, 45 и 225, 90 и 270, 135 и 315. Близкие друг к другу центры объединяются. Если в одной точке аккумулятора найдено несколько центров окружностей с разными радиусами, то эти центры также объединяются и берется максимальный радиус.

Результат работы алгоритма поиска окружностей показан на Рис. 6.

Рис. 6. Локализованные окружности, соответствующие двум запрещающим знакам.

Этап 2. Распознавание локализованных знаков

Локализованные на изображение окружности, которые должны соответствовать запрещающим знакам, вырезаются и нормализуются до размера 28х28 пикселя. Вырезанные изображения дополнительно обрабатываются оператором Собеля и передаются на вход сверточной нейронной сети, предварительно обученной на базе изображений запрещающих знаков.

О принципе работы нейросетей мы писали в одном из наших недавних проектов по распознаванию номеров банковских карт. Наша задача требовала работу с многослойными — сверточными — нейросетями. Когда сегментация знака завершена, мы получаем изображение, которое и передаем сверточной нейронной сети, построенной на основе работ Йэн ЛеКана, Леона Вотту, Йошуа Бенджио и Патрика Хаффнера. Для обучения нейросети была подготовлена небольшая база обучающих изображений.

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

Заключение

Прототип приложения-штурмана — наш пробный шар в использовании M2M-технологий, и мы планируем развивать это направление в дальнейшем. В ближайших планах — реализовать распознавание всех типов знаков и расширить диапазон яркости: день, сумерки, яркое солнце, закаты и др.

Основная сложность задачи по распознаванию других типов знаков — в определении форм отличных от круга: треугольников, квадратов и других. Пока у нас нет конечного решения, есть несколько вариантов, каждый со своими достоинствами и недостатками. Поэтому нам очень интересен ваш опыт решения задач по цветовой локализации, будем признательны вам за рекомендации и советы.

  • 0 Репосты

Комментарии

Фильтр

Закрыть

Технологии

Индустрии