// // PRFourier.m // PRICE // // Created by Riccardo Mottola on Fri Jan 24 2003. // Copyright (c) 2003-2005 Carduus. All rights reserved. // // This program is free software; you can redistribute it and/or modify it under the terms of the version 2 of the GNU General Public License as published by the Free Software Foundation. // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. #import "PRFourier.h" #import "PRGrayscaleFilter.h" #include "FFT.h" extern double *cosinus; extern double *sinus; extern unsigned int *bitRevIndex; @implementation PRFourier - (PRImage *)transformImage:(PRImage *)srcImage { NSBitmapImageRep *srcImageRep; PRImage *destImage; NSBitmapImageRep *destImageRep; unsigned int w, h; unsigned int x, y; /* image scanning variables */ unsigned int halfW, halfH; /* the middle */ unsigned int i; /* convolve matrix scanning */ unsigned char *srcData; unsigned char *destData; unsigned char *p1, *p2; int bytesPerPixel; int num; unsigned int bitNum; double *Aa; double *Ab; double *ya; double *yb; double **Ma; /* non quantized output */ double **Mb; double min, max, scale; char tempStr[256]; /* get source image representation and associated information */ srcImageRep = [srcImage tiffRep]; w = [srcImage width]; h = [srcImage height]; bytesPerPixel = [srcImage bitsPP] / 8; if (w > h) bitNum = binaryLog(w); else bitNum = binaryLog(h); num = binpow(bitNum); /* find the center, maybe a better way is needed */ halfW = (unsigned int) rint(w / 2); halfH = (unsigned int) rint(h / 2); sinus = (double*)calloc(num, sizeof(double)); cosinus = (double*)calloc(num, sizeof(double)); bitRevIndex = (unsigned int*)calloc(num, sizeof(unsigned int)); initTrigonometrics(num, bitNum); Aa = (double*)calloc(num, sizeof(double)); Ab = (double*)calloc(num, sizeof(double)); ya = (double*)calloc(num, sizeof(double)); yb = (double*)calloc(num, sizeof(double)); if ([srcImageRep hasAlpha]) { if ([srcImageRep samplesPerPixel] == 2) { printf("Grayscale image + alpha\n"); } else { printf("Color image + alpha\n"); return srcImage; } } else { if ([srcImageRep samplesPerPixel] == 1) { printf("Grayscale image\n"); } else { PRGrayscaleFilter *grayFilter; printf("Color image\n"); grayFilter = [[PRGrayscaleFilter alloc] init]; srcImage = [grayFilter filterImage:srcImage]; [grayFilter release]; NSLog (@"done greyscale converting"); /* we reget previous information that is no longer valid */ /* get source image representation and associated information */ srcImageRep = [NSBitmapImageRep imageRepWithData:[srcImage TIFFRepresentation]]; bytesPerPixel = [srcImageRep bitsPerPixel] /8; } } /* allocate float destination matrix */ Ma = (double**)calloc(num, sizeof(double*)); for (i = 0; i < num; i++) { Ma[i] = (double*)calloc(num, sizeof(double)); if (!Ma[i]) { printf("out of memory allocating float matrix?\n"); return srcImage; } memset(Ma[i], '\000', num); } Mb = (double**)calloc(num, sizeof(double*)); for (i = 0; i < num; i++) { Mb[i] = (double*)calloc(num, sizeof(double)); if (!Mb[i]) { printf("out of memory allocating float matrix?\n"); return srcImage; } memset(Mb[i], '\000', num); } /* allocate destination image and its representation */ destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)]; destImageRep = [[NSBitmapImageRep alloc] \ initWithBitmapDataPlanes:NULL \ pixelsWide:w \ pixelsHigh:h \ bitsPerSample:8 \ samplesPerPixel:1 \ hasAlpha:NO \ isPlanar:NO \ colorSpaceName:NSCalibratedWhiteColorSpace \ bytesPerRow:0 \ bitsPerPixel:0] ; srcData = [srcImageRep bitmapData]; destData = [destImageRep bitmapData]; [[srcImageRep colorSpaceName] getCString:tempStr]; // printf("image space: %s\n", tempStr); /* copy the image to the float matrix */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { p1 = srcData + (y * w + x); /* the image is greyscale, no bit-depth displace */ Ma[y][x] = (double) *p1 / UCHAR_MAX; } } /* replicate borders */ if (w < num) { for (y = 0; y < h; y++) { for (x = w; x < num; x++) { p1 = srcData + (y * w + (w - (x-w+1))); Ma[y][x] = (double) *p1 / UCHAR_MAX; } } } if (h < num) { for (y = h; y < num; y++) { for (x = 0; x < w; x++) { p1 = srcData + ((h - (y-h+1)) * w + x); Ma[y][x] = (double) *p1 / UCHAR_MAX; } } } /* execute the actual filtering */ /* horizontal pass */ for (y = 0; y < num; y++) { for (i = 0; i < num; i++) { Aa[i] = Ma[y][i]; Ab[i] = Mb[y][i]; } fft(num, bitNum, Aa, Ab, ya, yb); for (i = 0; i < num; i++) { Ma[y][i] = ya[i]; Mb[y][i] = yb[i]; } } /* vertical pass */ for (x = 0; x < num; x++) { for (i = 0; i < num; i++) { Aa[i] = Ma[i][x]; Ab[i] = Mb[i][x]; } fft(num, bitNum, Aa, Ab, ya, yb); for (i = 0; i < num; i++) { Ma[i][x] = ya[i]; Mb[i][x] = yb[i]; } } /* log of rised square modulus */ for (y = 0; y < num; y++) { for (x = 0; x < num; x++) { double temp; temp = Ma[y][x]*Ma[y][x] + Mb[y][x]*Mb[y][x] + 1; if (temp <= 1) Ma[y][x] = 0; else Ma[y][x] = log(temp); } } /* now we find the range */ min = DBL_MAX; max = DBL_MIN; y = 0; for (x = 1; x < w; x++) { if (Ma[y][x] > max) max = Ma[y][x]; if (Ma[y][x] < min) min = Ma[y][x]; } for (y = 1; y < h; y++) { for (x = 0; x < w; x++) { if (Ma[y][x] > max) max = Ma[y][x]; if (Ma[y][x] < min) min = Ma[y][x]; } } scale = fabs(max - min)/(double)UCHAR_MAX; printf ("min = %f, max = %f, scale = %f\n", min, max, scale); /* now we copy the result back, after scaling */ /* we recenter the FFT */ /* top left */ for (y = 0; y < halfH; y++) { p2 = destData + (y * w); for (x = 0; x < halfW; x++) { p2[x] = (unsigned char) rint((Ma[num-1-halfH+y][num-1-halfW+x]-min)/scale); } } /* top right */ for (y = 0; y < halfH; y++) { p2 = destData + (y * w); for (x = halfW; x < w; x++) { p2[x] = (unsigned char) rint((Ma[num-1-halfH+y][x-halfW]-min)/scale); } } /* bottom left */ for (y = halfH; y < h; y++) { p2 = destData + (y * w); for (x = 0; x < halfW; x++) { p2[x] = (unsigned char) rint((Ma[y-halfH][num-1-halfW+x]-min)/scale); } } /* bottom right */ for (y = halfH; y < h; y++) { p2 = destData + (y * w); for (x = halfW; x < w; x++) { p2[x] = (unsigned char) rint((Ma[y-halfH][x-halfW]-min)/scale); } } [destImage addRepresentation:destImageRep]; [destImageRep release]; /* now we free our float matrix */ for (i = 0; i < num; i++) free(Ma[i]); free(Ma); for (i = 0; i < num; i++) free(Mb[i]); free(Mb); [destImage autorelease]; return destImage; } @end