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.processor.SinglebandImageProcessor;
34 import org.openimaj.math.matrix.MatrixUtils;
35
36 import Jama.SingularValueDecomposition;
37
38
39
40
41
42
43
44
45 public class FConvolution implements SinglebandImageProcessor<Float, FImage> {
46
47 public FImage kernel;
48
49 private ConvolveMode mode;
50
51 interface ConvolveMode {
52 public void convolve(FImage f);
53
54 class OneD implements ConvolveMode {
55 private float[] kernel;
56 private boolean rowMode;
57
58 OneD(FImage image) {
59 if (image.height == 1) {
60 this.rowMode = true;
61 this.kernel = image.pixels[0];
62
63 } else {
64 this.rowMode = false;
65 this.kernel = new float[image.height];
66 for (int i = 0; i < image.height; i++)
67 this.kernel[i] = image.pixels[i][0];
68 }
69 }
70
71 @Override
72 public void convolve(FImage f) {
73 if (this.rowMode)
74 FImageConvolveSeparable.convolveHorizontal(f, kernel);
75 else
76 FImageConvolveSeparable.convolveVertical(f, kernel);
77 }
78
79 }
80
81 class Separable implements ConvolveMode {
82 private float[] row;
83 private float[] col;
84
85 Separable(SingularValueDecomposition svd) {
86
87 final int nrows = svd.getU().getRowDimension();
88
89 this.row = new float[nrows];
90 this.col = new float[nrows];
91
92 final float factor = (float) Math.sqrt(svd.getS().get(0, 0));
93 for (int i = 0; i < nrows; i++) {
94 this.row[i] = (float) svd.getU().get(i, 0) * factor;
95 this.col[i] = (float) svd.getV().get(i, 0) * factor;
96 }
97 }
98
99 @Override
100 public void convolve(FImage f) {
101 FImageConvolveSeparable.convolveHorizontal(f, col);
102 FImageConvolveSeparable.convolveVertical(f, row);
103 }
104 }
105
106 class BruteForce implements ConvolveMode {
107 protected FImage kernel;
108
109 BruteForce(FImage kernel) {
110 this.kernel = kernel;
111 }
112
113 @Override
114 public void convolve(FImage image) {
115 final int kh = kernel.height;
116 final int kw = kernel.width;
117 final int hh = kh / 2;
118 final int hw = kw / 2;
119 final FImage clone = image.newInstance(image.width, image.height);
120 for (int y = hh; y < image.height - (kh - hh); y++) {
121 for (int x = hw; x < image.width - (kw - hw); x++) {
122 float sum = 0;
123 for (int j = 0, jj = kh - 1; j < kh; j++, jj--) {
124 for (int i = 0, ii = kw - 1; i < kw; i++, ii--) {
125 final int rx = x + i - hw;
126 final int ry = y + j - hh;
127
128 sum += image.pixels[ry][rx] * kernel.pixels[jj][ii];
129 }
130 }
131 clone.pixels[y][x] = sum;
132 }
133 }
134 image.internalAssign(clone);
135 }
136 }
137 }
138
139
140
141
142
143
144
145 public FConvolution(FImage kernel) {
146 this.kernel = kernel;
147 setup(false);
148 }
149
150
151
152
153
154
155
156 public FConvolution(float[][] kernel) {
157 this.kernel = new FImage(kernel);
158 setup(false);
159 }
160
161
162
163
164
165
166
167 public void setBruteForce(boolean brute) {
168 setup(brute);
169 }
170
171 private void setup(boolean brute) {
172 if (brute) {
173 this.mode = new ConvolveMode.BruteForce(this.kernel);
174 return;
175 }
176 if (this.kernel.width == 1 || this.kernel.height == 1) {
177 this.mode = new ConvolveMode.OneD(kernel);
178 } else {
179 final SingularValueDecomposition svd = new SingularValueDecomposition(
180 MatrixUtils.matrixFromFloat(this.kernel.pixels));
181 if (svd.rank() == 1)
182 this.mode = new ConvolveMode.Separable(svd);
183 else
184 this.mode = new ConvolveMode.BruteForce(this.kernel);
185 }
186 }
187
188
189
190
191
192
193
194 @Override
195 public void processImage(FImage image) {
196 mode.convolve(image);
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210 public float responseAt(int x, int y, FImage image) {
211 float sum = 0;
212 final int kh = kernel.height;
213 final int kw = kernel.width;
214 final int hh = kh / 2;
215 final int hw = kw / 2;
216
217 for (int j = 0, jj = kh - 1; j < kh; j++, jj--) {
218 for (int i = 0, ii = kw - 1; i < kw; i++, ii--) {
219 final int rx = x + i - hw;
220 final int ry = y + j - hh;
221
222 sum += image.pixels[ry][rx] * kernel.pixels[jj][ii];
223 }
224 }
225 return sum;
226 }
227 }