Skip to content

Commit fef3e6c

Browse files
committed
add code that executes samj in macro
1 parent dc497a4 commit fef3e6c

File tree

2 files changed

+116
-3
lines changed

2 files changed

+116
-3
lines changed

src/main/java/ai/nets/samj/ij/SAMJ_Annotator.java

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,29 @@
1919
*/
2020
package ai.nets.samj.ij;
2121

22+
import java.awt.GraphicsEnvironment;
23+
import java.awt.Rectangle;
2224
import java.io.IOException;
25+
import java.util.List;
2326

2427
import javax.swing.SwingUtilities;
2528

29+
import ai.nets.samj.annotation.Mask;
30+
import ai.nets.samj.communication.model.SAMModel;
2631
import ai.nets.samj.gui.MainGUI;
2732
import ai.nets.samj.ui.SAMJLogger;
33+
import ij.IJ;
2834
import ij.ImageJ;
35+
import ij.Macro;
2936
import ij.gui.GUI;
3037
import ij.plugin.PlugIn;
3138
import ij.plugin.frame.Recorder;
39+
import net.imglib2.RandomAccessibleInterval;
40+
import net.imglib2.type.NativeType;
41+
import net.imglib2.type.numeric.RealType;
42+
import net.imglib2.util.Cast;
3243
import ai.nets.samj.ij.ui.Consumer;
44+
import ai.nets.samj.models.AbstractSamJ.BatchCallback;
3345

3446
// TODO I (Carlos) don't know how to develop in IJ2 @Plugin(type = Command.class, menuPath = "Plugins>SAMJ>Annotator")
3547
//TODO I (Carlos) don't know how to develop in IJ2 public class Plugin_SamJAnnotator implements Command {
@@ -41,16 +53,60 @@
4153
* @author Vladimir Ulman
4254
*/
4355
public class SAMJ_Annotator implements PlugIn {
56+
57+
private String macroModelName;
58+
59+
private String macroMaskPrompt;
60+
4461
final static long MAX_IMAGE_SIZE_IN_BYTES = ((long)4)<<30; //4 GB
4562

63+
private final static String MACRO_INFO = "https://github.com/segment-anything-models-java/SAMJ-IJ/blob/main/README.md#macros";
64+
4665
final static String MACRO_RECORD_COMMENT = ""
4766
+ System.lineSeparator()
4867
+ "// Note: SAMJ macros are supported only in BatchSAMize mode with preset prompts." + System.lineSeparator()
4968
+ "// The macro recording feature will capture the command 'run(\"SAMJ Annotator\");', but executing it will have no effect." + System.lineSeparator()
5069
+ "// To record something, please click the 'SAMJ BatchSAMize' button." + System.lineSeparator()
5170
+ "// For more information, visit:" + System.lineSeparator()
52-
+ "// https://github.com/segment-anything-models-java/SAMJ-IJ/blob/main/README.md#macros" + System.lineSeparator()
71+
+ "// " + MACRO_INFO + System.lineSeparator()
5372
+ System.lineSeparator();
73+
74+
/**
75+
* Keys required to run deepImageJ with a macro
76+
*/
77+
private final static String[] macroKeys = new String[] {"modelName="};
78+
/**
79+
* Optional keys to run deepImageJ with a macro or in headless mode
80+
*/
81+
private final static String[] macroOptionalKeys = new String[] {"maskPrompt="};
82+
83+
private static Consumer MACRO_CONSUMER;
84+
85+
private final static BatchCallback MACRO_CALLBACK = new BatchCallback() {
86+
@Override
87+
public void setTotalNumberOfRois(int nRois) {}
88+
@Override
89+
public void updateProgress(int n) {}
90+
91+
@Override
92+
public void drawRoi(List<Mask> masks) {
93+
SwingUtilities.invokeLater(() -> MACRO_CONSUMER.addPolygonsFromGUI(masks));
94+
95+
}
96+
97+
@Override
98+
public void deletePointPrompt(List<int[]> promptList) {
99+
SwingUtilities.invokeLater(() -> promptList.forEach(proi -> MACRO_CONSUMER.deletePointRoi(proi)));
100+
}
101+
102+
@Override
103+
public void deleteRectPrompt(List<int[]> promptList) {
104+
SwingUtilities.invokeLater(() -> promptList.stream()
105+
.map(rect -> new Rectangle(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]))
106+
.forEach(roi -> MACRO_CONSUMER.deleteRectRoi(roi)));
107+
}
108+
109+
};
54110

55111
// TODO I (Carlos) don't know how to develop in IJ2 @Parameter
56112
//private LogService logService = new LogService();
@@ -112,11 +168,68 @@ public static void main(String[] args) throws IOException, InterruptedException
112168

113169
@Override
114170
public void run(String arg) {
171+
boolean isMacro = IJ.isMacro();
172+
boolean isHeadless = GraphicsEnvironment.isHeadless();
115173
try {
116-
run();
174+
if (isMacro) {
175+
runMacro();
176+
} else if (isHeadless) {
177+
} else {
178+
run();
179+
}
117180
} catch (IOException | InterruptedException e) {
118181
e.printStackTrace();
119182
}
183+
}
184+
185+
private < T extends RealType< T > & NativeType< T > >
186+
void runMacro() throws IOException, RuntimeException, InterruptedException {
187+
parseCommand();
188+
if (macroModelName == null)
189+
return;
120190

191+
MACRO_CONSUMER = new Consumer();
192+
SAMModel selected = MainGUI.DEFAULT_MODEL_LIST.stream()
193+
.filter(mm -> mm.getName().equals(macroModelName)).findFirst().orElse(null);
194+
if (selected == null)
195+
throw new IllegalArgumentException("Specified model does not exist. Please, for more info visit: "
196+
+ MACRO_INFO);
197+
RandomAccessibleInterval<T> rai = MACRO_CONSUMER.getFocusedImageAsRai();
198+
selected.setImage(rai, null);
199+
List<int[]> pointPrompts = MACRO_CONSUMER.getPointRoisOnFocusImage();
200+
List<Rectangle> rectPrompts = MACRO_CONSUMER.getRectRoisOnFocusImage();
201+
202+
selected.processBatchOfPrompts(pointPrompts, rectPrompts, rai, MACRO_CALLBACK);
203+
}
204+
205+
206+
private void parseCommand() {
207+
String macroArg = Macro.getOptions();
208+
if (macroArg == null)
209+
return;
210+
211+
macroModelName = parseArg(macroArg, macroKeys[0], true);
212+
macroMaskPrompt = parseArg(macroArg, macroOptionalKeys[0], false);
213+
}
214+
215+
private static String parseArg(String macroArg, String arg, boolean required) {
216+
int modelFolderInd = macroArg.indexOf(arg);
217+
if (modelFolderInd == -1 && required)
218+
throw new IllegalArgumentException("SAMJ macro requires to the variable '" + arg + "'. "
219+
+ "For more info, please visit: " + MACRO_INFO);
220+
else if (modelFolderInd == -1)
221+
return null;
222+
int modelFolderInd2 = macroArg.indexOf(arg + "[");
223+
int endInd = macroArg.indexOf(" ", modelFolderInd);
224+
String value;
225+
if (modelFolderInd2 != -1) {
226+
endInd = macroArg.indexOf("] ", modelFolderInd2);
227+
value = macroArg.substring(modelFolderInd2 + arg.length() + 1, endInd);
228+
} else {
229+
value = macroArg.substring(modelFolderInd + arg.length(), endInd);
230+
}
231+
if (value.equals("null") || value.equals(""))
232+
value = null;
233+
return value;
121234
}
122235
}

src/main/java/ai/nets/samj/ij/ui/Consumer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ public void notifyBatchSamize(String modelName, String maskPrompt) {
680680
return;
681681

682682
String formatedMacro = "run(\"SAMJ Annotator\", \"model=[%s]%s\");" + System.lineSeparator();
683-
String formatedMaskPrompt = " mask_prompt=[%s]";
683+
String formatedMaskPrompt = " maskPrompt=[%s]";
684684
String promptArg = maskPrompt == null ? "" : String.format(formatedMaskPrompt, maskPrompt);
685685
Recorder.recordString(String.format(formatedMacro, modelName, promptArg));
686686
}

0 commit comments

Comments
 (0)