Я использую следующий код для вычисления свертки изображения с указанным ядром (в моем случае гауссовский). Каждый раз, когда я получаю другой результат, и полученное изображение даже не близко к тому, которое я получил путем свертки в Пространственной области. Сначала я подумал, что проблема в типе данных изображений. Я изменил их на 32 и 64, но результаты остались прежними. Может кто-нибудь сказать мне, что может быть не так?
http://opencv.willowgarage.com/documentation/cpp/core_operations_on_arrays.html#dft
эта функция выше дает мне черное изображение. У меня есть вход в GRAYSCALE.
void convol_fft(const Mat& A,const vector<vector<float>>& kernel2d,Mat& result)
{
Mat B = Mat(3,3,CV_64F);
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++){
B.at<uchar>(row,col) = (uchar)kernel2d[row][col];
}
int dft_M = getOptimalDFTSize( A.rows+B.rows-1 );
int dft_N = getOptimalDFTSize( A.cols+B.cols-1 );
Mat dft_A = Mat::zeros(dft_M, dft_N, CV_64F);
Mat dft_B = Mat::zeros(dft_M, dft_N, CV_64F);
Mat dft_A_part = dft_A(Rect(0, 0, A.cols,A.rows));
A.convertTo(dft_A_part, dft_A_part.type(), 1, -mean(A)[0]);
Mat dft_B_part = dft_B(Rect(0, 0, B.cols,B.rows));
B.convertTo(dft_B_part, dft_B_part.type(), 1, -mean(B)[0]);
dft(dft_A, dft_A, 0, A.rows);
dft(dft_B, dft_B, 0, B.rows);
// set the last parameter to false to compute convolution instead of correlation
mulSpectrums( dft_A, dft_B, dft_A, 0, false );
idft(dft_A, dft_A, DFT_SCALE, A.rows + B.rows - 1 );
result = dft_A(Rect(0, 0, A.cols + B.cols - 1, A.rows + B.rows - 1));
normalize(result, result, 0, 1, NORM_MINMAX, result.type());
pow(result, 3., result);
// B ^= Scalar::all(255);
}
Я не уверен насчет OpenCV … но это выглядит подозрительно.
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++){
B.at<uchar>(row,col) = (uchar)kernel2d[row][col];
}
Если вы заполняете ядро B, тогда строка должна быть kernel2d [col] .size (). Похоже, вы обгоняете ядро B. Что такое значение kernel2d.size ()?
Почему бы просто не загрузить значения напрямую? Сохранение всех вызовов функций.
Для гауссовского ядра это должно выглядеть примерно так: {1,2,1,2,3,2,1,2,1}.
Следующий код, основанный на openCV phaseCorrelateRes()
сделаем корреляцию в 2-х измерениях.
static void fftShift(InputOutputArray _out)
{
Mat out = _out.getMat();
if(out.rows == 1 && out.cols == 1)
{
// trivially shifted.
return;
}
vector<Mat> planes;
split(out, planes);
int xMid = out.cols >> 1;
int yMid = out.rows >> 1;
bool is_1d = xMid == 0 || yMid == 0;
if(is_1d)
{
xMid = xMid + yMid;
for(size_t i = 0; i < planes.size(); i++)
{
Mat tmp;
Mat half0(planes[i], Rect(0, 0, xMid, 1));
Mat half1(planes[i], Rect(xMid, 0, xMid, 1));
half0.copyTo(tmp);
half1.copyTo(half0);
tmp.copyTo(half1);
}
}
else
{
for(size_t i = 0; i < planes.size(); i++)
{
// perform quadrant swaps...
Mat tmp;
Mat q0(planes[i], Rect(0, 0, xMid, yMid));
Mat q1(planes[i], Rect(xMid, 0, xMid, yMid));
Mat q2(planes[i], Rect(0, yMid, xMid, yMid));
Mat q3(planes[i], Rect(xMid, yMid, xMid, yMid));
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
}
merge(planes, out);
}
void Correlate2d(
const cv::Mat& src1,
const cv::Mat& src2,
cv::Mat& dst,
double* response)
{
CV_Assert( src1.type() == src2.type());
CV_Assert( src1.type() == CV_32FC1 || src1.type() == CV_64FC1 );
CV_Assert( src1.size == src2.size);
int M = getOptimalDFTSize(src1.rows);
int N = getOptimalDFTSize(src1.cols);
Mat padded1, padded2, paddedWin;
if(M != src1.rows || N != src1.cols)
{
copyMakeBorder(src1, padded1, 0, M - src1.rows, 0, N - src1.cols, BORDER_CONSTANT, Scalar::all(0));
copyMakeBorder(src2, padded2, 0, M - src2.rows, 0, N - src2.cols, BORDER_CONSTANT, Scalar::all(0));
}
else
{
padded1 = src1;
padded2 = src2;
}
Mat FFT1, FFT2, P, Pm, C;
// correlation equation
// Reference: http://en.wikipedia.org/wiki/Phase_correlation
dft(padded1, FFT1, DFT_REAL_OUTPUT);
dft(padded2, FFT2, DFT_REAL_OUTPUT);
mulSpectrums(FFT1, FFT2, dst, 0, true);
idft(dst, dst, DFT_SCALE); // gives us the correlation result...
fftShift(dst); // shift the energy to the center of the frame.
// locate the highest peak
Point peakLoc;
minMaxLoc(dst, NULL, NULL, NULL, &peakLoc);
// max response is scaled
if( response )
*response = dst.at<float>(peakLoc);
}
Вы можете найти код в \ opencv \ sources \ modules \ imgproc \ src \ phasecorr.cpp
Чтобы изменить код на свертку, просто измените эту строку:
mulSpectrums(FFT1, FFT2, dst, 0, true);
в
mulSpectrums(FFT1, FFT2, dst, 0, false);
Это эквивалентно выполнению в Matlab:
dst = fftshift(ifft2(fft2(src1).*conj(fft2(src2))))