1 package mpi
.fruitfly
.registration
;
4 * <p>Title: ImageFilter</p>
8 * <p>Copyright: Copyright (c) 2007</p>
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License 2
16 * as published by the Free Software Foundation.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 * @author Stephan Preibisch
31 import mpi
.fruitfly
.math
.datastructures
.*;
32 import static mpi
.fruitfly
.math
.General
.*;
33 import java
.util
.Random
;
35 public class ImageFilter
38 * Does Kaiser-Bessel-Windowing to prevent the fourier spectra from getting infinite numbers,
39 * the border will be faded to black.
41 * @param FloatArray2D image Input image stored in row-major order
42 * @param inverse If true, fading to black in the middle
43 * @return FloatArray2D The resulting image
45 public static void filterKaiserBessel(FloatArray2D img
, boolean inverse
)
51 float twoPiDivWidth
= (float)(2.0 * Math
.PI
) / (float)w
;
52 float twoPiDivHeight
= (float)(2.0 * Math
.PI
) / (float)h
;
55 // pre-compute filtering values
56 float[] kbx
= new float[w
];
57 float[] kby
= new float[h
];
59 for (x
= 0; x
< w
; x
++)
60 kbx
[x
] = (float)(0.40243 - (0.49804 * Math
.cos(twoPiDivWidth
* (float) x
)) +
61 (0.09831 * Math
.cos(twoPiDivWidth
* 2.0 * (float) x
)) -
62 (0.00122 * Math
.cos(twoPiDivWidth
* 3.0 * (float) x
)));
64 for (y
= 0; y
< h
; y
++)
65 kby
[y
] = (float)(0.40243 - (0.49804 * Math
.cos(twoPiDivHeight
* (float) y
)) +
66 (0.09831 * Math
.cos(twoPiDivHeight
* 2.0 * (float) y
)) -
67 (0.00122 * Math
.cos(twoPiDivHeight
* 3.0 * (float) y
)));
69 for (y
= 0; y
< h
; y
++)
70 for (x
= 0; x
< w
; x
++)
72 val
= (float) img
.get(x
,y
);
78 img
.set(kb
* val
, x
, y
);
81 for (x
= 0; x
< w
; x
++)
82 for (y
= 0; y
< h
; y
++)
84 val
= (float) img
.get(x
,y
);
90 img
.set(kb
* val
, x
, y
);
94 public static void exponentialWindow(FloatArray2D img
)
98 // create lookup table
99 double weightsX
[] = new double[img
.width
];
100 double weightsY
[] = new double[img
.height
];
102 for (int x
= 0; x
< img
.width
; x
++)
104 double relPos
= (double)x
/ (double)(img
.width
-1);
107 weightsX
[x
] = 1.0-(1.0/(Math
.pow(a
,(relPos
*2))));
109 weightsX
[x
] = 1.0-(1.0/(Math
.pow(a
,((1-relPos
)*2))));
112 for (int y
= 0; y
< img
.height
; y
++)
114 double relPos
= (double)y
/ (double)(img
.height
-1);
117 weightsY
[y
] = 1.0-(1.0/(Math
.pow(a
,(relPos
*2))));
119 weightsY
[y
] = 1.0-(1.0/(Math
.pow(a
,((1-relPos
)*2))));
123 for (int y
= 0; y
< img
.height
; y
++)
124 for (int x
= 0; x
< img
.width
; x
++)
125 img
.set((float) (img
.get(x
, y
) * weightsX
[x
] * weightsY
[y
]), x
, y
);
128 public static void exponentialWindow(FloatArray3D img
)
132 // create lookup table
133 double weightsX
[] = new double[img
.width
];
134 double weightsY
[] = new double[img
.height
];
135 double weightsZ
[] = new double[img
.depth
];
137 for (int x
= 0; x
< img
.width
; x
++)
139 double relPos
= (double)x
/ (double)(img
.width
-1);
142 weightsX
[x
] = 1.0-(1.0/(Math
.pow(a
,(relPos
*2))));
144 weightsX
[x
] = 1.0-(1.0/(Math
.pow(a
,((1-relPos
)*2))));
147 for (int y
= 0; y
< img
.height
; y
++)
149 double relPos
= (double)y
/ (double)(img
.height
-1);
152 weightsY
[y
] = 1.0-(1.0/(Math
.pow(a
,(relPos
*2))));
154 weightsY
[y
] = 1.0-(1.0/(Math
.pow(a
,((1-relPos
)*2))));
157 for (int z
= 0; z
< img
.depth
; z
++)
159 double relPos
= (double)z
/ (double)(img
.depth
-1);
162 weightsZ
[z
] = 1.0-(1.0/(Math
.pow(a
,(relPos
*2))));
164 weightsZ
[z
] = 1.0-(1.0/(Math
.pow(a
,((1-relPos
)*2))));
168 for (int z
= 0; z
< img
.depth
; z
++)
169 for (int y
= 0; y
< img
.height
; y
++)
170 for (int x
= 0; x
< img
.width
; x
++)
171 img
.set((float) (img
.get(x
, y
, z
) * weightsX
[x
] * weightsY
[y
]* weightsZ
[z
]), x
, y
, z
);
175 * This class creates a gaussian kernel
177 * @param sigma Standard Derivation of the gaussian function
178 * @param normalize Normalize integral of gaussian function to 1 or not...
179 * @return float[] The gaussian kernel
181 * @author Stephan Saalfeld
183 public static float[] createGaussianKernel1D(float sigma
, boolean normalize
)
186 float[] gaussianKernel
;
190 gaussianKernel
= new float[3];
191 gaussianKernel
[1] = 1;
195 size
= max(3, (int)(2*(int)(3*sigma
+ 0.5)+1));
197 float two_sq_sigma
= 2*sigma
*sigma
;
198 gaussianKernel
= new float[size
];
200 for (int x
= size
/2; x
>= 0; --x
)
202 float val
= (float)Math
.exp(-(float)(x
*x
)/two_sq_sigma
);
204 gaussianKernel
[size
/2-x
] = val
;
205 gaussianKernel
[size
/2+x
] = val
;
212 for (float value
: gaussianKernel
)
215 for (int i
= 0; i
< gaussianKernel
.length
; i
++)
216 gaussianKernel
[i
] /= sum
;
220 return gaussianKernel
;
223 public static void normalize(FloatArray img
)
227 for (float value : img.data)
230 avg /= (float)img.data.length;*/
232 float avg
= computeTurkeyBiMedian(img
.data
, 5);
236 for (float value
: img
.data
)
237 stDev
+= (value
- avg
) * (value
- avg
);
239 stDev
/= (float)(img
.data
.length
- 1);
240 stDev
= (float)Math
.sqrt(stDev
);
242 float min
= Float
.MAX_VALUE
;
243 for (int i
= 0; i
< img
.data
.length
; i
++)
245 img
.data
[i
] = (img
.data
[i
] - avg
) / stDev
;
246 if (img
.data
[i
] < min
)
250 for (int i
= 0; i
< img
.data
.length
; i
++)
255 public static FloatArray2D
createGaussianKernel2D(float sigma
, boolean normalize
)
258 FloatArray2D gaussianKernel
;
262 gaussianKernel
= new FloatArray2D(3, 3);
263 gaussianKernel
.data
[4] = 1;
267 size
= max(3, (int)(2*(int)(3*sigma
+ 0.5)+1));
269 float two_sq_sigma
= 2*sigma
*sigma
;
270 gaussianKernel
= new FloatArray2D(size
, size
);
272 for (int y
= size
/2; y
>= 0; --y
)
274 for (int x
= size
/2; x
>= 0; --x
)
276 float val
= (float)Math
.exp(-(float)(y
*y
+x
*x
)/two_sq_sigma
);
278 gaussianKernel
.set(val
, size
/2-x
, size
/2-y
);
279 gaussianKernel
.set(val
, size
/2-x
, size
/2+y
);
280 gaussianKernel
.set(val
, size
/2+x
, size
/2-y
);
281 gaussianKernel
.set(val
, size
/2+x
, size
/2+y
);
289 for (float value
: gaussianKernel
.data
)
292 for (int i
= 0; i
< gaussianKernel
.data
.length
; i
++)
293 gaussianKernel
.data
[i
] /= sum
;
297 return gaussianKernel
;
301 ** create a normalized gaussian impulse with appropriate size and offset center
303 static public FloatArray2D
create_gaussian_kernel_2D_offset(
310 FloatArray2D gaussian_kernel
;
313 gaussian_kernel
= new FloatArray2D(3 ,3);
314 gaussian_kernel
.data
[4] = 1;
318 size
= Math
.max(3, (int)( 2 * Math
.round( 3 * sigma
) + 1 ) );
319 float two_sq_sigma
= 2*sigma
*sigma
;
320 // float normalization_factor = 1.0/(float)M_PI/two_sq_sigma;
321 gaussian_kernel
= new FloatArray2D( size
, size
);
322 for ( int x
= size
- 1; x
>= 0; --x
)
324 float fx
= (float)( x
- size
/ 2 );
325 for ( int y
= size
-1; y
>= 0; --y
)
327 float fy
= (float)(y
-size
/2);
328 float val
= (float)( Math
.exp( -( Math
.pow( fx
- offset_x
, 2)+Math
.pow(fy
-offset_y
, 2))/two_sq_sigma
));
329 gaussian_kernel
.set(val
, x
, y
);
336 for (float value
: gaussian_kernel
.data
)
339 for (int i
= 0; i
< gaussian_kernel
.data
.length
; i
++)
340 gaussian_kernel
.data
[i
] /= sum
;
342 return gaussian_kernel
;
345 public static FloatArray3D
createGaussianKernel3D(float sigma
, boolean normalize
)
348 FloatArray3D gaussianKernel
;
352 gaussianKernel
= new FloatArray3D(3, 3, 3);
353 gaussianKernel
.set(1f
, 1, 1, 1);
357 size
= max(3, (int)(2*(int)(3*sigma
+ 0.5)+1));
359 float two_sq_sigma
= 2*sigma
*sigma
;
360 gaussianKernel
= new FloatArray3D(size
, size
, size
);
362 for (int z
= size
/2; z
>= 0; --z
)
364 for (int y
= size
/ 2; y
>= 0; --y
)
366 for (int x
= size
/ 2; x
>= 0; --x
)
368 float val
= (float) Math
.exp( -(float) (z
* z
+ y
* y
+ x
* x
) / two_sq_sigma
);
370 gaussianKernel
.set(val
, size
/ 2 - x
, size
/ 2 - y
, size
/ 2 - z
);
372 gaussianKernel
.set(val
, size
/ 2 - x
, size
/ 2 - y
, size
/ 2 + z
);
373 gaussianKernel
.set(val
, size
/ 2 - x
, size
/ 2 + y
, size
/ 2 - z
);
374 gaussianKernel
.set(val
, size
/ 2 + x
, size
/ 2 - y
, size
/ 2 - z
);
376 gaussianKernel
.set(val
, size
/ 2 + x
, size
/ 2 + y
, size
/ 2 - z
);
377 gaussianKernel
.set(val
, size
/ 2 + x
, size
/ 2 - y
, size
/ 2 + z
);
378 gaussianKernel
.set(val
, size
/ 2 - x
, size
/ 2 + y
, size
/ 2 + z
);
380 gaussianKernel
.set(val
, size
/ 2 + x
, size
/ 2 + y
, size
/ 2 + z
);
389 for (float value
: gaussianKernel
.data
)
392 for (int i
= 0; i
< gaussianKernel
.data
.length
; i
++)
393 gaussianKernel
.data
[i
] /= sum
;
397 return gaussianKernel
;
400 public static FloatArray2D
computeIncreasingGaussianX(FloatArray2D input
, float stDevStart
, float stDevEnd
)
402 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
404 int width
= input
.width
;
405 float changeFilterSize
= (float)(stDevEnd
- stDevStart
)/(float)width
;
411 for (int x
= 0; x
< input
.width
; x
++)
413 sigma
= stDevStart
+ changeFilterSize
* (float) x
;
414 FloatArray2D kernel
= createGaussianKernel2D(sigma
, true);
415 filterSize
= kernel
.width
;
417 for (int y
= 0; y
< input
.height
; y
++)
421 for (int fx
= -filterSize
/ 2; fx
<= filterSize
/ 2; fx
++)
422 for (int fy
= -filterSize
/ 2; fy
<= filterSize
/ 2; fy
++)
426 avg
+= input
.get(x
+ fx
, y
+ fy
) * kernel
.get(fx
+ filterSize
/2, fy
+ filterSize
/2);
434 output
.set(avg
, x
, y
);
440 public static FloatArray2D
computeGaussian(FloatArray2D input
, float sigma
)
442 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
444 float avg
, kernelsum
;
446 FloatArray2D kernel
= createGaussianKernel2D(sigma
, true);
447 int filterSize
= kernel
.width
;
449 for (int x
= 0; x
< input
.width
; x
++)
451 for (int y
= 0; y
< input
.height
; y
++)
456 for (int fx
= -filterSize
/ 2; fx
<= filterSize
/ 2; fx
++)
457 for (int fy
= -filterSize
/ 2; fy
<= filterSize
/ 2; fy
++)
461 avg
+= input
.get(x
+ fx
, y
+ fy
) * kernel
.get(fx
+ filterSize
/2, fy
+ filterSize
/2);
462 kernelsum
+= kernel
.get(fx
+ filterSize
/2, fy
+ filterSize
/2);
469 output
.set(avg
/kernelsum
, x
, y
);
475 public static FloatArray3D
computeGaussian(FloatArray3D input
, float sigma
)
477 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
479 float avg
, kernelsum
;
481 FloatArray3D kernel
= createGaussianKernel3D(sigma
, true);
482 int filterSize
= kernel
.width
;
484 for (int x
= 0; x
< input
.width
; x
++)
486 for (int y
= 0; y
< input
.height
; y
++)
488 for (int z
= 0; z
< input
.depth
; z
++)
493 for (int fx
= -filterSize
/ 2; fx
<= filterSize
/ 2; fx
++)
494 for (int fy
= -filterSize
/ 2; fy
<= filterSize
/ 2; fy
++)
495 for (int fz
= -filterSize
/ 2; fz
<= filterSize
/ 2; fz
++)
499 avg
+= input
.get(x
+ fx
, y
+ fy
, z
+ fz
) * kernel
.get(fx
+ filterSize
/ 2, fy
+ filterSize
/ 2, fz
+ filterSize
/ 2);
500 kernelsum
+= kernel
.get(fx
+ filterSize
/ 2, fy
+ filterSize
/ 2, fz
+ filterSize
/ 2);
501 } catch (Exception e
)
507 output
.set(avg
/ kernelsum
, x
, y
, z
);
514 public static FloatArray3D
computeGaussianFast(FloatArray3D input
, float sigma
)
516 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
518 float avg
, kernelsum
;
520 float[] kernel
= createGaussianKernel1D(sigma
, true);
522 int filterSize
= kernel
.length
;
525 for (int x
= 0; x
< input
.width
; x
++)
526 for (int y
= 0; y
< input
.height
; y
++)
527 for (int z
= 0; z
< input
.depth
; z
++)
532 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
534 if (x
+f
>= 0 && x
+f
< input
.width
)
536 avg
+= input
.get(x
+ f
, y
, z
) * kernel
[f
+ filterSize
/ 2];
537 kernelsum
+= kernel
[f
+ filterSize
/ 2];
541 output
.set(avg
/ kernelsum
, x
, y
, z
);
546 for (int x
= 0; x
< input
.width
; x
++)
547 for (int z
= 0; z
< input
.depth
; z
++)
549 float[] temp
= new float[input
.height
];
551 for (int y
= 0; y
< input
.height
; y
++)
556 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
558 if (y
+f
>= 0 && y
+f
< input
.height
)
560 avg
+= output
.get(x
, y
+ f
, z
) * kernel
[f
+ filterSize
/ 2];
561 kernelsum
+= kernel
[f
+ filterSize
/ 2];
564 temp
[y
] = avg
/ kernelsum
;
567 for (int y
= 0; y
< input
.height
; y
++)
568 output
.set(temp
[y
], x
, y
, z
);
572 for (int x
= 0; x
< input
.width
; x
++)
573 for (int y
= 0; y
< input
.height
; y
++)
575 float[] temp
= new float[input
.depth
];
577 for (int z
= 0; z
< input
.depth
; z
++)
582 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
584 if (z
+f
>= 0 && z
+f
< input
.depth
)
586 avg
+= output
.get(x
, y
, z
+ f
) * kernel
[f
+ filterSize
/ 2];
587 kernelsum
+= kernel
[f
+ filterSize
/ 2];
590 temp
[z
] = avg
/ kernelsum
;
593 for (int z
= 0; z
< input
.depth
; z
++)
594 output
.set(temp
[z
], x
, y
, z
);
600 public static FloatArray2D
computeGaussianFastMirror(final FloatArray2D input
, final float sigma
)
602 final FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
604 float avg
, kernelsum
= 0;
605 final float[] kernel
= createGaussianKernel1D(sigma
, true);
606 final int filterSize
= kernel
.length
;
609 for (double value
: kernel
)
613 for (int x
= 0; x
< input
.width
; x
++)
614 for (int y
= 0; y
< input
.height
; y
++)
618 if (x
-filterSize
/ 2 >= 0 && x
+ filterSize
/ 2 < input
.width
)
619 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
620 avg
+= input
.get(x
+ f
, y
) * kernel
[f
+ filterSize
/ 2];
622 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
623 avg
+= input
.getMirror(x
+ f
, y
) * kernel
[f
+ filterSize
/ 2];
625 output
.set(avg
/ kernelsum
, x
, y
);
630 final float[] temp
= new float[input
.height
];
631 for (int x
= 0; x
< input
.width
; x
++)
634 for (int y
= 0; y
< input
.height
; y
++)
638 if (y
-filterSize
/ 2 >= 0 && y
+ filterSize
/ 2 < input
.height
)
639 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
640 avg
+= output
.get(x
, y
+ f
) * kernel
[f
+ filterSize
/ 2];
642 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
643 avg
+= output
.getMirror(x
, y
+ f
) * kernel
[f
+ filterSize
/ 2];
645 temp
[y
] = avg
/ kernelsum
;
648 for (int y
= 0; y
< input
.height
; y
++)
649 output
.set(temp
[y
], x
, y
);
656 * This class does the gaussian filtering of an image. On the edges of
657 * the image it does mirror the pixels. It also uses the seperability of
658 * the gaussian convolution.
660 * @param input FloatProcessor which should be folded (will not be touched)
661 * @param sigma Standard Derivation of the gaussian function
662 * @return FloatProcessor The folded image
664 * @author Stephan Preibisch
667 public static FloatArray3D
computeGaussianFastMirror(FloatArray3D input
, float sigma
)
669 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
671 float avg
, kernelsum
= 0;
672 float[] kernel
= createGaussianKernel1D(sigma
, true);
673 int filterSize
= kernel
.length
;
676 for (double value
: kernel
)
680 for (int x
= 0; x
< input
.width
; x
++)
681 for (int y
= 0; y
< input
.height
; y
++)
682 for (int z
= 0; z
< input
.depth
; z
++)
686 if (x
-filterSize
/ 2 >= 0 && x
+ filterSize
/ 2 < input
.width
)
687 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
688 avg
+= input
.get(x
+ f
, y
, z
) * kernel
[f
+ filterSize
/ 2];
690 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
691 avg
+= input
.getMirror(x
+ f
, y
, z
) * kernel
[f
+ filterSize
/ 2];
693 output
.set(avg
/ kernelsum
, x
, y
, z
);
698 for (int x
= 0; x
< input
.width
; x
++)
699 for (int z
= 0; z
< input
.depth
; z
++)
701 float[] temp
= new float[input
.height
];
703 for (int y
= 0; y
< input
.height
; y
++)
707 if (y
-filterSize
/ 2 >= 0 && y
+ filterSize
/ 2 < input
.height
)
708 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
709 avg
+= output
.get(x
, y
+ f
, z
) * kernel
[f
+ filterSize
/ 2];
711 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
712 avg
+= output
.getMirror(x
, y
+ f
, z
) * kernel
[f
+ filterSize
/ 2];
714 temp
[y
] = avg
/ kernelsum
;
717 for (int y
= 0; y
< input
.height
; y
++)
718 output
.set(temp
[y
], x
, y
, z
);
722 for (int x
= 0; x
< input
.width
; x
++)
723 for (int y
= 0; y
< input
.height
; y
++)
725 float[] temp
= new float[input
.depth
];
727 for (int z
= 0; z
< input
.depth
; z
++)
731 if (z
-filterSize
/ 2 >= 0 && z
+ filterSize
/ 2 < input
.depth
)
732 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
733 avg
+= output
.get(x
, y
, z
+ f
) * kernel
[f
+ filterSize
/ 2];
735 for (int f
= -filterSize
/ 2; f
<= filterSize
/ 2; f
++)
736 avg
+= output
.getMirror(x
, y
, z
+ f
) * kernel
[f
+ filterSize
/ 2];
738 temp
[z
] = avg
/ kernelsum
;
741 for (int z
= 0; z
< input
.depth
; z
++)
742 output
.set(temp
[z
], x
, y
, z
);
748 public static FloatArray2D
distortSamplingX(FloatArray2D input
)
750 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
755 Random rnd
= new Random(353245632);
757 for (int x
= 0; x
< input
.width
; x
++)
759 FloatArray2D kernel
= new FloatArray2D(3,1);
761 float random
= (rnd
.nextFloat()-0.5f
)*2;
762 float val1
, val2
, val3
;
777 kernel
.set(val1
, 0, 0);
778 kernel
.set(val2
, 1, 0);
779 kernel
.set(val3
, 2, 0);
781 for (int y
= 0; y
< input
.height
; y
++)
785 for (int fx
= -filterSize
/ 2; fx
<= filterSize
/ 2; fx
++)
789 avg
+= input
.get(x
+ fx
, y
) * kernel
.get(fx
+ filterSize
/ 2, 0);
790 } catch (Exception e
)
795 output
.set(avg
, x
, y
);
801 public static FloatArray2D
distortSamplingY(FloatArray2D input
)
803 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
808 Random rnd
= new Random(7893469);
810 for (int y
= 0; y
< input
.height
; y
++)
812 FloatArray2D kernel
= new FloatArray2D(1,3);
814 float random
= (rnd
.nextFloat()-0.5f
)*2;
815 float val1
, val2
, val3
;
830 kernel
.set(val1
, 0, 0);
831 kernel
.set(val2
, 0, 1);
832 kernel
.set(val3
, 0, 2);
834 for (int x
= 0; x
< input
.width
; x
++)
838 for (int fy
= -filterSize
/ 2; fy
<= filterSize
/ 2; fy
++)
842 avg
+= input
.get(x
, y
+ fy
) * kernel
.get(0, fy
+ filterSize
/ 2);
843 } catch (Exception e
)
848 output
.set(avg
, x
, y
);
854 public static FloatArray3D
computeSobelFilter(FloatArray3D input
)
856 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
858 float sobelX
, sobelY
, sobelZ
;
859 float v1
, v2
, v3
, v4
, v5
, v6
, v7
, v8
, v9
, v10
;
861 for (int z
= 1; z
< input
.depth
-1 ; z
++)
862 for (int y
= 1; y
< input
.height
-1 ; y
++)
863 for (int x
= 1; x
< input
.width
-1; x
++)
866 v1
= input
.get(x
-1,y
,z
-1);
867 v2
= input
.get(x
+1,y
,z
-1);
869 v3
= input
.get(x
-1,y
-1,z
);
870 v4
= input
.get(x
-1,y
, z
);
871 v5
= input
.get(x
-1,y
+1,z
);
873 v6
= input
.get(x
+1,y
-1,z
);
874 v7
= input
.get(x
+1,y
, z
);
875 v8
= input
.get(x
+1,y
+1,z
);
877 v9
= input
.get(x
-1,y
,z
+1);
878 v10
= input
.get(x
+1,y
,z
+1);
880 sobelX
= v1
+ (-v2
) +
882 (-v6
) + (-2*v7
) + (-v8
) +
886 v1
= input
.get(x
,y
-1,z
-1);
887 v2
= input
.get(x
,y
+1,z
-1);
889 v3
= input
.get(x
-1,y
-1,z
);
890 v4
= input
.get(x
, y
-1,z
);
891 v5
= input
.get(x
+1,y
-1,z
);
893 v6
= input
.get(x
-1,y
+1,z
);
894 v7
= input
.get(x
,y
+1,z
);
895 v8
= input
.get(x
+1,y
+1,z
);
897 v9
= input
.get(x
,y
-1,z
+1);
898 v10
= input
.get(x
,y
+1,z
+1);
900 sobelY
= v1
+ (-v2
) +
902 (-v6
) + (-2*v7
) + (-v8
) +
907 v1
= input
.get(x
,y
-1,z
-1);
908 v2
= input
.get(x
-1,y
, z
-1);
909 v3
= input
.get(x
,y
, z
-1);
910 v4
= input
.get(x
+1,y
, z
-1);
911 v5
= input
.get(x
,y
+1,z
-1);
913 v6
= input
.get(x
,y
-1,z
+1);
914 v7
= input
.get(x
-1,y
, z
+1);
915 v8
= input
.get(x
,y
, z
+1);
916 v9
= input
.get(x
+1,y
, z
+1);
917 v10
= input
.get(x
,y
+1,z
+1);
923 (-v7
) + (-2*v8
) + (-v9
) +
927 output
.set((float)Math
.sqrt(Math
.pow(sobelX
,2) + Math
.pow(sobelY
,2) + Math
.pow(sobelZ
,2)), x
, y
, z
);
933 public static FloatArray3D
computeBinaryFilter3(FloatArray3D input
, float threshold
)
935 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
937 for (int z
= 1; z
< input
.depth
- 1; z
++)
938 for (int y
= 1; y
< input
.height
- 1; y
++)
939 for (int x
= 1; x
< input
.width
- 1; x
++)
943 for (int xs
= x
-1; xs
<= x
+ 1; xs
++)
944 for (int ys
= y
-1; ys
<= y
+ 1; ys
++)
945 for (int zs
= z
-1; zs
<= z
+ 1; zs
++)
946 avg
+= input
.get(xs
, ys
, zs
);
951 output
.set(1, x
, y
, z
);
953 output
.set(0, x
, y
, z
);
959 public static FloatArray3D
computeBinaryPlusSobelFilter3(FloatArray3D input
, float threshold
)
961 FloatArray3D output
= computeSobelFilter(input
);
965 float min
= Float
.MAX_VALUE
;
967 for (float value
: output
.data
)
977 for (int i
= 0; i
< output
.data
.length
; i
++)
978 output
.data
[i
] = (output
.data
[i
]-min
)/(max
-min
)*2;
981 for (int z
= 1; z
< input
.depth
- 1; z
++)
982 for (int y
= 1; y
< input
.height
- 1; y
++)
983 for (int x
= 1; x
< input
.width
- 1; x
++)
987 for (int xs
= x
-1; xs
<= x
+ 1; xs
++)
988 for (int ys
= y
-1; ys
<= y
+ 1; ys
++)
989 for (int zs
= z
-1; zs
<= z
+ 1; zs
++)
990 avg
+= input
.get(xs
, ys
, zs
);
995 output
.set(output
.get(x
,y
,z
) + 1, x
, y
, z
);
1001 public static FloatArray2D
computeLaPlaceFilter3(FloatArray2D input
)
1003 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
1005 float derivX
, derivY
;
1009 for (int y
= 1; y
< input
.height
-1 ; y
++)
1010 for (int x
= 1; x
< input
.width
-1; x
++)
1012 x1
= input
.get(x
-1,y
);
1013 x2
= input
.get(x
,y
);
1014 x3
= input
.get(x
+1,y
);
1016 derivX
= x1
- 2*x2
+ x3
;
1018 y1
= input
.get(x
,y
-1);
1019 y2
= input
.get(x
,y
);
1020 y3
= input
.get(x
,y
+1);
1022 derivY
= y1
- 2*y2
+ y3
;
1024 output
.set((float)Math
.sqrt(Math
.pow(derivX
,2) + Math
.pow(derivY
,2)), x
, y
);
1030 /*public static void computeLaPlaceFilterInPlace3(FloatArray2D input)
1033 float buffer = max(input.height, input.width);
1035 float derivX, derivY;
1039 for (int diag = 1; diag < input.width + input.height - 1; diag++)
1044 for (int y = 1; y < input.height -1 ; y++)
1045 for (int x = 1; x < input.width -1; x++)
1047 x1 = input.get(x-1,y);
1048 x2 = input.get(x,y);
1049 x3 = input.get(x+1,y);
1051 derivX = x1 - 2*x2 + x3;
1053 y1 = input.get(x,y-1);
1054 y2 = input.get(x,y);
1055 y3 = input.get(x,y+1);
1057 derivY = y1 - 2*y2 + y3;
1059 //output.set((float)Math.sqrt(Math.pow(derivX,2) + Math.pow(derivY,2)), x, y);
1065 public static FloatArray2D
computeLaPlaceFilter5(FloatArray2D input
)
1067 FloatArray2D output
= new FloatArray2D(input
.width
, input
.height
);
1069 float derivX
, derivY
;
1073 for (int y
= 2; y
< input
.height
-2 ; y
++)
1074 for (int x
= 2; x
< input
.width
-2; x
++)
1076 x1
= input
.get(x
-2,y
);
1077 x3
= input
.get(x
,y
);
1078 x5
= input
.get(x
+2,y
);
1080 derivX
= x1
- 2*x3
+ x5
;
1082 y1
= input
.get(x
,y
-2);
1083 y3
= input
.get(x
,y
);
1084 y5
= input
.get(x
,y
+2);
1086 derivY
= y1
- 2*y3
+ y5
;
1088 output
.set((float)Math
.sqrt(Math
.pow(derivX
,2) + Math
.pow(derivY
,2)), x
, y
);
1094 public static FloatArray3D
computeLaPlaceFilter5(FloatArray3D input
)
1096 FloatArray3D output
= new FloatArray3D(input
.width
, input
.height
, input
.depth
);
1098 float derivX
, derivY
, derivZ
;
1103 for (int z
= 2; z
< input
.depth
-2 ; z
++)
1104 for (int y
= 2; y
< input
.height
-2 ; y
++)
1105 for (int x
= 2; x
< input
.width
-2; x
++)
1107 x1
= input
.get(x
-2,y
,z
);
1108 x3
= input
.get(x
,y
,z
);
1109 x5
= input
.get(x
+2,y
,z
);
1111 derivX
= x1
- 2*x3
+ x5
;
1113 y1
= input
.get(x
,y
-2,z
);
1114 y3
= input
.get(x
,y
,z
);
1115 y5
= input
.get(x
,y
+2,z
);
1117 derivY
= y1
- 2*y3
+ y5
;
1119 z1
= input
.get(x
,y
,z
-2);
1120 z3
= input
.get(x
,y
,z
);
1121 z5
= input
.get(x
,y
,z
+2);
1123 derivZ
= z1
- 2*z3
+ z5
;
1125 output
.set((float)Math
.sqrt(Math
.pow(derivX
,2) + Math
.pow(derivY
,2) + Math
.pow(derivZ
,2)), x
, y
, z
);
1131 public static FloatArray2D
[] createGradients( FloatArray2D array
)
1133 FloatArray2D
[] gradients
= new FloatArray2D
[2];
1134 gradients
[0] = new FloatArray2D(array
.width
, array
.height
);
1135 gradients
[1] = new FloatArray2D(array
.width
, array
.height
);
1137 for (int y
= 0; y
< array
.height
; ++y
)
1139 int[] ro
= new int[3];
1140 ro
[0] = array
.width
* Math
.max(0, y
- 1);
1141 ro
[1] = array
.width
* y
;
1142 ro
[2] = array
.width
* Math
.min(y
+ 1, array
.height
- 1);
1143 for (int x
= 0; x
< array
.width
; ++x
)
1145 // L(x+1, y) - L(x-1, y)
1147 array
.data
[ro
[1] + Math
.min(x
+ 1, array
.width
- 1)] -
1148 array
.data
[ro
[1] + Math
.max(0, x
- 1)]) / 2;
1150 // L(x, y+1) - L(x, y-1)
1152 array
.data
[ro
[2] + x
] -
1153 array
.data
[ro
[0] + x
]) / 2;
1156 gradients
[0].data
[ro
[1]+x
] = (float)Math
.sqrt( Math
.pow( der_x
, 2 ) + Math
.pow( der_y
, 2 ) );
1158 gradients
[1].data
[ro
[1]+x
] = (float)Math
.atan2( der_y
, der_x
);
1161 //ImageArrayConverter.FloatArrayToImagePlus( gradients[ 1 ], "gradients", 0, 0 ).show();
1166 * in place enhance all values of a FloatArray to fill the given range
1168 public static final void enhance( FloatArray2D src
, float scale
)
1170 float min
= Float
.MAX_VALUE
;
1171 float max
= Float
.MIN_VALUE
;
1172 for ( int i
= 0; i
< src
.data
.length
; ++i
)
1174 if ( src
.data
[ i
] < min
) min
= src
.data
[ i
];
1175 else if ( src
.data
[ i
] > max
) max
= src
.data
[ i
];
1177 scale
/= ( max
- min
);
1178 for ( int i
= 0; i
< src
.data
.length
; ++i
)
1179 src
.data
[ i
] = scale
* ( src
.data
[ i
] - min
);
1183 * convolve an image with a horizontal and a vertical kernel
1184 * simple straightforward, not optimized---replace this with a trusted better version soon
1186 * @param input the input image
1187 * @param h horizontal kernel
1188 * @param v vertical kernel
1190 * @return convolved image
1192 public static FloatArray2D
convolveSeparable( FloatArray2D input
, float[] h
, float[] v
)
1194 FloatArray2D output
= new FloatArray2D( input
.width
, input
.height
);
1195 FloatArray2D temp
= new FloatArray2D( input
.width
, input
.height
);
1197 int hl
= h
.length
/ 2;
1198 int vl
= v
.length
/ 2;
1200 int xl
= input
.width
- h
.length
+ 1;
1201 int yl
= input
.height
- v
.length
+ 1;
1203 // create lookup tables for coordinates outside the image range
1204 int[] xb
= new int[ h
.length
+ hl
- 1 ];
1205 int[] xa
= new int[ h
.length
+ hl
- 1 ];
1206 for ( int i
= 0; i
< xb
.length
; ++i
)
1208 xb
[ i
] = flipInRange( i
- hl
, input
.width
);
1209 xa
[ i
] = flipInRange( i
+ xl
, input
.width
);
1212 int[] yb
= new int[ v
.length
+ vl
- 1 ];
1213 int[] ya
= new int[ v
.length
+ vl
- 1 ];
1214 for ( int i
= 0; i
< yb
.length
; ++i
)
1216 yb
[ i
] = input
.width
* flipInRange( i
- vl
, input
.height
);
1217 ya
[ i
] = input
.width
* flipInRange( i
+ yl
, input
.height
);
1220 // String xa_str = "xa: ";
1221 // String xb_str = "xb: ";
1222 // String ya_str = "ya: ";
1223 // String yb_str = "yb: ";
1224 // for ( int i = 0; i < xa.length; ++i )
1226 // xa_str = xa_str + xa[ i ] + ", ";
1227 // xb_str = xb_str + xb[ i ] + ", ";
1228 // ya_str = ya_str + ( ya[ i ] / input.width ) + ", ";
1229 // yb_str = yb_str + ( yb[ i ] / input.width ) + ", ";
1232 // System.out.println( xb_str );
1233 // System.out.println( xa_str );
1234 // System.out.println( yb_str );
1235 // System.out.println( ya_str );
1240 // horizontal convolution per row
1241 int rl
= input
.height
* input
.width
;
1242 for ( int r
= 0; r
< rl
; r
+= input
.width
)
1244 for ( int x
= hl
; x
< xl
; ++x
)
1248 for ( int xk
= 0; xk
< h
.length
; ++xk
)
1250 val
+= h
[ xk
] * input
.data
[ r
+ c
+ xk
];
1252 temp
.data
[ r
+ x
] = val
;
1254 for ( int x
= 0; x
< hl
; ++x
)
1258 for ( int xk
= 0; xk
< h
.length
; ++xk
)
1260 valb
+= h
[ xk
] * input
.data
[ r
+ xb
[ x
+ xk
] ];
1261 vala
+= h
[ xk
] * input
.data
[ r
+ xa
[ x
+ xk
] ];
1263 temp
.data
[ r
+ x
] = valb
;
1264 temp
.data
[ r
+ x
+ xl
] = vala
;
1268 // vertical convolution per column
1269 rl
= yl
* temp
.width
;
1270 int vlc
= vl
* temp
.width
;
1271 for ( int x
= 0; x
< temp
.width
; ++x
)
1273 for ( int r
= vlc
; r
< rl
; r
+= temp
.width
)
1278 for ( int yk
= 0; yk
< v
.length
; ++yk
)
1280 val
+= v
[ yk
] * temp
.data
[ c
+ rk
+ x
];
1283 output
.data
[ r
+ x
] = val
;
1285 for ( int y
= 0; y
< vl
; ++y
)
1287 int r
= y
* temp
.width
;
1290 for ( int yk
= 0; yk
< v
.length
; ++yk
)
1292 valb
+= h
[ yk
] * temp
.data
[ yb
[ y
+ yk
] + x
];
1293 vala
+= h
[ yk
] * temp
.data
[ ya
[ y
+ yk
] + x
];
1295 output
.data
[ r
+ x
] = valb
;
1296 output
.data
[ r
+ rl
+ x
] = vala
;