1 package com.github.celldynamics.quimp;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Collections;
7
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10
11 import com.github.celldynamics.quimp.filesystem.FileExtensions;
12 import com.github.celldynamics.quimp.filesystem.IQuimpSerialize;
13 import com.github.celldynamics.quimp.plugin.ParamList;
14 import com.github.celldynamics.quimp.plugin.binaryseg.BinarySegmentation_;
15 import com.github.celldynamics.quimp.plugin.engine.PluginFactory;
16 import com.github.celldynamics.quimp.utils.QuimpToolsCollection;
17
18 import ij.ImagePlus;
19 import ij.io.FileInfo;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public class BOAState implements IQuimpSerialize {
73
74 private static final Logger LOGGER = LoggerFactory.getLogger(BOAState.class.getName());
75
76
77
78
79
80
81
82
83
84
85 public transient SegParam segParam;
86
87
88
89 public BOAp boap;
90
91
92
93
94
95
96 public transient BinarySegmentation_ binarySegmentationPlugin;
97
98
99
100 ParamList binarySegmentationParam;
101
102
103
104 private ArrayList<SegParam> segParamSnapshots;
105
106
107
108
109
110 public ArrayList<SnakePluginList> snakePluginListSnapshots;
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public transient SnakePluginList snakePluginList;
125
126
127
128
129 public Nest nest;
130
131
132
133
134 public ArrayList<Boolean> isFrameEdited;
135
136
137
138
139
140
141
142
143
144
145 class SegParam {
146
147
148
149
150
151 private double nodeRes;
152
153
154
155
156
157 public int blowup;
158
159
160
161
162
163 public double vel_crit;
164
165
166
167
168
169 public double f_central;
170
171
172
173
174
175 public double f_image;
176
177
178
179
180
181 public int max_iterations;
182
183
184
185
186
187 public int sample_tan;
188
189
190
191
192
193 public int sample_norm;
194
195
196
197
198
199 public double f_contract;
200
201
202
203
204
205 public double finalShrink;
206
207
208
209
210 public boolean use_previous_snake;
211
212
213
214
215
216 public boolean showPaths;
217
218
219
220
221
222
223
224
225 public boolean expandSnake;
226
227
228
229
230
231 private double min_dist;
232
233
234
235
236
237 private double max_dist;
238
239
240
241
242
243
244
245 public boolean contractingDirection = true;
246
247
248
249
250
251
252 public SegParam(final SegParam src) {
253 this.nodeRes = src.nodeRes;
254 this.blowup = src.blowup;
255 this.vel_crit = src.vel_crit;
256 this.f_central = src.f_central;
257 this.f_image = src.f_image;
258 this.max_iterations = src.max_iterations;
259 this.sample_tan = src.sample_tan;
260 this.sample_norm = src.sample_norm;
261 this.f_contract = src.f_contract;
262 this.finalShrink = src.finalShrink;
263 this.use_previous_snake = src.use_previous_snake;
264 this.showPaths = src.showPaths;
265 this.expandSnake = src.expandSnake;
266 this.min_dist = src.min_dist;
267 this.max_dist = src.max_dist;
268 this.contractingDirection = src.contractingDirection;
269 }
270
271
272
273
274 public SegParam() {
275 setDefaults();
276
277 showPaths = false;
278 use_previous_snake = true;
279 expandSnake = false;
280
281 }
282
283
284
285
286
287
288 @Override
289 public int hashCode() {
290 final int prime = 31;
291 int result = 1;
292 result = prime * result + blowup;
293 result = prime * result + (expandSnake ? 1231 : 1237);
294 long temp;
295 temp = Double.doubleToLongBits(f_central);
296 result = prime * result + (int) (temp ^ (temp >>> 32));
297 temp = Double.doubleToLongBits(f_contract);
298 result = prime * result + (int) (temp ^ (temp >>> 32));
299 temp = Double.doubleToLongBits(max_dist);
300 result = prime * result + (int) (temp ^ (temp >>> 32));
301 temp = Double.doubleToLongBits(min_dist);
302 result = prime * result + (int) (temp ^ (temp >>> 32));
303 temp = Double.doubleToLongBits(f_image);
304 result = prime * result + (int) (temp ^ (temp >>> 32));
305 temp = Double.doubleToLongBits(finalShrink);
306 result = prime * result + (int) (temp ^ (temp >>> 32));
307 result = prime * result + max_iterations;
308 temp = Double.doubleToLongBits(nodeRes);
309 result = prime * result + (int) (temp ^ (temp >>> 32));
310 result = prime * result + sample_norm;
311 result = prime * result + sample_tan;
312 result = prime * result + (showPaths ? 1231 : 1237);
313 result = prime * result + (use_previous_snake ? 1231 : 1237);
314 temp = Double.doubleToLongBits(vel_crit);
315 result = prime * result + (int) (temp ^ (temp >>> 32));
316 result = prime * result + (contractingDirection ? 1231 : 1237);
317 return result;
318 }
319
320
321
322
323
324
325 @Override
326 public boolean equals(Object obj) {
327 if (this == obj) {
328 return true;
329 }
330 if (obj == null) {
331 return false;
332 }
333 if (!(obj instanceof SegParam)) {
334 return false;
335 }
336 SegParam other = (SegParam) obj;
337 if (blowup != other.blowup) {
338 return false;
339 }
340 if (expandSnake != other.expandSnake) {
341 return false;
342 }
343 if (Double.doubleToLongBits(f_central) != Double.doubleToLongBits(other.f_central)) {
344 return false;
345 }
346 if (Double.doubleToLongBits(min_dist) != Double.doubleToLongBits(other.min_dist)) {
347 return false;
348 }
349 if (Double.doubleToLongBits(max_dist) != Double.doubleToLongBits(other.max_dist)) {
350 return false;
351 }
352 if (Double.doubleToLongBits(f_contract) != Double.doubleToLongBits(other.f_contract)) {
353 return false;
354 }
355 if (Double.doubleToLongBits(f_image) != Double.doubleToLongBits(other.f_image)) {
356 return false;
357 }
358 if (Double.doubleToLongBits(finalShrink) != Double.doubleToLongBits(other.finalShrink)) {
359 return false;
360 }
361 if (max_iterations != other.max_iterations) {
362 return false;
363 }
364 if (Double.doubleToLongBits(nodeRes) != Double.doubleToLongBits(other.nodeRes)) {
365 return false;
366 }
367 if (sample_norm != other.sample_norm) {
368 return false;
369 }
370 if (sample_tan != other.sample_tan) {
371 return false;
372 }
373 if (showPaths != other.showPaths) {
374 return false;
375 }
376 if (use_previous_snake != other.use_previous_snake) {
377 return false;
378 }
379 if (Double.doubleToLongBits(vel_crit) != Double.doubleToLongBits(other.vel_crit)) {
380 return false;
381 }
382 if (contractingDirection != other.contractingDirection) {
383 return false;
384 }
385 return true;
386 }
387
388
389
390
391
392
393 public double getNodeRes() {
394 return nodeRes;
395 }
396
397
398
399
400
401
402 public void setNodeRes(double d) {
403 nodeRes = d;
404 if (nodeRes < 1) {
405 min_dist = 1;
406 max_dist = 2.3;
407 return;
408 }
409 min_dist = nodeRes;
410 max_dist = nodeRes * 1.9;
411 }
412
413
414
415
416
417
418 public void setDefaults() {
419 setNodeRes(6.0);
420 blowup = 20;
421 vel_crit = 0.005;
422 f_central = 0.04;
423 f_image = 0.2;
424 max_iterations = 4000;
425 sample_tan = 4;
426 sample_norm = 12;
427 f_contract = 0.04;
428 finalShrink = 3d;
429 contractingDirection = true;
430 }
431
432
433
434
435
436
437 public double getMax_dist() {
438 return max_dist;
439 }
440
441
442
443
444
445
446 public double getMin_dist() {
447 return min_dist;
448 }
449
450
451
452
453
454
455 @Override
456 public String toString() {
457 return "SegParam [nodeRes=" + nodeRes + ", blowup=" + blowup + ", velCrit=" + vel_crit
458 + ", centralForce=" + f_central + ", imageForce=" + f_image + ", maxIterations="
459 + max_iterations + ", sampleTan=" + sample_tan + ", sampleNorm=" + sample_norm
460 + ", contractForce=" + f_contract + ", finalShrink=" + finalShrink
461 + ", use_previous_snake=" + use_previous_snake + ", showPaths=" + showPaths
462 + ", expandSnake=" + expandSnake + ", min_dist=" + min_dist + ", max_dist=" + max_dist
463 + " contractingDirection=" + contractingDirection + "]";
464 }
465
466
467
468
469
470
471 public void reverseForces() {
472 if (contractingDirection == true) {
473 finalShrink = Math.abs(finalShrink);
474 f_image = Math.abs(f_image);
475 f_central = Math.abs(f_central);
476
477 blowup = 20;
478 } else {
479 finalShrink = -1.0 * Math.abs(finalShrink);
480 f_image = -1.0 * Math.abs(f_image);
481 f_central = -1.0 * Math.abs(f_central);
482
483 blowup = -1;
484 }
485 }
486
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509 public class BOAp {
510
511
512
513
514
515
516 private File orgFile;
517
518
519
520
521
522
523
524 private File outputFileCore;
525
526
527
528 private String fileName;
529
530
531
532 transient QParams readQp;
533
534
535
536
537 int NMAX;
538
539
540
541
542 double delta_t;
543
544
545
546
547 double sensitivity;
548
549
550
551
552 double f_friction;
553
554
555
556 private int FRAMES;
557 private int WIDTH;
558 private int HEIGHT;
559
560
561
562 int cut_every;
563
564
565
566 boolean oldFormat;
567
568
569
570 boolean saveSnake;
571
572
573
574
575 double proximity;
576
577
578
579 double proxFreeze;
580
581
582
583
584 boolean savedOne;
585
586
587
588 boolean savePretty = true;
589
590
591
592
593 public int frame;
594
595
596
597 public int snakeToZoom = -1;
598
599
600
601
602 boolean singleImage;
603
604
605
606
607 String paramsExist;
608
609
610
611
612 boolean zoom;
613
614
615
616
617 boolean doDelete;
618
619
620
621 transient boolean doFreeze;
622
623
624
625
626 boolean doDeleteSeg;
627
628
629
630 boolean editMode;
631
632
633
634 int editingID;
635
636
637
638
639 boolean useSubPixel = true;
640
641
642
643 int callCount;
644
645 private double imageScale;
646 private boolean scaleAdjusted = false;
647
648
649
650
651
652
653 public double getImageScale() {
654 return imageScale;
655 }
656
657
658
659
660
661
662 public void setImageScale(double imageScale) {
663 if (imageScale == 0) {
664 this.imageScale = 1;
665 this.scaleAdjusted = true;
666 } else {
667 this.imageScale = imageScale;
668 }
669 }
670
671
672
673
674
675
676 public boolean isScaleAdjusted() {
677 return scaleAdjusted;
678 }
679
680 private double imageFrameInterval;
681 private boolean fIAdjusted = false;
682
683
684
685
686
687
688 public double getImageFrameInterval() {
689 return imageFrameInterval;
690 }
691
692
693
694
695
696
697 public void setImageFrameInterval(double imageFrameInterval) {
698 if (imageFrameInterval == 0) {
699 this.imageFrameInterval = 1;
700 this.fIAdjusted = true;
701 } else {
702 this.imageFrameInterval = imageFrameInterval;
703 }
704 }
705
706
707
708
709
710
711 public boolean isfIAdjusted() {
712 return fIAdjusted;
713 }
714
715
716
717
718 public BOAp() {
719 savedOne = false;
720
721
722 NMAX = 250;
723 delta_t = 1.;
724 sensitivity = 0.5;
725 cut_every = 8;
726 oldFormat = false;
727 saveSnake = true;
728 proximity = 150;
729 proxFreeze = 1;
730 f_friction = 0.6;
731 doDelete = false;
732 doDeleteSeg = false;
733 zoom = false;
734 editMode = false;
735 editingID = -1;
736 callCount = 0;
737 frame = 1;
738 savePretty = true;
739 }
740
741
742
743
744
745
746 boolean isProcessedSnakePlotted = true;
747
748
749
750
751 boolean isHeadPlotted = false;
752
753
754
755
756 boolean isZoomFreeze = false;
757
758
759
760
761
762
763
764
765
766
767 boolean stopOnPluginError = true;
768
769
770
771
772
773
774
775
776
777
778 public void setup(final ImagePlus ip) {
779 FileInfo fileinfo = ip.getOriginalFileInfo();
780 if (fileinfo == null) {
781 orgFile = new File(File.separator, ip.getTitle());
782 setOutputFileCore(File.separator + ip.getTitle());
783 } else {
784 orgFile = new File(fileinfo.directory, fileinfo.fileName);
785 setOutputFileCore(fileinfo.directory + orgFile.getName());
786 }
787
788 FRAMES = ip.getStackSize();
789
790 WIDTH = ip.getWidth();
791 HEIGHT = ip.getHeight();
792 paramsExist = "YES";
793
794 }
795
796
797
798
799
800
801 public int getFrames() {
802 return FRAMES;
803 }
804
805
806
807
808
809
810 public int getWidth() {
811 return WIDTH;
812 }
813
814
815
816
817
818
819 public int getHeight() {
820 return HEIGHT;
821 }
822
823
824
825
826
827
828 public File getOrgFile() {
829 return orgFile;
830 }
831
832
833
834
835
836
837 public void setOrgFile(File orgFile) {
838 this.orgFile = orgFile;
839 }
840
841
842
843
844
845
846
847 public File getOutputFileCore() {
848 return outputFileCore;
849 }
850
851
852
853
854
855
856
857
858 private void setOutputFileCore(File outputFileCore) {
859 this.outputFileCore = outputFileCore;
860 fileName = outputFileCore.getName();
861 }
862
863
864
865
866
867
868 public void setOutputFileCore(String outputFileCore) {
869 setOutputFileCore(new File(QuimpToolsCollection.removeExtension(outputFileCore)));
870 }
871
872
873
874
875
876
877 public String getFileName() {
878 return fileName;
879 }
880
881
882
883
884
885
886
887
888
889 public String deductSnakeFileName(int id) {
890 LOGGER.trace(getOutputFileCore().getAbsoluteFile().toString());
891 return getOutputFileCore().getAbsoluteFile() + "_" + id + FileExtensions.snakeFileExt;
892 }
893
894
895
896
897
898
899
900
901
902 public String deductStatsFileName(int id) {
903 return getOutputFileCore().getAbsoluteFile() + "_" + id + FileExtensions.statsFileExt;
904 }
905
906
907
908
909
910
911
912
913
914 public String deductParamFileName(int id) {
915 return getOutputFileCore().getAbsoluteFile() + "_" + id + FileExtensions.configFileExt;
916 }
917
918
919
920
921
922
923
924
925 public String deductFilterFileName() {
926 return getOutputFileCore().getAbsoluteFile() + FileExtensions.pluginFileExt;
927 }
928
929
930
931
932
933
934
935
936 public String deductNewParamFileName() {
937 return getOutputFileCore().getAbsoluteFile() + FileExtensions.newConfigFileExt;
938 }
939
940 }
941
942
943
944
945
946
947
948 public BOAState() {
949 boap = new BOAp();
950 segParam = new SegParam();
951 snakePluginList = new SnakePluginList();
952 binarySegmentationParam = new ParamList();
953 nest = new Nest();
954 }
955
956
957
958
959
960
961
962 public BOAState(final ImagePlus ip) {
963 this(ip, null, null);
964
965 }
966
967
968
969
970
971
972
973
974
975 public BOAState(final ImagePlus ip, final PluginFactory pf, final ViewUpdater vu) {
976 this();
977 snakePluginList = new SnakePluginList(BOA_.NUM_SNAKE_PLUGINS, pf, vu);
978 if (ip == null) {
979 return;
980 }
981
982 initializeSnapshots(ip, pf, vu);
983
984 boap.setImageScale(ip.getCalibration().pixelWidth);
985
986 boap.setImageFrameInterval(ip.getCalibration().frameInterval);
987 boap.setup(ip);
988 }
989
990 private void initializeSnapshots(final ImagePlus ip, final PluginFactory pf,
991 final ViewUpdater vu) {
992 int numofframes = ip.getStackSize();
993
994 segParamSnapshots = new ArrayList<SegParam>(Collections.nCopies(numofframes, new SegParam()));
995 snakePluginListSnapshots = new ArrayList<SnakePluginList>(
996 Collections.nCopies(numofframes, new SnakePluginList(BOA_.NUM_SNAKE_PLUGINS, pf, vu)));
997 isFrameEdited = new ArrayList<Boolean>(Collections.nCopies(numofframes, false));
998 LOGGER.debug("Initialize storage of size: " + numofframes + " size of segParams: "
999 + segParamSnapshots.size());
1000 }
1001
1002
1003
1004
1005
1006
1007
1008 public void store(int frame) {
1009 LOGGER.debug(
1010 "Data stored at frame:" + frame + " size of segParams is " + segParamSnapshots.size());
1011 segParamSnapshots.set(frame - 1, new SegParam(segParam));
1012
1013 snakePluginListSnapshots.set(frame - 1, snakePluginList.getDeepCopy());
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 public void restore(int frame) {
1025 LOGGER.trace("Data restored from frame:" + frame);
1026 SegParam tmp = segParamSnapshots.get(frame - 1);
1027 if (tmp != null) {
1028 segParam = tmp;
1029 }
1030 snakePluginList = snakePluginListSnapshots.get(frame - 1);
1031 snakePluginList.uploadPluginsConfig();
1032
1033 }
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 public void copySegParamFromSnapshot(int sourceFrame) {
1045 SegParam tmp = segParamSnapshots.get(sourceFrame - 1);
1046 if (tmp != null) {
1047 segParam = new SegParam(tmp);
1048 }
1049 }
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060 public void copyPluginListFromSnapshot(int sourceFrame) {
1061 snakePluginList.clear();
1062
1063
1064 SnakePluginList previous = snakePluginListSnapshots.get(sourceFrame - 1);
1065
1066 previous.afterSerialize();
1067
1068 snakePluginList = previous.getDeepCopy();
1069 snakePluginList.afterSerialize();
1070
1071
1072
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 public void storeOnlyEdited(int frame) {
1084 isFrameEdited.set(frame - 1, true);
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102 public void reset(final ImagePlus ip, final PluginFactory pf, final ViewUpdater vu) {
1103 if (snakePluginList != null) {
1104 snakePluginList.clear();
1105 }
1106 if (snakePluginListSnapshots != null) {
1107 for (SnakePluginList sp : snakePluginListSnapshots) {
1108 if (sp != null) {
1109 sp.clear();
1110 }
1111 }
1112 }
1113
1114
1115 segParam = new SegParam();
1116 initializeSnapshots(ip, pf, vu);
1117 }
1118
1119
1120
1121
1122
1123
1124 @Override
1125 public void beforeSerialize() {
1126 nest.beforeSerialize();
1127 if (binarySegmentationPlugin != null) {
1128 binarySegmentationParam = binarySegmentationPlugin.getPluginConfig();
1129 } else {
1130 binarySegmentationParam = new ParamList();
1131 }
1132
1133
1134 }
1135
1136
1137
1138
1139
1140
1141 @Override
1142 public void afterSerialize() throws Exception {
1143 LOGGER.trace("After serialize called");
1144 nest.afterSerialize();
1145 snakePluginList.afterSerialize();
1146
1147
1148
1149
1150 boap.outputFileCore = new File(boap.outputFileCore.toString());
1151 boap.orgFile = new File(boap.orgFile.toString());
1152
1153 if (segParamSnapshots.size() > 0) {
1154 if (segParamSnapshots.get(0) != null) {
1155 segParam = new SegParam(segParamSnapshots.get(0));
1156
1157 }
1158 }
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177 public void writeParams(int sid, int startF, int endF) {
1178 try {
1179 if (boap.saveSnake) {
1180 File paramFile = new File(boap.deductParamFileName(sid));
1181 QParamsuimp/QParams.html#QParams">QParams qp = new QParams(paramFile);
1182 qp.setSegImageFile(boap.orgFile);
1183 qp.setSnakeQP(new File(boap.deductSnakeFileName(sid)));
1184 qp.setStatsQP(new File(boap.deductStatsFileName(sid)));
1185 qp.setImageScale(BOA_.qState.boap.imageScale);
1186 qp.setFrameInterval(BOA_.qState.boap.imageFrameInterval);
1187 qp.setStartFrame(startF);
1188 qp.setEndFrame(endF);
1189 qp.nmax = boap.NMAX;
1190 qp.setBlowup(segParam.blowup);
1191 qp.maxIterations = segParam.max_iterations;
1192 qp.sampleTan = segParam.sample_tan;
1193 qp.sampleNorm = segParam.sample_norm;
1194 qp.deltaT = boap.delta_t;
1195 qp.setNodeRes(segParam.nodeRes);
1196 qp.velCrit = segParam.vel_crit;
1197 qp.centralForce = segParam.f_central;
1198 qp.contractForce = segParam.f_contract;
1199 qp.imageForce = segParam.f_image;
1200 qp.frictionForce = boap.f_friction;
1201 qp.finalShrink = segParam.finalShrink;
1202 qp.sensitivity = boap.sensitivity;
1203
1204 qp.writeParams();
1205 }
1206 } catch (IOException e) {
1207 LOGGER.debug(e.getMessage(), e);
1208 LOGGER.error("Could not write parameters to file", e.getMessage());
1209 }
1210 }
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 public boolean readParams(File paramFile) {
1227 boap.readQp = new QParams(paramFile);
1228
1229 try {
1230 boap.readQp.readParams();
1231 } catch (QuimpException e) {
1232 BOA_.log("Failed to read parameter file " + e.getMessage());
1233 return false;
1234 }
1235 loadParams(boap.readQp);
1236 BOA_.log("Successfully read parameters");
1237 return true;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250 public void loadParams(QParams readQp) {
1251
1252 boap.NMAX = readQp.nmax;
1253 segParam.blowup = readQp.getBlowup();
1254 segParam.max_iterations = readQp.maxIterations;
1255 segParam.sample_tan = readQp.sampleTan;
1256 segParam.sample_norm = readQp.sampleNorm;
1257 boap.delta_t = readQp.deltaT;
1258 segParam.nodeRes = readQp.getNodeRes();
1259 segParam.vel_crit = readQp.velCrit;
1260 segParam.f_central = readQp.centralForce;
1261 segParam.f_contract = readQp.contractForce;
1262 segParam.f_image = readQp.imageForce;
1263
1264 if (readQp.paramFormat == QParams.QUIMP_11) {
1265 segParam.finalShrink = readQp.finalShrink;
1266 }
1267 boap.readQp = readQp;
1268
1269 for (int f = readQp.getStartFrame(); f <= readQp.getEndFrame(); f++) {
1270 store(f);
1271 }
1272 }
1273 }