MIN-Fakultät
Fachbereich Informatik
Szenenanalyse und Visualisierung (SAV)

Infoseite zur "schnellen" normierten Kreuzkorrelation im Rahmen der Vorlesung BV1 im WiSe 2008/09

Materialien:

...speziell für die schnelle Bildverarbeitung unter Mac OS X:

Benutzung der FFT des Accelerate Frameworks unter Mac OS X (Objective-C)

Um ein Bild an die FFT zu übergeben, muss es zunächst folgendes erfüllen:

  • Es sollte in der richtigen Größe vorliegen: Im Idealfall: Länge = Breite = 2^n
    Sollte dies nicht der Fall sein, muss das Bild evt. vorher in ein größeres kopiert werden.
  • Es muss ein einzelnes C-Array vom Typ DSPComplex sein.
    Dabei sollte es zeilenweise hintereinander (siehe Grafik) abgelegt sein.
0 1 2 3 4
1 0 1 2 3
2 4 5 6 7
3 8 9 10 11
4 12 13 14 15

Abbildung 1: Ein Bild mit Koordinatenachse (fett) und Scanadresse der einzelnen Pixel (Offset)

Die Umwandlung eines eingelesenen Bildes (genauer: eines CGImages) kann man hier nachlesen:
Technical Q&A QA1509 - Getting the pixel data from a CGImage object

Liegt das Bild als 1-Kanal-Repräsentation im geforderten Format vor, so kann man es an die FFT übergeben

#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
#import <Accelerate/Accelerate.h>

int fft_forward(DSPComplex * img, int width, int height){
	return fft(img, width, height, FFT_FORWARD);
}

int fft_backward(DSPComplex * img, int width, int height){
	return fft(img, width, height, FFT_INVERSE);
}

int fft(DSPComplex * data, int width, int height, FFTDirection dir){
	
	/* Total area or volume covered by the dimensions */
	int dims = width*height;
	
	/* Get log (base 2) of each dimension */
	int logX = log2((double)width);
	int logY = log2((double)height);

	
	/* Setup and allocate some memory for performing the FFTs */
	DSPSplitComplex input;
	
	input.realp = (float*)malloc(dims*sizeof(float));
	input.imagp = (float*)malloc(dims*sizeof(float));
	
	/* Setup the weights (twiddle factors) for performing the FFT */
	FFTSetup fft_weights;
	fft_weights = create_fftsetup(MIN(logX,logY),kFFTRadix2);
	
	/* Split the complex (interleaved) data into two arrays */
	ctoz(data,2,&input,1,dims);
	
	/* Perform the FFT */
	fft2d_zip(fft_weights,&input,1,0,logX,logY,dir);
	/* Merge the separate data (real and imaginary) parts into a single array */
	ztoc(&input,1,data,2,dims);
	
	//Normalize energy 
	if(dir == FFT_INVERSE){
		int i;
		for(i=0;i<dims;i++){
			data[i].real=data[i].real/dims;
			data[i].imag=data[i].imag/dims;
		}
	}
	/* Free up the allocations */
	free(input.realp);
	free(input.imagp);
	
	destroy_fftsetup(fft_weights);
	
	return 0;
}

Download:

Selbstverständlich kann der Quelltext (deutlich umfangreicher als oben) hier heruntergeladen werden. Es wird ein Bild eingelesen, automatisch vergrößert und im Anschluß wieder abgespeichert. Dabei habe ich für die Bildrepräsentation allerdings Objekte vom Typ NSImage gewählt.