1+ /*
2+ * #%L
3+ * ImageJ2 software for multidimensional image processing and analysis.
4+ * %%
5+ * Copyright (C) 2014 - 2023 ImageJ2 developers.
6+ * %%
7+ * Redistribution and use in source and binary forms, with or without
8+ * modification, are permitted provided that the following conditions are met:
9+ *
10+ * 1. Redistributions of source code must retain the above copyright notice,
11+ * this list of conditions and the following disclaimer.
12+ * 2. Redistributions in binary form must reproduce the above copyright notice,
13+ * this list of conditions and the following disclaimer in the documentation
14+ * and/or other materials provided with the distribution.
15+ *
16+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+ * POSSIBILITY OF SUCH DAMAGE.
27+ * #L%
28+ */
129
2- package net . imagej .ops .coloc .saca ;
30+ package org . scijava .ops . image .coloc .saca ;
331
32+ import java .lang .Math ;
433import java .util .ArrayList ;
534import java .util .List ;
635import java .util .Random ;
7- import java .util .function .Function ;
836
9- import net .imglib2 .Cursor ;
10- import net .imglib2 .Localizable ;
1137import net .imglib2 .RandomAccess ;
12- import net .imglib2 .RandomAccessibleInterval ;
38+ import net .imglib2 .Localizable ;
1339import net .imglib2 .loops .LoopBuilder ;
1440import net .imglib2 .type .numeric .RealType ;
15- import net .imglib2 .type . numeric . real . DoubleType ;
16- import net .imglib2 .util . Intervals ;
41+ import net .imglib2 .RandomAccessibleInterval ;
42+ import net .imglib2 .img . ImgFactory ;
1743import net .imglib2 .util .Localizables ;
1844import net .imglib2 .util .Util ;
1945import net .imglib2 .view .IntervalView ;
2046import net .imglib2 .view .Views ;
2147import net .imglib2 .view .composite .CompositeIntervalView ;
2248import net .imglib2 .view .composite .GenericComposite ;
49+ import net .imglib2 .type .numeric .real .DoubleType ;
2350
2451/**
25- * Adapted from Shulei's original Java code for AdaptiveSmoothedKendallTau from
26- * his RKColocal R package.
27- * (https://github.com/lakerwsl/RKColocal/blob/master/RKColocal_0.0.1.0000.tar.gz)
52+ * Helper class for Spatially Adaptive Colocalization Analysis (SACA) op.
2853 *
2954 * @author Shulei Wang
30- * @author Curtis Rueden
31- * @author Ellen T Arena
55+ * @author Ellen TA Dobson
3256 */
57+
3358public final class AdaptiveSmoothedKendallTau {
3459
3560 private AdaptiveSmoothedKendallTau () {}
3661
37- public static <I extends RealType <I >, O extends RealType <O >> void execute (
38- final RandomAccessibleInterval <I > image1 ,
39- final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
40- final RandomAccessibleInterval <O > result , final long seed )
41- {
42- execute (image1 , image2 , thres1 , thres2 , new DoubleType (), result , seed );
43- }
44-
45- public static <I extends RealType <I >, T extends RealType <T >, O extends RealType <O >> void execute (
46- final RandomAccessibleInterval <I > image1 ,
47- final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
48- final T intermediate , final RandomAccessibleInterval <O > result ,
49- final long seed )
50- {
51- final Function <RandomAccessibleInterval <I >, RandomAccessibleInterval <T >> factory =
52- img -> Util .getSuitableImgFactory (img , intermediate ).create (img );
53- execute (image1 , image2 , thres1 , thres2 , factory , result , seed );
54- }
55-
56- public static <I extends RealType <I >, T extends RealType <T >, O extends RealType <O >> void execute (
57- final RandomAccessibleInterval <I > image1 ,
58- final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
59- Function <RandomAccessibleInterval <I >, RandomAccessibleInterval <T >> factory ,
60- final RandomAccessibleInterval <O > result , final long seed )
62+ // TODO: check that output float type is actually what we want here.
63+ public static <I extends RealType <I >> RandomAccessibleInterval <DoubleType >
64+ execute (final RandomAccessibleInterval <I > image1 ,
65+ final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
66+ final long seed )
6167 {
6268 final long nr = image1 .dimension (1 );
6369 final long nc = image1 .dimension (0 );
64- final RandomAccessibleInterval <T > oldtau = factory .apply (image1 );
65- final RandomAccessibleInterval <T > newtau = factory .apply (image1 );
66- final RandomAccessibleInterval <T > oldsqrtN = factory .apply (image1 );
67- final RandomAccessibleInterval <T > newsqrtN = factory .apply (image1 );
68- final List <RandomAccessibleInterval <T >> stop = new ArrayList <>();
69- for (int s = 0 ; s < 3 ; s ++)
70- stop .add (factory .apply (image1 ));
70+ final ImgFactory <DoubleType > factory = Util .getSuitableImgFactory (image1 ,
71+ new DoubleType ());
72+ final RandomAccessibleInterval <DoubleType > oldtau = factory .create (image1 );
73+ final RandomAccessibleInterval <DoubleType > newtau = factory .create (image1 );
74+ final RandomAccessibleInterval <DoubleType > oldsqrtN = factory .create (
75+ image1 );
76+ final RandomAccessibleInterval <DoubleType > newsqrtN = factory .create (
77+ image1 );
78+ final RandomAccessibleInterval <DoubleType > result = factory .create (image1 );
79+ final List <RandomAccessibleInterval <DoubleType >> stop = new ArrayList <>();
7180 final double Dn = Math .sqrt (Math .log (nr * nc )) * 2 ;
7281 final int TU = 15 ;
7382 final int TL = 8 ;
7483 final double Lambda = Dn ;
75-
76- LoopBuilder . setImages ( oldsqrtN ). forEachPixel ( t -> t . setOne () );
77-
84+ final double stepsize = 1.15 ;
85+ final Random rng = new Random ( seed );
86+ boolean isCheck = false ;
7887 double size = 1 ;
79- final double stepsize = 1.15 ; // empirically the best, but could have users
80- // set
8188 int intSize ;
82- boolean IsCheck = false ;
8389
84- final Random rng = new Random (seed );
90+ for (int s = 0 ; s < 3 ; s ++)
91+ stop .add (factory .create (image1 ));
92+
93+ LoopBuilder .setImages (oldsqrtN ).forEachPixel (t -> t .setOne ());
8594
8695 for (int s = 0 ; s < TU ; s ++) {
8796 intSize = (int ) Math .floor (size );
8897 singleiteration (image1 , image2 , thres1 , thres2 , stop , oldtau , oldsqrtN ,
89- newtau , newsqrtN , result , Lambda , Dn , intSize , IsCheck , rng );
98+ newtau , newsqrtN , result , Lambda , Dn , intSize , isCheck , rng );
9099 size *= stepsize ;
91100 if (s == TL ) {
92- IsCheck = true ;
101+ isCheck = true ;
93102 LoopBuilder .setImages (stop .get (1 ), stop .get (2 ), newtau , newsqrtN )
94103 .forEachPixel ((ts1 , ts2 , tTau , tSqrtN ) -> {
95104 ts1 .set (tTau );
96105 ts2 .set (tSqrtN );
97106 });
98107 }
99108 }
109+ // get factory and create imgs
110+ return result ;
100111 }
101112
102- private static <I extends RealType <I >, T extends RealType < T >, O extends RealType < O >>
103- void singleiteration ( final RandomAccessibleInterval <I > image1 ,
104- final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
105- final List <RandomAccessibleInterval <T >> stop ,
106- final RandomAccessibleInterval <T > oldtau ,
107- final RandomAccessibleInterval <T > oldsqrtN ,
108- final RandomAccessibleInterval <T > newtau ,
109- final RandomAccessibleInterval <T > newsqrtN ,
110- final RandomAccessibleInterval <O > result , final double Lambda ,
111- final double Dn , final int Bsize , final boolean isCheck , final Random rng )
113+ private static <I extends RealType <I >> void singleiteration (
114+ final RandomAccessibleInterval <I > image1 ,
115+ final RandomAccessibleInterval <I > image2 , final I thres1 , final I thres2 ,
116+ final List <RandomAccessibleInterval <DoubleType >> stop ,
117+ final RandomAccessibleInterval <DoubleType > oldtau ,
118+ final RandomAccessibleInterval <DoubleType > oldsqrtN ,
119+ final RandomAccessibleInterval <DoubleType > newtau ,
120+ final RandomAccessibleInterval <DoubleType > newsqrtN ,
121+ final RandomAccessibleInterval <DoubleType > result , final double Lambda ,
122+ final double Dn , final int Bsize , final boolean isCheck , final Random rng )
112123 {
113124 final double [][] kernel = kernelGenerate (Bsize );
114125
@@ -127,25 +138,28 @@ void singleiteration(final RandomAccessibleInterval<I> image1,
127138 final double [] w2 = new double [totnum ];
128139 final double [] cumw = new double [totnum ];
129140
130- RandomAccessibleInterval <T > workingImageStack = Views .stack (oldtau , newtau , oldsqrtN , newsqrtN , stop .get (0 ), stop .get (1 ), stop .get (2 ));
131- CompositeIntervalView <T , ? extends GenericComposite <T >> workingImage =
141+ RandomAccessibleInterval <DoubleType > workingImageStack = Views .stack (oldtau ,
142+ newtau , oldsqrtN , newsqrtN , stop .get (0 ), stop .get (1 ), stop .get (2 ));
143+ CompositeIntervalView <DoubleType , ? extends GenericComposite <DoubleType >> workingImage =
132144 Views .collapse (workingImageStack );
133145
134- IntervalView <Localizable > positions = Views .interval ( Localizables .randomAccessible (result .numDimensions () ), result );
146+ IntervalView <Localizable > positions = Views .interval (Localizables
147+ .randomAccessible (result .numDimensions ()), result );
135148 final long nr = result .dimension (1 );
136149 final long nc = result .dimension (0 );
137150 final RandomAccess <I > gdImage1 = image1 .randomAccess ();
138151 final RandomAccess <I > gdImage2 = image2 .randomAccess ();
139- final RandomAccess <T > gdTau = oldtau .randomAccess ();
140- final RandomAccess <T > gdSqrtN = oldsqrtN .randomAccess ();
141- LoopBuilder .setImages (positions , result , workingImage ).forEachPixel ((pos , resPixel , workingPixel ) -> {
142- T oldtauPix = workingPixel .get (0 );
143- T newtauPix = workingPixel .get (1 );
144- T oldsqrtNPix = workingPixel .get (2 );
145- T newsqrtNPix = workingPixel .get (3 );
146- T stop0Pix = workingPixel .get (4 );
147- T stop1Pix = workingPixel .get (5 );
148- T stop2Pix = workingPixel .get (6 );
152+ final RandomAccess <DoubleType > gdTau = oldtau .randomAccess ();
153+ final RandomAccess <DoubleType > gdSqrtN = oldsqrtN .randomAccess ();
154+ LoopBuilder .setImages (positions , result , workingImage ).forEachPixel ((pos ,
155+ resPixel , workingPixel ) -> {
156+ DoubleType oldtauPix = workingPixel .get (0 );
157+ DoubleType newtauPix = workingPixel .get (1 );
158+ DoubleType oldsqrtNPix = workingPixel .get (2 );
159+ DoubleType newsqrtNPix = workingPixel .get (3 );
160+ DoubleType stop0Pix = workingPixel .get (4 );
161+ DoubleType stop1Pix = workingPixel .get (5 );
162+ DoubleType stop2Pix = workingPixel .get (6 );
149163 final long row = pos .getLongPosition (1 );
150164 updateRange (row , Bsize , nr , rowrange );
151165 if (isCheck ) {
@@ -157,15 +171,15 @@ void singleiteration(final RandomAccessibleInterval<I> image1,
157171 updateRange (col , Bsize , nc , colrange );
158172 getData (Dn , kernel , gdImage1 , gdImage2 , gdTau , gdSqrtN , LocX , LocY , LocW ,
159173 rowrange , colrange , totnum );
160- newsqrtNPix .setReal (Math .sqrt (NTau (thres1 , thres2 , LocW , LocX ,
161- LocY )));
174+ newsqrtNPix .setReal (Math .sqrt (NTau (thres1 , thres2 , LocW , LocX , LocY )));
162175 if (newsqrtNPix .getRealDouble () <= 0 ) {
163176 newtauPix .setZero ();
164177 resPixel .setZero ();
165178 }
166179 else {
167- final double tau = WtKendallTau .calculate (LocX , LocY , LocW , combinedData ,
168- rankedindex , rankedw , index1 , index2 , w1 , w2 , cumw , rng );
180+ final double tau = WtKendallTau .calculate (LocX , LocY , LocW ,
181+ combinedData , rankedindex , rankedw , index1 , index2 , w1 , w2 , cumw ,
182+ rng );
169183 newtauPix .setReal (tau );
170184 resPixel .setReal (tau * newsqrtNPix .getRealDouble () * 1.5 );
171185 }
@@ -179,16 +193,15 @@ void singleiteration(final RandomAccessibleInterval<I> image1,
179193 newsqrtNPix .set (oldsqrtNPix );
180194 }
181195 }
182- });
183-
196+ });
197+
184198 // TODO: instead of copying pixels here, swap oldTau and newTau every time.
185199 // :-)
186200 LoopBuilder .setImages (oldtau , newtau , oldsqrtN , newsqrtN ).forEachPixel ((
187201 tOldTau , tNewTau , tOldSqrtN , tNewSqrtN ) -> {
188202 tOldTau .set (tNewTau );
189203 tOldSqrtN .set (tNewSqrtN );
190204 });
191-
192205 }
193206
194207 private static <I extends RealType <I >, T extends RealType <T >> void getData (
0 commit comments