2011-10-17 14 views
7

Sto provando a FFT un'immagine utilizzando la libreria da http://www.fftw.org/ in modo da poter eseguire una convoluzione nel dominio della frequenza. Ma non riesco a capire come farlo funzionare. Per capire come farlo, sto provando a inoltrare a FFT un'immagine come una matrice di pixelcolors e quindi a ritroso FFT per ottenere la stessa serie di pixelcolors. Ecco quello che faccio:Inoltra FFT un'immagine e FFT indietro un'immagine per ottenere lo stesso risultato

fftw_plan planR, planG, planB; 
fftw_complex *inR, *inG, *inB, *outR, *outG, *outB, *resultR, *resultG, *resultB; 

//Allocate arrays. 
inR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
inG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
inB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 

outR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
outG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
outB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 

resultR = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
resultG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 
resultB = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * width * width); 

//Fill in arrays with the pixelcolors. 
for (int y = 0; y < height; y++) { 
    for (int x = 0; x < width; x++) { 
     int currentIndex = ((y * width) + (x)) * 3; 
     inR[y * width + x][0] = pixelColors[currentIndex]; 
     inG[y * width + x][0] = pixelColors[currentIndex + 1]; 
     inB[y * width + x][0] = pixelColors[currentIndex + 2]; 
    } 
} 

//Forward plans. 
planR = fftw_plan_dft_2d(width, width, inR, outR, FFTW_FORWARD, FFTW_MEASURE); 
planG = fftw_plan_dft_2d(width, width, inG, outG, FFTW_FORWARD, FFTW_MEASURE); 
planB = fftw_plan_dft_2d(width, width, inB, outB, FFTW_FORWARD, FFTW_MEASURE); 

//Forward FFT. 
fftw_execute(planR); 
fftw_execute(planG); 
fftw_execute(planB); 

//Backward plans. 
planR = fftw_plan_dft_2d(width, width, outR, resultR, FFTW_BACKWARD, FFTW_MEASURE); 
planG = fftw_plan_dft_2d(width, width, outG, resultG, FFTW_BACKWARD, FFTW_MEASURE); 
planB = fftw_plan_dft_2d(width, width, outB, resultB, FFTW_BACKWARD, FFTW_MEASURE); 

//Backward fft 
fftw_execute(planR); 
fftw_execute(planG); 
fftw_execute(planB); 

//Overwrite the pixelcolors with the result. 
for (int y = 0; y < height; y++) { 
    for (int x = 0; x < width; x++) { 
     int currentIndex = ((y * width) + (x)) * 3; 
     pixelColors[currentIndex] = resultR[y * width + x][0]; 
     pixelColors[currentIndex + 1] = resultG[y * width + x][0]; 
     pixelColors[currentIndex + 2] = resultB[y * width + x][0]; 
    } 
} 

Qualcuno potrebbe farmi vedere un esempio di come inoltrare FFT un'immagine e FFT poi indietro l'immagine utilizzando FFTW per ottenere lo stesso risultato? Ho visto molti esempi che mostrano come usare FFTW in FFT, ma non riesco a capire come si applica alla mia situazione in cui ho una serie di pixel colorati che rappresentano un'immagine.

risposta

15

Una cosa importante da notare quando si esegue la FFT seguita dalla FFT inversa è che questo normalmente produce un fattore di scala di N applicato al risultato finale, vale a dire che i valori dei pixel dell'immagine risultanti dovranno essere divisi per N in ordine per abbinare i valori dei pixel originali. (N è la dimensione della FFT.) Così il vostro circuito di uscita dovrebbe probabilmente cercare qualcosa di simile:

//Overwrite the pixelcolors with the result. 
for (int y = 0; y < height; y++) { 
    for (int x = 0; x < width; x++) { 
     int currentIndex = ((y * width) + (x)) * 3; 
     pixelColors[currentIndex] = resultR[y * width + x][0]/(width * height); 
     pixelColors[currentIndex + 1] = resultG[y * width + x][0]/(width * height); 
     pixelColors[currentIndex + 2] = resultB[y * width + x][0]/(width * height); 
    } 
} 

Si noti inoltre che, probabilmente, si vuole fare un vero e proprio FFT-to-complesso seguito da un complesso-to- IFFT reale (un po 'più efficiente in termini di memoria e prestazioni). Per ora anche se sembra che tu stia facendo complesso a complesso in entrambe le direzioni, che va bene, ma non stai riempiendo correttamente gli array di input. Se avete intenzione di attaccare con complessi-to-complesso allora probabilmente desidera modificare il ciclo di ingresso a qualcosa di simile:

//Fill in arrays with the pixelcolors. 
for (int y = 0; y < height; y++) { 
    for (int x = 0; x < width; x++) { 
     int currentIndex = ((y * width) + (x)) * 3; 
     inR[y * width + x][0] = (double)pixelColors[currentIndex]; 
     inR[y * width + x][1] = 0.0; 
     inG[y * width + x][0] = (double)pixelColors[currentIndex + 1]; 
     inG[y * width + x][1] = 0.0; 
     inB[y * width + x][0] = (double)pixelColors[currentIndex + 2]; 
     inB[y * width + x][1] = 0.0; 
    } 
} 

cioè i valori dei pixel andare nelle parti reali dei valori di input complessi e la le parti immaginarie devono essere azzerate.

Un'altra cosa da notare: quando riuscirai a farlo funzionare, scoprirai che le prestazioni sono terribili - ci vuole molto tempo per creare un piano relativo al tempo impiegato per la FFT effettiva. L'idea è di creare il piano una sola volta, ma usarlo per eseguire molti FFT. Quindi dovrai separare la creazione del piano dal codice FFT e metterlo in una routine di inizializzazione o costruttore o altro.

2

Ma se si utilizza il metodo RealToComplex o ComplexToRealFunction prestare attenzione al fatto che l'immagine verrà memorizzata in una matrice di dimensioni [altezza x (larghezza/2 +1)] e se si desidera eseguire alcuni calcoli intermedi in il dominio della frequenza diventerà un po 'più difficile ...