OpenCV: эффективная разность гауссовских

Я пытаюсь реализовать различие guassians (DoG), для конкретного случая обнаружения края. Как следует из названия алгоритма, он на самом деле довольно прост:

Mat g1, g2, result;
Mat img = imread("test.png", CV_LOAD_IMAGE_COLOR); 
GaussianBlur(img, g1, Size(1,1), 0);
GaussianBlur(img, g2, Size(3,3), 0);
result = g1 - g2;

Однако у меня есть ощущение, что это можно сделать более эффективно. Может ли это быть сделано за меньшее количество проходов по данным?

Этот вопрос научил меня разделять фильтры, но я слишком новичок в обработке изображений, чтобы понять, как их применять в этом случае.

Кто-нибудь может дать мне несколько советов о том, как можно оптимизировать это?

2 ответа

Решение

Разделимые фильтры работают так же, как обычные фильтры Гаусса. Разделимые фильтры работают быстрее, чем обычный гауссов, когда размер изображения большой. Ядро фильтра может быть сформировано аналитически, и фильтр может быть разделен на два одномерных вектора, один горизонтальный и один вертикальный.

например..

рассмотреть фильтр как

1 2 1
2 4 2
1 2 1

этот фильтр можно разделить на горизонтальный вектор (H) 1 2 1 и вертикальный вектор (V) 1 2 1. Теперь эти наборы из двух фильтров применяются к изображению. Вектор H применяется к горизонтальным пикселям, а V - к вертикальным пикселям. Затем результаты складываются, чтобы получить размытие по Гауссу. Я предоставляю функцию, которая делает разделяемое размытие по Гауссу. (Пожалуйста, не спрашивайте меня о комментариях, я слишком ленив:P)

Mat sepConv(Mat input, int radius)
{


Mat sep;
Mat dst,dst2;

int ksize = 2 *radius +1;
double sigma = radius / 2.575;

Mat gau = getGaussianKernel(ksize, sigma,CV_32FC1);

Mat newgau = Mat(gau.rows,1,gau.type());
gau.col(0).copyTo(newgau.col(0));


filter2D(input, dst2, -1, newgau);


filter2D(dst2.t(), dst, -1, newgau);


return dst.t();


}

Еще один способ улучшить вычисление размытия по Гауссу - использовать БПФ. Свертка на основе FFT намного быстрее, чем метод разделяемого ядра, если размер данных довольно велик.

Быстрый поиск в Google предоставил мне следующую функцию

Mat Conv2ByFFT(Mat A,Mat B)
{
Mat C;
// reallocate the output array if needed
C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type());
Size dftSize;
// compute the size of DFT transform
dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);

// allocate temporary buffers and initialize them with 0's
Mat tempA(dftSize, A.type(), Scalar::all(0));
Mat tempB(dftSize, B.type(), Scalar::all(0));

// copy A and B to the top-left corners of tempA and tempB, respectively
Mat roiA(tempA, Rect(0,0,A.cols,A.rows));
A.copyTo(roiA);
Mat roiB(tempB, Rect(0,0,B.cols,B.rows));
B.copyTo(roiB);

// now transform the padded A & B in-place;
// use "nonzeroRows" hint for faster processing
Mat Ax = computeDFT(tempA);
Mat Bx = computeDFT(tempB);

// multiply the spectrums;
// the function handles packed spectrum representations well
mulSpectrums(Ax, Bx, Ax,0,true);

// transform the product back from the frequency domain.
// Even though all the result rows will be non-zero,
// we need only the first C.rows of them, and thus we
// pass nonzeroRows == C.rows
//dft(Ax, Ax, DFT_INVERSE + DFT_SCALE, C.rows);

updateMag(Ax);
Mat Cx = updateResult(Ax);

//idft(tempA, tempA, DFT_SCALE, A.rows + B.rows - 1 );
// now copy the result back to C.
Cx(Rect(0, 0, C.cols, C.rows)).copyTo(C);
//C.convertTo(C, CV_8UC1);
// all the temporary buffers will be deallocated automatically
return C;

}

Надеюсь это поможет.:)

Я знаю, что этот пост старый. Но вопрос интересен и может заинтересовать будущих читателей. Насколько я знаю, фильтр DoG не отделим. Таким образом, остается два решения: 1) вычислить обе свертки, дважды вызвав функцию GaussianBlur(), затем вычесть два изображения. 2) Сделать ядро, вычислив разность двух гауссовых ядер, затем свернуть его с изображением.

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

Однако, если использовать метод FFT для свертки, второе решение, безусловно, быстрее. Если у кого-нибудь есть какие-либо советы по добавлению или пожелания исправить меня, пожалуйста, сделайте это.

Другие вопросы по тегам