Отрисовка спектра изображения на 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
Звучит как проблема масштабирования - вы должны проверить диапазон значений выходной величины БПФ.   -  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. Теперь у меня есть черное изображение с одной белой точкой. Я читал, что такая проблема возникает, когда мы работаем с целыми числами вместо числа с плавающей запятой. Но в моем случае, как видите, я сохраняю выходные данные прямо в изображение 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 и посмотреть, восстановите ли вы исходное изображение? затем вы можете шаг за шагом проверить, в чем ваша проблема. Другим решением для поиска проблемы является выполнение этого процесса с заранее определенной вами небольшой матрицей, вычисление ее БПФ в MATLAB и проверка шаг за шагом, у меня это сработало!

person Antonio    schedule 01.09.2011