При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка? |
Базовые операции обработки изображений
2.5. Оператор Лапласа
Математически оператор Лапласа представляет сумму квадратов вторых частных производных функции . Дискретный аналог оператора Лапласа используется при обработке изображений, в частности, для определения ребер объектов на изображении. Ребра формируются из множества пикселей, в которых оператор Лапласа принимает нулевые значения, т.к. нули вторых производных функции соответствуют экстремальным перепадам интенсивности.
Библиотека OpenCV содержит функцию Laplacian, обеспечивающую вычисление оператора Лапласа [7].
void Laplacian(const Mat& src, Mat& dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
Параметры функции:
- src, dst, ddepth, scale, delta, borderType имеют тот же смысл, что и при вызове функции Sobel.
- kSize – размер апертуры для вычисление второй производной, является положительным четным числом. При использовании значения по умолчанию kSize=1 применяется апертура размером 3x3 и ядро представляется матрицей:
Приведем пример программы, которая обеспечивает поиск ребер объектов на изображения с помощью оператора Лапласа. Перед непосредственным применением оператора выполняется сглаживание с использованием фильтра Гаусса (GaussianBlur) и преобразование исходного изображения в оттенки серого (cvtColor). Заметим, что результирующие значения оператора Лапласа записываются в матрицу, глубина которой аналогично примеру с фильтром Собеля отличается от глубины исходного изображения, поэтому перед отображением выполняется преобразование полученной матрицы в 8-битную целочисленную посредством вызова функции convertScaleAbs.
#include <stdio.h> #include <opencv2/opencv.hpp> using namespace cv; const char helper[] = $quot;Sample_Laplacian.exe <img_file>\n\ \t<img_file> - image file name\n$quot;; int main(int argc, char* argv[]) { const char *initialWinName = $quot;Initial Image$quot;, *laplacianWinName = $quot;Laplacian$quot;; Mat img, grayImg, laplacianImg, laplacianImgAbs; int ddepth = CV_16S; if (argc < 2) { printf($quot;%s$quot;, helper); return 1; } // загрузка изображения img = imread(argv[1], 1); // сглаживание с помощью фильтра Гаусса GaussianBlur(img, img, Size(3,3), 0, 0, BORDER_DEFAULT); // преобразование в оттенки серого cvtColor(img, grayImg, CV_RGB2GRAY); // применение оператора Лапласа Laplacian(grayImg, laplacianImg, ddepth); convertScaleAbs(laplacianImg, laplacianImgAbs); // отображение результата namedWindow(initialWinName, CV_WINDOW_AUTOSIZE); namedWindow(laplacianWinName, CV_WINDOW_AUTOSIZE); imshow(initialWinName, img); imshow(laplacianWinName, laplacianImgAbs); waitKey(); // закрытие окон destroyAllWindows(); // осовобождение памяти img.release(); grayImg.release(); laplacianImg.release(); laplacianImgAbs.release(); return 0; }
Далее показан результат выделения ребер с использованием оператора Лапласа (рис. 7.8) на тестовом изображении, показанном ранее (рис. 7.2, слева).
2.6. Детектор ребер Канни
Детектор ребер Канни [4, 8, 9] предназначен для поиска границ объектов на изображении. Детектор строится на основании оператора Собеля и включает несколько этапов:
- Удаление шума на изображении посредством применения фильтра Гаусса с ядром размера 5:
- Вычисление первых производных (магнитуд и направлений) функции интенсивности пикселей по горизонтальному и вертикальному направлениям посредством применения оператора Собеля с ядрами и (см. раздел 2.4). Направления градиентов округляются до одного из возможных значений .
- Отбор пикселей, которые потенциально принадлежат ребру с использованием процедуры non-maximum suppression [4]. Пиксели, которым соответствуют вектора производных по направлениям, являющиеся локальными максимумами, считаются потенциальными кандидатами на принадлежность ребру.
- Двойное отсечение (гистерезис). Выделяются "сильные" и "слабые" ребра. Пиксели, интенсивность которых превышает максимальный порог, считаются пикселями, принадлежащими "сильным" ребрам. Принимается, что пиксели с интенсивностью, входящей в интервал от минимального до максимального порогового значения, принадлежат "слабым" ребрам. Пиксели, интенсивность которых меньше минимального порога, отбрасываются из дальнейшего рассмотрения. Результирующие ребра содержат пиксели всех "сильных" ребер и те пиксели "слабых" ребер, чья окрестность содержит хотя бы один пиксель "сильных" ребер.
Детектор Канни реализован в библиотеке OpenCV [7] в виде отдельной функции, прототип которой приведен далее.
void Canny(const Mat& image, Mat& edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false)
Функция принимает на вход следующие параметры:
- image – одноканальное 8-битное изображение.
- edges – результирующая карта ребер, представляется матрицей, размер которой совпадает с размером исходного изображения.
- threshold1, threshold2 – параметры алгоритма, пороговые значения для отсечения.
- apertureSize – размер апертуры для применения оператора Собеля.
- L2gradient – флаг, который указывает, по какой норме будет вычисляться магнитуда градиента. Принимает истинное значение, если используется норма (корень квадратный из суммы квадратов частных производных), в противном случае (сумма модулей частных производных). Как правило, нормы достаточно, и вычисляется она быстрее в связи с отсутствием вызова функции sqrt.
Приведем пример использования детектора Канни. Отметим, что перед непосредственным применением детектора выполняется размытие изображения (blur) и преобразование в оттенки серого (cvtColor).
#include <stdio.h> #include <opencv2/opencv.hpp> using namespace cv; const char helper[] = $quot;Sample_Canny.exe <img_file>\n\ \t<img_file> - image file name\n$quot;; int main(int argc, char* argv[]) { const char *cannyWinName = $quot;Canny detector$quot;; Mat img, grayImg, edgesImg; double lowThreshold = 70, uppThreshold = 260; if (argc < 2) { printf($quot;%s$quot;, helper); return 1; } // загрузка изображения img = imread(argv[1], 1); // удаление шумов blur(img, img, Size(3,3)); // преобразование в оттенки серого cvtColor(img, grayImg, CV_RGB2GRAY); // применение детектора Канни Canny(grayImg, edgesImg, lowThreshold, uppThreshold); // отображение результата namedWindow(cannyWinName, CV_WINDOW_AUTOSIZE); imshow(cannyWinName, edgesImg); waitKey(); // закрытие окон destroyAllWindows(); // осовобождение памяти img.release(); grayImg.release(); edgesImg.release(); return 0; }
На рисунке (рис. 7.9) показан результат применения детектора Канни к тестовому изображению (рис. 7.2, слева).