Опубликован: 20.08.2013 | Уровень: для всех | Доступ: платный | ВУЗ: Новосибирский Государственный Университет
Самостоятельная работа 1:

Сборка и установка библиотеки OpenCV. Использование библиотеки в среде Microsoft Visual Studio

< Лекция 5 || Самостоятельная работа 1: 12345678910 || Самостоятельная работа 2 >
4.2.9. Бинаризация изображения

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

Функция threshold реализует указанную операцию отсечения для изображения src по порогу thresh и записывает результат в матрицу dst.

double threshold(const Mat& src, Mat& dst, double thresh, 
    double maxVal, int thresholdType)       
      

Рассмотрим возможные значения параметра thresholdType, который определяет правило отсечения:

  • THRESH_BINARY, вычисление интенсивности пикселя с координатами (x,y) осуществляется согласно формуле (по существу реализует операцию бинаризации):
    dst(x,y)=\begin{cases}
maxVal,\ если\ src(x,y)\ > thresh\\
0,\ в\ противном\ случае\\
\end{cases}
  • THRESH_BINARY_INV:
    dst(x,y)=\begin{cases}
0,\ если\ src(x,y)\ > thresh\\
maxVal,\ в\ противном\ случае\\
\end{cases}
  • THRESH_TRUNC:
    dst(x,y)=\begin{cases}
thresh,\ если\ src(x,y)\ > thresh\\
src(x,y),\ в\ противном\ случае\\
\end{cases}
  • THRESH_TOZERO:
    dst(x,y)=\begin{cases}
src(x,y),\ если\ src(x,y)\ > thresh\\
0,\ в\ противном\ случае\\
\end{cases}
  • THRESH_TOZERO_INV:
    dst(x,y)=\begin{cases}
0,\ если\ src(x,y)\ > thresh\\
src(x,y),\ в\ противном\ случае\\
\end{cases}
4.2.10. Поиск контуров на бинарном изображении

Рассмотрим функцию findContours для определения контуров объектов на бинарном (черно-белом) изображении. Данная функция реализует алгоритм, описанный в работе [21]. Позднее будет разработано приложение, демонстрирующее ее использование. Ниже приведены прототипы соответствующей функции.

void findContours(const Mat& image, 
    vector<vector<Point> >& contours, 
    vector<Vec4i>& hierarchy, int mode, 
    int method, Point offset=Point()) 
void findContours(const Mat& image, 
    vector<vector<Point> >& contours, 
    int mode, int method, 
    Point offset=Point())       
      

Функция принимает на вход одноканальное 8-битное изображение image и возвращает набор контуров contours, каждый из которых задается совокупностью точек. Опционально функция возвращает иерархию отношений между контурами hierarchy, для каждого контура contours[i] в hierarchy[i][0], hierarchy[i][1], hierarchy[i][2], hierarchy[i][3] хранятся индексы следующего и предыдущего контуров того же уровня иерархии, индексы первого дочернего и родительского контуров соответственно. Если какого-либо элемента приведенной последовательности нет, то в соответствующей ячейке хранится отрицательное значение. Наряду с описанными параметрами функция принимает идентификаторы способа восстановления контура mode и метода аппроксимации контура method. Параметр mode может принимать следующие значения:

  • CV_RETR_EXTERNAL обеспечивает восстановление только внешних контуров, т.е. hierarchy[i][2]= hierarchy[i][3] d= -1;
  • CV_RETR_LIST позволяет восстанавливать все контуры без установления иерархии;
  • CV_RETR_CCOMP обеспечивает восстановление всех контуров (внешних и внутренних) и собирает их в двухуровневую иерархию;
  • CV_RETR_TREE предоставляет возможность получения полной иерархии контуров.

Перечислим возможные значения параметра method.

  • CV_CHAIN_APPROX_NONE – метод, согласно которому хранятся все точки контуров;
  • CV_CHAIN_APPROX_SIMPLE обеспечивает хранение горизонтальных, вертикальных и диагональных сегментов, сохраняя только их конечные точки;
  • CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS обеспечивают применение одной из разновидностей алгоритма Тех-Чин (Teh-Chin) [23].

Осталось сказать несколько слов о последнем параметре offset функции findContours. Данный параметр задает постоянное смещение каждой точки контура. Как правило, используется в случае, если поиск контура выполняется в некоторой области интереса, а отображение контуров необходимо выполнить на полном изображении.

4.2.11. Отображение контуров на изображении

На данный момент известно, как получить контуры объектов на изображении, и можно переходить к вопросу, как отобразить полученные контуры. Такой функционал сосредоточен в функции drawContours, которая позволяет отобразить на изображении image контур contours[contourIdx] посредством отрисовки линии, имеющей цвет color и толщину thickness. Наряду с этим можно указать тип связности линии lineType (8, 4, CV_AA). Опционально также можно передать иерархию контуров hierarchy, максимальное количество уровней иерархии для отображения maxLevel и сдвиг каждой точки контура offset.

void drawContours(Mat& image, 
    const vector<vector<Point> >& contours, 
    int contourIdx, const Scalar& color, 
    int thickness=1, int lineType=8, 
    const vector<Vec4i>& 
      hierarchy=vector<Vec4i>(), 
    int maxLevel=INT_MAX, 
    Point offset=Point()) 
      

4.3. Разработка приложения для определения контуров объектов

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

Сначала создадим решение и проект 01_Contours согласно схеме, описанной в разделе 3.1, и добавим файл исходного кода, в который поместим основную функцию main.

Опираясь на рассмотренные ранее операции работы с изображениями, последовательность действий можно представить следующим образом:

  1. Загрузить исходное изображение.
    // загрузка исходного изображения 
    Mat src = imread("apple.bmp", 1); 
    if (src.data == 0) 
    { 
      printf("Incorrect image name or format.\n"); 
      return 1; 
    }       
          
  2. Создать копию изображения, т.к. впоследствии необходимо видеть не только изображение с отрисованными контурами, но и исходное.
    // создание копии исходного изображения 
    Mat copy = src.clone();       
          
  3. Конвертировать копию изображения в оттенки серого.
    Mat gray; 
    cvtColor(src, gray, CV_BGR2GRAY);       
          
  4. Выполнить бинаризацию полученного изображения. Операция необходима, т.к. функция поиска контуров работает на черно-белых изображениях.
    Mat grayThresh; 
    threshold(gray, grayThresh, 120, 255, CV_THRESH_BINARY);       
          
  5. Определить контуры на бинарном изображении.
    // поиск контуров 
    vector<vector<Point> > contours; 
    findContours(grayThresh, contours, CV_RETR_CCOMP, 
        CV_CHAIN_APPROX_SIMPLE);       
          
  6. Отобразить исходное изображение и его копию с отрисованными контурами объектов. // создание окон для отображения const char *srcWinName = "src", *contourWinName = "contour"; namedWindow(srcWinName, 1); namedWindow(contourWinName,1); // отображение контуров Scalar color(0, 255, 0); drawContours(copy, contours, -1, color, 2); // отображение изображений imshow(contourWinName, copy); imshow(srcWinName, src); // ожидание нажатия какой-либо клавиши waitKey(0);
  7. Освободить все занятые ресурсы.
    // освобождение ресурсов 
    gray.release(); 
    grayThresh.release(); 
    copy.release(); 
    src.release();       
          

4.4. Запуск приложения и анализ результатов

Исходный код приложения разработан, поэтому осталось его запустить, нажав, например, комбинацию клавиш Ctrl+F5. На рис. 6.16 показан результат исполнения приложения, полученный на тестовом изображении. Посмотрим внимательно на исходное изображение и полученные контуры, попробуем проинтерпретировать результат.

Результат работы приложения для определения контуров объектов

Рис. 6.16. Результат работы приложения для определения контуров объектов

Первый шаг, который выполняется в приложении, – это конвертация исходного изображения в оттенки серого. Результат показан на рис. 6.17 (слева). Затем выполняется отсечение с порогом интенсивности 120, т.е. для всех пикселей, интенсивность которых меньше 120, в бинарном изображении будет поставлен черный цвет, в противном случае, белый (рис. 6.17, справа). Уже из бинарного изображения можно приблизительно оценить контуры. Заметим, что блики на объекте воспринимаются как отдельные компоненты, т.к. они соответствуют перепадам интенсивности. Очевидно, что контуры, которые определяются на основании бинарного изображения, отвечают контурам компонент связности.

Результаты выполнения промежуточных операций преобразования изображения в оттенки серого (слева) и отсечения (справа)

Рис. 6.17. Результаты выполнения промежуточных операций преобразования изображения в оттенки серого (слева) и отсечения (справа)
< Лекция 5 || Самостоятельная работа 1: 12345678910 || Самостоятельная работа 2 >
Александра Максимова
Александра Максимова

При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка?
 

Алена Борисова
Алена Борисова

В лекции по обработке полутоновых изображений (http://www.intuit.ru/studies/courses/10621/1105/lecture/17979?page=2) увидела следующий фильтр:


    \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 2 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array} - \frac{1}{9} \begin{array}{|c|c|c|}
    \hline \\
    0 & 0 & 0 \\
    \hline \\
    0 & 1 & 0 \\
    \hline \\
    0 & 0 & 0 \\
    \hline 
    \end{array}

В описании говорится, что он "делает изображение более чётким, потому что, как видно из конструкции фильтра, в однородных частях изображение не изменяется, а в местах изменения яркости это изменение усиливается".

Что вижу я в конструкции фильтра (скорее всего ошибочно): F(x, y) = 2 * I(x, y) - 1/9 I(x, y) = 17/9 * I(x, y), где F(x, y) - яркость отфильтрованного пикселя, а I(x, y) - яркость исходного пикселя с координатами (x, y). Что означает обычное повышение яркости изображения, при этом без учета соседних пикселей (так как их множители равны 0).

Объясните, пожалуйста, как данный фильтр может повышать четкость изображения?

Сергей Кротов
Сергей Кротов
Россия
Дмитрий Донсков
Дмитрий Донсков
Россия, Москва, Московский Авиационный Институт