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;
31
32 import java.util.Comparator;
33
34 import org.openimaj.image.colour.ColourSpace;
35 import org.openimaj.image.pixel.Pixel;
36 import org.openimaj.image.renderer.MBFImageRenderer;
37 import org.openimaj.image.renderer.RenderHints;
38
39
40
41
42
43
44 public class MBFImage extends MultiBandImage<Float, MBFImage, FImage> {
45 private static final long serialVersionUID = 1L;
46
47
48
49
50 public MBFImage() {
51 super(ColourSpace.RGB);
52 }
53
54
55
56
57
58
59
60
61
62
63 public MBFImage(final ColourSpace colourSpace, final FImage... images) {
64 super(colourSpace, images);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78 public MBFImage(final FImage... images) {
79 super(images.length == 3 ? ColourSpace.RGB : images.length == 4 ? ColourSpace.RGBA : ColourSpace.CUSTOM, images);
80 }
81
82
83
84
85
86
87
88
89
90 public MBFImage(final int width, final int height) {
91 this(width, height, ColourSpace.RGB);
92 }
93
94
95
96
97
98
99
100
101
102
103
104 public MBFImage(final int width, final int height, final ColourSpace colourSpace) {
105 this.colourSpace = colourSpace;
106
107 for (int i = 0; i < colourSpace.getNumBands(); i++) {
108 this.bands.add(new FImage(width, height));
109 }
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public MBFImage(final int width, final int height, final int nbands) {
125 if (nbands == 3)
126 this.colourSpace = ColourSpace.RGB;
127 else if (nbands == 4)
128 this.colourSpace = ColourSpace.RGBA;
129
130 for (int i = 0; i < nbands; i++) {
131 this.bands.add(new FImage(width, height));
132 }
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146 public MBFImage(final int[] data, final int width, final int height) {
147 this(data, width, height, false);
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 public MBFImage(final int[] data, final int width, final int height, final boolean alpha) {
164 this(width, height, alpha ? 4 : 3);
165 this.internalAssign(data, width, height);
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public MBFImage(double[] ds, int width, int height, int nbands, boolean interlaced) {
187 if (interlaced) {
188 for (int i = 0; i < nbands; i++) {
189 bands.add(new FImage(width, height));
190 }
191 for (int y = 0, c = 0; y < height; y++) {
192 for (int x = 0; x < width; x++) {
193 for (int i = 0; i < nbands; i++, c++) {
194 bands.get(i).pixels[y][x] = (float) ds[c];
195 }
196 }
197 }
198 } else {
199 for (int i = 0; i < nbands; i++) {
200 bands.add(new FImage(ds, width, height, i * width * height));
201 }
202 }
203 }
204
205
206
207
208
209
210 @Override
211 public FImage flattenMax() {
212 final int width = this.getWidth();
213 final int height = this.getHeight();
214
215 final FImage out = new FImage(width, height);
216
217 for (int y = 0; y < height; y++) {
218 for (int x = 0; x < width; x++) {
219 float max = (this.bands.get(0)).pixels[y][x];
220
221 for (int i = 1; i < this.numBands(); i++)
222 if (max < (this.bands.get(i)).pixels[y][x])
223 max = (this.bands.get(i)).pixels[y][x];
224
225 out.pixels[y][x] = max;
226 }
227 }
228
229 return out;
230 }
231
232 @Override
233 public FImage flatten() {
234
235
236 final int width = this.getWidth();
237 final int height = this.getHeight();
238
239 final FImage out = new FImage(width, height);
240 final float[][] outp = out.pixels;
241 final int nb = this.numBands();
242
243 for (int i = 1; i < nb; i++) {
244 final float[][] bnd = this.bands.get(i).pixels;
245
246 for (int y = 0; y < height; y++) {
247 for (int x = 0; x < width; x++) {
248 outp[y][x] += bnd[y][x];
249
250 }
251 }
252 }
253
254 final float norm = 1f / nb;
255 final float[][] bnd = this.bands.get(0).pixels;
256 for (int y = 0; y < height; y++) {
257 for (int x = 0; x < width; x++) {
258 outp[y][x] = (outp[y][x] + bnd[y][x]) * norm;
259 }
260 }
261
262 return out;
263 }
264
265
266
267
268
269
270 @Override
271 public Float[] getPixel(final int x, final int y) {
272 final Float[] pixels = new Float[this.bands.size()];
273
274 for (int i = 0; i < this.bands.size(); i++) {
275 pixels[i] = this.bands.get(i).getPixel(x, y);
276 }
277
278 return pixels;
279 }
280
281 @Override
282 public Comparator<? super Float[]> getPixelComparator() {
283 return new Comparator<Float[]>() {
284
285 @Override
286 public int compare(final Float[] o1, final Float[] o2) {
287 int sumDiff = 0;
288 boolean anyDiff = false;
289 for (int i = 0; i < o1.length; i++) {
290 sumDiff += o1[i] - o2[i];
291 anyDiff = sumDiff != 0 || anyDiff;
292 }
293 if (anyDiff) {
294 if (sumDiff > 0)
295 return 1;
296 else
297 return -1;
298 } else
299 return 0;
300 }
301
302 };
303 }
304
305
306
307
308
309
310 @Override
311 public Float[] getPixelInterp(final double x, final double y) {
312 final Float[] result = new Float[this.bands.size()];
313
314 for (int i = 0; i < this.bands.size(); i++) {
315 result[i] = this.bands.get(i).getPixelInterp(x, y);
316 }
317
318 return result;
319 }
320
321
322
323
324
325
326
327 @Override
328 public Float[] getPixelInterp(final double x, final double y, final Float[] b) {
329 final Float[] result = new Float[this.bands.size()];
330
331 for (int i = 0; i < this.bands.size(); i++) {
332 result[i] = this.bands.get(i).getPixelInterp(x, y, b[i]);
333 }
334
335 return result;
336 }
337
338
339
340
341
342
343
344
345
346
347
348
349 public MBFImage internalAssign(final byte[] bytes, final int width, final int height) {
350 if (this.getWidth() != width || this.getHeight() != height)
351 this.internalAssign(this.newInstance(width, height));
352
353 final float[][] br = this.bands.get(0).pixels;
354 final float[][] bg = this.bands.get(1).pixels;
355 final float[][] bb = this.bands.get(2).pixels;
356
357 for (int i = 0, y = 0; y < height; y++) {
358 for (int x = 0; x < width; x++) {
359 final int red = (bytes[i++]) & 0xff;
360 final int green = (bytes[i++]) & 0xff;
361 final int blue = bytes[i++] & 0xff;
362 br[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[red];
363 bg[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[green];
364 bb[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[blue];
365 }
366 }
367
368 return this;
369 }
370
371
372
373
374
375
376 @Override
377 public MBFImage internalAssign(final int[] data, final int width, final int height) {
378 if (this.getWidth() != width || this.getHeight() != height)
379 this.internalAssign(this.newInstance(width, height));
380
381 final float[][] br = this.bands.get(0).pixels;
382 final float[][] bg = this.bands.get(1).pixels;
383 final float[][] bb = this.bands.get(2).pixels;
384 float[][] ba = null;
385
386 if (this.colourSpace == ColourSpace.RGBA)
387 ba = this.bands.get(3).pixels;
388
389 for (int i = 0, y = 0; y < height; y++) {
390 for (int x = 0; x < width; x++, i++) {
391 final int rgb = data[i];
392 final int alpha = ((rgb >> 24) & 0xff);
393 final int red = ((rgb >> 16) & 0xff);
394 final int green = ((rgb >> 8) & 0xff);
395 final int blue = ((rgb) & 0xff);
396 br[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[red];
397 bg[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[green];
398 bb[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[blue];
399
400 if (ba != null)
401 ba[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[alpha];
402 }
403 }
404
405 return this;
406 }
407
408 @Override
409 protected Float intToT(final int n) {
410 return (float) n;
411 }
412
413 @Override
414 public FImage newBandInstance(final int width, final int height) {
415 return new FImage(width, height);
416 }
417
418 @Override
419 public MBFImage newInstance() {
420 return new MBFImage();
421 }
422
423
424
425
426
427
428 @Override
429 public MBFImage newInstance(final int width, final int height) {
430 final MBFImage ret = new MBFImage(width, height, this.bands.size());
431
432 ret.colourSpace = this.colourSpace;
433
434 return ret;
435 }
436
437 @Override
438 public MBFImageRenderer createRenderer() {
439 return new MBFImageRenderer(this);
440 }
441
442 @Override
443 public MBFImageRenderer createRenderer(final RenderHints options) {
444 return new MBFImageRenderer(this, options);
445 }
446
447
448
449
450
451
452
453
454
455 public float[] getPixelNative(final Pixel p) {
456 return this.getPixelNative(p.x, p.y);
457 }
458
459
460
461
462
463
464
465
466
467
468
469 public float[] getPixelNative(final int x, final int y) {
470 final float[] pixels = new float[this.bands.size()];
471
472 for (int i = 0; i < this.bands.size(); i++) {
473 pixels[i] = this.bands.get(i).getPixelNative(x, y);
474 }
475
476 return pixels;
477 }
478
479
480
481
482
483
484
485
486
487
488 public float[][] getPixelVectorNative(final float[][] f) {
489 for (int y = 0; y < this.getHeight(); y++)
490 for (int x = 0; x < this.getWidth(); x++)
491 f[x + y * this.getWidth()] = this.getPixelNative(x, y);
492
493 return f;
494 }
495
496
497
498
499
500
501
502
503
504
505
506
507 public void setPixelNative(final int x, final int y, final float[] val) {
508 final int np = this.bands.size();
509 if (np == val.length)
510 for (int i = 0; i < np; i++)
511 this.bands.get(i).setPixel(x, y, val[i]);
512 else {
513 final int offset = val.length - np;
514 for (int i = 0; i < np; i++)
515 if (i + offset >= 0)
516 this.bands.get(i).setPixel(x, y, val[i + offset]);
517 }
518 }
519
520
521
522
523
524
525
526
527
528
529
530 @Override
531 public MBFImage overlayInplace(final MBFImage image, final int x, final int y) {
532
533 final FImage alpha = image.getBand(image.numBands() - 1);
534
535 for (int i = 0; i < this.numBands(); i++)
536 this.bands.get(i).overlayInplace(image.bands.get(i), alpha, x, y);
537
538 return this;
539 }
540
541
542
543
544
545
546
547
548
549
550 public static MBFImage randomImage(final int width, final int height) {
551 final MBFImage img = new MBFImage();
552 img.colourSpace = ColourSpace.RGB;
553
554 for (int i = 0; i < 3; i++) {
555 img.bands.add(FImage.randomImage(width, height));
556 }
557
558 return img;
559 }
560
561
562
563
564
565
566
567
568
569
570 public static MBFImage createRGB(final FImage image) {
571 return new MBFImage(image.clone(), image.clone(), image.clone());
572 }
573
574 @Override
575 public MBFImage fill(final Float[] colour) {
576 return super.fill(this.colourSpace.sanitise(colour));
577 }
578
579 @Override
580 public void setPixel(final int x, final int y, final Float[] val) {
581
582
583
584 if (this.colourSpace == ColourSpace.RGBA && this.numBands() >= 4 && val.length >= 4
585 && x >= 0 && x < this.getWidth() && y >= 0 && y < this.getHeight())
586 {
587 final float[] p = ImageUtilities.alphaCompositePixel(this.getPixel(x, y), val);
588 this.getBand(0).pixels[y][x] = p[0];
589 this.getBand(1).pixels[y][x] = p[1];
590 this.getBand(2).pixels[y][x] = p[2];
591 if (this.numBands() >= 4)
592 this.getBand(3).pixels[y][x] = p[3];
593 } else
594 super.setPixel(x, y, val);
595 }
596
597 @Override
598 protected Float[] createPixelArray(int n) {
599 return new Float[n];
600 }
601
602
603
604
605
606
607 public double[] getDoublePixelVector() {
608 final int height = getHeight();
609 final int width = getWidth();
610 final double f[] = new double[width * height * this.numBands()];
611 for (int i = 0; i < this.bands.size(); i++) {
612 final float[][] pixels = bands.get(i).pixels;
613
614 for (int y = 0; y < height; y++)
615 for (int x = 0; x < width; x++)
616 f[x + y * width + i * height * width] = pixels[y][x];
617 }
618 return f;
619 }
620 }