Нахожу в тесте вопросы, которые в принципе не освещаются в лекции. Нужно гуглить на других ресурсах, чтобы решить тест, или же он всё же должен испытывать знания, полученные в ходе лекции? |
Базовые операции обработки изображений
2. Обзор возможностей модуля imgproc библиотеки OpenCV
2.1. Cвертка и линейные фильтры
Линейные фильтры – семейство самых простых фильтров изображений с точки зрения математического описания [6]. Предположим, что имеется полутоновое изображение I. Тогда любой линейный фильтр определяется вещественнозначной функцией F, заданной на растре. Данная функция называется ядром фильтра, а операция фильтрации выполняется посредством вычисления дискретной свертки:
Как правило, ядро фильтра применяется к некоторой окрестности 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. Новое значение интенсивности пикселя вычисляется по формуле:
В случае многоканального изображения ядро применяется к каждому каналу в отдельности.
Ниже приведен пример использования функции 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, слева).
Отметим, что в случае больших ядер (размера порядка 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)