Опубликован: 02.09.2013 | Доступ: свободный | Студентов: 429 / 54 | Длительность: 19:27:00
Самостоятельная работа 2:

Базовые операции обработки изображений

2. Обзор возможностей модуля imgproc библиотеки OpenCV

2.1. Cвертка и линейные фильтры

Линейные фильтры – семейство самых простых фильтров изображений с точки зрения математического описания [6]. Предположим, что имеется полутоновое изображение I. Тогда любой линейный фильтр определяется вещественнозначной функцией F, заданной на растре. Данная функция называется ядром фильтра, а операция фильтрации выполняется посредством вычисления дискретной свертки:

I'(x,y)=\sum_i \sum_j F(i,j) \cdot I(x+i,y+j)

Как правило, ядро фильтра применяется к некоторой окрестности O точки, поэтому пределы изменения индексов i и j определяются выбранной формой и размером окрестности. Данная окрестность в некоторых источниках называется шаблоном или апертурой. В процессе вычисления свертки выполняется проход по пикселям всего изображения, шаблон накладывается на каждый текущий пиксель посредством совмещения пикселя с конкретной точкой шаблона – ведущей позицией шаблона, после чего вычисляется свертка. Необходимо отдельно обратить внимание на ситуацию, когда текущий пиксель находится на границе изображения. Указанную проблему можно решить несколькими способами:

  • Обрезать края, т.е. не проводить фильтрацию для всех граничных пикселей, на которые невозможно наложить шаблон без выхода за пределы изображения.
  • Не учитывать в процессе суммирования пиксель, который реально не существует.
  • Доопределить окрестности граничных пикселей посредством экстраполяции (например, простым дублированием граничных пикселей).
  • Доопределить окрестности граничных пикселей посредством зеркального отражения, т.е. завернуть изображение в тор.

Выбор решения во многом зависит от приложения, так например, зеркальное отражение на практике не совсем естественный способ.

Для вычисления сверток в библиотеке OpenCV присутствует функция filter2D.

void filter2D(const Mat& src, Mat& dst, int ddepth,         const Mat& kernel,  
       Point anchor=Point(-1, -1), double delta=0,  
       int borderType=BORDER_DEFAULT) 
       

Рассмотрим подробнее параметры приведенной функции.

  • src – исходное изображение.
  • dst – свертка. Имеет такое же количество каналов и глубину, что и исходное изображение.
  • ddepth – глубина результирующего изображения. Если на вход функции передано отрицательное значение, то глубина совпадает с глубиной входного изображения.
  • kernel – ядро свертки, одноканальная вещественная матрица.
  • anchor – ведущая позиция ядра. По умолчанию принимает значение (-1,-1), которое означает, что ведущая позиция расположена в центре ядра.
  • delta – константа, которая может быть добавлена к значению интенсивности после фильтрации перед непосредственной записью результата.
  • borderType – параметр, определяющий метод дополнения границы, чтобы можно было применять фильтр к граничным пикселям исходного изображения. Принимает любое значение вида BORDER_* за исключением BORDER_TRANSPARENT и BORDER_ISOLATED.

Функция обеспечивает применение произвольного линейного фильтра с ядром kernel к изображению src. Результат фильтрации записывается в массив dst. Если апертура выходит за пределы изображения, то граничные пиксели дополняются в соответствии с методом, указанным в borderType. Новое значение интенсивности пикселя вычисляется по формуле:

dst(x,y)=\sum_{0\leqslant x'<anchor.x;0\leqslant y'<anchor.y} \left{kernel(x',y')\cdot src(x+x'-anchor.x,y+y'-anchor.y)}

В случае многоканального изображения ядро применяется к каждому каналу в отдельности.

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

#include <stdlib.h> 
#include <stdio.h> 
#include <opencv2/opencv.hpp> 
 
using namespace cv; 
 
const char helper[] =  
    "Sample_filter2D.exe <img_file>\n\ 
    \t<img_file> - image file name\n"; 
 
int main(int argc, char* argv[]) 
{ 
    // константы для определения названия окон 
    const char *initialWinName = "Initial Image",  
               *resultWinName = "Filter2D";     
    // константы для хранения ядра фильтра 
    const float kernelData[] = {-0.1f, 0.2f, -0.1f, 
                                 0.2f, 3.0f,  0.2f, 
                                -0.1f, 0.2f, -0.1f}; 
    const Mat kernel(3, 3, CV_32FC1, (float *)kernelData); 
    // объекты для хранения исходного  
    // и результирующего изображений 
    Mat src, dst;    
    // проверка аргументов командной строки 
    if (argc < 2) 
    { 
        printf("%s", helper); 
        return 1; 
    }     
    // загрузка изображения 
    src = imread(argv[1], 1);      
    // применение фильтра 
    filter2D(src, dst, -1, kernel); 
   
    // отображение исходного изображения и  
    // результата применения фильтра 
    namedWindow(initialWinName, CV_WINDOW_AUTOSIZE); 
    imshow(initialWinName, src); 
    namedWindow(resultWinName, CV_WINDOW_AUTOSIZE); 
    imshow(resultWinName, dst); 
    waitKey(); 
     
    // закрытие окон 
    destroyAllWindows(); 
    // освобождение ресурсов 
    src.release(); 
    dst.release(); 
    return 0; 
} 

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

Результат применения фильтра

Рис. 9.1. Результат применения фильтра

Отметим, что в случае больших ядер (размера порядка 11x11 пикселей) для вычисления свертки используется быстрое преобразование Фурье, в случае небольших ядер – прямой алгоритм. Также если ядро сепарабельное, т.е. может быть представлено в виде пары ядер, которые могут быть последовательно применены к строкам и столбцам изображения в отдельности, то предусмотрена более эффективная реализация линейного фильтра с использованием функции sepFilter2D . При вызове данная функция требует явного указания двух одномерных ядер rowKernel и columnKernel.

void sepFilter2D(const Mat& src, Mat& dst, int ddepth,  
          const Mat& rowKernel,  
          const Mat& columnKernel,  
          Point anchor=Point(-1, -1),  
          double delta=0,  
            int borderType=BORDER_DEFAULT) 
            
Андрей Терёхин
Андрей Терёхин

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

Демянчик Иван
Демянчик Иван

В главе 14 мы видим понятие фильтра, но не могу разобраться, чем он является в теории и практике.

" Искомый объект можно описать с помощью фильтра F= \lbrace f_{x',y'},x' \in \lbrace0, ...,w_f \rbrace , y' \in \lbrace 0,...,h_f \rbrace \rbrace "