-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMicrograph_Analysis_Single.ijm
1035 lines (890 loc) · 35.9 KB
/
Micrograph_Analysis_Single.ijm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
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
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Micrograph_Analysis_Single.ijm
* Author: Pawel Cislo <pawel.cisloo@gmail.com> <pawelcislo.com>
* Version: 1.1
* Start of Development: 19/09/2018
* License: https://creativecommons.org/licenses/by-sa/4.0/
*
* REQUIREMENTS:
* 1) ImageJ/Fiji distribution
* a) Fiji is recommended: https://imagej.net/Fiji/Downloads
* 2) NND plugin: https://icme.hpc.msstate.edu/mediawiki/index.php/Nearest_Neighbor_Distances_Calculation_with_ImageJ
* 3) Graph plugin: https://imagej.nih.gov/ij/plugins/graph/index.html
* 4) Activation of BioVoxxel Toolbox: https://imagej.net/BioVoxxel_Toolbox
* 5) Activation of BAR Toolbox: http://imagej.net/BAR
* 6) 3 files in the "macros" folder of ImageJ
* a) "Micrograph_Analysis.ijm"
* b) "Micrograph_Analysis_Single.ijm"
* c) "Micrograph_Analysis_Multiple.ijm"
* 7) The input files must have one of the extensions specified below. The inclusion of different formats requires code modification
* a) TIFF (.tiff, .tif)
* b) PNG (.png)
* c) JPEG (.jpeg, .jpg)
* d) BMP (.bmp)
*
*
* INSTALLATION:
* 1) Install ImageJ/Fiji distribution from the official website
* a) Fiji is recommended https://imagej.net/Fiji/Downloads
* 2) Install all the requirements mentioned in points 2-5 of the "REQUIREMENTS" list.
* The up to date installation instructions are placed on the websites mentioned in the points.
* 3) Find Fiji installation directory and place “Micrograph_Analysis” folder in the “Fiji/Macros” folder.
* 4) In the Fiji toolbar menu, choose “Plugins > Install…”
* a) From the file selection menu, locate and choose “Micrgraph_Analysis.ijm” file
* b) Locate Fiji installation directory and save the file in “Fiji/plugins/Macros” folder
*
*
* USING THE SYSTEM:
* After successful installation, please find the “Micrograph Analysis” entry in the “Plugins” menu of the ImageJ/Fiji toolbar:
* “Plugins > Macros > Micrograph Analysis”.
* After selecting “Micrograph Analysis” entry, please follow the on-screen instructions.
*
*
* DESCRIPTION:
* This macro will perform the following operations:
* 1) ask the user for input image or directory of images
* 2) check if the specified input has a supported format and is not empty
* 3) request to determine the output directory
* 4) using a GUI, ask the user for:
* a) desired output (specified in point 11)
* b) preference of analysing interparticle range
* a) minimum and maximum particle size taken into analysis
* b) minimum and maximum particle circularity taken into analysis
* c) preview of the particles before analysis
* d) analysis preferences (specified in point 9)
* e) preference of setting the scale (specified in point 7)
* f) preference of removing the label (specified in point 8)
* 5) ask to specify output images (optionally)
* 6) ask to specify area distribution plot analysis (optionally)
* 7) ask to set accurate scale (optionally)
* a) manually (by drawing a line over scale)
* b) typing in the known distances
* c) using predefined scale
* a) skipping the part (by default 1 pixel = 1 known distance)
* 8) crop the image to remove the bottom label (optionally)
* a) provide predefined option to remove the label as for micrographs taken at Coventry University
* b) provide an option to crop the image manually
* c) leave the image without cropping
* 9) perform segmentation
* a) run machine learning segmentation instead of automatic thresholding (optionally)
* b) transform input into 8-bit image
* c) apply automatic threshold
* d) convert input into binary values (optionally)
* e) remove small particles from the image (outliers) (oprionally)
* f) fill holes in particles on the image (optionally)
* g) apply watershed algorithm on the image (optionally)
* h) exclude particles on edges during the analysis (optionally)
* i) include holes of particles in analysis (optionally
* 10) ask the user if he is satisfied with the particles taken into analysis (optionally)
* a) if not, specify particle size and circularity again, till the user is satisfied
* b) if yes, continue to run the script
* 11) ask to specify interparticle range analysis (optionally)
* 12) analyze particles, close windows, optionally save:
* a) overall results (including nearest neighbor distances from centroids) (saved in “RESULTS…” file)
* b) summary (saved in “SUMMARY…” file)
* c) interparticle distances (saved in the “INTERPARTICLE_DISTANCES” folder)
* d) area distribution plot (saved in the “PLOTS” folder)
* e) cluster indication (saved in the “CLUSTERS” folder)
* f) images
* g) specifications used in analysis (saved in “ANALYSIS_INFO(…)” file)
* h) time of running manual and automatic operations of the script (saved in “ANALYSIS_INFO…” file)
* i) machine learning results (saved in the main folder)
*
*
* HELP:
* For more help, please read the attached "User Manual.pdf" file, or if it is missed, contact the developer using the e-mail provided above
*
*/
// ==========START==========
// START TIME TRACKING (FOR THE ENTIRE PROCESS)
start = getTime();
// DEFINE VARIABLES
analysis_options = "";
interp_total_number = 0;
interp_max_distance = 0;
interp_total_distance = 0;
interp_total_variance = 0;
preview_particles_run = 0;
// GET DATE AND TIME
MonthNames = newArray("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
DayNames = newArray("Sun", "Mon","Tue","Wed","Thu","Fri","Sat");
getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec);
TimeString ="Date: "+DayNames[dayOfWeek]+" ";
if (dayOfMonth<10) {TimeString = TimeString+"0";}
TimeString = TimeString+dayOfMonth+"-"+MonthNames[month]+"-"+year+"\nTime: ";
if (hour<10) {TimeString = TimeString+"0";}
TimeString = TimeString+hour+":";
if (minute<10) {TimeString = TimeString+"0";}
TimeString = TimeString+minute+":";
if (second<10) {TimeString = TimeString+"0";}
TimeString = TimeString+second;
// SET BATCH MODE ON (DON'T DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(true);
// ==========GET INPUT FILE==========
input_image = File.openDialog("Select Input Image");
// ==========CHECK IF THE INPUT FILE IS AN IMAGE==========
if ((indexOf(toLowerCase(input_image), ".tif")>0) || (indexOf(toLowerCase(input_image), ".tiff")>0) ||
(indexOf(toLowerCase(input_image), ".png")>0) || (indexOf(toLowerCase(input_image), ".jpg")>0) ||
(indexOf(toLowerCase(input_image), ".jpeg")>0) || (indexOf(toLowerCase(input_image), ".bmp")>0)) {
open(input_image);
//FIX THE EXTENSION
image_title = getTitle();
dotIndex = indexOf( image_title, "." );
image_title = substring( image_title, 0, dotIndex );
rename(image_title+".tif");
image_title = getTitle();
}
else {
Dialog.create("Error!")
Dialog.addMessage("The input file is not an image:\n");
Dialog.addMessage(input_image);
Dialog.addMessage("\nPlease specify a different file.\n");
items = newArray("Yes", "No");
Dialog.setInsets(0,24,0);
Dialog.addRadioButtonGroup("Would you like to run the script again?", items, 2, 1, "No");
Dialog.show();
input = Dialog.getRadioButton();
if (input=="Yes") {
runMacro("Micrograph_Analysis/Micrograph_Analysis_Single");
}
else {
exit();
}
}
// ==========GET OUTPUT DIRECTORY==========
dir2 = getDirectory("Choose Output Directory");
// ==========ASK FOR OUTPUT SETTINGS==========
Dialog.create("Output Settings");
// ASK FOR DESIRED OUTPUT
Dialog.setInsets(0,10,0);
Dialog.addMessage("What would you like to output?");
labels = newArray("Results", "Summary", "Interparticle Distances", "Area Distribution Plot", "Cluster Indication", "Generated Images", "Analysis Specifications");
defaults = newArray(labels.length);
defaults[0] = true;
defaults[1] = true;
defaults[5] = true;
defaults[6] = true;
rows = 7;
columns = 1;
Dialog.setInsets(0,24,0);
Dialog.addCheckboxGroup(rows, columns, labels, defaults);
// ASK FOR PARTICLE SIZE
Dialog.setInsets(10,10,0);
Dialog.addMessage("What is the particle size you want to analyse? (in um^2 | between 0 and Infinity)");
Dialog.addNumber("Minimum Size:", 0.10);
Dialog.setInsets(0,20,0);
Dialog.addString("Maximum Size:", "Infinity");
Dialog.setInsets(10,10,0);
Dialog.addMessage("What is the particle circularity you want to analyse? (in um^2 | between 0 and 1)");
Dialog.setInsets(0,10,0);
Dialog.addNumber("Minimum Circularity:", 0.00);
Dialog.setInsets(0,10,0);
Dialog.addNumber("Maximum Circularity:", 1);
// ASK FOR "PREVIEW" OF THE ANALYSIS (SHOW OUTLINED IMAGE AND ASK IF THE SELECTED PARTICLES ARE CORRECT)
Dialog.addCheckbox("Preview selected particles before the analysis", false);
// ASK FOR ANALYSIS PREFERENCES
Dialog.setInsets(10,10,0);
Dialog.addMessage("What are your analysis preferences?");
labels2 = newArray("Run machine learning segmentation instead of automatic thresholding", "Make binary image", "Remove small particles (outliers) from the image", "Fill holes of the particles on the image", "Apply Watershed Algorithm on the image", "Exclude edges in analysis", "Include holes in analysis");
defaults2 = newArray(labels2.length);
defaults2[1] = true;
defaults2[2] = true;
defaults2[3] = true;
defaults2[5] = true;
defaults2[6] = true;
rows = 7;
columns = 1;
Dialog.setInsets(0,24,0);
Dialog.addCheckboxGroup(rows, columns, labels2, defaults2);
// ASK FOR TYPE OF SCALE SETTING
items = newArray("Draw line", "Type in known distance in pixels for the marked scale", "Use predefined scale for CU micrographs (18.375 pixels = 1 um)", "Leave default scale (1 pixel = 1 um)");
Dialog.addRadioButtonGroup("How would you like to set the scale?", items, 4, 1, "Draw line");
// ASK FOR TYPE OF LABEL REMOVAL
items = newArray("Draw rectangle over the area to be measured", "Use predefined method for CU micrographs", "There is no label to remove");
Dialog.addRadioButtonGroup("How would you like to remove the label?", items, 3, 1, "Draw rectangle over the area to be measured");
// DISPLAY MENU
Dialog.show()
// GET USER'S PREFERENCES
chosenOption=newArray(labels.length);
for (i=0; i<labels.length; i++) {
chosenOption[i]=Dialog.getCheckbox();
}
preview_particles = Dialog.getCheckbox();
chosenOption2=newArray(labels2.length);
for (i=0; i<labels2.length; i++) {
chosenOption2[i]=Dialog.getCheckbox();
}
min_size = Dialog.getNumber();
max_size = Dialog.getString();
min_circularity = Dialog.getNumber();
max_circularity = Dialog.getNumber();
input_scale = Dialog.getRadioButton();
input_label = Dialog.getRadioButton();
// IF CHOSEN OPTION IS TRUE
if(chosenOption2[5]==1) {
analysis_options += " exclude";
edges = "excluded";
}
else {
edges = "included";
}
if(chosenOption2[6]==1) {
analysis_options += " include";
holes = "included";
}
else {
holes = "excluded";
}
// ASK FOR OUTPUT IMAGES (OPTIONALLY)
if(chosenOption[5]==1) {
Dialog.create("Output Images");
Dialog.setInsets(10,10,0);
Dialog.addMessage("Which images would you like to save?");
Dialog.addCheckbox("Processed", true);
Dialog.addCheckbox("Outlined", true);
if(chosenOption[2]==1) {
Dialog.addCheckbox("Masks", true);
Dialog.addCheckbox("Interparticle Adjacencies", true);
}
if(chosenOption[3]==1) {
Dialog.addCheckbox("Slices used in area distribution plot", true);
Dialog.addCheckbox("Montage of the image slices", true);
}
if(chosenOption[4]==1) {
Dialog.addCheckbox("Clustered", true);
}
Dialog.show()
image_processed = Dialog.getCheckbox();
image_outlined = Dialog.getCheckbox();
if(chosenOption[2]==1) {
image_masks = Dialog.getCheckbox();
image_interparticle = Dialog.getCheckbox();
}
if(chosenOption[3]==1) {
image_slices = Dialog.getCheckbox();
image_montage = Dialog.getCheckbox();
}
if(chosenOption[4]==1) {
image_clustered = Dialog.getCheckbox();
}
}
// ASK FOR "AREA DISTRIBUTION PLOT" SPECIFICATIONS (OPTIONALLY)
if(chosenOption[3]==1) {
Dialog.create("Area Distribution Plot");
Dialog.setInsets(0,0,0);
Dialog.addMessage("Please specify the preferences of your area distribution analysis.");
Dialog.setInsets(0,0,0);
Dialog.addNumber("Slices per row:", 2);
Dialog.setInsets(0,0,0);
Dialog.addNumber("Slices per column:", 1);
Dialog.show();
input_images_per_row = Dialog.getNumber();
input_images_per_column = Dialog.getNumber();
}
// SET BATCH MODE OFF FOR THE 1ST IMAGE(DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(false);
// ==========BEGIN OPERATIONS==========
// ==========CREATE OUTPUT DIRECTORY==========
dir3=dir2+image_title+"_RESULTS("+year+"-"+month+"-"+dayOfMonth+" "+hour+";"+minute+";"+second+")"+File.separator;
File.makeDirectory(dir3);
// ==========SCALE SETTING==========
// REMOVE PREVIOUS SCALE
run("Set Scale...", "distance=1 known=1");
if(input_scale=="Draw line"){
// SET THE SCALE (MANUALLY - BY DRAWING A LINE)
setTool("line");
waitForUser("Set the scale for this image","Hold Shift to draw a straight line of a known length, then click 'OK'\n \nHINT 1: Zoom in/out for more precision using:\n---> Control and Mouse Wheel\n---> Control and arrow keys on your keyboard\n \nHINT 2: After the selection, move the line using arrow keys on your keyboard");
run("Measure");
length_of_line = getResult('Length', 0);
run("Clear Results");
run("Close");
Dialog.create("Known distance");
Dialog.addMessage("You have drew a line distance of "+length_of_line+" pixels");
Dialog.addNumber("What is the known distance for the drawn line?" , 2);
Dialog.addString("What is the unit of length (scale) for this image?" , "um");
Dialog.show();
known_distance = Dialog.getNumber();
unit_of_length = Dialog.getString();
run("Set Scale...", "known="+known_distance+" pixel=1 unit="+unit_of_length+" global");
}
else if(input_scale=="Type in known distance in pixels for the marked scale") {
// SET THE SCALE (MANUALLY - BY TYPING A DISTANCE)
Dialog.create("Known distance");
Dialog.addNumber("What is the length of line (in pixels) that covers the marked scale on the image?" , 36.75);
Dialog.addNumber("What is the known distance for the drawn line?" , 2);
Dialog.addString("What is the unit of length (scale) for this image?" , "um");
Dialog.show();
length_of_line = Dialog.getNumber();
known_distance = Dialog.getNumber();
unit_of_length = Dialog.getString();
run("Set Scale...", "distance="+length_of_line+" known="+known_distance+" pixel=1 unit="+unit_of_length+" global");
}
else if(input_scale=="Use predefined scale for CU micrographs (18.375 pixels = 1 um)") {
length_of_line = 36.75;
known_distance = 2;
unit_of_length = "um";
run("Set Scale...", "distance="+length_of_line+" known="+known_distance+" pixel=1 unit="+unit_of_length+" global");
}
else {
//LEAVE DEFAULT SCALE (1 PIXEL = 1 UM)
length_of_line = 1;
known_distance = 1;
unit_of_length = "um";
run("Set Scale...", "distance="+length_of_line+" known="+known_distance+" pixel=1 unit="+unit_of_length+" global");
}
// ==========CROP THE IMAGE==========
if(input_label=="Draw rectangle over the area to be measured"){
// CROP THE IMAGE (MANUALLY)
setTool("rectangle");
waitForUser("Remove the label","Mark the area which should be taken into analysis, then click 'OK'\n \nHINT: Zoom in/out for more precision using:\n---> Control and Mouse Wheel\n---> Control and arrow keys on your keyboard\n \nHINT 2: You can move the selection using arrow keys on your keyboard");
getSelectionBounds(x, y, width, height);
makeRectangle(x, y, width, height);
run("Crop");
}
else if(input_label=="Use predefined method for CU micrographs"){
// CROP THE IMAGE AUTOMATICALLY (FOR COVENTRY UNI ENGINEERING DEPARTMENT)
makeRectangle(0, 0, 1024, 691);
run("Crop");
}
else {
// There is no label to remove
}
// SET BATCH MODE ON (DON'T DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(true);
// START TIME TRACKING (FOR AUTOMATIC PROCESSES)
start2 = getTime();
// ==========BEGIN SEGMENTATION==========
// RUN TRAINABLE MACHINE LEARNING WEKA SEGMENTATION INSTEAD OF AUTOMATIC THRESHOLDING (OPTIONALLY)
if (chosenOption2[0]==1) {
setBatchMode(false);
run("Trainable Weka Segmentation");
weka_window = getTitle();
title_for_weka_segmentation = "Follow the steps";
msg_for_weka_segmentation = "1. Mark classes using your mouse and add them to classes 1 (particles) and 2 (background).\n\n2. Click 'Train classifier'.\n\n3. Wait for the fully green and red image (be patient).\n\n4. Click 'Create result'.\n\n5. Close main Weka Segmentation and input image window (you should be left with 'Log' and 'Classified image' windows).\n\n6. Click 'OK' button in the window of this message."; waitForUser(title_for_weka_segmentation, msg_for_weka_segmentation);
call("trainableSegmentation.Weka_Segmentation.getResult");
selectWindow("Classified image");
rename(image_title);
if (isOpen("Log")) {
selectWindow("Log");
saveAs("Text", dir3+"MACHINE_LEARNING_RESULTS_"+image_title+".txt");
print("\\Clear");
run("Close");
}
// TRANSFORM IMAGE INTO 8-BIT TYPE (it is a must for analysing particles)
run("8-bit");
// APPLY THRESHOLD (it is a must for analysing particles. No worries, it does not change the weka segmentation results)
setAutoThreshold("Default dark");
setOption("BlackBackground", true);
run("Convert to Mask");
run("Invert");
}
else {
// TRANSFORM IMAGE INTO 8-BIT TYPE
run("8-bit");
// APPLY THRESHOLD
setAutoThreshold("Default dark");
setOption("BlackBackground", true);
run("Convert to Mask");
}
setBatchMode(true);
// TRANSFORM IMAGE INTO BINARY VALUES (OPTIONALLY)
if (chosenOption2[1]==1) {
run("Make Binary", "thresholded remaining white");
}
// REMOVE OUTLIERS (OPTIONALLY)
if(chosenOption2[2]==1) {
run("Remove Outliers...", "radius=1 threshold=50 which=Bright");
}
// FILL HOLES (OPTIONALLY)
if(chosenOption2[3]==1) {
run("Fill Holes");
}
// RUN WATERSHED ALGORITHM (OPTIONALLY)
if(chosenOption2[4]==1) {
run("Watershed");
}
// ==========RUN ANALYSIS==========
// PREVIEW THE ANALYSED PARTICLES (OPTIONALLY)
if (preview_particles == true) {
setBatchMode(false);
while (preview_particles_run == 0) {
selectWindow(image_title);
run("Extended Particle Analyzer", " area="+min_size+"-"+max_size+" circularity="+min_circularity+"-"+max_circularity+" show=Outlines redirect=None keep=None display summarize"+analysis_options+"");
outlined_image_title = getTitle();
selectWindow(outlined_image_title);
// MAKE COMPARISON MONTAGE
open(input_image);
input_image_for_preview = getTitle();
run("Images to Stack", "method=[Copy (center)] name=Stack title=[] use keep");
stack = getTitle();
run("Delete Slice");
run("Make Montage...", "columns=2 rows=1 scale=1 border=3 use");
preview_montage = getTitle();
selectWindow(stack);
close();
selectWindow(input_image_for_preview);
close();
selectWindow(preview_montage);
run("Maximize");
// CREATE DIALOG
Dialog.create("Preview particles taken into analysis");
items = newArray("Yes, continue analysis", "No, specify particle parameters again");
Dialog.addRadioButtonGroup("Are you satisfied with the particles selected for the analysis?", items, 2, 1, "Yes, continue analysis");
Dialog.show();
input = Dialog.getRadioButton();
if (input=="No, specify particle parameters again") {
selectWindow(preview_montage);
close();
selectWindow(outlined_image_title);
close();
selectWindow("Results");
run("Clear Results");
run("Close");
if (isOpen("Summary")) {
selectWindow("Summary");
Table.deleteRows(0, Table.size, "Summary");
run("Close");
}
selectWindow(image_title);
// CREATE DIALOG TO SPECIFY THE PARTICLE SIZE AND CIRCULARITY
Dialog.create("New Interparticle Specifications");
// ASK FOR PARTICLE SIZE
Dialog.setInsets(10,10,0);
Dialog.addMessage("What is the new particle size you want to analyse? (in um^2 | between 0 and Infinity)");
Dialog.addNumber("Minimum Size:", 0.10);
Dialog.setInsets(0,20,0);
Dialog.addString("Maximum Size:", "Infinity");
Dialog.setInsets(10,10,0);
Dialog.addMessage("What is the new particle circularity you want to analyse? (in um^2 | between 0 and 1)");
Dialog.setInsets(0,10,0);
Dialog.addNumber("Minimum Circularity:", 0.00);
Dialog.setInsets(0,10,0);
Dialog.addNumber("Maximum Circularity:", 1);
Dialog.show();
min_size = Dialog.getNumber();
max_size = Dialog.getString();
min_circularity = Dialog.getNumber();
max_circularity = Dialog.getNumber();
}
else {
selectWindow(preview_montage);
close();
preview_particles_run = 1;
selectWindow(image_title);
}
}
}
else {
run("Extended Particle Analyzer", " area="+min_size+"-"+max_size+" circularity="+min_circularity+"-"+max_circularity+" show=Outlines redirect=None keep=None display summarize"+analysis_options+"");
outlined_image_title = getTitle();
}
// CONTINUE ANALYSIS
run("Summarize");
run("Nnd ");
// ==========SAVE RESULTS==========
// TRANSFER NND TO THE "RESULTS" TABLE
selectWindow("Nearest Neighbor Distances");
nnd = Table.getColumn("C1");
run("Close");
selectWindow("Results");
Table.setColumn("Nearest_Neighbor_Distance",nnd);
//REARRANGE THE "RESULTS" TABLE
Table.renameColumn("Perim.", "Perim");
Table.renameColumn("Circ.", "Circ");
code = "Area2=Area; NearestNeighborDistance=Nearest_Neighbor_Distance;"
+"Perimeter=Perim; Circularity=Circ; Roundness=Round;"
+"AR2=AR; Solidity2=Solidity; Feret2=Feret;"
+"FeretAR2=FeretAR; Compactness=Compact; Extent2=Extent;"
+"IntegratedDensity=IntDen; RawIntegratedDensity=RawIntDen; FeretAngle2=FeretAngle;"
+"MinFeret2=MinFeret; FeretX2=FeretX; FeretY2=FeretY;"
+"XM2=XM; YM2=YM; BX2=BX; BY2=BY; Major2=Major; Minor2=Minor;"
+"Angle2=Angle; XStart2=XStart; YStart2=YStart";
Table.applyMacro(code);
Table.deleteColumn("Nearest_Neighbor_Distance");
Table.deleteColumn("Area");
Table.deleteColumn("Mean");
Table.deleteColumn("StdDev");
Table.deleteColumn("Mode");
Table.deleteColumn("Min");
Table.deleteColumn("Max");
Table.deleteColumn("XM");
Table.deleteColumn("YM");
Table.deleteColumn("Perim");
Table.deleteColumn("BX");
Table.deleteColumn("BY");
Table.deleteColumn("Major");
Table.deleteColumn("Minor");
Table.deleteColumn("Angle");
Table.deleteColumn("Slice");
Table.deleteColumn("Circ");
Table.deleteColumn("Feret");
Table.deleteColumn("IntDen");
Table.deleteColumn("Median");
Table.deleteColumn("Skew");
Table.deleteColumn("Kurt");
Table.deleteColumn("%Area");
Table.deleteColumn("RawIntDen");
Table.deleteColumn("FeretX");
Table.deleteColumn("FeretY");
Table.deleteColumn("FeretAngle");
Table.deleteColumn("MinFeret");
Table.deleteColumn("AR");
Table.deleteColumn("Round");
Table.deleteColumn("Solidity");
Table.deleteColumn("XStart");
Table.deleteColumn("YStart");
Table.deleteColumn("FeretAR");
Table.deleteColumn("Compact");
Table.deleteColumn("Extent");
Table.renameColumn("Area2", "Area");
Table.renameColumn("AR2", "AR");
Table.renameColumn("Solidity2", "Solidity");
Table.renameColumn("Feret2", "Feret");
Table.renameColumn("FeretAR2", "FeretAR");
Table.renameColumn("Extent2", "Extent");
Table.renameColumn("FeretAngle2", "FeretAngle");
Table.renameColumn("MinFeret2", "MinFeret");
Table.renameColumn("FeretX2", "FeretX");
Table.renameColumn("FeretY2", "FeretY");
Table.renameColumn("XM2", "XM");
Table.renameColumn("YM2", "YM");
Table.renameColumn("BX2", "BX");
Table.renameColumn("BY2", "BY");
Table.renameColumn("Major2", "Major");
Table.renameColumn("Minor2", "Minor");
Table.renameColumn("Angle2", "Angle");
Table.renameColumn("XStart2", "XStart");
Table.renameColumn("YStart2", "YStart");
Table.update;
// SAVE RESULTS
if(chosenOption[0]==1) {
saveAs("Results", dir3+"RESULTS_"+image_title+".csv");
}
run("Clear Results");
run("Close");
// SAVE SUMMARY, COUNT AND SAVE "PARTICLE DENSITY", CLEAN THE TABLE
selectWindow("Summary");
// CALCULATE "Particle Density"
particle_count = Table.get("Count", 0);
total_area = Table.get("Total Area", 0);
particle_density = particle_count/total_area;
//REARRANGE THE "SUMMARY" TABLE
Table.set("Particle Density", 0, particle_density);
Table.renameColumn("Count", "Particle Count");
Table.renameColumn("%Area", "Area Fraction");
Table.renameColumn("Perim.", "Perim");
Table.renameColumn("Circ.", "Circ");
code = "IntegratedDensity=IntDen; Perimeter=Perim; Circularity=Circ;"
+"Solidity2=Solidity; Major2=Major; Minor2=Minor;"
+"Angle2=Angle; Feret2=Feret; FeretX2=FeretX;"
+"FeretY2=FeretY; FeretAngle2=FeretAngle; MinFeret2=MinFeret";
Table.applyMacro(code);
Table.deleteColumn("Perim");
Table.deleteColumn("Major");
Table.deleteColumn("Minor");
Table.deleteColumn("Angle");
Table.deleteColumn("Circ");
Table.deleteColumn("Solidity");
Table.deleteColumn("Feret");
Table.deleteColumn("FeretX");
Table.deleteColumn("FeretY");
Table.deleteColumn("FeretAngle");
Table.deleteColumn("MinFeret");
Table.deleteColumn("IntDen");
Table.deleteColumn("Mean");
Table.deleteColumn("Mode");
Table.deleteColumn("Median");
Table.deleteColumn("Skew");
Table.deleteColumn("Kurt");
Table.renameColumn("IntegratedDensity", "Integrated Density");
Table.renameColumn("Solidity2", "Solidity");
Table.renameColumn("Major2", "Major");
Table.renameColumn("Minor2", "Minor");
Table.renameColumn("Angle2", "Angle");
Table.renameColumn("Feret2", "Feret");
Table.renameColumn("FeretX2", "FeretX");
Table.renameColumn("FeretY2", "FeretY");
Table.renameColumn("FeretAngle2", "FeretAngle");
Table.renameColumn("MinFeret2", "MinFeret");
Table.update;
if(chosenOption[1]==1) {
saveAs("Results", dir3+"SUMMARY_"+image_title+".csv");
}
run("Clear Results");
run("Close");
// SAVE PROCESSED IMAGE
selectWindow(image_title);
if(image_processed==true) {
saveAs("tiff", dir3+"PROCESSED_"+image_title);
}
else {
rename("PROCESSED_"+image_title);
}
// SAVE OUTLINED IMAGE
selectWindow(outlined_image_title);
if(image_outlined==true) {
saveAs("tiff", dir3+"OUTLINED_"+image_title);
}
else {
rename("OUTLINED_"+image_title);
}
close();
// ==========RUN AND SAVE CLUSTER INDICATION (OPTIONALLY)==========
if(chosenOption[4]==1) {
// MAKE DIRECTORY FOR CLUSTER OUTPUTS
dir_cluster=dir3+"CLUSTERS"+File.separator;
File.makeDirectory(dir_cluster);
run("Set Scale...", "distance=1 known=1 pixel=1 unit=um global");
run("Cluster Indicator", "");
selectWindow("PROCESSED_"+image_title);
if(image_clustered==true) {
saveAs("png", dir_cluster+"CLUSTERED_"+image_title);
}
else {
rename("CLUSTERED_"+image_title);
}
clustered_image_title = getTitle();
if (isOpen("Log")) {
selectWindow("Log");
saveAs("Text", dir_cluster+"CLUSTERS_"+image_title+".txt");
print("\\Clear");
run("Close");
}
run("Set Scale...", "distance="+length_of_line+" known="+known_distance+" pixel=1 unit="+unit_of_length+" global");
}
// ==========RUN AREA DISTRIBUTION (OPTIONALLY)==========
if(chosenOption[3]==1) {
// SET BATCH MODE OFF (DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(false);
// MAKE SLICES OF THE IMAGE
run("Montage to Stack...", "images_per_row="+input_images_per_row+" images_per_column="+input_images_per_column+" border=0");
stack = getTitle();
run("Set Measurements...", "area mean centroid feret's area_fraction stack display redirect=None decimal=3");
// GET NUMBER OF SLICES AND ASSIGN IT TO THE VARIABLE
n = nSlices;
// MAKE DIRECTORY FOR PLOT OUTPUTS
dir_plot=dir3+"PLOTS"+File.separator;
File.makeDirectory(dir_plot);
// MAKE MONTAGE
if (image_montage==true) {
selectWindow(stack);
run("Make Montage...", "columns="+input_images_per_row+" rows="+input_images_per_column+" scale=0.50 font=50 border=3 label");
selectWindow("Montage");
saveAs("Tiff", dir_plot+"Montage of "+image_title+".tif");
close();
}
// START OPERATIONS
for (slice=1; slice<=n; slice++) {
showProgress(slice, n);
selectWindow(stack);
Stack.setSlice(slice);
if(image_slices==true) {
saveAs("PNG", dir_plot+"Slice #"+slice+" of "+image_title+".png");
}
else {
rename("Slice #"+slice+" of "+image_title+".png");
}
rename(stack);
run("Analyze Particles...", " size="+min_size+"-"+max_size+" circularity="+min_circularity+"-"+max_circularity+" show=Nothing slice");
saveAs("Results", dir_plot+"Overall Analysis Results of slice #"+slice+" of "+image_title+".csv");
run("Distribution Plotter", "parameter=Area tabulate=[Number of values] automatic=Freedman-Diaconis bins=24");
low_resolution_plot_title = getTitle();
Plot.getValues(x, y);
// CLEAN "RESULTS" TABLE AND TRANSFER PLOT VALUES TO IT
run("Clear Results");
Table.setColumn("X",x);
Table.setColumn("Y (bin value)",y);
Table.update;
saveAs("Results", dir_plot+"Distribution Plot (bin) values of slice #"+slice+" of "+image_title+".csv");
run("Clear Results");
run("Close");
// GENERATE HIGH RESOLUTION PLOT
Plot.makeHighResolution("Histograms for slice #"+slice+" of "+image_title+"",4.0);
// SAVE THE PLOT
saveAs("PNG", dir_plot+"Distribution Plot of slice #"+slice+" of "+image_title+".png");
high_resolution_plot_title = getTitle();
// CLOSE THE WINDOWS
selectWindow(low_resolution_plot_title);
run("Close");
selectWindow(high_resolution_plot_title);
run("Close");
}
// CLOSE "STACK" WINDOW
selectWindow(stack);
run("Close");
}
// ==========RUN INTERPARTICLE DISTANCES (OPTIONALLY)==========
// GET MAXIMUM NEIGHBOR DISTANCE (USING GUI)
if(chosenOption[2]==1) {
// MAKE DIRECTORY FOR INTERPARTICLE OUTPUTS
dir_interparticle=dir3+"INTERPARTICLE_DISTANCES"+File.separator;
File.makeDirectory(dir_interparticle);
Dialog.create("Maximum Neighbor Distance");
Dialog.addNumber("Maximum neighbor distance taken to calculations (in um):", 1);
Dialog.setInsets(20,0,0);
Dialog.addMessage("IMPORTANT: Unfortunetaly, the next window cannot be automated.");
Dialog.setInsets(0,0,0);
Dialog.addMessage("To correctly run the calculations, in the next window:\n---> Specify the same number\n---> Mark all the three checkboxes");
Dialog.show();
maximum_neighbor_distance = Dialog.getNumber();
// SET BATCH MODE OFF (DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(false);
// RUN ANALYSIS AND SHOW "MASKS" IMAGE
run("Extended Particle Analyzer", " area="+min_size+"-"+max_size+" circularity="+min_circularity+"-"+max_circularity+" show=Masks redirect=None keep=None display summarize"+analysis_options+"");
// CLOSE "PROCESSED" IMAGE
if(chosenOption[4]==1) {
selectWindow(clustered_image_title);
close();
}
else {
selectWindow("PROCESSED_"+image_title);
close();
}
// INVERT COLORS OF "MASKS" IMAGE
setOption("BlackBackground", true);
run("Make Binary");
// SAVE MASKS WINDOW (OPTIONALLY)
if(image_masks==true) {
saveAs("tiff", dir3+"MASKS_"+image_title);
}
else {
rename("MASKS_"+image_title);
}
// RUN INTERPARTICLE DISTANCE (WAIT FOR USER INPUT AS THE FUNCTION CANNOT BE AUTOMATED)
run("Graph ", "");
// SAVE ADJACENCIES
selectWindow("Adjacencies");
if(image_interparticle==true) {
saveAs("png", dir_interparticle+"INTERPARTICLE_ADJACENCIES_"+image_title);
}
else {
rename("INTERPARTICLE_ADJACENCIES_"+image_title);
}
//SAVE "LOG" WINDOW
selectWindow("Log");
saveAs("Text", dir_interparticle+"INTERPARTICLE_CONNECTIONS("+year+"-"+month+"-"+dayOfMonth+" "+hour+";"+minute+";"+second+").txt");
//TRANSFER "DISTANCE MATRIX" TO "RESULTS" TABLE
selectWindow("Results");
run("Clear Results");
close();
selectWindow("Distance Matrix");
Table.rename("Distance Matrix", "Results");
//SAVE "DISTANCE MATRIX"
selectWindow("Results");
saveAs("Results", dir_interparticle+"INTERPARTICLE_DISTANCE_MATRIX_"+image_title+".csv");
// GET COLUMNS OF "RESULTS" TABLE
headings = split(String.getResultsHeadings);
// CALCULATIONS ON INTERPARTICLE DISTANCES
for (row=0; row<nResults(); row++) {
for (col=0; col<lengthOf(headings); col++) {
interp_distance = getResult(headings[col],row);
if ((interp_distance>0) && (interp_distance<maximum_neighbor_distance)) {
interp_total_number = interp_total_number+1;
// MAX DISTANCE
if (interp_distance>interp_max_distance){
interp_max_distance=interp_distance;
}
// TOTAL DISTANCE
if (interp_distance < maximum_neighbor_distance){
interp_total_distance += interp_distance;
}
}
}
}
// AVERAGE DISTANCE
interp_average_distance=interp_total_distance/interp_total_number;
// MIN DISTANCE
interp_min_distance=interp_max_distance;
for (row=0; row<nResults(); row++) {
for (col=0; col<lengthOf(headings); col++) {
interp_distance = getResult(headings[col],row);
if ((interp_distance>0) && (interp_distance<maximum_neighbor_distance)) {
// VARIANCE DISTANCE
interp_total_variance=interp_total_variance+(interp_distance-interp_average_distance)*(interp_distance-interp_average_distance);
interp_variance=interp_total_variance/(interp_total_number-1);
//SD OF DISTANCE
interp_sd=sqrt(interp_variance);
}
// MIN DISTANCE
if ((interp_distance>0) && (interp_distance<maximum_neighbor_distance) && (interp_distance<interp_min_distance)) {
interp_min_distance=interp_distance;
}
}
}
// SAVE INTERPARTICLE ANALYSIS
if(chosenOption[2]==1) {
print("\\Clear");
print("========== INTERPARTICLE DISTANCES ==========");
print("Number of connections below the maximum neighbor distance: "+interp_total_number/2+"");
print("\nTotal interparticle distance: "+interp_total_distance+"");
print("\nMinimum interparticle distance: "+interp_min_distance+"");
print("Maximum interparticle distance: "+interp_max_distance+"");
print("Average interparticle distance: "+interp_average_distance+"");
print("\nVariance of interparticle distance: "+interp_variance+"");
print("SD of interparticle distance: "+interp_sd+"");
selectWindow("Log");
saveAs("Text", dir_interparticle+"INTERPARTICLE_DISTANCES("+year+"-"+month+"-"+dayOfMonth+" "+hour+";"+minute+";"+second+").txt");
run("Close");
}
}
//CLOSE AND CLEAR OPENED WINDOWS (IF THEY EXIST)
if (isOpen("Log")) {
selectWindow("Log");
print("\\Clear");
run("Close");
}
if (isOpen("Results")) {
selectWindow("Results");
run("Clear Results");
run("Close");
}
if (isOpen("Summary")) {
selectWindow("Summary");
Table.deleteRows(0, Table.size, "Summary");
run("Close");
}
close("*");
// SET BATCH MODE OFF (DISPLAY IMAGES WHILE RUNNING MACRO)
setBatchMode(false);
// ==========INFORM THE USER ABOUT SUCCESSFUL OPERATION==========
// SAVE ANALYSIS SPECIFICATIONS (OPTIONALLY)
if(chosenOption[6]==1) {
print("========== ANALYSIS SPECIFICATIONS ==========\n");
print("\n=== DAY AND TIME OF ANALYSIS ===");
print(""+TimeString+"");
print("\n=== INPUT/OUTPUT FILES ===");
print("Output folder: "+dir3+"");
print("Directory of input file: "+input_image+"");