Laplacian of Gaussian (LoG) blob detector c++

Пишу blob detector на основе LoG. Использую библиотеку openCV. Задача детектировать светлые круги на темном фоне. Тип картинки CV_8UC1

Исходная картинка (зашумленная специально) введите сюда описание изображения

Все началось с того, что почему то минимальный отклик давал блоб большего радиуса, чем сам искомый круг. Дошёл до того, что ошибка заключается в согласовании размеров ядер cv::GaussianBlur и cv::Laplacian. Например, первая картинка со всеми найденными блобами (отсортированы чтобы убрать ложные срабатывания), вторая картинка - это оставленные блобы с минимальным откликом. Для нахождения блобов разных размеров я использую пирамиду масштабов cv::pyrDown и нормализацю отклика LoG sigma^2

введите сюда описание изображения введите сюда описание изображения

Из документации не понял какой размер нужно указывать в параметрах к функциям - размер крыла или реальный размер ядра. Например, если я укажу в параметрах ksize = 5. Размер гауссовского ядра будет равен 5? А размер ядра Лапласа будет равен 11 - по формуле 2*n + 1?

Ответ пытался найти с помощью получения ядер. То есть использовал функции cv::getGaussianKernel и cv::getDerivKernels. Но по каким-то причинам результат применения cv::Laplacian к полученному ядру гаусса, даёт немного другой результат. А именно в случае применения cv::GaussianBlur и cv::Laplacian минимальный отклик я получил в точке [155, 710] со значением -144004136960.000000, а в случае применения cv::getGaussianKernel и cv::Laplacian минимальный отклик я получил в точке [155, 710] со значением -9097119744.000000. Размеры ядер использовал одинаковые. Ядро полученное cv::getGaussianKernel я умножил на транспонированное ядро, так как функция cv::getGaussianKernel даёт одномерное ядро.

Не понимаю причины такого поведения.

Первая картинка полученная классическим методом, вторая полученная с помощью применения cv::Laplacian к ядру гаусса cv::getGaussianKernel. введите сюда описание изображения введите сюда описание изображения

Так выглядит LoG при нахождении ядра гаусса cv::getGaussianKernel введите сюда описание изображения

Далее я пытался получить ядро Лапласа. Для этого использовал

cv::getDerivKernels(sobelKernelX, sobelKernelY, 2, 2, kernelsizes);
cv::Mat sobelKernel = sobelKernelX * sobelKernelX.t() + sobelKernelY * sobelKernelY.t();

Но получал совсем ужасный и неправильный результат

введите сюда описание изображения

Так выглядел LoG введите сюда описание изображения

//используемые значения
double sigmakz = 3.2;
int kernelsizes = static_cast<int>(6*sigmakz);
 
//классический вариант
image.convertTo(temprrrr_reverse, CV_32F);
cv::GaussianBlur(temprrrr_reverse, tryinguff, cv::Size(kernelsizes, kernelsizes), sigmakz);
cv::Laplacian(tryinguff, outtt, CV_32F, kernelsizes);

//вариант с получением ядра гаусса
cv::Mat gausKernel = cv::getGaussianKernel(kernelsizes, sigmakz, CV_32F);
cv::Mat temprrrr = gausKernel * gausKernel.t();
cv::Mat smth;
cv::Laplacian(temprrrr, smth, CV_32F, kernelsizes);
cv::Mat hrrr;
cv::filter2D(image, hrrr, CV_32F, smth);

//вариант с получением ядра второй производной
cv::Mat sobelKernelX;
cv::Mat sobelKernelY;
cv::getDerivKernels(sobelKernelX, sobelKernelY, 2, 2, kernelsizes);

cv::Mat sobelKernel = sobelKernelX * sobelKernelX.t() + sobelKernelY * sobelKernelY.t();

cv::Mat tryinguff;
//temprr = gausKernel * gausKernel.t();
cv::filter2D(temprrrr, tryinguff, CV_32F, sobelKernel);

cv::Mat outtt;
cv::filter2D(image, outtt, CV_32F, tryinguff);

Главный вопрос как правильно с технической точки зрения согласовать размеры ядер? Какое значения указывать в параметрах ksize для Laplacian и Gaussian?


Ответы (0 шт):