1 package com.github.celldynamics.quimp.plugin.randomwalk;
2
3 import java.awt.Color;
4 import java.awt.FileDialog;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.WindowEvent;
8 import java.awt.event.WindowFocusListener;
9 import java.net.URI;
10 import java.nio.file.Paths;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15
16 import javax.swing.JOptionPane;
17 import javax.swing.SwingWorker;
18
19 import org.scijava.vecmath.Point2d;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import com.github.celldynamics.quimp.BoaException;
24 import com.github.celldynamics.quimp.PropertyReader;
25 import com.github.celldynamics.quimp.QuimpException.MessageSinkTypes;
26 import com.github.celldynamics.quimp.geom.SegmentedShapeRoi;
27 import com.github.celldynamics.quimp.geom.filters.HatSnakeFilter;
28 import com.github.celldynamics.quimp.plugin.AbstractOptionsParser;
29 import com.github.celldynamics.quimp.plugin.AbstractPluginOptions;
30 import com.github.celldynamics.quimp.plugin.AbstractPluginTemplate;
31 import com.github.celldynamics.quimp.plugin.QuimpPluginException;
32 import com.github.celldynamics.quimp.plugin.binaryseg.BinarySegmentation;
33 import com.github.celldynamics.quimp.plugin.generatemask.GenerateMask_;
34 import com.github.celldynamics.quimp.plugin.randomwalk.RandomWalkModel.SeedSource;
35 import com.github.celldynamics.quimp.plugin.randomwalk.RandomWalkSegmentation.SeedTypes;
36 import com.github.celldynamics.quimp.plugin.utils.QuimpDataConverter;
37 import com.github.celldynamics.quimp.utils.QuimpToolsCollection;
38
39 import ch.qos.logback.core.status.OnConsoleStatusListener;
40 import ij.IJ;
41 import ij.ImagePlus;
42 import ij.ImageStack;
43 import ij.WindowManager;
44 import ij.gui.Roi;
45 import ij.io.OpenDialog;
46 import ij.plugin.ContrastEnhancer;
47 import ij.plugin.Converter;
48 import ij.plugin.tool.BrushTool;
49 import ij.process.AutoThresholder;
50 import ij.process.ByteProcessor;
51 import ij.process.ImageProcessor;
52 import ij.process.StackStatistics;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 public class RandomWalkSegmentationPlugin_ extends AbstractPluginTemplate {
99
100
101 private static String thisPluginName = "RandomWalk";
102
103
104
105
106 static final Logger LOGGER =
107 LoggerFactory.getLogger(RandomWalkSegmentationPlugin_.class.getName());
108
109
110 RandomWalkView view;
111
112
113 private SeedPicker seedPickerWnd = null;
114
115
116 private BrushTool br = new BrushTool();
117
118
119 private String lastTool;
120
121
122 private boolean isCanceled;
123
124
125 private boolean isRun;
126
127
128 private boolean oneSlice = false;
129
130
131 private int startSlice = 1;
132
133
134
135 private ImagePlus segmented = null;
136
137
138
139
140 public RandomWalkSegmentationPlugin_() {
141 super(new RandomWalkModel(), thisPluginName);
142 if (IJ.getInstance() != null) {
143 lastTool = IJ.getToolName();
144 }
145 isCanceled = false;
146 isRun = false;
147 view = new RandomWalkView();
148 seedPickerWnd = new SeedPicker(false);
149 writeUI();
150 view.addWindowController(new ActivateWindowController());
151 view.addImageController(new ImageController());
152 view.addSeedController(new SeedController());
153 view.addRunController(new RunBtnController());
154 view.addCancelController(new CancelBtnController());
155 view.addBgController(new BgController());
156 view.addFgController(new FgController());
157 view.addCloneController(new CloneController());
158 view.addLoadQconfController(new LoadQconfController());
159 view.addQconfShowSeedImageController(new QconfShowSeedImageController());
160 view.addRunActiveController(new RunActiveBtnController());
161 view.addHelpController(new HelpBtnController());
162 view.addSeedRoiController(new SeedRoiController());
163 seedPickerWnd.addFinishController(new FinishControllerSeedPicker());
164 }
165
166
167
168
169
170
171
172 public RandomWalkSegmentationPlugin_(String paramString) throws QuimpPluginException {
173 super(paramString, new RandomWalkModel(), thisPluginName);
174 view = new RandomWalkView();
175 writeUI();
176 }
177
178
179
180
181
182
183
184
185
186 public RandomWalkSegmentationPlugin_(AbstractPluginOptions options) {
187 super(options, thisPluginName);
188 apiCall = true;
189 errorSink = MessageSinkTypes.CONSOLE;
190 view = new RandomWalkView();
191 writeUI();
192 }
193
194
195
196
197 public void writeUI() {
198 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
199 if (model.getOriginalImage() != null) {
200 view.setCbOrginalImage(new String[] { model.getOriginalImage().getTitle() }, "");
201 }
202
203 view.setSeedSource(model.getSeedSources(), model.getSelectedSeedSource().name());
204 if (model.getSeedImage() != null) {
205 view.setCbRgbSeedImage(new String[] { model.getSeedImage().getTitle() }, "");
206 view.setCbCreatedSeedImage(new String[] { model.getSeedImage().getTitle() }, "");
207 view.setCbMaskSeedImage(new String[] { model.getSeedImage().getTitle() }, "");
208 }
209
210 view.setSrAlpha(model.algOptions.alpha);
211 view.setSrBeta(model.algOptions.beta);
212 view.setSrGamma0(model.algOptions.gamma[0]);
213 view.setSrGamma1(model.algOptions.gamma[1]);
214 view.setSrIter(model.algOptions.iter);
215 view.setSrRelerr(model.algOptions.relim[0]);
216
217 view.setShrinkMethod(model.getShrinkMethods(), model.getselectedShrinkMethod().name());
218 view.setSrShrinkPower(model.shrinkPower);
219 view.setSrExpandPower(model.expandPower);
220 view.setSrScaleSigma(model.scaleSigma);
221 view.setSrScaleMagn(model.scaleMagn);
222 view.setSrScaleCurvDistDist(model.scaleCurvDistDist);
223 view.setSrScaleEqNormalsDist(model.scaleEqNormalsDist);
224 view.setFilteringMethod(model.getFilteringMethods(), model.getSelectedFilteringMethod().name());
225 view.setChLocalMean(model.algOptions.useLocalMean);
226 view.setSrLocalMeanWindow(model.algOptions.localMeanMaskSize);
227 view.setChTrueBackground(model.estimateBackground);
228 view.setChInterFrameFilter(model.interFrameFilter);
229
230 view.setChHatFilter(model.hatFilter);
231 view.setSrAlev(model.alev);
232 view.setSrNum(model.num);
233 view.setSrWindow(model.window);
234 view.setFilteringPostMethod(model.getFilteringMethods(),
235 model.getSelectedFilteringPostMethod().name());
236 view.setChMaskCut(model.algOptions.maskLimit);
237
238 view.setChShowSeed(model.showPreview);
239 view.setChShowPreview(model.showPreview);
240 view.setChShowProbMaps(model.showProbMaps);
241
242 }
243
244
245
246
247
248
249 public RandomWalkModel readUI() {
250 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
251 model.setOriginalImage(WindowManager.getImage(view.getCbOrginalImage()));
252 model.setSelectedSeedSource(view.getSeedSource());
253 switch (model.getSelectedSeedSource()) {
254 case RGBImage:
255 model.setSeedImage(WindowManager.getImage(view.getCbRgbSeedImage()));
256 break;
257 case CreatedImage:
258 model.setSeedImage(WindowManager.getImage(view.getCbCreatedSeedImage()));
259 break;
260 case MaskImage:
261 model.setSeedImage(WindowManager.getImage(view.getCbMaskSeedImage()));
262 break;
263 case QconfFile:
264 break;
265 case Rois:
266 break;
267 default:
268 throw new IllegalArgumentException("Unknown seed source");
269 }
270
271 model.algOptions.alpha = view.getSrAlpha();
272 model.algOptions.beta = view.getSrBeta();
273 model.algOptions.gamma[0] = view.getSrGamma0();
274 model.algOptions.gamma[1] = view.getSrGamma1();
275 model.algOptions.iter = view.getSrIter();
276 model.algOptions.relim[0] = view.getSrRelerr();
277 model.algOptions.relim[1] = model.algOptions.relim[0] * 10;
278
279 model.setselectedShrinkMethod(view.getShrinkMethod());
280 model.shrinkPower = view.getSrShrinkPower();
281 model.expandPower = view.getSrExpandPower();
282 model.scaleSigma = view.getSrScaleSigma();
283 model.scaleMagn = view.getSrScaleMagn();
284 model.scaleCurvDistDist = view.getSrScaleCurvDistDist();
285 model.scaleEqNormalsDist = view.getSrScaleEqNormalsDist();
286 model.setSelectedFilteringMethod(view.getFilteringMethod());
287 model.algOptions.useLocalMean = view.getChLocalMean();
288 model.algOptions.localMeanMaskSize = view.getSrLocalMeanWindow();
289 model.estimateBackground = view.getChTrueBackground();
290
291 model.hatFilter = view.getChHatFilter();
292 model.alev = view.getSrAlev();
293 model.num = view.getSrNum();
294 model.window = view.getSrWindow();
295 model.setSelectedFilteringPostMethod(view.getFilteringPostMethod());
296 model.algOptions.maskLimit = view.getChMaskCut();
297
298 model.showSeeds = view.getChShowSeed();
299 model.showPreview = view.getChShowPreview();
300 model.showProbMaps = view.getChShowProbMaps();
301
302 return model;
303 }
304
305
306
307
308
309
310
311
312
313
314 public void showUi(boolean val) {
315 view.show();
316 }
317
318
319
320
321
322
323
324
325
326 class FinishControllerSeedPicker implements ActionListener {
327
328
329
330
331
332
333 @Override
334 public void actionPerformed(ActionEvent e) {
335 if (seedPickerWnd == null) {
336 return;
337 }
338 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
339 model.getOriginalImage().deleteRoi();
340 List<Seeds> rois = seedPickerWnd.seedsRoi;
341 if (rois != null) {
342 String fgsize;
343 String bgsize;
344 if (rois.get(0).get(SeedTypes.FOREGROUNDS) == null) {
345 fgsize = "<no FG>";
346 } else {
347 fgsize = "" + rois.get(0).get(SeedTypes.FOREGROUNDS).size();
348 }
349 if (rois.get(0).get(SeedTypes.BACKGROUND) == null) {
350 bgsize = "<no BG>";
351 } else {
352 bgsize = "" + rois.get(0).get(SeedTypes.BACKGROUND).size();
353 }
354 view.setLroiSeedsInfo("Objects: " + fgsize + " FG and " + bgsize + " BG");
355 }
356 }
357
358 }
359
360
361
362
363
364
365
366 class ActivateWindowController implements WindowFocusListener {
367
368
369
370
371
372
373 @Override
374 public void windowGainedFocus(WindowEvent e) {
375 action();
376 }
377
378
379
380
381
382
383 @Override
384 public void windowLostFocus(WindowEvent e) {
385 action();
386 }
387
388
389
390
391 private void action() {
392 if (isRun == true) {
393 return;
394 }
395 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
396
397 String[] images = WindowManager.getImageTitles();
398 String selection = "";
399
400 if (model.getOriginalImage() != null) {
401 selection = model.getOriginalImage().getTitle();
402 }
403
404 view.setCbOrginalImage(images, selection);
405 selection = "";
406
407 if (model.getSeedImage() != null) {
408 selection = model.getSeedImage().getTitle();
409 }
410
411 view.setCbCreatedSeedImage(images, selection);
412 view.setCbRgbSeedImage(images, selection);
413 view.setCbMaskSeedImage(images, selection);
414
415 }
416 }
417
418
419
420
421
422
423
424
425
426
427 class ImageController implements ActionListener {
428
429
430
431
432
433
434 @Override
435 public void actionPerformed(ActionEvent e) {
436 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
437 model.setOriginalImage(WindowManager.getImage(view.getCbOrginalImage()));
438 }
439 }
440
441
442
443
444
445
446
447
448
449
450 class SeedController implements ActionListener {
451
452
453
454
455
456
457 @Override
458 public void actionPerformed(ActionEvent e) {
459 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
460 SeedSource src = SeedSource.valueOf(model.getSeedSources()[view.getSeedSource()]);
461 switch (src) {
462 case RGBImage:
463 model.setSeedImage(WindowManager.getImage(view.getCbRgbSeedImage()));
464 break;
465 case MaskImage:
466 model.setSeedImage(WindowManager.getImage(view.getCbMaskSeedImage()));
467 break;
468 case CreatedImage:
469 model.setSeedImage(WindowManager.getImage(view.getCbCreatedSeedImage()));
470 break;
471 case QconfFile:
472 break;
473 case Rois:
474 break;
475 default:
476 throw new IllegalArgumentException("Unknown seed source");
477 }
478 }
479 }
480
481
482
483
484
485
486
487
488
489 class RunBtnController implements ActionListener {
490
491
492
493
494
495
496 @Override
497 public void actionPerformed(ActionEvent e) {
498 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
499 startSlice = 1;
500 oneSlice = false;
501 readUI();
502 RWWorker rww = new RWWorker();
503 rww.execute();
504 LOGGER.trace("model: " + model.toString());
505 }
506 }
507
508
509
510
511
512
513
514
515
516 class HelpBtnController implements ActionListener {
517
518
519
520
521
522
523 @Override
524 public void actionPerformed(ActionEvent e) {
525 String url = new PropertyReader().readProperty("quimpconfig.properties", "manualURL");
526 try {
527 java.awt.Desktop.getDesktop().browse(new URI(url));
528 } catch (Exception e1) {
529 LOGGER.error("Could not open help: " + e1.getMessage(), e1);
530 }
531 }
532 }
533
534
535
536
537
538
539
540
541
542 class RunActiveBtnController implements ActionListener {
543
544
545
546
547
548
549 @Override
550 public void actionPerformed(ActionEvent e) {
551 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
552 ImagePlus orgImg = model.getOriginalImage();
553 if (orgImg == null) {
554 return;
555 }
556 readUI();
557 startSlice = orgImg.getCurrentSlice();
558 oneSlice = true;
559 RWWorker rww = new RWWorker();
560 rww.execute();
561 LOGGER.trace("model: " + model.toString());
562
563 }
564 }
565
566
567
568
569
570
571
572 public class CancelBtnController implements ActionListener {
573
574
575
576
577
578
579 @Override
580 public void actionPerformed(ActionEvent arg0) {
581 isCanceled = true;
582 if (isRun == false) {
583 view.getWnd().dispose();
584 }
585
586 }
587 }
588
589
590
591
592
593
594
595 public class CloneController implements ActionListener {
596
597
598
599
600
601
602 @Override
603 public void actionPerformed(ActionEvent arg0) {
604 ImagePlus tmpImage = WindowManager.getImage(view.getCbOrginalImage());
605 if (tmpImage == null) {
606 return;
607 }
608 ImagePlus duplicatedImage;
609 Object[] options = { "Whole stack", "Current slice", "Cancel" };
610 int ret = JOptionPane.showOptionDialog(view.getWnd(),
611 QuimpToolsCollection
612 .stringWrap("Do you want to duplicte the whole stack or only current slice?"),
613 "Duplicate stack", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
614 null, options, null);
615 switch (ret) {
616 case 0:
617 duplicatedImage = tmpImage.duplicate();
618 break;
619 case 1:
620 duplicatedImage = new ImagePlus("",
621 tmpImage.getStack().getProcessor(tmpImage.getCurrentSlice()).duplicate());
622 break;
623 case 2:
624 default:
625 return;
626 }
627 duplicatedImage.show();
628 new Converter().run("RGB Color");
629 duplicatedImage.setTitle("SEED_" + tmpImage.getTitle());
630 view.setCbCreatedSeedImage(WindowManager.getImageTitles(), duplicatedImage.getTitle());
631 }
632 }
633
634
635
636
637
638
639
640 public class SeedRoiController implements ActionListener {
641
642
643
644
645
646
647 @Override
648 public void actionPerformed(ActionEvent e) {
649 ImagePlus tmpImage = WindowManager.getCurrentImage();
650 if (tmpImage == null) {
651 return;
652 }
653 if (seedPickerWnd != null) {
654 seedPickerWnd.image = tmpImage;
655 seedPickerWnd.reset();
656 seedPickerWnd.setVisible(true);
657 }
658 }
659
660 }
661
662
663
664
665
666
667
668 private ImagePlus cloneImageAndAsk(ImagePlus tmpImage) {
669 Object[] options = { "Whole stack", "Current slice", "Cancel" };
670 int ret = JOptionPane.showOptionDialog(view.getWnd(),
671 QuimpToolsCollection
672 .stringWrap("Do you want to duplicte the whole stack or only current slice?"),
673 "Duplicate stack", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
674 options, null);
675 ImagePlus duplicatedImage;
676 switch (ret) {
677 case 0:
678 duplicatedImage = tmpImage.duplicate();
679 break;
680 case 1:
681 duplicatedImage = new ImagePlus("",
682 tmpImage.getStack().getProcessor(tmpImage.getCurrentSlice()).duplicate());
683 break;
684 case 2:
685 default:
686 return null;
687 }
688 return duplicatedImage;
689 }
690
691
692
693
694
695
696
697 public class FgController implements ActionListener {
698
699
700
701
702
703
704 @Override
705 public void actionPerformed(ActionEvent arg0) {
706 if (view.getBnFore().isSelected()) {
707 IJ.setForegroundColor(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue());
708 BrushTool.setBrushWidth(10);
709 br.run("");
710 } else {
711 IJ.setTool(lastTool);
712 }
713 }
714 }
715
716
717
718
719
720
721
722 public class BgController implements ActionListener {
723
724
725
726
727
728
729 @Override
730 public void actionPerformed(ActionEvent arg0) {
731 if (view.getBnBack().isSelected()) {
732 IJ.setForegroundColor(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue());
733 BrushTool.setBrushWidth(10);
734 br.run("");
735 } else {
736 IJ.setTool(lastTool);
737 }
738 }
739 }
740
741
742
743
744
745
746
747 public class LoadQconfController implements ActionListener {
748
749
750
751
752
753
754 @Override
755 public void actionPerformed(ActionEvent arg0) {
756 FileDialog od = new FileDialog(IJ.getInstance(), "Open Qconf file");
757 od.setFile("*.QCONF");
758 od.setDirectory(OpenDialog.getLastDirectory());
759 od.setMultipleMode(false);
760 od.setMode(FileDialog.LOAD);
761 od.setVisible(true);
762 if (od.getFile() == null) {
763 IJ.log("Cancelled - exiting...");
764 return;
765 }
766 String directory = od.getDirectory();
767 String filename = od.getFile();
768 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
769 model.setQconfFile(Paths.get(directory, filename).toString());
770 view.setLqconfFile(filename);
771 }
772 }
773
774
775
776
777
778
779
780 public class QconfShowSeedImageController implements ActionListener {
781
782
783
784
785
786
787 @Override
788 public void actionPerformed(ActionEvent arg0) {
789 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
790 if (model.getQconfFile() == null || model.getQconfFile().isEmpty()
791 || Paths.get(model.getQconfFile()).getFileName() == null) {
792 return;
793 }
794 try {
795 ImagePlus seedImage;
796
797 seedImage =
798 new GenerateMask_("opts={paramFile:(" + model.getQconfFile() + "),binary:false}")
799 .getRes();
800 seedImage.setTitle(
801 "Mask-" + Paths.get(model.getQconfFile()).getFileName().toString() + ".tif");
802 new ContrastEnhancer().stretchHistogram(seedImage, 0.35);
803 seedImage.show();
804 } catch (QuimpPluginException e) {
805 LOGGER.debug("Can not load QCONF");
806 }
807
808 }
809
810 }
811
812
813
814
815
816
817 @Override
818 public void run(String arg) {
819 super.run(arg);
820 }
821
822
823
824
825
826
827
828
829
830
831
832 @Override
833 public void runPlugin() {
834 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
835 ImagePlus prev = null;
836
837
838 boolean useSeedStack;
839 isCanceled = false;
840 Color foreColor;
841 Color backColor;
842 boolean localMeanUserStatus = model.algOptions.useLocalMean;
843 ImageStack ret;
844 ImageStack is = null;
845 Seeds seeds;
846 PropagateSeeds propagateSeeds;
847 isRun = true;
848
849 if (model.showPreview) {
850 prev = new ImagePlus();
851 }
852 AutoThresholder.Method thresholdBackground = null;
853 if (model.estimateBackground == true) {
854 thresholdBackground = AutoThresholder.Method.Otsu;
855 }
856 try {
857 ImagePlus image = model.getOriginalImage();
858 ImagePlus seedImage;
859
860 if (model.getSelectedSeedSource() == SeedSource.Rois) {
861 seedImage = seedPickerWnd.image;
862 } else {
863 seedImage = model.getSeedImage();
864 }
865 if (image == null || seedImage == null) {
866 throw new QuimpPluginException("Input image or seed image can not be opened.");
867 }
868 is = image.getStack();
869 if (seedImage.getStackSize() == 1) {
870 useSeedStack = false;
871 } else if (seedImage.getStackSize() == image.getStackSize()) {
872 useSeedStack = true;
873 } else {
874 throw new RandomWalkException("Seed stack and image stack must have the same z dimension");
875 }
876
877 propagateSeeds = PropagateSeeds.getPropagator(model.selectedShrinkMethod, model.showSeeds,
878 thresholdBackground);
879 if (propagateSeeds instanceof PropagateSeeds.Contour) {
880 ((PropagateSeeds.Contour) propagateSeeds).scaleMagn = model.scaleMagn;
881 ((PropagateSeeds.Contour) propagateSeeds).scaleSigma = model.scaleSigma;
882 ((PropagateSeeds.Contour) propagateSeeds).averageNormalsDist = model.scaleEqNormalsDist;
883 ((PropagateSeeds.Contour) propagateSeeds).averageCurvDist = model.scaleCurvDistDist;
884 ((PropagateSeeds.Contour) propagateSeeds).useFiltering = model.interFrameFilter;
885 }
886
887 ret = new ImageStack(image.getWidth(), image.getHeight());
888
889 RandomWalkSegmentation obj =
890 new RandomWalkSegmentation(is.getProcessor(startSlice), model.algOptions);
891
892 switch (model.getSelectedSeedSource()) {
893 case RGBImage:
894 case CreatedImage:
895 foreColor = Color.RED;
896 backColor = Color.GREEN;
897 if (seedImage != null && seedImage.equals(image)) {
898 throw new RandomWalkException("Seed image and segmented image are the same.");
899 }
900 if (seedImage.getNSlices() >= startSlice) {
901 seeds = SeedProcessor.decodeSeedsfromRgb(seedImage.getStack().getProcessor(startSlice),
902 Arrays.asList(foreColor), backColor);
903 } else {
904 seeds = SeedProcessor.decodeSeedsfromRgb(seedImage.getStack().getProcessor(1),
905 Arrays.asList(foreColor), backColor);
906 }
907 if (model.algOptions.useLocalMean) {
908 LOGGER.warn("LocalMean is not used for first frame when seed is RGB image");
909 }
910 model.algOptions.useLocalMean = false;
911 break;
912 case Rois:
913 if (seedPickerWnd.seedsRoi.isEmpty()) {
914 throw new RandomWalkException("No ROIs processed, did you forget to click Finish?");
915 }
916 seeds = seedPickerWnd.seedsRoi.get(0);
917 if (model.algOptions.useLocalMean) {
918 LOGGER.warn("LocalMean is not used for first frame when seeds are ROIs.");
919 }
920 model.algOptions.useLocalMean = false;
921 break;
922 case QconfFile:
923 seedImage =
924 new GenerateMask_("opts={paramFile:(" + model.getQconfFile() + "),binary:false}")
925 .getRes();
926
927 case MaskImage:
928 if (seedImage != null && seedImage.equals(image)) {
929 throw new RandomWalkException("Seed image and segmented image are the same.");
930 }
931 double max = new StackStatistics(seedImage).max;
932 if (max > 255) {
933 LOGGER.warn("There are more than 255 objects in loaded QCONF file. Only first"
934 + " 255 will be segmented");
935 }
936
937
938
939 seeds = propagateSeeds.propagateSeed(
940 seedImage.getStack().getProcessor(startSlice).duplicate().convertToByte(false),
941 is.getProcessor(startSlice), model.shrinkPower, model.expandPower);
942
943 seeds.put(SeedTypes.ROUGHMASK,
944 seedImage.getStack().getProcessor(startSlice).duplicate().convertToByte(false));
945 seeds.get(SeedTypes.ROUGHMASK, 1).threshold(0);
946 break;
947 default:
948 throw new IllegalArgumentException("Unsupported seed source");
949 }
950
951 ImageProcessor retIp = obj.run(seeds);
952 if (retIp == null) {
953 LOGGER.error("Segmentation failed - no Foreground maps provided");
954 retIp = new ByteProcessor(image.getWidth(), image.getHeight());
955 }
956 model.algOptions.useLocalMean = localMeanUserStatus;
957 if (model.hatFilter) {
958 retIp = applyHatSnakeFilter(retIp, is.getProcessor(startSlice));
959 }
960 ret.addSlice(retIp.convertToByte(true));
961 if (model.showPreview) {
962 prev.setProcessor(retIp);
963 prev.setTitle("Previev - frame: " + 1);
964 prev.show();
965 prev.updateAndDraw();
966 }
967
968 for (int s = 2; s <= is.getSize() && isCanceled == false && oneSlice == false; s++) {
969 LOGGER.info("----- Slice " + s + " -----");
970 Seeds/quimp/plugin/randomwalk/Seeds.html#Seeds">Seeds nextseed = new Seeds();
971 obj = new RandomWalkSegmentation(is.getProcessor(s), model.algOptions);
972
973 if (useSeedStack) {
974 switch (model.getSelectedSeedSource()) {
975 case RGBImage:
976 case Rois:
977
978 throw new RandomWalkException(
979 "This combination is not supported - for ROI seeds should be selected in "
980 + "single image, " + "not a stack");
981 case QconfFile:
982 case MaskImage:
983
984
985 nextseed = propagateSeeds.propagateSeed(
986 seedImage.getStack().getProcessor(s).duplicate().convertToByte(false),
987 is.getProcessor(s), model.shrinkPower, model.expandPower);
988 nextseed.put(SeedTypes.ROUGHMASK,
989 seedImage.getStack().getProcessor(s).duplicate().convertToByte(false));
990 nextseed.get(SeedTypes.ROUGHMASK, 1).threshold(0);
991 break;
992 default:
993 }
994 } else {
995
996
997
998 nextseed = propagateSeeds.propagateSeed(retIp, is.getProcessor(s), model.shrinkPower,
999 model.expandPower);
1000 nextseed.put(SeedTypes.ROUGHMASK, retIp.duplicate());
1001 nextseed.get(SeedTypes.ROUGHMASK, 1).threshold(0);
1002 }
1003
1004 retIp = obj.run(nextseed);
1005 if (retIp == null) {
1006 LOGGER.error("Segmentation failed - no Foreground maps provided");
1007 retIp = new ByteProcessor(image.getWidth(), image.getHeight());
1008 }
1009 if (model.hatFilter) {
1010 retIp = applyHatSnakeFilter(retIp, is.getProcessor(s));
1011 }
1012 ret.addSlice(retIp);
1013 if (model.showPreview) {
1014 prev.setProcessor(retIp);
1015 prev.setTitle("Previev - frame: " + s);
1016 prev.setActivated();
1017 prev.updateAndDraw();
1018 }
1019 IJ.showProgress(s - 1, is.getSize());
1020 }
1021
1022 segmented = new ImagePlus("Segmented_" + image.getTitle(), ret);
1023 if (!apiCall) {
1024 segmented.show();
1025 segmented.updateAndDraw();
1026 }
1027
1028 if (model.showProbMaps == true) {
1029 ProbabilityMaps pm = obj.getProbabilityMaps();
1030 if (pm != null) {
1031 ImageStack pmstackfg = pm.convertToImageStack(SeedTypes.FOREGROUNDS);
1032 if (pmstackfg == null) {
1033 logger.warn("showProbMaps is selected but segmentation returned empty FG maps.");
1034 } else {
1035 ImageStack pmstackbg = pm.convertToImageStack(SeedTypes.BACKGROUND);
1036
1037 if (pmstackbg != null) {
1038 for (int s = 1; s <= pmstackbg.size(); s++) {
1039 pmstackfg.addSlice(pmstackbg.getProcessor(s));
1040 }
1041 }
1042 new ImagePlus("Last Probability maps", pmstackfg).show();
1043 }
1044 }
1045 }
1046
1047 if (model.showSeeds) {
1048 if (useSeedStack == true) {
1049 switch (model.getSelectedSeedSource()) {
1050 case QconfFile:
1051 case MaskImage:
1052 if (oneSlice) {
1053 propagateSeeds.getCompositeSeed(image.duplicate(), startSlice).show();
1054 } else {
1055 propagateSeeds.getCompositeSeed(image.duplicate(), 0).show();
1056 }
1057 break;
1058 default:
1059 LOGGER.warn("Effective seeds are not displayed if"
1060 + " initial seeds are provided as stack");
1061 }
1062 } else {
1063 propagateSeeds.getCompositeSeed(image.duplicate(), 0).show();
1064 }
1065 }
1066 } catch (QuimpPluginException rwe) {
1067
1068 rwe.setMessageSinkType(errorSink);
1069
1070 rwe.handleException(view.getWnd(), "Segmentation problem.");
1071 } catch (Exception e) {
1072 LOGGER.debug(e.getMessage(), e);
1073 IJ.error("Random Walk Segmentation error",
1074 e.getClass().getSimpleName() + ": " + e.getMessage());
1075 } finally {
1076 isRun = false;
1077 IJ.showProgress(2, 1);
1078 if (prev != null) {
1079 prev.close();
1080 }
1081 model.algOptions.useLocalMean = localMeanUserStatus;
1082 }
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092 public ImagePlus getResult() {
1093 return segmented;
1094 }
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104 private ImageProcessor applyHatSnakeFilter(ImageProcessor retIp, ImageProcessor orIp)
1105 throws QuimpPluginException {
1106 RandomWalkModel/../../../com/github/celldynamics/quimp/plugin/randomwalk/RandomWalkModel.html#RandomWalkModel">RandomWalkModel model = (RandomWalkModel) options;
1107 BinarySegmentationlugin/binaryseg/BinarySegmentation.html#BinarySegmentation">BinarySegmentation obj = new BinarySegmentation(new ImagePlus("", retIp));
1108 obj.trackObjects();
1109 ArrayList<ArrayList<SegmentedShapeRoi>> ret = obj.getChains();
1110 for (ArrayList<SegmentedShapeRoi> asS : ret) {
1111 for (SegmentedShapeRoi ss : asS) {
1112 ss.setInterpolationParameters(1, false);
1113 }
1114 }
1115 SegmentedShapeRoi ssR = ret.get(0).get(0);
1116 HatSnakeFiltermp/geom/filters/HatSnakeFilter.html#HatSnakeFilter">HatSnakeFilter hsf = new HatSnakeFilter(model.window, model.num, model.alev);
1117 hsf.setMode(HatSnakeFilter.CAVITIES);
1118
1119 List<Point2d> retf = hsf.runPlugin(ssR.getOutlineasRawPoints(), orIp);
1120 Roi ssRF;
1121 try {
1122 ssRF = new QuimpDataConverter(retf).getSnake(0).asFloatRoi();
1123 } catch (BoaException e) {
1124 e.setMessageSinkType(MessageSinkTypes.IJERROR);
1125 e.handleException(null, "HatSnake Filter failed");
1126 return retIp;
1127 }
1128 ImageProcessor retIptmp = new ByteProcessor(orIp.getWidth(), orIp.getHeight());
1129 retIptmp.setColor(Color.WHITE);
1130 retIptmp.fill(ssRF);
1131 return retIptmp;
1132 }
1133
1134
1135
1136
1137
1138
1139 @Override
1140 public String about() {
1141 return "Random Walk plugin.\n" + "Author: Piotr Baniukiewicz\n"
1142 + "mail: p.baniukiewicz@warwick.ac.uk\n"
1143 + "This plugin does support macro parameters\n";
1144 }
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154 class RWWorker extends SwingWorker<Object, Object> {
1155
1156
1157
1158
1159
1160
1161 @Override
1162 protected Object doInBackground() throws Exception {
1163 view.setCancelLabel("STOP");
1164 view.enableUI(false);
1165 runPlugin();
1166 view.enableUI(true);
1167 view.setCancelLabel("Cancel");
1168 return true;
1169 }
1170
1171
1172
1173
1174
1175
1176 @Override
1177 protected void done() {
1178 try {
1179 get();
1180 } catch (ExecutionException e) {
1181 LOGGER.error(e.getMessage());
1182 } catch (InterruptedException e) {
1183 e.printStackTrace();
1184 } finally {
1185 view.enableUI(true);
1186 view.setCancelLabel("Cancel");
1187 }
1188 }
1189 }
1190
1191 }