1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.openimaj.image.processing.convolution;
31
32 import org.openimaj.image.FImage;
33 import org.openimaj.image.processing.algorithm.FourierTransform;
34 import org.openimaj.image.processor.SinglebandImageProcessor;
35
36 import edu.emory.mathcs.jtransforms.fft.FloatFFT_2D;
37
38
39
40
41
42
43
44 public class FourierConvolve implements SinglebandImageProcessor<Float, FImage> {
45 private float[][] kernel;
46
47
48
49
50
51
52
53 public FourierConvolve(float[][] kernel) {
54 this.kernel = kernel;
55 }
56
57
58
59
60
61
62
63 public FourierConvolve(FImage kernel) {
64 this.kernel = kernel.pixels;
65 }
66
67 @Override
68 public void processImage(FImage image) {
69 convolve(image, kernel, true);
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public static FImage convolve(FImage image, float[][] kernel, boolean inplace) {
85 final int cols = image.getCols();
86 final int rows = image.getRows();
87
88 final FloatFFT_2D fft = new FloatFFT_2D(rows, cols);
89
90 final float[][] preparedImage = FourierTransform.prepareData(image.pixels, rows, cols, false);
91 fft.complexForward(preparedImage);
92
93 final float[][] preparedKernel = FourierTransform.prepareData(kernel, rows, cols, false);
94 fft.complexForward(preparedKernel);
95
96 for (int y = 0; y < rows; y++) {
97 for (int x = 0; x < cols; x++) {
98 final float reImage = preparedImage[y][x * 2];
99 final float imImage = preparedImage[y][1 + x * 2];
100
101 final float reKernel = preparedKernel[y][x * 2];
102 final float imKernel = preparedKernel[y][1 + x * 2];
103
104 final float re = reImage * reKernel - imImage * imKernel;
105 final float im = reImage * imKernel + imImage * reKernel;
106
107 preparedImage[y][x * 2] = re;
108 preparedImage[y][1 + x * 2] = im;
109 }
110 }
111
112 fft.complexInverse(preparedImage, true);
113
114 FImage out = image;
115 if (!inplace)
116 out = new FImage(cols, rows);
117
118 FourierTransform.unprepareData(preparedImage, out, false);
119
120 return out;
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 public static FImage convolvePrepared(FImage image, FImage filter, boolean centered) {
139 final int cols = image.getCols();
140 final int rows = image.getRows();
141
142 final FloatFFT_2D fft = new FloatFFT_2D(rows, cols);
143
144 final float[][] preparedImage = FourierTransform.prepareData(image.pixels, rows, cols, centered);
145 fft.complexForward(preparedImage);
146
147 final float[][] preparedKernel = filter.pixels;
148
149 for (int y = 0; y < rows; y++) {
150 for (int x = 0; x < cols; x++) {
151 final float reImage = preparedImage[y][x * 2];
152 final float imImage = preparedImage[y][1 + x * 2];
153
154 final float reKernel = preparedKernel[y][x * 2];
155 final float imKernel = preparedKernel[y][1 + x * 2];
156
157 final float re = reImage * reKernel - imImage * imKernel;
158 final float im = reImage * imKernel + imImage * reKernel;
159
160 preparedImage[y][x * 2] = re;
161 preparedImage[y][1 + x * 2] = im;
162 }
163 }
164
165 fft.complexInverse(preparedImage, true);
166
167 final FImage out = new FImage(cols, rows);
168 FourierTransform.unprepareData(preparedImage, out, centered);
169 return out;
170 }
171 }