Чертане на спектър на изображение в C++ (fftw, OpenCV)

Опитвам се да създам програма, която ще начертае двумерен спектър в сивата скала на дадено изображение. Използвам OpenCV и FFTW библиотеки. Използвайки съвети и кодове от интернет и модифицирайки ги, успях да заредя изображение, да изчисля fft на това изображение и да пресъздам изображението от fft (същото е). Това, което не мога да направя, е да начертая самия спектър на Фурие. Бихте ли ми помогнали, моля? Ето кода (по-малко важните редове са премахнати):

/* Copy input image */

/* Create output image */

/* Allocate input data for FFTW */
in   = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
dft  = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);

/* Create plans */
plan_f = fftw_plan_dft_2d(w, h, in, dft, FFTW_FORWARD, FFTW_ESTIMATE);

/* Populate input data in row-major order */
for (i = 0, k = 0; i < h; i++) 
{
    for (j = 0; j < w; j++, k++)
    {
        in[k][0] = ((uchar*)(img1->imageData + i * img1->widthStep))[j];
        in[k][1] = 0.;
    }
}

/* forward DFT */
fftw_execute(plan_f);

/* spectrum */
for (i = 0, k = 0; i < h; i++)
{
    for (j = 0; j < w; j++, k++)
        ((uchar*)(img2->imageData + i * img2->widthStep))[j] = sqrt(pow(dft[k][0],2) + pow(dft[k][1],2));
}       

cvShowImage("iplimage_dft(): original", img1);
cvShowImage("iplimage_dft(): result", img2);
cvWaitKey(0);

/* Free memory */

}

Проблемът е в секцията "Спектър". Вместо спектър получавам някакъв шум. какво правя грешно Ще бъда благодарен за вашата помощ.


person Narren    schedule 31.07.2011    source източник
comment
Звучи като проблем с мащабирането - трябва да проверите обхвата на стойностите на изходната величина на FFT.   -  person Paul R    schedule 31.07.2011
comment
И бихте ли предложили как да направя това? От това, което четох в различни форуми, ако беше за големината, щях да получа черно изображение (с бяла точка в центъра). Благодаря Ви за отговора.   -  person Narren    schedule 31.07.2011
comment
Тъй като не правите никаква проверка на диапазона на величината, тогава, ако е голям, той ще обвие модул 2, когато го присвоите на 8-битов пиксел (и ще изглежда като шум). Ето защо казах, че трябва да проверите диапазона - напр. добавете друг цикъл, за да намерите максималната и минималната величина и след това мащабирайте стойностите си съответно, така че да знаете, че ще се поберат в 8-битов диапазон.   -  person Paul R    schedule 31.07.2011
comment
Приложете мащабиране на дневника към спектъра на мощността, след което премащабирайте данните, за да се поберат в [0,255].   -  person jeff7    schedule 01.08.2011
comment
Проверих най-високата стойност (и най-ниската), след което разделих изходните данни на тази стойност и ги умножих по 255. Сега имам черно изображение с една бяла точка. Четох, че такъв проблем е, когато работим с цели числа вместо float. Но в моя случай, както виждате, записвам изходните данни директно в изображението img2. Няма променливи между тях. Какво правя грешно сега?   -  person Narren    schedule 02.08.2011


Отговори (2)


Трябва да начертаете големината на спектъра. ето кода.

void ForwardFFT(Mat &Src, Mat *FImg)
{
    int M = getOptimalDFTSize( Src.rows );
    int N = getOptimalDFTSize( Src.cols );
    Mat padded;    
    copyMakeBorder(Src, padded, 0, M - Src.rows, 0, N - Src.cols, BORDER_CONSTANT, Scalar::all(0));
    // Создаем комплексное представление изображения
    // planes[0] содержит само изображение, planes[1] его мнимую часть (заполнено нулями)
    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexImg;
    merge(planes, 2, complexImg); 
    dft(complexImg, complexImg);    
    // После преобразования результат так-же состоит из действительной и мнимой части
    split(complexImg, planes);

    // обрежем спектр, если у него нечетное количество строк или столбцов
    planes[0] = planes[0](Rect(0, 0, planes[0].cols & -2, planes[0].rows & -2));
    planes[1] = planes[1](Rect(0, 0, planes[1].cols & -2, planes[1].rows & -2));

    Recomb(planes[0],planes[0]);
    Recomb(planes[1],planes[1]);
    // Нормализуем спектр
    planes[0]/=float(M*N);
    planes[1]/=float(M*N);
    FImg[0]=planes[0].clone();
    FImg[1]=planes[1].clone();
}
void ForwardFFT_Mag_Phase(Mat &src, Mat &Mag,Mat &Phase)
{
    Mat planes[2];
    ForwardFFT(src,planes);
    Mag.zeros(planes[0].rows,planes[0].cols,CV_32F);
    Phase.zeros(planes[0].rows,planes[0].cols,CV_32F);
    cv::cartToPolar(planes[0],planes[1],Mag,Phase);
}
Mat LogMag;
    LogMag.zeros(Mag.rows,Mag.cols,CV_32F);
    LogMag=(Mag+1);
    cv::log(LogMag,LogMag);
    //---------------------------------------------------
    imshow("Логарифм амплитуды", LogMag);
    imshow("Фаза", Phase);
    imshow("Результат фильтрации", img);  
person mrgloom    schedule 16.08.2012

Можете ли да опитате да направите стъпката IFFT и да видите дали ще възстановите оригиналното изображение? след това можете да проверите стъпка по стъпка къде е вашият проблем. Друго решение за намиране на проблема е да направите този процес с малка матрица, предварително дефинирана от вас, и да я изчислите FFT в MATLAB, и да проверите стъпка по стъпка, при мен работи!

person Antonio    schedule 01.09.2011