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.resize;
31
32 import org.openimaj.image.FImage;
33 import org.openimaj.image.processing.resize.ResizeProcessor.PixelContribution;
34 import org.openimaj.image.processing.resize.ResizeProcessor.PixelContributions;
35 import org.openimaj.image.processing.resize.filters.TriangleFilter;
36 import org.openimaj.image.processor.SinglebandImageProcessor;
37
38
39
40
41
42
43
44
45
46 public class FixedResizeProcessor implements SinglebandImageProcessor<Float, FImage> {
47
48 private float newX;
49 private float newY;
50 private ResizeFilterFunction filterFunction;
51 private float srcX;
52 private float srcY;
53 private ImageContributions ic;
54 final float[] work;
55
56
57
58
59
60 public static final ResizeFilterFunction DEFAULT_FILTER = TriangleFilter.INSTANCE;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public FixedResizeProcessor(float srcX, float srcY, float newX, float newY, ResizeFilterFunction ff) {
78 this.srcX = srcX;
79 this.srcY = srcY;
80 this.newX = newX;
81 this.newY = newY;
82 this.filterFunction = ff;
83 prepareResample(true);
84 this.work = new float[(int)newY];
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 public FixedResizeProcessor(float srcX, float srcY, float newX, float newY) {
102 this(srcX,srcY,newX, newY, DEFAULT_FILTER);
103 }
104
105
106
107
108
109
110
111
112
113 public FixedResizeProcessor(FImage image, int newX, int newY) {
114 this(image.width,image.height,newX,newY);
115 }
116
117 private void prepareResample(boolean aspect) {
118
119
120 int nx = (int)newX;
121 int ny = (int)newY;
122 if (aspect) {
123 if (ny > nx)
124 nx = (int) Math.round((this.srcX * ny) / (double) this.srcY);
125 else
126 ny = (int) Math.round((this.srcY * nx) / (double) this.srcX);
127 }
128 this.newX = nx;
129 this.newY = ny;
130
131 this.ic = FixedResizeProcessor.prepareZoom((int)srcX,(int)srcY,(int)newX,(int)newY,this.filterFunction);
132 }
133 static class ImageContributions{
134 PixelContributions[] xContributions;
135 PixelContributions[] yContributions;
136 }
137 private static ImageContributions prepareZoom(int srcWidth, int srcHeight, int dstWidth, int dstHeight, ResizeFilterFunction filterf) {
138 final double xscale = (double) dstWidth / (double) srcWidth;
139 final double yscale = (double) dstHeight / (double) srcHeight;
140
141 final PixelContributions[] contribY = new PixelContributions[dstHeight];
142 for (int i = 0; i < contribY.length; i++) {
143 contribY[i] = new PixelContributions();
144 }
145
146 final PixelContributions[] contribX = new PixelContributions[dstWidth];
147 for (int i = 0; i < contribX.length; i++) {
148 contribX[i] = new PixelContributions();
149 }
150
151 final double fwidth = filterf.getSupport();
152 if (yscale < 1.0) {
153 double width = fwidth / yscale;
154 double fscale = 1.0 / yscale;
155
156 if (width <= .5) {
157
158 width = .5 + 1.0e-6;
159 fscale = 1.0;
160 }
161
162 for (int i = 0; i < dstHeight; i++) {
163 contribY[i].contributions = new PixelContribution[(int) (width * 2.0 + 1)];
164 contribY[i].numberOfContributors = 0;
165
166 final double center = i / yscale;
167 final int left = (int) Math.ceil(center - width);
168 final int right = (int) Math.floor(center + width);
169
170 double density = 0.0;
171
172 for (int j = left; j <= right; j++) {
173 double weight = center - j;
174 weight = filterf.filter(weight / fscale) / fscale;
175 int n;
176 if (j < 0) {
177 n = -j;
178 }
179 else if (j >= srcHeight) {
180 n = (srcHeight - j) + srcHeight - 1;
181 }
182 else {
183 n = j;
184 }
185
186
187
188
189
190
191
192
193
194
195 final int k = contribY[i].numberOfContributors++;
196 contribY[i].contributions[k] = new PixelContribution();
197 contribY[i].contributions[k].pixel = n;
198 contribY[i].contributions[k].weight = weight;
199
200 density += weight;
201 }
202
203 if ((density != 0.0) && (density != 1.0)) {
204
205 density = 1.0 / density;
206 for (int k = 0; k < contribY[i].numberOfContributors; k++) {
207 contribY[i].contributions[k].weight *= density;
208 }
209 }
210 }
211 }
212 else {
213 for (int i = 0; i < dstHeight; ++i) {
214 contribY[i].contributions = new PixelContribution[(int) (fwidth * 2 + 1)];
215 contribY[i].numberOfContributors = 0;
216
217 final double center = i / yscale;
218 final double left = Math.ceil(center - fwidth);
219 final double right = Math.floor(center + fwidth);
220 for (int j = (int) left; j <= right; ++j) {
221 double weight = center - j;
222 weight = filterf.filter(weight);
223 int n;
224 if (j < 0) {
225 n = -j;
226 }
227 else if (j >= srcHeight) {
228 n = (srcHeight - j) + srcHeight - 1;
229 }
230 else {
231 n = j;
232 }
233
234
235
236
237
238
239
240
241
242
243 final int k = contribY[i].numberOfContributors++;
244 contribY[i].contributions[k] = new PixelContribution();
245 contribY[i].contributions[k].pixel = n;
246 contribY[i].contributions[k].weight = weight;
247 }
248 }
249 }
250
251 if (xscale < 1.0) {
252 for (int i = 0; i < dstWidth; ++i) {
253
254 double width = fwidth / xscale;
255 double fscale = 1.0 / xscale;
256
257 if (width <= .5) {
258
259 width = .5 + 1.0e-6;
260 fscale = 1.0;
261 }
262
263 contribX[i].numberOfContributors = 0;
264 contribX[i].contributions = new PixelContribution[(int) (width * 2.0 + 1.0)];
265
266 double center = i / xscale;
267 final int left = (int) Math.ceil(center - width);
268
269 final int right = (int) Math.floor(center + width);
270
271 double density = 0.0;
272
273 for (int j = left; j <= right; j++) {
274 double weight = center - j;
275 weight = filterf.filter(weight / fscale) / fscale;
276 int n;
277 if (j < 0) {
278 n = -j;
279 }
280 else if (j >= srcWidth) {
281 n = (srcWidth - j) + srcWidth - 1;
282 }
283 else {
284 n = j;
285 }
286
287
288
289
290
291
292
293
294
295
296 final int k = contribX[i].numberOfContributors++;
297 contribX[i].contributions[k] = new PixelContribution();
298 contribX[i].contributions[k].pixel = n;
299 contribX[i].contributions[k].weight = weight;
300
301 density += weight;
302
303 }
304
305 if ((density != 0.0) && (density != 1.0)) {
306
307 density = 1.0 / density;
308 for (int k = 0; k < contribX[i].numberOfContributors; k++) {
309 contribX[i].contributions[k].weight *= density;
310 }
311 }
312 }
313 }
314 else {
315 for (int i = 0; i < dstWidth; ++i) {
316
317 contribX[i].numberOfContributors = 0;
318 contribX[i].contributions = new PixelContribution[(int) (fwidth * 2.0 + 1.0)];
319
320 double center = i / xscale;
321 final int left = (int) Math.ceil(center - fwidth);
322 final int right = (int) Math.floor(center + fwidth);
323
324 for (int j = left; j <= right; j++) {
325 double weight = center - j;
326 weight = filterf.filter(weight);
327
328 int n;
329 if (j < 0) {
330 n = -j;
331 }
332 else if (j >= srcWidth) {
333 n = (srcWidth - j) + srcWidth - 1;
334 }
335 else {
336 n = j;
337 }
338
339
340
341
342
343
344
345
346
347
348 final int k = contribX[i].numberOfContributors++;
349 contribX[i].contributions[k] = new PixelContribution();
350 contribX[i].contributions[k].pixel = n;
351 contribX[i].contributions[k].weight = weight;
352 }
353 }
354 }
355
356 ImageContributions ic = new ImageContributions();
357 ic.xContributions = contribX;
358 ic.yContributions = contribY;
359
360 return ic;
361 }
362
363
364
365
366
367
368 @Override
369 public void processImage(FImage in) {
370 if(in.width != this.srcX || in.height != srcY){
371 throw new RuntimeException("Incompatible image type used with FixedResizeProcessor, try the normal ResizeProcessor");
372 }
373
374
375 FImage dst = new FImage((int)this.newX,(int)this.newY);
376 final float maxValue = in.max();
377 for (int xx = 0; xx < dst.width; xx++) {
378 final PixelContributions contribX = this.ic.xContributions[xx];
379
380
381 for (int k = 0; k < in.height; k++) {
382 double weight = 0.0;
383 boolean bPelDelta = false;
384
385
386 final double pel = in.pixels[k][contribX.contributions[0].pixel];
387 for (int j = 0; j < contribX.numberOfContributors; j++) {
388 final double pel2 = j == 0 ? pel : in.pixels[k][contribX.contributions[j].pixel];
389 if (pel2 != pel) {
390 bPelDelta = true;
391 }
392 weight += pel2 * contribX.contributions[j].weight;
393 }
394 weight = bPelDelta ? Math.round(weight * 255) / 255f : pel;
395
396 if (weight < 0) {
397 weight = 0;
398 }
399 else if (weight > maxValue) {
400 weight = maxValue;
401 }
402
403 work[k] = (float) weight;
404 }
405
406
407
408
409
410 for (int i = 0; i < dst.height; i++) {
411 double weight = 0.0;
412 boolean bPelDelta = false;
413 final double pel = work[ic.yContributions[i].contributions[0].pixel];
414
415 for (int j = 0; j < ic.yContributions[i].numberOfContributors; j++) {
416
417
418 final double pel2 = j == 0 ? pel : work[ic.yContributions[i].contributions[j].pixel];
419 if (pel2 != pel) {
420 bPelDelta = true;
421 }
422 weight += pel2 * ic.yContributions[i].contributions[j].weight;
423 }
424 weight = bPelDelta ? Math.round(weight * 255) / 255f : pel;
425
426 if (weight < 0) {
427 weight = 0;
428 }
429 else if (weight > maxValue) {
430 weight = maxValue;
431 }
432
433 dst.pixels[i][xx] = (float) weight;
434 }
435 }
436
437 in.internalAssign(dst);
438 }
439
440 }