/Users/lyon/j4p/src/ip/transforms/FFTImage.java
|
1 package ip.transforms;
2
3 import math.transforms.fft.FFT2d;
4 import math.transforms.fft.IFFT2d;
5 import math.transforms.fft.ImageUtils;
6
7 import java.awt.*;
8 import java.awt.image.ImageObserver;
9 import java.awt.image.MemoryImageSource;
10 import java.awt.image.PixelGrabber;
11
12 // Calculate the transforms.fft of input image, using transforms.fft.FFT2d.
13
14 public class FFTImage implements ImageObserver {
15
16 int intImage[];
17 int imageWidth, imageHeight;
18 // image.length, or imageWidth * imageHeight
19 int N;
20 // scale is used to scale the FFT input to prevent overflow,
21 // N = imageWidth * imageHeight is often used.
22 int scale;
23 // Scale the FFT output magnitude to get the best display result.
24 float magScale;
25
26 boolean fftShift;
27
28 short alpha[];
29 float redRe[], greenRe[], blueRe[];
30 float redIm[], greenIm[], blueIm[];
31
32 public boolean imageUpdate(Image img, int infoflags,
33 int x, int y, int width, int height) {
34 initImage(img);
35 return true;
36 }
37
38 public FFTImage(Image img) {
39
40 initImage(img);
41 }
42
43 /**
44 * uses one image to filter another.
45 * only works if the two images are the same size.
46 */
47 public static Image filter(Image img1, Image img2) {
48 FFTImage fimg1 = new FFTImage(img1);
49 FFTImage fimg2 = new FFTImage(img2);
50 fimg1.fft();
51 fimg2.fft();
52 fimg1.mult(fimg2);
53 fimg1.ifft();
54 return fimg1.getImage();
55 }
56
57 public Image getImage() {
58 Toolkit tk = Toolkit.getDefaultToolkit();
59 return tk.createImage(
60 new MemoryImageSource(
61 imageWidth,
62 imageHeight,
63 tk.getColorModel(),
64 intImage, 0,
65 imageWidth));
66 }
67
68 private void initImage(Image img) {
69 if (img == null) return;
70 int width = img.getWidth(this);
71 int height = img.getHeight(this);
72
73
74 int intImage[] = new int[width * height];
75
76 PixelGrabber grabber =
77 new PixelGrabber(
78 img, 0, 0,
79 width, height, true);
80 imageWidth = grabber.getWidth();
81 imageHeight = grabber.getHeight();
82
83 try {
84 grabber.grabPixels();
85 } catch (InterruptedException e) {
86 }
87 initVariables((int[]) grabber.getPixels(), imageWidth, 100.0f, true);
88 }
89
90
91 /**
92 * complex multiply, for filtering
93 */
94 public void mult(FFTImage f) {
95 for (int i = 0; i < redRe.length; i++) {
96 redRe[i] *= f.redRe[i] / 255.0f;
97 greenRe[i] *= f.greenRe[i] / 255.0f;
98 blueRe[i] *= f.blueRe[i] / 255.0f;
99 redIm[i] *= f.redIm[i] / 255.0f;
100 greenIm[i] *= f.greenIm[i] / 255.0f;
101 blueIm[i] *= f.blueIm[i] / 255.0f;
102 }
103 }
104
105 // getPels(), width, 100.0f, true
106 public FFTImage(int intImage[], int imageWidth,
107 float magScale, boolean fftShift) {
108 initVariables(intImage, imageWidth, magScale, fftShift);
109
110 }
111
112 private void initVariables(int[] intImage, int imageWidth, float magScale, boolean fftShift) {
113 this.intImage = intImage;
114 this.imageWidth = imageWidth;
115 N = intImage.length;
116 imageHeight = N / imageWidth;
117 this.magScale = magScale;
118 this.fftShift = fftShift;
119 scale = N;
120
121 alpha = ImageUtils.getAlpha(intImage);
122 short red[] = ImageUtils.getRed(intImage);
123 short green[] = ImageUtils.getGreen(intImage);
124 short blue[] = ImageUtils.getBlue(intImage);
125
126 // If fftShift is true, shift the zero frequency to the center.
127 redRe = fftReorder(red);
128 greenRe = fftReorder(green);
129 blueRe = fftReorder(blue);
130 redIm = new float[N];
131 greenIm = new float[N];
132 blueIm = new float[N];
133 }
134
135 public void fft() {
136 intImage = getFftIntArray();
137 }
138
139 public int[] getFftIntArray() {
140 new FFT2d(redRe, redIm, imageWidth);
141 new FFT2d(greenRe, greenIm, imageWidth);
142 new FFT2d(blueRe, blueIm, imageWidth);
143
144 float resultRed[] = magnitude(redRe, redIm);
145 float resultGreen[] = magnitude(greenRe, greenIm);
146 float resultBlue[] = magnitude(blueRe, blueIm);
147
148 int resultImage[] = ImageUtils.argbToInt(alpha, resultRed,
149 resultGreen, resultBlue);
150 return resultImage;
151 }
152
153 public void ifft() {
154 intImage = getIfftIntArray();
155 }
156
157 public int[] getIfftIntArray() {
158 new IFFT2d(redRe, redIm, imageWidth);
159 new IFFT2d(greenRe, greenIm, imageWidth);
160 new IFFT2d(blueRe, blueIm, imageWidth);
161
162 short resultRed[] = ifftReorder(redRe);
163 short resultGreen[] = ifftReorder(greenRe);
164 short resultBlue[] = ifftReorder(blueRe);
165
166 int resultImage[] = ImageUtils.argbToInt(alpha, resultRed,
167 resultGreen, resultBlue);
168 return resultImage;
169 }
170
171 // reorder color data of transforms.fft input.
172 // 1. Convert color data from short to float.
173 // 2. Scale the color data by scale.
174 // 3. If fftShift is true, shift the zero frequency in the center of matrix.
175 private float[] fftReorder(short color[]) {
176 float result[] = new float[N];
177
178 if (!fftShift) { // Without zero frequency shift.
179 for (int i = 0; i < N; i++)
180 result[i] = (float) color[i] / scale;
181 } else { // With zero frequency shift.
182 int k = 0;
183 float alternateSign = 1;
184 for (int i = 0; i < imageHeight; i++)
185 for (int j = 0; j < imageWidth; j++) {
186 alternateSign = ((i + j) % 2 == 0) ? -1 : 1;
187 result[i * imageWidth + j] = (float) (color[k++] * alternateSign / scale);
188 }
189 }
190 return result;
191 } // End of function fftReorder().
192
193 private short[] ifftReorder(float re[]) {
194 short result[] = new short[N];
195
196 if (!fftShift) { // Without zero frequency shift.
197 for (int i = 0; i < N; i++)
198 result[i] = (short) (re[i] * scale);
199 } else { // With zero frequency shift.
200 int k = 0;
201 float alternateSign = 1;
202 for (int i = 0; i < imageHeight; i++)
203 for (int j = 0; j < imageWidth; j++) {
204 alternateSign = ((i + j) % 2 == 0) ? -1 : 1;
205 result[i * imageWidth + j] = (short) (re[k++] * alternateSign * scale);
206 }
207 }
208 return result;
209 } // End of function fftReorder().
210
211 // Scale the FFT output magnitude to get the best display result.
212 private float[] magnitude(float re[], float im[]) {
213 float result[] = new float[N];
214 for (int i = 0; i < N; i++) {
215 result[i] = (float) (magScale *
216 Math.log(1 + Math.sqrt(re[i] * re[i] + im[i] * im[i])));
217 if (result[i] > 255)
218 result[i] = 255;
219 }
220 return result;
221 } // End of function magnitude().
222
223 } // End of class FFTImage.
224