home *** CD-ROM | disk | FTP | other *** search
- /*
- * powspec.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /* POWSPEC: program performs 2-dimensional FFT on image and yields
- * image containing power spectrum
- * usage: powspec inimg outimg [-l] [-p] [-w] [-c] [-L]
- * Note: image sidelength must be power of 2; if not the case,
- * this program changes the size to be so, either the
- * next higher or lower power of 2 as user-chosen (<-p>).
- *
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <string.h>
-
- #include "ip.h"
-
- #if defined(WIN32) || defined(LINUX)
- #define M_PI 3.14159265358979323846
- #define log2(a) (log(a)/ 0.6931471805599)
- #define exp2(a) (pow((double)2, (double)a))
- #endif
- #define CROSSSEC_HEIGHT 128 /* height of cross section display */
-
- void input (int argc, char *argv[], short *linear, short *zeroPad, short *noWndw, short *crossSec);
- void window (float **image, long nRow, long nCol, long nRowS, long nColS);
- void usage (short flag);
-
- int
- main (argc, argv)
- int argc;
- char *argv[];
-
- {
- register long x, y, nCol, nRow, /* image input sidelengths */
- nCol2, nRow2, /* power of 2 spectrum sidelengths */
- nColD2, nRowD2; /* middle row/column of spectrum image */
- long xStart, yStart; /* beginning coord.s of pow spec in image */
- Image *imgI, *imgO; /* I/O image structures */
- unsigned char **imgIn, /* image array */
- **imgOut; /* output image */
- short linear; /* if 1, linear power scale; 0 => log */
- short zeroPad; /* if 1, upsize image to pow of 2; 0 => down */
- short noWndw; /* if 1, no smoothing window; 0 otherwise */
- short crossSec; /* if 1, display cross section; 0 otherwise */
- float **imgReal, **imgImag; /* complex image arrays */
- //float *wndwX, *wndwY; /* row and column window vectors */
- double min, max; /* maximum value in power spectrum */
- double temp;
- long sum, nSum; /* sum of intensities */
- long avg; /* average image intensity (dc) */
- long nRow3, nRow4; /* image heights with cross section displays */
- long *radialP; /* radial power for cross section display */
- long *nRadialP; /* no. of power measurements at each radius */
- long radius; /* radius from (0,0) for radial power */
- long *angleP; /* angular power for cross section display */
- long *nAngleP; /* no. of power measurements at each angle */
- long angle; /* angle (0 to 180) degrees */
- long maxR, maxA; /* max of powers for normalization */
- long minR, minA; /* min of powers for normalization */
- double xRad, yRad; /* x,y radii from (0,0) */
-
- input (argc, argv, &linear, &zeroPad, &noWndw, &crossSec);
-
- /* read input image */
- imgI = ImageIn (argv[1]);
- imgIn = imgI->img;
- nRow = ImageGetHeight (imgI);
- nCol = ImageGetWidth (imgI);
- printf ("Image is %3dx%3d.\n", nCol, nRow);
-
- /* check for image sidelengths powers of 2 */
- nRow2 = nRow;
- temp = log2 ((double) nRow);
- if ((temp - (long) temp) != 0.0)
- nRow2 = (zeroPad == 0) ?
- (long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
- nCol2 = nCol;
- temp = log2 ((double) nCol);
- if ((temp - (long) temp) != 0.0)
- nCol2 = (zeroPad == 0) ?
- (long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
- if (nRow2 != nRow || nCol2 != nCol)
- printf ("Image size changed to %dx%d so power of 2 (required for FFT).\n",
- nRow2, nCol2);
-
- /* allocate output image */
- nRow3 = (crossSec) ? nRow2 + CROSSSEC_HEIGHT : nRow2;
- nRow4 = (crossSec) ? nRow2 + 2 * CROSSSEC_HEIGHT : nRow2;
- imgO = ImageAlloc (nRow4, nCol2, ImageGetDepth (imgI));
- imgOut = ImageGetPtr (imgO);
-
- /* allocate memory for complex array */
- if ((imgReal = (float **) calloc (nRow2, sizeof (float *))) == NULL)
- exit (2);
- for (y = 0; y < nRow2; y++)
- if ((imgReal[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
- exit (3);
-
- if ((imgImag = (float **) calloc (nRow2, sizeof (float *))) == NULL)
- exit (4);
- for (y = 0; y < nRow2; y++)
- if ((imgImag[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
- exit (5);
-
- /* find image average intensity */
- for (y = 0, sum = 0, nSum = 0; y < nRow; y++) {
- for (x = 0; x < nCol; x++) {
- sum += (long) imgIn[y][x];
- nSum++;
- }
- }
- avg = sum / nSum;
-
-
- /* center the image, remove average, and zero-pad or reduce size if required */
- printf ("Forward 2-D FFT being performed.\n");
- if (zeroPad == 0) {
- yStart = (nRow - nRow2) / 2;
- xStart = (nCol - nCol2) / 2;
- for (y = 0; y < nRow2; y++) {
- for (x = 0; x < nCol2; x++) {
- imgReal[y][x] = (float) imgIn[y + yStart][x + xStart] - (float) avg;
- imgImag[y][x] = (float) 0.0;
- }
- }
- }
- else {
- yStart = (nRow2 - nRow) / 2;
- xStart = (nCol2 - nCol) / 2;
- for (y = 0; y < nRow; y++) {
- for (x = 0; x < nCol; x++) {
- imgReal[y + yStart][x + xStart] = (float) imgIn[y][x];
- imgImag[y][x] = (float) 0.0;
- }
- }
- }
- /* perform windowing */
- if (zeroPad == 0)
- window (imgReal, nRow2, nCol2, nRow2, nCol2);
- else
- window (imgReal, nRow2, nCol2, nRow, nCol);
-
- /* perform 2-dimensional FFT */
- fft2d (imgReal, imgImag, nRow2, nCol2, -1);
-
- /* construct power spectrum */
- printf ("Power spectrum being constructed.\n");
- for (y = 0, max = 0.0, min = 100000.0; y < nRow2; y++) {
- for (x = 0; x < nCol2; x++) {
- imgReal[y][x] = (float) sqrt ((double) (imgReal[y][x] * imgReal[y][x]
- + imgImag[y][x] * imgImag[y][x]));
- if (!(y == 0 && x == 0))
- max = (max > imgReal[y][x]) ? max : imgReal[y][x];
- min = (min < imgReal[y][x]) ? min : imgReal[y][x];
- }
- }
- if (imgReal[0][0] > max)
- imgReal[0][0] = (float) max;
-
- /* scale, center origin at middle, and write output bytes */
- max = (linear == 0) ? log10 (max - min + 1.0) : max - min;
- nColD2 = nCol2 / 2;
- nRowD2 = nRow2 / 2;
- for (y = 0; y < nRow2; y++)
- for (x = 0; x < nCol2; x++) {
- temp = (linear == 0) ?
- log10 ((double) imgReal[y][x] - min + 1.0) :
- (double) (imgReal[y][x] - min);
- imgOut[(y + nRowD2) % nRow2][(x + nColD2) % nCol2] =
- (unsigned char) (temp * 255.0 / max);
- }
-
- /* display cross section of horizontal line through (0,0) if flag set */
- if (crossSec) {
- if ((radialP = (long *) calloc (nColD2, sizeof (long))) == NULL)
- exit (6);
- if ((nRadialP = (long *) calloc (nColD2, sizeof (long))) == NULL)
- exit (7);
- if ((angleP = (long *) calloc (nColD2, sizeof (long))) == NULL)
- exit (8);
- if ((nAngleP = (long *) calloc (nColD2, sizeof (long))) == NULL)
- exit (9);
- for (x = 0; x < nColD2; x++) {
- radialP[x] = 0;
- nRadialP[x] = 1;
- angleP[x] = 0;
- nAngleP[x] = 1;
- }
- for (y = 0; y < nRow2; y++) {
- for (x = 0; x < nCol2; x++) {
- yRad = (double) (nRowD2 - y);
- xRad = (double) (nColD2 - x);
- radius = (long) (sqrt (yRad * yRad + xRad * xRad) + 0.5);
- if (radius < nColD2)
- radialP[radius] += (long) imgOut[y][x];
- nRadialP[radius]++;
- if (yRad == 0.0 && xRad == 0.0)
- angle = 0;
- else
- angle = (long) (atan2 (-yRad, xRad) *
- (double) (nColD2 - 1) / M_PI + 0.5);
- if (angle < 0)
- angle += nColD2;
- angleP[angle] += (long) imgOut[y][x];
- nAngleP[angle]++;
- }
- }
- for (x = 0, maxR = maxA = 0; x < nColD2; x++) {
- if (x != 0)
- radialP[x] /= nRadialP[x];
- if (radialP[x] > maxR)
- maxR = radialP[x];
- angleP[x] /= nAngleP[x];
- if (angleP[x] > maxA)
- maxA = angleP[x];
- }
- for (x = 0, minR = maxR, minA = maxA; x < nColD2; x++) {
- if (radialP[x] < minR)
- minR = radialP[x];
- if (angleP[x] < minA)
- minA = angleP[x];
- }
- for (y = nRow2 + 1; y < nRow4; y++)
- for (x = 0; x < nCol2; x++)
- imgOut[y][x] = 255;
- for (x = 0; x < nCol2; x++)
- imgOut[nRow2][x] = 0;
- maxR -= minR;
- for (radius = 0; radius < nColD2; radius++) {
- radialP[radius] = (radialP[radius] - minR) * CROSSSEC_HEIGHT / maxR;
- for (y = nRow3 - 1 - radialP[radius]; y < nRow3; y++)
- imgOut[y][nColD2 + radius] = imgOut[y][nColD2 - radius] = 0;
- }
- maxA -= minA;
- for (angle = 0; angle < nColD2; angle++) {
- angleP[angle] = (angleP[angle] - minA) * CROSSSEC_HEIGHT / maxA;
- for (y = nRow4 - 1 - angleP[angle]; y < nRow4; y++)
- imgOut[y][nColD2 + angle] = imgOut[y][nColD2 - angle] = 0;
- }
- }
-
- /* output power spectrum */
- ImageOut (argv[2], imgO);
- return (0);
- }
-
-
- /* WINDOW: function multiplies vector by smoothing window
- * usage: window (image, nRow, nCol, nRowS, nColS)
- * Note: There are 2 sets of image sizes for the following
- * reason. The (nRow, nCol) size is the image size to be
- * windowed; that is, this is a power of 2 for the FFT.
- * The (nRowS, nColS) size is a smaller size that is the original
- * image size before zero-padding. This smaller image has
- * been placed in the middle of the zero-padded image. It is
- * the SMALLER IMAGE, NOT THE FINAL IMAGE that should be windowed.
- */
-
- void
- window (image, nRow, nCol, nRowS, nColS)
- float **image; /* image to be smoothed */
- long nRow, nCol; /* size of image to be windowed */
- long nRowS, nColS; /* size of smaller image b4 padding */
- {
- float *hammingX, *hammingY; /* horiz. and vert. hamming windows */
- double nM1; /* no. rows/cols minus 1 */
- long xStart, yStart; /* offset smaller image in larger */
- long x, y;
-
- /* allocate space for Hamming windows */
- if ((hammingX = (float *) calloc (nCol, sizeof (*hammingX))) == NULL)
- exit (1);
- if ((hammingY = (float *) calloc (nRow, sizeof (*hammingY))) == NULL)
- exit (2);
-
- /* put window in middle of zeroed vector if image has been padded */
- for (x = 0; x < nCol; x++)
- hammingX[x] = (float) 0.0;
- for (y = 0; y < nRow; y++)
- hammingY[y] = (float) 0.0;
- xStart = (nCol - nColS) / 2;
- yStart = (nRow - nRowS) / 2;
-
- /* calculate Hamming window */
- nM1 = (double) (nColS - 1);
- for (x = 0; x < nColS; x++)
- hammingX[x + xStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) x) / nM1));
- nM1 = (double) (nRowS - 1);
- for (y = 0; y < nRowS; y++)
- hammingY[y + yStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) y) / nM1));
-
- /* apply window to image */
- for (y = 0; y < nRow; y++)
- for (x = 0; x < nCol; x++)
- image[y][x] = image[y][x] * hammingX[x] * hammingY[y];
-
- }
-
-
- /* USAGE: function gives instructions on usage of program
- * usage: usage (flag)
- * When flag is 1, the long message is given, 0 gives short.
- */
-
- void
- usage (flag)
- short flag; /* flag =1 for long message; =0 for short message */
- {
-
- /* print short usage message or long */
- printf ("USAGE: powspec inimg outimg [-l] [-p] [-w] [-c] [-L]\n");
-
- if (flag == 0)
- exit (1);
-
- printf ("\npowspec performs 2-D FFT to produce\n");
- printf ("image of power spectrum.\n");
- printf ("ARGUMENTS:\n");
- printf (" inimg: input image filename (TIF)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -l: if set, displays linear scale for power in\n");
- printf (" power spectrum, instead of logarithmic default.\n");
- printf (" -p: if set, and image row or column is\n");
- printf (" not a power of 2, image size is increased by zero-.\n");
- printf (" padding; otherwise image size is decreased (default).\n");
- printf (" -w: if set, no smoothing window is applied \n");
- printf (" to initial image; default is to apply window.\n");
- printf (" -c: display 2 plots: top plot is summation of power over all angles\n");
- printf (" shown as a function of frequency or distance from center;\n");
- printf (" bottom plot is summation of power over all frequencies\n");
- printf (" shown as a function of angle, where 0 degrees is in middle.\n");
- printf (" -L: print Software License for this module\n");
-
- exit (1);
- }
-
-
- /* INPUT: function reads input parameters
- * usage: input (argc, argv, &linear, &zeroPad, &noWndw)
- */
-
- void
- input (argc, argv, linear, zeroPad, noWndw, crossSec)
- int argc;
- char *argv[];
- short *linear; /* if 1, linear power display; 0 =>for log display */
- short *zeroPad; /* if 1, increase img size to 2-power; 0 => decrease */
- short *noWndw; /* if 1, do not use window; 0 => smoothing window */
- short *crossSec; /* if 1, display cross section; 0 otherwise */
- {
- long n;
- double atof ();
-
- if (argc < 3)
- usage (1);
-
- *linear = 0;
- *zeroPad = 0;
- *noWndw = 0;
- *crossSec = 0;
-
- for (n = 3; n < argc; n++) {
- if (strcmp (argv[n], "-l") == 0)
- *linear = 1;
- else if (strcmp (argv[n], "-p") == 0)
- *zeroPad = 1;
- else if (strcmp (argv[n], "-w") == 0)
- *noWndw = 1;
- else if (strcmp (argv[n], "-c") == 0)
- *crossSec = 1;
- else if (strcmp (argv[n], "-L") == 0) {
- print_sos_lic ();
- exit (0);
- }
- else
- usage (0);
- }
-
- return;
- }
-