-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathCMCImacrocourse_contents.tex
3148 lines (2573 loc) · 159 KB
/
CMCImacrocourse_contents.tex
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
\section{Aim: Why do we write ImageJ macro?}
Learn the basics of how to automate image processing and analysis using ImageJ macro language. We write macros to decrease our workloads in image processing: less clicking and less repetitive procedures.
\section{Introduction}
\subsection{ImageJ macro makes your life easier}
To customize functions in ImageJ, a typical way is to write a Java plugin that directly accesses the application interface of ImageJ.
This is a powerful method for customizing your own tool but in many cases is a bit too much for small tasks we often encounter in biological research projects. Compared to the Java programming, ImageJ macro is much easier for quickly solving problems.
A typical usage is to automate repetitive tasks with hundreds of times of mouse clicking. Clicking ranges from menu selections to inspection of single pixel value. By writing a macro, we could save such exhausting job to a single execution of a macro file, which is a text file with a sequence of image processing commands. As ImageJ macro functions are directly mirroring the GUI menu items, one could intuitively learn how to write one's own macro even without much experiences in programming.
Another important aspect of writing a macro is its role as a documentation: as the processing becomes complex, we easily forget the steps and details of the procedures and the values of parameters that were used for that task. Even if your job is not a repetitive one, a macro written for a task becomes a valuable record of what was done to the image, and ensures the \textbf{reproducibility} of your image analysis.
\subsection{Other ways to Customize ImageJ}
This and the next section explain the general capability of extending ImageJ by programming. If you are not interested in general aspects, you could skip these sections.
ImageJ could be extended by writing a Java plugin. Though you need to know or learn the Java programming, this capability affords almost infinite possibilities; you could write any kind of processing / analysis functions you could imagine. Compared to the plugin development by Java, ImageJ Macro language is much easier and lighter but has some limitations. It might be worth mentioning here what would be the limitations.
\begin{enumerate}
\item If you need to process large images or stacks with many steps,
you might recognize that it is slow. Some benchmarks indicate that a plugin would be about 40 times faster than a macro.
\item Macro cannot be used as a library
\footnote{It is possible to write a macro in a library fashion using the function \ilcom{eval} and use it from another macro,
but this is not as robust and as clear as it is in Java, which is a language designed to be so.}.
In Java, once a class is written, this could be used later again for another class.
\item Macro is not efficient in implementing real-time interactive input
during when the macro function is executed;
\textit{e.g.} If you want to design a program that requires real-time user input
to select a ROI interactively.
Macro could only do such interactive tasks by closely related macro set with each macro doing each step of interaction.
\item Macro is tightly coupled to GUI (Image Window), so that when you want to process images without showing them on desktop, macros are not really an optimal solution.
\end{enumerate}
If you become unsatisfied with these limitations,
learning more complicated but more flexible Java plugin development is recommended.
\subsection{Comparison with Other scripting languages}
Besides ImageJ macro, there are several scripting languages that
could be used for programming with ImageJ. The bare ImageJ supports Javascript (Rhino). Recent versions of ImageJ (> 1.47m, since 6 March 2013), Jython became included in the menu as well.
In the Fiji distribution, you could use the following languages off the shelf
\footnote{As of June, 2015}
:
\begin{itemize}
\item Javascript
\item BeanShell
\item Jython (Java implemented Python)
\item JRuby (Java implemented Ruby)
\item Clojure
\item Groovy
\end{itemize}
If you set up an environment by yourself, other languages such as Scala can be used.
Compared to the ImageJ macro language, all these languages are more general scripting languages.
There are pros and cons. Pros of using the ImageJ Macro compared to these scripting languages are:
\begin{itemize}
\item Easy to learn.
ImageJ macro build-in functions are mirrors of ImageJ menu, so scripting is intuitive if you know ImageJ already.
Macro recorder is a handy tool for finding out the macro function you need.
\item A significant hurdle for coding with general scripting languages is that one must know the
\textbf{ImageJ Java API} well, meaning that you basically have to know
fundamentals of Java programming language for using these scripting languages.
\item You could have multiple macros in one file (called 'Macro-set").
This is useful for packaging complex processing tasks.
\end{itemize}
Thus, ImageJ macro language is the easiest way to access the scripting
capability of ImageJ.
There are several disadvantages of ImageJ macro compared to other
scripting languages. First is its generality. Since others are based on major scripting languages, you do not need to learn a lot if you know one of them already. For example, if you know Python already,
it should be easy for you to start writing codes in Jython (note: but you also need to know about Java).
The second disadvantage of ImageJ macro is its extendability.
Codes you wrote could only be recycled by copying and pasting
\footnote{One could also use getArgument() and File related functions to pass
arguments from a macro file to the other, but ImageJ macro is not designed to
construct a library of functions.}.
With other scripting languages, once you write a code, it could be used from other programs
\footnote{ Calling other Javascript file from another Javascript file had been difficult but became easily possible in the Fiji distribution from March 2012.}.
Lastly, although ImageJ Macro processes with a speed comparable to
Javascript and Jython, it is slow compared to Clojure and Scala.
\subsection{How to learn Macro programming}
In this course, you will encounter many example codes.
You will write example codes using your own computer and run those macros.
Modifying these examples by yourself is an important learning process as in most
cases, that is the way to acquire programming literacy. There are many excellent macro codes you could find in Internet, which could be used as starting points for writing your code\footnote{200+ macros are available in ImageJ web site.
\href{http://rsb.info.nih.gov/ij/macros/}{http://rsb.info.nih.gov/ij/macros/}}.
\subsection{Summary}
ImageJ Macro radically decreases your work load and is a practical way to keep your image analysis workflow in text file. Less workload provides more time for us to analyze details of image data.
The potential of macro is similar to other scripting languages and Java Plugins, all adding capability to customize your image analysis. For coding interactive procedures PlugIn works better than macro. Macro cannot be used as a library.
Image processing by macro is slower than that by Java written plugins.
\newpage
\section{Basics}
\label{sec:ImageJMacroBasics}
\subsection{``Hello World!''}
We first try writing a simple macro that prints ''Hello World!'' in the log window of ImageJ.
To open the nacro editor, select \ijmenu{[PlugIns -> New -> Macro]} from the menu.
This will create a new window where you can write macro (we call this ''macro
editor'', fig\ref{fig_MacroEditor}).
\begin{indentFiji}
In Fiji you could use more advanced interface called ''script editor''
by \ijmenu{[File -> New -> Script]}. It should look like \ref{fig_ScriptEditor}.
In the script editor, you already see a blank text field where you could write a macro.
From script editor's own menu, select \ijmenu{[Language -> IJ1 Macro]}.
By sepcifying the language, syntax highlighter turns on to do automatic coloring of ImageJ functions.\footnote{The macro editor (also the Fiji script editor) has simple debugger function. Debugger assists you to correct mistakes in the code.
This is convenient when the code becomes long.
Macro can be written in any text editor such as "Notepad" in Windows but of course
there is no debugger function available in this case.}.
\end{indentFiji}
Later when you want to start writing another new macro, just generate a new tab by \ijmenu{[File > New]} and then select \ijmenu{[Language -> ImageJ Macro]} again.
Then write your first macro as shown below. In the second line DON'T forget to
indent the line using tab or spaces\footnote{In ImageJ macro, indenting is not a required
syntax for writing macros but doing this will be very very helpful afterward. You
will understand it as the macro you write becomes longer}. Omit the line
numbers! These numbers were added just for explanation.
%Code 1
%\begin{lstlisting}
%macro "print_out" {
% print("Hello World!");
%}
%\end{lstlisting}
\lstinputlisting{code/code01.ijm}
%\lstinputlisting[language=Java]{code/code01.ijm}
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/editor_helloworld_IJ.png}
\caption{Macro Editor of ImageJ} \label{fig_MacroEditor}
\end{center}
\end{figure}
\begin{figure}[hbtp]
\begin{center}
\includegraphics[scale=1.0]{fig/editor_helloworld_singleline.png}
\caption{Script Editor of the Fiji distribution} \label{fig_ScriptEditor}
\end{center}
\end{figure}
From the macro editor menu, running the code by \ijmenu{[Macros->
Run Macro]}\footnote{"Macros" in the menu appears only when the macro editing
window is active}. You could also run the code by shortcut keys (Windows:
ctrl-r, OSX command-r) as well.
\begin{indentFiji}
Fiji: Use \ijmenu{[Run -> Run]} from the script editor menu. Shortcut keys are
same as in ImageJ. You could also use ``run'' button in the script editor.
\end{indentFiji}
This will create a new window "Log". Within the log window, "Hello World" will
be printed.
\begin{figure}[hbtp]
\begin{center}
\includegraphics[scale=1.0]{fig/helloworld_logwindow.png}
\caption{Hello World Output} \label{fig_HelloWorldLog}
\end{center}
\end{figure}
Explanation for the Code 1:\\
\begin{itemize}
\item line 1: You are declaring that a macro code starts and the code is contained between
curly braces \{\}. "print\_out" will be the name of macro.
\item line2: print() function orders ImageJ to print out the content within the parenthesis
in the "Log" window. The text to be printed must be contained within the double quotes ("").
The best reference for ImageJ macro functions is in the ImageJ web site
\footnote{\url{http://rsbweb.nih.gov/ij/developer/macro/functions.html}}.
For example, you could find definition of print("") function on the web site as quoted below:\\
%\item
\begin{indentCom}
%\begin{minipage}[c][18em][c]{0.85\textwidth}
\fbox{
\parbox[b][20em][c]{0.80\textwidth}{
\textbf{print(string)}\\
Outputs a string to the "Log" window. Numeric arguments are automatically converted to strings.
The print() function accepts multiple arguments. For example, you can use print(x,y,width, height)
instead of print(x+" "+y+" "+width+" "+height).
If the first argument is a file handle returned by File.open(path),
then the second is saved in the referred file (see SaveTextFileDemo).
Numeric expressions are automatically converted to strings using four decimal places,
or use the \ilcom{d2s} function to specify the decimal places.
For example, print(2/3) outputs "0.6667" but print(d2s(2/3,1)) outputs "0.7".
}
}
\end{indentCom}
\item line 3: a brace tells ImageJ that the code "print\_out" finishes at this line.
\end{itemize}
So that was the very basic of how you use a macro. To integrate the macro into the ImageJ Menu bar,
the macro must be "installed". To do so, in the editor menu, \ijmenu{[Macros -> Install Macros]}
\begin{indentFiji}
Fiji: [Run -> Install Macro]).
\end{indentFiji}
Check IJ menu \ijmenu{[Macros -> ]} to see that the macro is now in the menu.\\
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/firstMacroInMenu.png}
\caption{Macro Now in ImageJ menu} \label{fig_MacroInMenu}
\end{center}
\end{figure}
Macro can be saved as a file and can be directly installed also.
In the editor, do \ijmenu{[File -> Save]}. Saving dialogue window appears,
and just save the file wherever you can remember afterwards .
To install the macro, do \ijmenu{[PlugIns -> Macro -> Install\ldots]}
Select the macro file you want to install.\\
%\begin{indentexercise}{1cm}
\begin{indentexercise}{1}
\item Add another line \texttt{"print("\textbackslash{}\textbackslash{}Clear");"}
after the second line (below, code 1.5. don't forget the semi-colon at the end!).
\item \lstinputlisting{code/code01_5.ijm}
Then test also another macro when you insert the same function in the third line (code 1.75).
What happened?
\item \lstinputlisting{code/code01_75.ijm}
\end{indentexercise}
\begin{indentexercise}{2}
\item Try modifying the third line in code 1.5
and check that the modified text will be printed in the "Log" window. \\
\end{indentexercise}
\begin{indentexercise}{3}
\item Multiple macros can exist in a single file. We call this \textbf{"macro sets"}.
Duplicate the code you wrote by copying and pasting it under the first macro.
The second macro should have a different name. In the example shown in fig.
\ref{fig_MacroSetInMenu}, the second macro is named "pirnt\_out2".
\end{indentexercise}
\begin{figure}[h!]
\begin{center}
\includegraphics[scale=0.6]{fig/editor_MacroSet.png}
\caption{Macro Set} \label{fig_MacroSetInMenu}
\end{center}
\end{figure}
When macro is properly declared in this way, you could install the macro to have it as a menu item. To do so, in the editor menu select:
\begin{indentFiji}
[Run -> Install Macro]).
\end{indentFiji}
In the main menu you should no be able to see the macro names under \ijmenu{[Plugins > Macros > ]}.
\subsection{Variables and Strings}
Texts such as "Hello World!" can be represented by a variable
\footnote{there is no declaration of types, such as number or string, in ImageJ macro.}.
Let's understand this by examining a short macro below.
\lstinputlisting{code/code02.ijm}
\ilcom{text} is a "String Variable" or simply a "String".
ImageJ prepares a memory space for this variable, and you can change the content by re-defining the content. Two (or maybe more) variables could be used to construct another variable.
\lstinputlisting{code/code03.ijm}
The above operation concatenates content of \ilcom{text2} to the content of \ilcom{text1} and produces a third variable \ilcom{text3} that holds the result of concatenation. It should be noted here, that macro has two ways of usage for \ilcom{+}. What we tested in above is ``concatenation''. Another usage is ``addition'' in the next section.
\begin{indentexercise}{1}
\item Add more string variables and make a longer sentence.\\
\end{indentexercise}
It is also possible to store a number in a variable. For example, \\
\begin{lstlisting}[numbers=none]
text = 256;
\end{lstlisting}
With this assignment, the variable is now a "numerical variable" or simply "variable".
In other programming languages such as C or Java, difference between numbers and characters matters a lot.
In ImageJ macro you do not have to care whether the variable is number or string (we call them ``types'') ad they are defined automatically by the type of value provided for a variable, and this makes the macro coding to be light and easy. However, since types are implicitly defined without declaration it could cause simple mistakes such as type mismatching.
So be sure keep the difference in types DOES matter but they are not shown in the code. We will see an example of such confusion,
and also a way to avoid the confusion.
Test the following macro to see how the numerical variable works.
\lstinputlisting{code/code04.ijm}
Did you get some results printed out? It should, but you should read the code carefully as there is a small trick in this code. This trick is something special in IJ macro language compared to other general scripting languages.
You might have noticed a strange expression at line 8, in the way it assigns the variable \ilcom{txt}.
It starts with double quotation marks. \\
%\lstinputlisting[language=Java, linerange={8-8}, numbers=none]{code/code04.ijm}
\begin{lstlisting}[numbers=none]
txt= "" + a + "+" + b + "=" + c;
\end{lstlisting}
Seemingly this looks like meaningless.
If you define ilcom{txt} without the first "useless" quotation marks, then it will be like\\
\begin{lstlisting}[numbers=none]
txt= a + "+"+ b + "=" + c;
\end{lstlisting}
Theoretically this should work,
since the double quote does not have any content so its presence should be meaningless. But if you try to run this what it seems to be straight-forward assignment,
ImageJ returns an error message.
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/ErrorStringNumericFunction.png}
\caption{Error with Variable Assignment} \label{fig_ErrorVariable}
\end{center}
\end{figure}
This is because when ImageJ scans through the macro from top to bottom, line by line,
it reaches the line for the assignment of the variable \ilcom{txt} and first sees the variable \ilcom{a} and interprets that \ilcom{txt} should be a numerical variable
(or function), since \ilcom{a} is known to be a number as it was defined so in one of the lines above. Then ImageJ goes on interpreting rightward thinking that this is math. Then finding a "+" which surprisingly is a character
ImageJ cannot interpret string variable within a numerical function, so it returns an error message. The macro aborts.
To overcome this problem, the programmer can tell ImageJ that
\textit{txt} is a string function at the beginning of the assignment
by putting a set of double quote. This tells the interpreter that this assignment is a string concatenation assignment and not a numerical assignment.
ImageJ does handle numerical values within string function,
so the line is interpreted without problem and prints out the result successfully. Note that such confusion of string and numerical types are rarely seen in general scripting languages and specific to ImageJ macro language.
\begin{indentexercise}{2}
Modify the code 4, so that the calculation involves subtraction (-), multiplication (*) and division (/).
\end{indentexercise}
\subsection{Parameter Input by User}
At some point you might want to make a macro to ask the user to input numerical
values or file names. We now learn how to do that, by first examining the
following code. Run the code first.
\lstinputlisting{code/code05.ijm}
Running this macro, a dialogue window pops-up.
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/getNumberDialog.png}
\caption{getNumber Dialog} \label{fig_getNUmber}
\end{center}
\end{figure}
The function \textit{getNumber} consists of two parameters (programmers call such parameters "arguments" so we use this word in the reminder of this textbook).
\begin{indentCom}
\textbf{getNumber}(message string, default number)
\end{indentCom}
The first argument is a string wrapped by double quotes (see code 5, line 3
and 4). This string will appear in the dialog window such as shown above.
Default number will appear in the input field in the dialog window,
and the user is expected to modifies this default number.
When OK button is clicked, the number given by the user will be returned to
the macro and then substituted to a variable. In the above case, this could be
either \textit{a} or \textit{b}.
To ask a user for providing a string in dialog, following is an example.
\lstinputlisting[morekeywords={*, getString}]{code/code06.ijm}
The function \textbf{getString} also has two arguments,
and only the difference is that the user input will be treated as a string. \\
\begin{indentexercise}{1}
Run the code 6 and input 1 for a and 2 for b. What happened? Explain the reason.
\end{indentexercise}
\subsection{Recording ImageJ macro functions}
There are many commands in ImageJ as you could see them by exploring the menu tree. In ImageJ native distribbution, there are ca. 500 commands. In the Fiji distribution, there are 900+ commands. Some plugins are not macro-ready, but except for those spacial cases almost all of these commands can be accessed by build-in macro functions. We then encounter a problem: how do we find a macro function that does what we want to do?
To show you how to find a function, we write a small macro that creates a new image, adds noise, blurs this image by Gaussian blurring, and then thresholds the image. There is a convenient tool called \textbf{Command Recorder}.
Do \ijmenu{[PlugIns -> Macros -> Record\ldots]}. A window shown in figure
\ref{fig_macroRecorderBlank} opens.
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/MacroRecorderBlank.png}
\caption{Macro Recorder} \label{fig_macroRecorderBlank}
\end{center}
\end{figure}
All the menu commands that you execute will be printed out as a history of macro functions in this window. For composing a macro using this recorder, we first do the processing manually from the menu as follows.
\begin{itemize}
\item Prepare a new image using \ijmenu{[File -> New]} command. The size of the image can be anything.
\item Then do \ijmenu{[Process -> Noise -> Salt and Pepper]} (Fig.
\ref{fig_SaltAndPepper}).
\item \ijmenu{[Process -> Filters -> Gaussian Blur]} (use Sigma = 2.0).
\item \ijmenu{[Image -> Adjust -> Threshold\ldots]}. Toggle the slider to make
signals red. Check "Dark Background", then click "Apply".
\end{itemize}
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/SaltandPepper300.png}
\caption{A demo image for Recording Macro}
\label{fig_SaltAndPepper}
\end{center}
\end{figure}
Now, check the Command Recorder window.
It should now look like Fig. \ref{fig_macroRecorderFilled}.
Each line is a macro function that corresponds to a menu command you selected.
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/MacroRecorderFilled.png}
\caption{Macro Recorder after some lines Recorded}
\label{fig_macroRecorderFilled}
\end{center}
\end{figure}
These texts generated in the recorder can be used as it is in your macro. You could copy and paste them\footnote{In case of OSX, you might probably need to click ``Create'' button to generate a duplicate of macro functions in a new script window. Then you could copy the macro functions from there.}. Compose a macro like below by copying and pasting the macro functions in the recorder. Delete the lines that are commented out (lines that begin with "//" are lines that are skipped by the macro interpreter).
\lstinputlisting{code/code06_9.ijm}
Run the macro! \ldots I hope that you are amazed by now with the power of Macro
Recorder! Now, you could simply add a line at the top and bottom to package this in a named macro by curly braces. This is optional in the current case, but it's always good to keep your macro packaged since the boundary of the macro becomes clear.
\lstinputlisting{code/code07.ijm}
The third line in the above macro has a function \ilcom{newImage()}. This
function creates a new image. It has five arguments (in coding jargon, we say
there are "five arguments"). To know what these arguments are,
the quickest way is to read the Build-In Macro Function page in ImageJ web site\footnote{\url{http://rsbweb.nih.gov/ij/developer/macro/functions.html}}.
In case of the function \ilcom{newImage}, the description looks like this.
\begin{indentCom}
\fbox{
\parbox[b][16em][c]{0.80\textwidth}{
\textbf{newImage}(title, type, width, height, depth)\\
Opens a new image or stack using the name title.
The string type should contain "8-bit", "16-bit", "32-bit" or "RGB".
In addition, it can contain "white", "black" or "ramp" (the default is "white").
As an example, use "16-bit ramp" to create a 16-bit image containing a grayscale ramp. Width and height specify the width and height of the image in pixels. Depth specifies the number of stack slices.
}}
\end{indentCom}
Using this information, you can modify the macro to change the size of the image.
\begin{indentexercise}{1}
Modify the code 8, so that user can input the desired Gaussian sigma.
\end{indentexercise}
Other optional lines you could add to the macro are ``comments''. This does not affect the macro but adding some comment about what the macro does helps you to understand what the macro is doing when you open the file some time later. There are two ways to add comment. One is the \textbf{block comment}. Texts bounded by \ilcom{ /*} and \ilcom{*/} will be ignored by interpreter. Another is the line comment. Texts in a line starting with double slash \ilcom{//} will be ignored by the interpreter. Below is an example of commenting code 07.
\lstinputlisting{code/code07_1.ijm}
\subsection{Batch Processing using "batch macro" function}
In above macro, list of functions were wrapped inside macro "title"\{ code \}
so that these macro functions could be executed by single command from menu.
To apply such a sequence of macro functions for many images in a single folder
(say you have one-thousand images you want to contrast enhance and also to Gaussian-blur),
there are two ways. One way is to further extend the macro by adding file-accessing macro functions and
looping those functions (you will learn this later).
Another way is to do such "batch processing" by copy and pasting list of
macro functions to batch-processing interface.
This interface could be used by \ijmenu{[Process -> Batch -> Macro]}
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.4]{fig/BatchProcessing.png}
\caption{Batch Processing Dialog} \label{fig_BatchProcessInterface}
\end{center}
\end{figure}
In "Input" field, select the folder where image files are stored.
In output field, select a destination folder where processed images will be stored.
You then copy and paste the list of macro functions in the code field such as
shown in Fig. \ref{fig_BatchProcessInterface}.
In the case shown in this figure, line 6 to 9 was copied and pasted.
Clicking "Process" button will start the processing.
\newpage
\section{Conditions and Loops}
In many cases, we want to iterate certain processing steps many times (see "Loops" in the figure \ref{fig_scriptscheme}), or we want to limit some of the process in the program only for certain situations (see "Conditions": in the figure \ref{fig_scriptscheme}). In this section we learn how to include these loops and conditional behaviors into macro.
\begin{figure}[htbp]
\begin{center}
\includegraphics[width=\textwidth]{fig/fig23_1_ScriptSchemes.png}
\caption{Schematic view of conditions and loops. Straightly top to bottom, line by line processing (left) and macro with loops (middle) and with a condition (right).} \label{fig_scriptscheme}
\end{center}
\end{figure}
\subsection{Loop: for-looping}
Here is a simple example macro using for-loop. Write the macro in your editor and run it.
\lstinputlisting[morekeywords={*, for}]{code/code09.ijm}
The result should look like figure \ref{fig_whateverOut}.
%whatever x 5 figure
\begin{figure}[h!]
\begin{center}
\includegraphics[scale=0.6]{fig/fig2311_whatever5.png}
\caption{Code 9 output in Log Window}
\label{fig_whateverOut}
\end{center}
\end{figure}
\begin{itemize}
\item Line 3 asks the user to input a string (we did this already).
If user does not change the default text ("whatever") and click "OK",
then the macro interpreter proceeds to line 4.
\item Line 4 \ilcom{for( i = 0 ; i < 5 ; i+= 1)} sets the number of loops.
Three parameters are required for "for" loop. The first parameter defines the variable used for the counting loop and its initial value (\ilcom{i = 0}). The second parameter sets the condition for exiting from the loop (\ilcom{i < 5}). Third parameter sets the step size of i, meaning that how much value is added per loop (\ilcom{i += 1}, could also be subtraction, multiplication, division e.g. \ilcom{i -= 1}).
Spaces between variables, numbers, operators and separators (e.g. semicolon, parenthesis) can be ignored and they could be written continuously. Macro runs without those spaces. However, this is not recommended for keeping a better readability of the code. Don't try to rush, make spaces!
\item After this \ilcom{for(\ldots;\ldots;\ldots)} statement, there is a brace (\{) at the end of line 4 and the second one (\}) in the line 6. These curly braces tell ImageJ to loop macro functions in between so the function in line 5 will be iterated according to the parameters defined in the parenthesis of \ilcom{for}.
Between braces, you could add as many more lines of macro functions as you want, including inner \ilcom{for}-loops and \ilcom{if-else} conditions.
\end{itemize}
So when the macro interpreter reaches line 4 and sees \ilcom{for(}, it starts looking inside the parenthesis and defines that the counting starts with 0 using a variable \ilcom{i}, and then line 5 is executed. The macro prints out "0 \ensuremath\colon whatever" using the content of \ilcom{i}, string \ilcom{\ensuremath\colon} and the string variable \ilcom{txt}.
Then in line 6 interpreter sees the boundary \ilcom{\}} and goes back to line 4 and adds 1 to i (because of \ilcom{i+=1}). i = 1 then, so \ilcom{i<5} is true. The interpreter proceeds to line 5 and executes the macro function and prints out "1\ensuremath\colon whatever". Such looping will continue until i = 5, since only by then \ilcom{i<5} is no longer true so interpreter exits from the for-loop. \\
\begin{indentexercise}{1}
(1) Change the first parameter in \ilcom{for(i=0;i<5;i+=1)} so that the macro prints out only 1 line.
(2) Change the second parameter in \ilcom{for(i=0;i<5;i+=1)} so that the macro prints out 10 lines.
(3) Change the third parameter in \ilcom{for(i=0;i<5;i+=1)} so that the macro prints out 10 lines.
\end{indentexercise}
\subsubsection{Stack Analysis by for-looping}
\label{sec:forloopStack}
One of frequently encountered tasks is image stack management,
such as measuring dynamics or multi-frame processing.
Many ImageJ functions work with only single frame within a stack.
Without macro programming, you need to execute the command while you flip the frame manually.
Macro programming enables you to automate this process.
Here is an example of measuring intensity change over time\footnote{What we write as macro here could be done with a single command \ilcom{[Image > Stacks > Plot Z-Profile]} but this only measures intensity. If you want to measure other values such as the minimum intensity, a macro should be written. }.
\lstinputlisting[morekeywords={*, run, setSlice, nSlices}]{code/code10.ijm}
\begin{itemize}
\item Line 3: \ilcom{nSlices} is a macro function that returns the number of slices in the active stack.
\item Line 4: Sets measurement parameters, from the menu would be \ilcom{[Analyze > Set measurements\ldots]}. In this case "mean min integrated" is added as part of the second argument. ``mean'' is the mean intensity, ``min'' is the minimum intensity and ``integrated'' is integrated density (total intensity). These keys for measured parameters could be known by using the command recorder.
You do not have to care for now about the "redirect" argument. ``decimal'' is the number of digits to
the right of the decimal point in real numbers displayed in the results table.
\item Line 5: clears the results table.
\item Line 6 to 9 is the loop. Loop starts from count i=0, and ends at i=frame-1. \ilcom{i++} is another way of writing \ilcom{i = i + 1}, so the increment is 1.
\item Line 7: calculates the current frame number.
\item Line 8: \ilcom{setSlice} function sets the frame according to the frame number calculated in line 6.
\item Line 9: actual measurement is done.
Result will be recorded in the memory and will be displayed in the Results table window.
\end{itemize}
Open an example stack \textbf{1703-2(3s-20s).stk}
\footnote{Some of you may realize that you used this sequence
in the Image Processing / Analysis Course for learning
stack measurements using Z-profiler \ilcom{[Image > Stacks > Plot Z-Profile]}. Now, you can program similar
device in macro.
Good thing about the custom program
is that you will be able to modify the program further to add more functions.
For example, You could measure the time course of standard deviation of
intensity within the selected ROI.}. This is a short sequence of FRAP analysis,
so the edge of the one of the cells is bleached and then fluorescence signal at that bleached position recovers by time.
Select the frapped region by ROI tool (such as in the figure below).
Execute the macro. Results will be printed in the Results window (see the table in the figure right: this table is showing only "Mean" column as only ``Mean Intensity'' was selected in the measurement option).
\begin{figure}[htbp]
\centering
% \subfloat[Setting a Segmented ROI at the FRAPped area.]{\label{fig:gull}\includegraphics[width=0.3\textwidth]{fig/fig2321a_frapimage.png}}
\subfloat[]{\label{fig:frapimage}\includegraphics[height = 60mm]{fig/fig2321a_frapimage.png}}
\quad
\subfloat[]{\label{fig:frapmeasured}\includegraphics[height = 60mm]{fig/fig2321b_frapResults.png}}
\caption{Measuring Stack Intensity Series. (a) Setting a Segmented ROI at the FRAPped area. (b) Results of Measuring Mean Intensity Dynamics.}
\label{fig:frapresults}
\end{figure}
Measurement parameters can be added as argument by modifying the line 4 in the code 10. "Set Measurement" could be added with more parameters to be measured, and the digits after the decimal point could be increased by increasing the number after ``decimal=''. For example,
\begin{lstlisting}[numbers=none]
run("Set Measurements...", "area mean standard modal min centroid center perimeter bounding integrated median stack redirect=None decimal=5");
\end{lstlisting}
\begin{indentexercise}{1}
Modify code 10 to include more measurement parameters (whatever you like), and test the macro. Check the results.
\end{indentexercise}
% figure
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.5]{fig/fig2322_moreResultsTable.png}
\caption{An example result after adding more measurement parameters.}
\label{fig_MoreMeasurementPara}
\end{center}
\end{figure}
\subsection{Loop: while-looping}
Another way of letting a part of macro to loop is \textbf{while}-statement. In this case, iteration is not defined strictly. Looping continues until certain condition is met. As soon as the condition is violated, macro interpreter goes out from the loop.
\subsubsection{Basics of while statement}
Here is a simple example macro using \ilcom{while}.
\lstinputlisting[morekeywords={*, while}]{code/code11.ijm}
This macro prints out characters 0 to 90 with a 10 increment.
%figure
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.4]{fig/fig2331_Code11out.png}
\caption{Output of code 11}
\label{fig:code11 output}
\end{center}
\end{figure}
\begin{itemize}
\item line 3: The macro interpreter first assigns 0 to the counter.
\item line 4: The interpreter evaluates if the counter value is less than or equal to 90. Since counter is initially 0\ldots
\item line 5: Printing function is executed.
\item line 6: counter is added with 10.
\item line 7: the interpreter realizes the end of "while" boundary and goes back to line 4. Since counter= 10 <= 90, line 5 is again executed\ldots and so on. When counter becomes 100 in line 6 after several more loops, counter is no longer <=90. So the interpreter goes out from the loop, moves to line 8. Then the macro is terminated.
\end{itemize}
Line 5 could be written in the following way as well.
\begin{lstlisting}[numbers=none]
counter += 10;
\end{lstlisting}
This means that "counter" is added with 10. Similarly, subtracting 10 from counter is
\begin{lstlisting}[numbers=none]
counter -= 10;
\end{lstlisting}
Multiplication is
\begin{lstlisting}[numbers=none]
counter *= 10;
\end{lstlisting}
Division is
\begin{lstlisting}[numbers=none]
counter /= 10;
\end{lstlisting}
If the increment is 1 or -1, (counter +=1 or counter-=1), then one could also write them as
\begin{lstlisting}[numbers=none]
counter++;
or
counter--;
\end{lstlisting}
These two last macro functions are said to work faster than +=1 or -=1, but I myself do not see much difference. Computers are fast enough these days.
\begin{indentexercise}{1}
(1) Try changing code 11 so that it uses "+=" sign.\\
(2) Change code 11 so that it uses "++" sign, and prints out integers from 0 to 9.\\
\end{indentexercise}
Evaluation of \ilcom{while} condition could also be at the end of loop. In this case, \ilcom{do} should be stated at the beginning of the loop. With do-while combination, the loop is always executed at least once, regardless of the condition defined by \ilcom{while} since macro interpreter reads lines from top to bottom. Try with the following exercise.
\begin{indentexercise}{2}
Change line 4 of code 11 to \ilcom{while (counter <0)} and check the effect (see below).
\end{indentexercise}
\lstinputlisting[morekeywords={*, while}]{code/code11_5.ijm}
Condition for the while-statement could be various. Here is a small list of comparison operators.
\begin{indentCom}
\begin{tabular*}{0.5\textwidth}{ l r }
< & less than \\
<= & less than or equal\\
> & greater than\\
>= & greater than or equal to\\
== & equal\\
!= & not equal\\
\end{tabular*}
\end{indentCom}
\begin{indentexercise}{3}
Modify code 11 so that the macro prints out numbers from 200 to 100, with an increment of -10.
\end{indentexercise}
\subsubsection{Why is there while-loop?}
An often raised question with the while-loop is why do we have two types of loops,
the for-loop and the while-loop. Answering to this question, they have different
flexibility. The for-loop is rather solid and the while-loop is more flexible. In the
example code below, the user is asked for a correct number and if the answer is wrong, the
question is asked 5 times repeatedly. Number of loop is not determined by the
programmer, but interactively when the code is running. We will study
the branching of the program based on if-else in the next section.
\lstinputlisting[morekeywords={*, while}]{code/code11_6.ijm}
Writing a similar code using the for-loop is possible but the code becomes tricky.
Below is the for-loop version of the above code.
\lstinputlisting[morekeywords={*, for}]{code/code11_7.ijm}
Note that the third argument of for-loop is missing. Since the variable
\ilcom{correct} does not change as long as the answer is wrong, we leave it not
incrementing nor decrementing. In such case we can leave the third argument
vacant.
\subsection{Conditions: if-else statements}
\subsubsection{Introducing if-else}
A macro program could have parts which are executed depending on some
conditions.
Here is an example of macro with conditions.
\lstinputlisting[morekeywords={*, if}]{code/code12.ijm}
\begin{itemize}
\item Line 3 The macro asks user to input a number and the number is substituted to the variable input\_num.
\item Line 4 Content of input\_num is evaluated. If input\_num is equal to 5, line 5 is executed and prints out the message in the Log window. Otherwise macro interpreter jumps to line 7, and ends the operation. By adding "else" which will be executed if input\_num is not 5, the macro prints out message in all cases (see code 12.5 for this if - else case).
\item Line 4 We used double equal signs for evaluating the value in the right side and the left side (e.g. \ilcom{if (a==5)}).
Note that the role of the sign \ilcom{=} is different from assignments, or substitution (e.g. \ilcom{a = b + c}).
\end{itemize}
%figure
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/fig2341_code12out.png}
\caption{Output of code 12}
\label{fig:code12 output}
\end{center}
\end{figure}
Now, we examine the content between
parenthesis after ``if'' in more detail.
Write the following code in your script editor and run it.
\lstinputlisting[morekeywords={*, ==}]{code/code12_1.ijm}
The output in the log window should be \textit{1} indicating that ``\ilcom{(5 ==
5)}'' is \textit{1}. Next, modify the code like below and run it.
\lstinputlisting[morekeywords={*, ==}]{code/code12_2.ijm}
The output is now 0, indicating that ``\ilcom{(5 == 4)}'' is
0.
What double equal signs \ilcom{==} are doing in these
examples are comparison of numbers in the left and the right side, and if
the numbers are the same, it returns 1 and if they are not the same, it returns 0. 1 and
0 actually are representing \textbf{true} (= 1) or \textbf{false} (= 0), the
\textbf{boolean values}.
We could also test if they are NOT equal. For this, replace \ilcom{==} by
\ilcom{!=}.
\lstinputlisting[morekeywords={*, !=}]{code/code12_3.ijm}
Run the code above, and it returns 1, because 5 is NOT 4 and that is true. Now,
you could introduce the \textit{if} again as follows.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_35.ijm}
In the parenthesis after ``if'', there is obvious TRUE statement (5 is not 4).
This is true, so the macro function bounded by curly braces is executed, which is to
print out ``true'' in the log window.
Try changing the line 2 to \ilcom{if (5 == 4)}. Running this prints nothing
in the log window, because 5 is not 4 (FALSE!) so that the macro function in
line 3 is ignored. To avoid such ignorant no-output behavior, you could add
``else'' as follows.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_4.ijm}
The code works also with the direct true or false
declaration inside the if parenthesis. Try the following code.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_5.ijm}
The above prints two lines of ``false!'' in the log window. You could replace
the if parenthesis values to 1 and true to check that it works as well.
By now, it is probably pretty clear to you wi what is going on in the code below.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_6.ijm}
\subsubsection{Complex Conditions}
In many cases, you might need to evaluate the condition of multiple variables at once.
For such demands, several different comparisons can be combined by using following Boolean operators.
\begin{indentCom}
\begin{tabular*}{0.5\textwidth}{ l l }
\&\& & boolean AND\\
|| & boolean OR\\
\end{tabular*}
\end{indentCom}
Let's first test what these symbols do by directly using
\ilcom{true} and \ilcom{false} in macro.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_65.ijm}
When you run this code as it is, line 4 and line 8 are both executed and prints
the messages. For the first \ilcom{if} parenthesis, \ilcom{\&\&} operator tests if
both sides are true. If both are indeed true, it returns true (1), and that is
the case above. If one of them or both are false, then \ilcom{\&\&}
operator returns false(0).
On the other hand, in the second if parenthesis,
\ilcom{||} operator tests if one of the two sides is true. Since both are
true in the above code, OR operator returns true because at least one of them is
true. Only when both sides are false, the returned value becomes false (0).
\begin{indentexercise}{1}
Change the values of \ilcom{a} and \ilcom{b} in code 12\_65 to \ilcom{false} and
compose other three possible combinations (e.g. \ilcom{a = true}, \ilcom{b = false} will print
only one line).
Check the output. Change the values of \ilcom{a} and \ilcom{b} also to 0 and/or
1 and check the results.
\end{indentexercise}
Here is a more realistic example (though not very useful), an extended version
of code 16\_6.
\lstinputlisting[morekeywords={*, if, else}]{code/code12_75.ijm}
\begin{itemize}
\item Line 4 and 5 ask user to input two parameters.
\item Line 6 is for setting a string variable, to abbreviate a long string assignment that appears four times in the macro.
\item Line 7 evaluates these input parameters by comparing each of them separately, but the decision is made by associating two decisions with \ilcom{\&\&}.
%\item Text after "//" is called comment. Text after this double slash will not be evaluated by the macro interpreter. Comments helps programmers later for remembering (or letting other programmer to understand) the purpose of the line.
\item Line 10, != compares left and right sides of the operators and returns true if they are NOT equal.
\end{itemize}
From line 10 to 17, there are several layers of conditions. Macro programmer should use tab-shifting for deeper condition layers as above for the visibility of code. Easy-to-understand code helps the programmer oneself to debug afterward, and also for other programmers who might reuse the code.
\subsubsection{Application of if-statement}
\label{sec:dotmove}
As an application of looping and conditions, we write a macro that produces an animation of moving dot. User inputs the speed of the dot, and then the animation is generated.
In the animation (which actually is a stack) the dot moves horizontally and bounces back from the edge
of the frame.
\ilcom(if) operator is used to switch the movement direction.
\lstinputlisting[morekeywords={*, setForegroundColor, setBackgroundColor, if}]{code/code13.ijm}
\begin{itemize}
\item Lines 4 to 11: Set parameters for drawing a dot. It is also possible to directly use numerical values in the later lines, but for the sake of readability of the code, and also for possible later extension of the code, it is always better to use easy-to-understand variable names and explicitly define them before the main part starts.
\end{itemize}
A short note on the x-y coordinate system in digital images: Since digital image is a matrix of numbers, each pixel position is represented as coordinates. The top left corner of image is the position (x, y) = (0, 0). X increases horizontally towards right side of the image. Y increases vertically towards the bottom of the image. In line 9, y-position of the dot is defined to be placed in the middle of the vertical axis.
\begin{itemize}
\item Lines 14, 15: These lines set the drawing and background color. Three arguments are for intensity of each RGB component. Here the image is in grayscale so all the RGB components are set to the same value. 0 is black, and \ilcom{int} is white (255).
\item Line 14 asks the user to input the speed of the dot movement.
\item Lines 16, 17 prepares a new stack with parameters defined in lines 7, 8 and 9.
\item Lines 21 to 34 is the loop for drawing moving dot. Loop will be iterated from the starting frame until the last frame. Line 21 creates an oval Region-of-Interest (ROI), which will be filled in line 22 with the foreground color that was already set in the line 14. \ilcom{makeOval} function is explained in the Built-on function page as follows.
\begin{indentCom}
\textbf{makeOval}(x, y, width, height)\\
Creates an elliptical selection, where (x,y) defines the upper left corner of the bounding rectangle of the ellipse.
\end{indentCom}
\item Line 27: Shifts the x position of the dot by ``speed'' distance.
\item Line 28: if the position calculated in the line 27 exceeds the boundary, either left \ilcom{(x\_position < 0)} OR right \ilcom{(x\_position > (w-sizenum))}, then the direction of movement is switched by multiplying -1.
\end{itemize}
\begin{indentexercise}{2}
Modify code 13 that the dot moves up and down vertically. Change the stack width and height as well.
If you are successful with this, try further on to extend the code so that the dot moves both in x and y directions. For this, you need to have two independent speed \ilcom{xspeed} and \ilcom{yspeed} since change in the direction by bouncing should be independent in x and y.
\end{indentexercise}
\subsubsection{Application of "while" and "if" in image processing.}
Now, we try solving a problem with image thresholding by an application of
\ilcom{while} loop in a macro. Open image \textbf{mt\_darkening.tif} in the sample image you downloaded.
This is a stack, so you could slide the bar at the bottom of the window to see what is happening:
the image gets darker and darker, as frame number increases. When you study fluorescence images,
you will find such effect very often, because fluorescence bleaches due to the irradiated excitation light
for the acquisition.
When you want to segment this structure (a microtubule), you might use image-thresholding as follows.
%figure
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/fig23441_mtStack.png}
\caption{A stack with darkening microtubule}
\label{fig:MTstack}
\end{center}
\end{figure}
Go back to the first frame and do \ijmenu{[Image -> Adjust -> Thresholding\ldots]}. The image is then automatically adjusted with threshold level. and it seems Ok that the structure is well segmented. But the problem appears as you slid the bar at the bottom. Since image is darkening, area where highlighted decreases.
%figure
\begin{figure}[htbp]
\centering
\subfloat[]{\label{fig:frame1Th}\includegraphics[height = 20mm]{fig/fig23442a_frame1threshold.png}}
\subfloat[]{\label{fig:framelastTh}\includegraphics[height = 20mm]{fig/fig23442b_frameLastthreshold.png}}
\caption{Adjusted with threshold level first frame (a) and the last frame (b)}
\label{fig:degradingThreshold}
\end{figure}
This is because the threshold minimum and the maximum is kept constant while the intensity of the image is decreasing. To segment the structure while the image darkening is occurring, we must adjust the threshold intensity range as the frame progresses.
The macro below finds the minimum value for the thresholding, that the highlighted area in each frame in a stack is approximately similar to the first frame. \ilcom{while} is used to loop the adjustment until the highlighted area is constant. Then the threshold is applied to the image to convert the stack to a binary stack.
\lstinputlisting[morekeywords={*, getThreshold, getSliceNumber, getImageID, getResult, while, setThreshold}]{code/code14.ijm}
%figure
\begin{figure}[htbp]
\centering
\subfloat[]{\label{fig:binMTorg}\includegraphics[height = 20mm]{fig/fig23443a_framelastbinOrg.png}}
\subfloat[]{\label{fig:binMTproc}\includegraphics[height = 20mm]{fig/fig23443b_framelastbinProc.png}}
\caption{Binarized last frame without threshold adjustment (a) and with adjustment using macro (b).}
\label{fig:ThresholdAdjustResults}
\end{figure}
\begin{itemize}
\item Lines 3 to 5 Check if the active window is a stack. If \ilcom{nSlices==1} (meaning that the image is not a stack), macro is terminated.
\item Lines 6 to 9: Get the threshold parameter from image and check if the image is adjusted with threshold level. If not, both upper and lower values are -1. In this case, macro is terminated.
\item Lines 10 to 14: Get stack information. \ilcom{getSliceNumber()} returns the current frame in the stack. Adjusted with threshold level area in this frame (first frame) will be used as the reference area. \ilcom{getImageID()} returns a number that specifically identifies the active window. This ImageID will be used later,by \ilcom{selectImageID(ImageID)} to re-activate the window.
%\end{itemize}
\begin{indentCom}
\textbf{getImageID()}\\
Returns the unique ID (a negative number) of the active image. Use the selectImage(id), isOpen(id) and isActive(id) functions to activate an image or to determine if it is open or active.
\end{indentCom}
%\begin{itemize}
\item Line 16: clears the results table without saving.
\item Line 17: sets the measurement parameter Area, and limits the measurement to the adjusted with threshold level region.
\item Line 18: Do the measurements. Result is recorded in the first row of the Results table.
\item Line 19: The measured area is stored in the variable ref\_area.
\item Line 20: temp\_area will be used later in the while loop.
\item Line 21: the variable ilcom{tol} is a tolerance ratio of error against the reference area. So the adjusted with threshold level area in each frame should be between 97 and 103\% of the reference area.
\item Line 22: Create a destination stack, where adjusted with threshold level images will be pasted.
\item Line 23: get the Image ID of newly created image.
\item Line 25: Loop for the frames starts.
\item Lines 26, 7: Select the original stack and sets the frame number according to the loop number. \ilcom{selectImageID} works with \ilcom{getImageID} function in line 14.
\begin{indentCom}
\textbf{selectImage(id)}\\
Activates the image with the specified ID (a negative number). If id is greater than zero, activates the idth image listed in the Window menu. With ImageJ 1.33n and later, id can be an image title (a string).
\end{indentCom}
\item Line 28: Copy the full frame.
\item Lines 29, 30: creates a temporally single frame image and the image copied in line 28 is pasted.
\item Lines 31 to 37: While loop. temp\_area is evaluated if the area is outside 97 and 103\% of the reference area. If true, then loop continues. Initial temp\_area value is 0 so the loop is at least one time. Set Threshold with lower and upper (line 32). Measure the adjusted with threshold level area, and then lower is incremented -1. The area is evaluated, and if it does not meet the criteria set in line 31, then the loop continues with wider threshold range.
\item Lines 38 to 40: The adjusted with threshold level image will be converted to black \& white image and then copied. The single frame temporary image is closed.
\item Line 41, 42: destination stack is activated and the same frame as the source stack is set.
\item Line 43: Binarized image in the clipboard is pasted into the destination stack.
\item Line 44: returns to Line 25 until all stack frames are processed.
\item Line 45: Terminates the macro.
\end{itemize}
\newpage
\section{Advanced Macro Programming}
This section could be a bit boring for you in terms of biology, but try to be patient.
All these knowledge are required for advanced programming.
Ability to do complex image processing using macro widens your view on planning experiments also.
\subsection{User-defined Functions}
As your code becomes longer,
you will start to realize that similar processing or
calculation appears several times in a macro or through macro sets.
To simplify such redundancy, one could write a
separate \ilcom{function} that works as a module for macros.
For example, if you have a simple code like:
\lstinputlisting[morekeywords={*,}]{code/code15.ijm}
It should be easy for you to expect that this macro will print out "3" in the Log window.
From this macro, we could extract part of it and make a separate function.
\lstinputlisting[morekeywords={*,}]{code/code15_1.ijm}
This is not a macro, but is a program that works as a unit.
Functions can be embedded in macro. \ilcom{ReturnAdd }(code 15.1) is the name of the function,
and the following \ilcom{(n, m)} are the variables that will be used in the function. Within the function,
n and m will be added and the result of which is substituted in to a new variable p.
\ilcom{return p} in line 4 will return a value as an output of the function.
We call such custom-made function as ``user-defined function''. Using this function, code 15 can be rewritten as
\lstinputlisting[morekeywords={*,}]{code/code15_2.ijm}
or simpler, by nesting the custom made function inside ImageJ native function \ilcom{print()},
\lstinputlisting[morekeywords={*,}]{code/code15_3.ijm}
Macro interpreter reads the macro line by line. When the interpreter sees \ilcom{ReturnAdd(a, b)},
the interpreter first tries to find the function within the ImageJ Build-in function.
If its not there, the interpreter looks for the function within the same macro file\ldots
(user-defined function (e.g. \ilcom{ReturnAdd(a, b)} must be written in the same macro file.
Here is how it looks like: a macro that uses a function.
%figure
\begin{figure}[htbp]
\begin{center}
\includegraphics[scale=0.6]{fig/fig2411_usingFunction.png}
\caption{A macro file with function}
\label{fig:MacroWithFunction}
\end{center}
\end{figure}
In this simple case,
you might not feel the convenience of the user-defined function,
but you will start to feel its power as you start writing longer codes.
Advantages of using \ilcom{function} are
\begin{enumerate}
\item Once written in a macro file, it could be used as a single line function
as many times as you want in the macro file. This also means that if there is a bug,
fixing the function solves the problem in all places where the function is used.
\item Long codes could be simplified to an explicit outline of events. Such as:
\begin{lstlisting}[numbers=none]
macro "whatever" {
function1;
function2;
function3;
}
\end{lstlisting}
\end{enumerate}
Let's go back to the code 14, the automatic threshold adjusting macro.