Странный, но близкий FFT и ifft изображения в переполнении стека

Я написал программу, которая загружает, сохраняет и выполняет FFT и IFFT для черно-белых изображений PNG. После большой отладочной головной боли я наконец-то получил внятный вывод и обнаружил, что он искажает исходное изображение.

вход:

вход

FFT:

быстрое преобразование Фурье

IFFT:

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

Насколько я тестировал, данные пикселей в каждом массиве сохраняются и преобразуются правильно. Пиксели хранятся в двух массивах: «данные», которые содержат ч / б значение каждого пикселя, и «комплексные данные», которые в два раза длиннее «данных» и хранят реальное ч / б значение и мнимые части каждого пикселя в чередующихся индексах. Мой алгоритм fft работает с массивом, структурированным как ‘complex_data’. После кода для чтения команд от пользователя вот такой код:

if (cmd == "fft")
{
if (height > width) size = height;
else size = width;

N = (int)pow(2.0, ceil(log((double)size)/log(2.0)));

temp_data = (double*) malloc(sizeof(double) * width * 2); //array to hold each row of the image for processing in FFT()

for (i = 0; i < (int) height; i++)
{
for (j = 0; j < (int) width; j++)
{
temp_data[j*2] = complex_data[(i*width*2)+(j*2)];
temp_data[j*2+1] = complex_data[(i*width*2)+(j*2)+1];
}
FFT(temp_data, N, 1);
for (j = 0; j < (int) width; j++)
{
complex_data[(i*width*2)+(j*2)] = temp_data[j*2];
complex_data[(i*width*2)+(j*2)+1] = temp_data[j*2+1];
}
}
transpose(complex_data, width, height); //tested
free(temp_data);
temp_data = (double*) malloc(sizeof(double) * height * 2);
for (i = 0; i < (int) width; i++)
{
for (j = 0; j < (int) height; j++)
{
temp_data[j*2] = complex_data[(i*height*2)+(j*2)];
temp_data[j*2+1] = complex_data[(i*height*2)+(j*2)+1];
}
FFT(temp_data, N, 1);
for (j = 0; j < (int) height; j++)
{
complex_data[(i*height*2)+(j*2)] = temp_data[j*2];
complex_data[(i*height*2)+(j*2)+1] = temp_data[j*2+1];
}
}
transpose(complex_data, height, width);

free(temp_data);
free(data);

data = complex_to_real(complex_data, image.size()/4); //tested
image = bw_data_to_vector(data, image.size()/4); //tested
cout << "*** fft success ***" << endl << endl;void FFT(double* data, unsigned long nn, int f_or_b){ // f_or_b is 1 for fft, -1 for ifft

unsigned long n, mmax, m, j, istep, i;
double wtemp, w_real, wp_real, wp_imaginary, w_imaginary, theta;
double temp_real, temp_imaginary;

// reverse-binary reindexing to separate even and odd indices
// and to allow us to compute the FFT in place

n = nn<<1;
j = 1;
for (i = 1; i < n; i += 2) {
if (j > i) {
swap(data[j-1], data[i-1]);
swap(data[j], data[i]);
}
m = nn;
while (m >= 2 && j > m) {
j -= m;
m >>= 1;
}
j += m;
};

// here begins the Danielson-Lanczos section

mmax = 2;
while (n > mmax) {
istep = mmax<<1;
theta = f_or_b * (2 * M_PI/mmax);
wtemp = sin(0.5 * theta);
wp_real = -2.0 * wtemp * wtemp;
wp_imaginary = sin(theta);
w_real = 1.0;
w_imaginary = 0.0;
for (m = 1; m < mmax; m += 2) {
for (i = m; i <= n; i += istep) {
j = i + mmax;
temp_real = w_real * data[j-1] - w_imaginary * data[j];
temp_imaginary = w_real * data[j] + w_imaginary * data[j-1];

data[j-1] = data[i-1] - temp_real;
data[j] = data[i] - temp_imaginary;
data[i-1] += temp_real;
data[i] += temp_imaginary;
}
wtemp = w_real;
w_real += w_real * wp_real - w_imaginary * wp_imaginary;
w_imaginary += w_imaginary * wp_real + wtemp * wp_imaginary;
}
mmax=istep;
}}

Мой ifft такой же, только с f_or_b, установленным в -1 вместо 1. Моя программа вызывает FFT () в каждой строке, транспонирует изображение, снова вызывает FFT () в каждой строке, а затем транспонирует обратно. Может быть, ошибка с моей индексацией?

4

Решение

Спасибо всем за ваше мнение. Все эти вещи о повреждении памяти, хотя и имеют значение, но не являются корнем проблемы. Размеры данных, которые я искажаю, не слишком велики, и я освобождаю их в нужных местах. У меня было много практики с этим во время обучения в. Проблема была не в алгоритме fft, и даже не в его 2D-реализации.

Все, что я пропустил, это масштабирование на 1 / (M * N) в самом конце моего кода ifft. Поскольку изображение 512×512, мне нужно было увеличить вывод ifft на 1 / (512 * 512). Кроме того, мой FFT выглядит как белый шум, потому что данные пикселей не были изменены, чтобы соответствовать от 0 до 255.

1

Другие решения

Не фактический ответ, так как этот вопрос только Debug, поэтому вместо этого есть несколько подсказок:

ваши результаты действительно плохие

это должно выглядеть так:

хорошие результаты

  • первая строка фактическая DFFT результат
  • Re,Im,Power усиливается константой, иначе вы увидите черное изображение
  • последнее изображение IDFFT оригинал не усилен Re,IM результат
  • вторая строка такая же, но DFFT результат оборачивается на половину размера изображения в кабинке x,y чтобы соответствовать общим результатам в большинстве DIP / CV тексты

Как вы можете видеть, если вы IDFFT верните завернутые результаты, результат не верный (маска доски проверки)

В результате DFFT у вас есть только одно изображение

  • это спектр мощности?
  • или вы забыли включить мнимую часть? только для просмотра или, возможно, также для вычислений где-то?

ваш 1D ** DFFT за работой?**

  • для реальных данных результат должен быть симметричным
  • проверьте ссылки из моего комментария и сравните результаты для некоторого образца 1D массива
  • отладка / ремонт вашего 1D FFT сначала и только потом переходите на следующий уровень
  • не забудьте проверить реальные и сложные данные …

ваш IDFFT выглядит BW (без серого) насыщенный

  • так вы усилили DFFT результаты, чтобы увидеть изображение и использовать это для IDFFT вместо оригинала DFFT результат?
  • также проверьте, если вы не округлите до целых чисел где-то вдоль вычисления

остерегайтесь (I) DFFT переполнения / недополнения

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

1

Предлагаю вам посмотреть статью http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html

У Кристофа есть хорошее замечание, но он ошибается в том, что он не связан с проблемой, потому что кажется, что в наше время использование malloc вместо new () / free () не инициализирует память или не выбирает лучший тип данных, что привело бы ко всем проблемам перечислено ниже:-

Возможные причины:

  1. Признак изменения числа где-то, я видел похожие проблемы, когда вызов вызова платформы был использован в dll, и значение передается по значению, а не по ссылке. Это вызвано тем, что память не обязательно должна быть пустой, поэтому при вводе данных изображения в ней будут выполняться логические вычисления. Я бы посоветовал вам убедиться, что память пуста, прежде чем помещать туда данные своего изображения.

  2. Память вращается вправо (ROR в ассемблере) или влево (ROL). Это произойдет, если используются типы данных, которые не обязательно совпадают, например. значение со знаком, вводящее тип данных без знака или если число битов в одной переменной отличается от другого.

  3. Данные теряются из-за того, что значение без знака входит в переменную со знаком. Результаты теряются на 1 бит, потому что они будут использоваться для определения отрицательного или положительного значения, или в крайних случаях, если имеет место дополнение до двух, значение станет инвертированным по смыслу, ищите дополнение к двум в Википедии.

Также посмотрите, как память должна быть очищена / назначена перед использованием. http://www.cprogramming.com/tutorial/memory_debugging_parallel_inspector.html

0
По вопросам рекламы [email protected]