View Javadoc
1   package com.github.celldynamics.quimp.plugin.randomwalk;
2   
3   import java.util.Arrays;
4   
5   import com.github.celldynamics.quimp.geom.TrackOutline;
6   import com.github.celldynamics.quimp.geom.filters.OutlineProcessor;
7   import com.github.celldynamics.quimp.plugin.AbstractPluginOptions;
8   import com.github.celldynamics.quimp.plugin.EscapedPath;
9   import com.github.celldynamics.quimp.plugin.generatemask.GenerateMask_;
10  import com.github.celldynamics.quimp.plugin.randomwalk.BinaryFilters.Filters;
11  import com.github.celldynamics.quimp.plugin.randomwalk.PropagateSeeds.Propagators;
12  
13  import ij.ImagePlus;
14  import ij.WindowManager;
15  import ij.io.Opener;
16  
17  /**
18   * This class holds all possible RW parameters.
19   * 
20   * @author p.baniukiewicz
21   * @see RandomWalkSegmentationPlugin_
22   * @see RandomWalkView
23   * @see RandomWalkOptions
24   */
25  public class RandomWalkModel extends AbstractPluginOptions {
26  
27    /**
28     * Possible sources of seeds.
29     * 
30     * @author p.baniukiewicz
31     *
32     */
33    public enum SeedSource {
34      /**
35       * Seed for IJ RGB image.
36       */
37      RGBImage,
38      /**
39       * Seed form RGB image created from UI.
40       */
41      CreatedImage,
42      /**
43       * Seed form binary mask image.
44       */
45      MaskImage,
46      /**
47       * Seed from binary mask image read from Qconf file.
48       */
49      QconfFile,
50      /**
51       * ROIs.
52       */
53      Rois
54    }
55  
56    /**
57     * Parameters of Random Walk algorithm itself.
58     * 
59     * @see RandomWalkSegmentation
60     */
61    public RandomWalkOptions algOptions;
62  
63    /**
64     * Get shrink methods supported by PropagateSeeds class in form of String[].
65     * 
66     * @return array of filters
67     * @see PropagateSeeds
68     * @see RandomWalkSegmentationPlugin_#runPlugin()
69     */
70    public String[] getShrinkMethods() {
71      return Arrays.stream(Propagators.values()).map(Enum::name).toArray(String[]::new);
72    }
73  
74    /**
75     * Get filtering methods supported by BinaryFilters class in form of String[].
76     * 
77     * @return array of filters
78     * @see BinaryFilters
79     * @see RandomWalkSegmentation#run(Seeds)
80     * @see RandomWalkSegmentation
81     */
82    public String[] getFilteringMethods() {
83      return Arrays.stream(Filters.values()).map(Enum::name).toArray(String[]::new);
84    }
85  
86    /**
87     * Get seed sources defined in {@link SeedSource}.
88     * 
89     * @return array of seed sources
90     * @see SeedSource
91     */
92    public String[] getSeedSources() {
93      return Arrays.stream(SeedSource.values()).map(Enum::name).toArray(String[]::new);
94    }
95  
96    /**
97     * Image to process.
98     */
99    private transient ImagePlus originalImage;
100   /**
101    * Image to process - name or full path. This is required for proper serialisation. Only string is
102    * remembered.
103    * 
104    * @see #getOriginalImage()
105    */
106   @EscapedPath
107   private String originalImageName;
108 
109   /**
110    * Get original image from this object.
111    * 
112    * <p>If not available try to restore from remembered title searched among opened images. If it
113    * fails tries to load from disk.
114    * 
115    * @return the originalImage or null if it can not be obtained
116    */
117   public ImagePlus getOriginalImage() {
118     if (this.originalImage != null) {
119       return originalImage;
120     } else if (WindowManager.getImage(originalImageName) != null) { // try get opened
121       return WindowManager.getImage(originalImageName);
122     } else if (originalImageName != null && !originalImageName.isEmpty()) { // try to load
123       Opener op = new Opener();
124       return op.openImage(originalImageName);
125     } else {
126       return null;
127     }
128   }
129 
130   /**
131    * Set original image and update name field for serialisation.
132    * 
133    * @param originalImage the originalImage to set
134    */
135   public void setOriginalImage(ImagePlus originalImage) {
136     this.originalImage = originalImage;
137     if (originalImage == null) {
138       this.originalImageName = "";
139     } else {
140       this.originalImageName = originalImage.getTitle();
141     }
142   }
143 
144   /**
145    * Selected seed source. Depending on value some of fields may be invalid.
146    */
147   private SeedSource selectedSeedSource;
148 
149   /**
150    * SeedSource getter.
151    * 
152    * @return the seedSource
153    * @see SeedSource
154    */
155   public SeedSource getSelectedSeedSource() {
156     return selectedSeedSource;
157   }
158 
159   /**
160    * SeedSource setter.
161    * 
162    * @param selectedSeedSource the selectedSeedSource to set
163    */
164   public void setSelectedSeedSource(SeedSource selectedSeedSource) {
165     this.selectedSeedSource = selectedSeedSource;
166   }
167 
168   /**
169    * SeedSource setter.
170    * 
171    * @param selectedSeedSource index of SeedSource to set according to order returned by
172    *        {@link #getSeedSources()}
173    */
174   public void setSelectedSeedSource(int selectedSeedSource) {
175     this.selectedSeedSource = SeedSource.valueOf(getSeedSources()[selectedSeedSource]);
176   }
177 
178   /**
179    * Seed given by RGB image selected from IJ. Valid for all seed sources.
180    */
181   private transient ImagePlus seedImage;
182   /**
183    * Seed image - name or path. This is required for proper serialisation.
184    * 
185    * @see #getSeedImage()
186    */
187   @EscapedPath
188   private String seedImageName;
189 
190   /**
191    * Get seed image.
192    * 
193    * <p>It returns image from this object. If it is null it tries to get it from opened images or
194    * finally read from disk.
195    * 
196    * @return the seedImage or null if it can not be obtained
197    */
198   public ImagePlus getSeedImage() {
199     if (this.seedImage != null) {
200       return seedImage;
201     } else if (WindowManager.getImage(seedImageName) != null) {
202       return WindowManager.getImage(seedImageName);
203     } else if (seedImageName != null && !seedImageName.isEmpty()) { // try to load
204       Opener op = new Opener();
205       return op.openImage(seedImageName);
206     } else {
207       return null;
208     }
209   }
210 
211   /**
212    * Set seed image and update name for serialisation.
213    * 
214    * @param seedImage the seedImage to set
215    */
216   public void setSeedImage(ImagePlus seedImage) {
217     this.seedImage = seedImage;
218     if (seedImage == null) {
219       this.seedImageName = "";
220     } else {
221       this.seedImageName = seedImage.getTitle();
222     }
223   }
224 
225   /**
226    * Selected QCONF file. Will fill seedImage.
227    */
228   @EscapedPath
229   private String qconfFile;
230 
231   /**
232    * Get qconffile field.
233    * 
234    * @return the qconfFile
235    */
236   public String getQconfFile() {
237     return qconfFile;
238   }
239 
240   /**
241    * Setter of qconffile filed.
242    * 
243    * <p>Replaces windows paths for Linux. required for proper call of {@link GenerateMask_} from
244    * {@link RandomWalkSegmentationPlugin_#runPlugin()}
245    * 
246    * @param qconfFile the qconfFile to set
247    */
248   public void setQconfFile(String qconfFile) {
249     if (qconfFile != null) {
250       this.qconfFile = qconfFile.replace("\\", "/");
251     } else {
252       this.qconfFile = qconfFile;
253     }
254   }
255 
256   /**
257    * Selected shrink algorithm.
258    * 
259    * @see PropagateSeeds
260    */
261   public Propagators selectedShrinkMethod;
262 
263   /**
264    * Shrink method getter.
265    * 
266    * @return the selectedFilteringMethod number
267    * @see PropagateSeeds#getPropagator(Propagators, boolean, ij.process.AutoThresholder.Method)
268    * @see Propagators
269    */
270   public Propagators getselectedShrinkMethod() {
271     return selectedShrinkMethod;
272   }
273 
274   /**
275    * Seed propagator setter.
276    * 
277    * @param selectedShrinkMethod the selectedFilteringMethod to set
278    */
279   public void setselectedShrinkMethod(Propagators selectedShrinkMethod) {
280     this.selectedShrinkMethod = selectedShrinkMethod;
281   }
282 
283   /**
284    * Seed propagator setter.
285    * 
286    * @param selectedShrinkMethod index of shrink method respecting order returned by
287    *        {@link RandomWalkModel#getShrinkMethods()}
288    */
289   public void setselectedShrinkMethod(int selectedShrinkMethod) {
290     this.selectedShrinkMethod = Propagators.valueOf(getShrinkMethods()[selectedShrinkMethod]);
291   }
292 
293   /**
294    * ShrinkPower parameter.
295    * 
296    * <p>Number of erosions for generating next seed from previous one. Also number of pixels to
297    * shrink contour.
298    */
299   public double shrinkPower;
300   /**
301    * ExpandPower parameter.
302    * 
303    * <p>Number of dilations for generating next seed from previous one. Also number of pixels to
304    * expand contour.
305    */
306   public double expandPower;
307   /**
308    * Scale sigma parameter.
309    * 
310    * <p>Shape of Gaussian curve used to estimate magnitude of scaling related to local curvature.
311    * 
312    * @see PropagateSeeds.Contour#propagateSeed(ij.process.ImageProcessor, ij.process.ImageProcessor,
313    *      double, double)
314    * @see OutlineProcessor#shrinknl(double, double, double, double, double, double, double, double)
315    * @see PropagateSeeds.Contour#scaleSigma
316    */
317   public double scaleSigma = 0.3;
318   /**
319    * Maximal magnitude of scaling for regions with smallest curvature.
320    * 
321    * @see PropagateSeeds.Contour#propagateSeed(ij.process.ImageProcessor,
322    *      ij.process.ImageProcessor,
323    *      double, double)
324    * @see OutlineProcessor#shrinknl(double, double, double, double, double, double, double, double)
325    * @see PropagateSeeds.Contour#scaleMagn
326    */
327   public double scaleMagn = 1.0;
328   /**
329    * If non zero, normals are set to direction of normal of node with smallest curvature (negative).
330    * Work locally within defined range.
331    * 
332    * @see PropagateSeeds.Contour#propagateSeed(ij.process.ImageProcessor, ij.process.ImageProcessor,
333    *      double, double)
334    * @see OutlineProcessor#shrinknl(double, double, double, double, double, double, double, double)
335    * @see PropagateSeeds.Contour#averageNormalsDist
336    */
337   public double scaleEqNormalsDist = 0;
338   /**
339    * Range of averaging of curvature. Roughly equals to number of nodes being averaged. Regardless
340    * this value always at least three nodes are averaged.
341    * 
342    * @see PropagateSeeds.Contour#propagateSeed(ij.process.ImageProcessor, ij.process.ImageProcessor,
343    *      double, double)
344    * @see OutlineProcessor#shrinknl(double, double, double, double, double, double, double, double)
345    * @see PropagateSeeds.Contour#averageCurvDist
346    */
347   public double scaleCurvDistDist = 1.0;
348   /**
349    * Estimate background if true.
350    * 
351    * @see PropagateSeeds#getTrueBackground(ij.process.ImageProcessor, ij.process.ImageProcessor)
352    * @see PropagateSeeds
353    */
354   public boolean estimateBackground;
355   /**
356    * If true add extra filtering during applying {@link Propagators#CONTOUR} shrink method.
357    * 
358    * <p>By default none filtering is applied (use of {@link TrackOutlinNoFilter} object. Otherwise
359    * {@link TrackOutline} is used.
360    * 
361    * @see TrackOutlinNoFilter
362    * @see TrackOutline
363    * @see PropagateSeeds.Contour#useFiltering
364    */
365   public boolean interFrameFilter = false;
366   /**
367    * Selected intermediate filtering algorithm.
368    */
369   private Filters selectedFilteringMethod;
370 
371   /**
372    * Filtering getter.
373    * 
374    * @return the selectedFilteringMethod
375    * @see BinaryFilters#getFilter(Filters)
376    * @see Filters
377    */
378   public Filters getSelectedFilteringMethod() {
379     return selectedFilteringMethod;
380   }
381 
382   /**
383    * Filtering setter. Creates instance of filter.
384    * 
385    * @param selectedFilteringMethod the selectedFilteringMethod to set
386    */
387   public void setSelectedFilteringMethod(Filters selectedFilteringMethod) {
388     this.selectedFilteringMethod = selectedFilteringMethod;
389     algOptions.intermediateFilter = BinaryFilters.getFilter(selectedFilteringMethod);
390   }
391 
392   /**
393    * Post filtering setter. Creates instance of filter.
394    * 
395    * @param selectedFilteringMethod index of filter to set according to order returned by
396    *        {@link #getFilteringMethods()}
397    */
398   public void setSelectedFilteringMethod(int selectedFilteringMethod) {
399     this.selectedFilteringMethod = Filters.valueOf(getFilteringMethods()[selectedFilteringMethod]);
400     algOptions.intermediateFilter = BinaryFilters.getFilter(this.selectedFilteringMethod);
401   }
402 
403   /**
404    * true for HatFilter active.
405    */
406   public boolean hatFilter;
407   /**
408    * alev parameter. Valid for hatFilter==true.
409    */
410   public double alev;
411   /**
412    * num parameter. Valid for hatFilter==true.
413    */
414   public int num;
415   /**
416    * window parameter. Valid for hatFilter==true.
417    */
418   public int window;
419   /**
420    * Selected final binary filtering.
421    */
422   private Filters selectedFilteringPostMethod;
423 
424   /**
425    * Post filtering getter.
426    * 
427    * @return the selectedFilteringPostMethod
428    * @see BinaryFilters#getFilter(Filters)
429    * @see Filters
430    */
431   public Filters getSelectedFilteringPostMethod() {
432     return selectedFilteringPostMethod;
433   }
434 
435   /**
436    * Post filtering setter. Creates instance of filter.
437    * 
438    * @param selectedFilteringPostMethod the selectedFilteringPostMethod to set
439    */
440   public void setSelectedFilteringPostMethod(Filters selectedFilteringPostMethod) {
441     this.selectedFilteringPostMethod = selectedFilteringPostMethod;
442     algOptions.finalFilter = BinaryFilters.getFilter(selectedFilteringPostMethod);
443   }
444 
445   /**
446    * Post filtering setter. Creates instance of filter.
447    * 
448    * @param selectedFilteringPostMethod index of filter to set according to order returned by
449    *        {@link #getFilteringMethods()}
450    */
451   public void setSelectedFilteringPostMethod(int selectedFilteringPostMethod) {
452     this.selectedFilteringPostMethod =
453             Filters.valueOf(getFilteringMethods()[selectedFilteringPostMethod]);
454     algOptions.finalFilter = BinaryFilters.getFilter(this.selectedFilteringPostMethod);
455   }
456 
457   /**
458    * true for showing seeds.
459    */
460   public boolean showSeeds;
461   /**
462    * true for showing preview.
463    */
464   public boolean showPreview;
465   /**
466    * true for showing probability maps.
467    */
468   public boolean showProbMaps;
469 
470   /**
471    * Default constructor setting default parameters.
472    */
473   public RandomWalkModel() {
474     algOptions = new RandomWalkOptions();
475     originalImage = null;
476     setSelectedSeedSource(SeedSource.RGBImage);
477     seedImage = null;
478     qconfFile = null;
479     selectedShrinkMethod = Propagators.NONE;
480     shrinkPower = 10;
481     expandPower = 15;
482     estimateBackground = false;
483     setSelectedFilteringMethod(Filters.NONE);
484     hatFilter = false;
485     alev = 0.9;
486     num = 1;
487     window = 15;
488     setSelectedFilteringPostMethod(Filters.NONE);
489     showSeeds = false;
490     showPreview = false;
491     showProbMaps = false;
492   }
493 
494   /*
495    * (non-Javadoc)
496    * 
497    * @see java.lang.Object#toString()
498    */
499   @Override
500   public String toString() {
501     return "RandomWalkModel [params=" + algOptions + ", originalImage=" + originalImage
502             + ", seedSource=" + getSelectedSeedSource() + ", seedImage=" + seedImage
503             + ", qconfFile=" + qconfFile + ", selectedShrinkMethod=" + selectedShrinkMethod
504             + ", shrinkPower=" + shrinkPower + ", expandPower=" + expandPower
505             + ", estimateBackground=" + estimateBackground + ", interFrameFilter="
506             + interFrameFilter + ", selectedFilteringMethod=" + selectedFilteringMethod
507             + ", hatFilter=" + hatFilter + ", alev=" + alev + ", num=" + num + ", window=" + window
508             + ", selectedFilteringPostMethod=" + selectedFilteringPostMethod + ", showSeeds="
509             + showSeeds + ", showPreview=" + showPreview + ", showPprobMaps=" + showProbMaps
510             + ", getShrinkMethods()=" + Arrays.toString(getShrinkMethods())
511             + ", getFilteringMethods()=" + Arrays.toString(getFilteringMethods())
512             + ", getselectedShrinkMethod()=" + getselectedShrinkMethod()
513             + ", getSelectedFilteringMethod()=" + getSelectedFilteringMethod()
514             + ", getSelectedFilteringPostMethod()=" + getSelectedFilteringPostMethod() + "]";
515   }
516 
517   /*
518    * (non-Javadoc)
519    * 
520    * @see java.lang.Object#hashCode()
521    */
522   @Override
523   public int hashCode() {
524     final int prime = 31;
525     int result = 1;
526     long temp;
527     temp = Double.doubleToLongBits(alev);
528     result = prime * result + (int) (temp ^ (temp >>> 32));
529     temp = Double.doubleToLongBits(expandPower);
530     result = prime * result + (int) (temp ^ (temp >>> 32));
531     result = prime * result + (hatFilter ? 1231 : 1237);
532     result = prime * result + num;
533     result = prime * result + ((originalImage == null) ? 0 : originalImage.getTitle().hashCode());
534     result = prime * result + ((algOptions == null) ? 0 : algOptions.hashCode());
535     result = prime * result + ((qconfFile == null) ? 0 : qconfFile.hashCode());
536     result = prime * result + ((seedImage == null) ? 0 : seedImage.getTitle().hashCode());
537     result = prime * result + ((selectedSeedSource == null) ? 0 : selectedSeedSource.hashCode());
538     result = prime * result
539             + ((selectedFilteringMethod == null) ? 0 : selectedFilteringMethod.hashCode());
540     result = prime * result
541             + ((selectedFilteringPostMethod == null) ? 0 : selectedFilteringPostMethod.hashCode());
542     result = prime * result
543             + ((selectedShrinkMethod == null) ? 0 : selectedShrinkMethod.hashCode());
544     result = prime * result + (showPreview ? 1231 : 1237);
545     result = prime * result + (showSeeds ? 1231 : 1237);
546     result = prime * result + (showProbMaps ? 1231 : 1237);
547     result = prime * result + (estimateBackground ? 1231 : 1237);
548     result = prime * result + (interFrameFilter ? 1231 : 1237);
549     temp = Double.doubleToLongBits(shrinkPower);
550     result = prime * result + (int) (temp ^ (temp >>> 32));
551     result = prime * result + window;
552     return result;
553   }
554 
555   /*
556    * (non-Javadoc)
557    * 
558    * @see java.lang.Object#equals(java.lang.Object)
559    */
560   @Override
561   public boolean equals(Object obj) {
562     if (this == obj) {
563       return true;
564     }
565     if (obj == null) {
566       return false;
567     }
568     if (getClass() != obj.getClass()) {
569       return false;
570     }
571     RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel other = (RandomWalkModel) obj;
572     if (Double.doubleToLongBits(alev) != Double.doubleToLongBits(other.alev)) {
573       return false;
574     }
575     if (Double.doubleToLongBits(expandPower) != Double.doubleToLongBits(other.expandPower)) {
576       return false;
577     }
578     if (hatFilter != other.hatFilter) {
579       return false;
580     }
581     if (num != other.num) {
582       return false;
583     }
584     if (originalImage == null) {
585       if (other.originalImage != null) {
586         return false;
587       }
588     } else if (!originalImage.getTitle().equals(other.originalImage.getTitle())) {
589       return false;
590     }
591     if (algOptions == null) {
592       if (other.algOptions != null) {
593         return false;
594       }
595     } else if (!algOptions.equals(other.algOptions)) {
596       return false;
597     }
598     if (qconfFile == null) {
599       if (other.qconfFile != null) {
600         return false;
601       }
602     } else if (!qconfFile.equals(other.qconfFile)) {
603       return false;
604     }
605     if (seedImage == null) {
606       if (other.seedImage != null) {
607         return false;
608       }
609     } else if (!seedImage.getTitle().equals(other.seedImage.getTitle())) {
610       return false;
611     }
612     if (selectedSeedSource != other.selectedSeedSource) {
613       return false;
614     }
615     if (selectedFilteringMethod != other.selectedFilteringMethod) {
616       return false;
617     }
618     if (selectedFilteringPostMethod != other.selectedFilteringPostMethod) {
619       return false;
620     }
621     if (selectedShrinkMethod != other.selectedShrinkMethod) {
622       return false;
623     }
624     if (showPreview != other.showPreview) {
625       return false;
626     }
627     if (showSeeds != other.showSeeds) {
628       return false;
629     }
630     if (showProbMaps != other.showProbMaps) {
631       return false;
632     }
633     if (estimateBackground != other.estimateBackground) {
634       return false;
635     }
636     if (interFrameFilter != other.interFrameFilter) {
637       return false;
638     }
639     if (Double.doubleToLongBits(shrinkPower) != Double.doubleToLongBits(other.shrinkPower)) {
640       return false;
641     }
642     if (window != other.window) {
643       return false;
644     }
645     return true;
646   }
647 
648   /*
649    * (non-Javadoc)
650    * 
651    * @see com.github.celldynamics.quimp.plugin.AbstractPluginOptions#afterSerialize()
652    */
653   @Override
654   public void afterSerialize() throws Exception {
655     setSelectedFilteringPostMethod(selectedFilteringPostMethod);
656     setSelectedFilteringMethod(selectedFilteringMethod);
657   }
658 
659 }