1919import java .nio .file .Path ;
2020import java .util .ArrayList ;
2121import java .util .Arrays ;
22- import java .util .HashMap ;
2322import java .util .HashSet ;
2423import java .util .List ;
25- import java .util .Map ;
2624import java .util .Set ;
2725
2826import javax .xml .parsers .ParserConfigurationException ;
5048import qupath .lib .plugins .parameters .ParameterList ;
5149import qupath .lib .regions .ImagePlane ;
5250import qupath .lib .regions .RegionRequest ;
51+ import qupath .lib .roi .PointsROI ;
5352import qupath .lib .roi .ROIs ;
5453import qupath .lib .roi .interfaces .ROI ;
5554import qupath .lib .scripting .QP ;
@@ -80,38 +79,27 @@ public void run() {
8079 }
8180
8281 ResponseInfo info = MonaiLabelClient .info ();
83- List <String > names = new ArrayList <String >();
84- Map <String , String []> labels = new HashMap <String , String []>();
85- for (String n : info .models .keySet ()) {
86- names .add (n );
87- labels .put (n , info .models .get (n ).labels .labels ());
88- }
82+ List <String > names = Arrays .asList (info .models .keySet ().toArray (new String [0 ]));
8983
90- ParameterList list = new ParameterList ();
9184 if (selectedModel == null || selectedModel .isEmpty ()) {
9285 selectedModel = names .isEmpty () ? "" : names .get (0 );
9386 }
9487
88+ ParameterList list = new ParameterList ();
9589 list .addChoiceParameter ("Model" , "Model Name" , selectedModel , names );
9690 list .addStringParameter ("Location" , "Location (x,y,w,h)" , Arrays .toString (bbox ));
9791 list .addIntParameter ("TileSize" , "TileSize" , tileSize );
9892
99- boolean override = !info .models .get (selectedModel ).nuclick ;
100- list .addBooleanParameter ("Override" , "Override" , override );
101-
10293 if (Dialogs .showParameterDialog ("MONAILabel" , list )) {
10394 String model = (String ) list .getChoiceParameterValue ("Model" );
10495 bbox = Utils .parseStringArray (list .getStringParameterValue ("Location" ));
105- override = list .getBooleanParameterValue ("Override" ).booleanValue ();
10696 tileSize = list .getIntParameterValue ("TileSize" ).intValue ();
10797
10898 selectedModel = model ;
10999 selectedBBox = bbox ;
110100 selectedTileSize = tileSize ;
111101
112- boolean validateClicks = info .models .get (selectedModel ).nuclick ;
113- runInference (model , new HashSet <String >(Arrays .asList (labels .get (model ))), bbox , tileSize , imageData ,
114- override , validateClicks );
102+ runInference (model , info , bbox , tileSize , imageData );
115103 }
116104 } catch (Exception ex ) {
117105 ex .printStackTrace ();
@@ -124,13 +112,16 @@ ArrayList<Point2> getClicks(String name, ImageData<BufferedImage> imageData, ROI
124112 List <PathObject > objs = imageData .getHierarchy ().getFlattenedObjectList (null );
125113 ArrayList <Point2 > clicks = new ArrayList <Point2 >();
126114 for (int i = 0 ; i < objs .size (); i ++) {
127- String pname = objs .get (i ).getPathClass () == null ? "" : objs .get (i ).getPathClass ().getName ();
128- if (pname .equalsIgnoreCase (name )) {
129- ROI r = objs .get (i ).getROI ();
130- List <Point2 > points = r .getAllPoints ();
131- for (Point2 p : points ) {
132- if (monaiLabelROI .contains (p .getX (), p .getY ())) {
133- clicks .add (new Point2 (p .getX () - offsetX , p .getY () - offsetY ));
115+ var obj = objs .get (i );
116+ String pname = obj .getPathClass () == null ? "" : obj .getPathClass ().getName ();
117+ if (name .isEmpty () || pname .equalsIgnoreCase (name )) {
118+ ROI r = obj .getROI ();
119+ if (r instanceof PointsROI ) {
120+ List <Point2 > points = r .getAllPoints ();
121+ for (Point2 p : points ) {
122+ if (monaiLabelROI .contains (p .getX (), p .getY ())) {
123+ clicks .add (new Point2 (p .getX () - offsetX , p .getY () - offsetY ));
124+ }
134125 }
135126 }
136127 }
@@ -140,12 +131,17 @@ ArrayList<Point2> getClicks(String name, ImageData<BufferedImage> imageData, ROI
140131 return clicks ;
141132 }
142133
143- private void runInference (String model , Set < String > labels , int [] bbox , int tileSize ,
144- ImageData <BufferedImage > imageData , boolean override , boolean validateClicks )
134+ private void runInference (String model , ResponseInfo info , int [] bbox , int tileSize ,
135+ ImageData <BufferedImage > imageData )
145136 throws SAXException , IOException , ParserConfigurationException , InterruptedException {
146137 logger .info ("MONAILabel:: Running Inference..." );
147- logger .info ("MONAILabel:: Model: " + model + "; override: " + override + "; clicks:" + validateClicks
148- + "; Labels: " + labels );
138+
139+ boolean isNuClick = info .models .get (model ).nuclick ;
140+ boolean override = !isNuClick ;
141+ boolean validateClicks = isNuClick ;
142+ var labels = new HashSet <String >(Arrays .asList (info .models .get (model ).labels .labels ()));
143+
144+ logger .info ("MONAILabel:: Model: " + model + "; Labels: " + labels );
149145
150146 Path imagePatch = null ;
151147 try {
@@ -178,30 +174,38 @@ private void runInference(String model, Set<String> labels, int[] bbox, int tile
178174 req .location [0 ] = req .location [1 ] = 0 ;
179175 req .size [0 ] = req .size [1 ] = 0 ;
180176
181- var fg = getClicks ("Positive" , imageData , roi , offsetX , offsetY );
182- var bg = getClicks ("Negative" , imageData , roi , offsetX , offsetY );
183- if (validateClicks ) {
184- if (fg .size () == 0 && bg .size () == 0 ) {
185- Dialogs .showErrorMessage ("MONAILabel" ,
186- "Need atleast one Postive/Negative annotation/click point within the ROI" );
187- return ;
188- }
189- if (roi .getBoundsHeight () < 128 || roi .getBoundsWidth () < 128 ) {
190- Dialogs .showErrorMessage ("MONAILabel" ,
191- "Min Height/Width of ROI should be more than 128" );
192- return ;
193- }
194- }
195-
196- req .params .addClicks (fg , true );
197- req .params .addClicks (bg , false );
198177
199178 imagePatch = java .nio .file .Files .createTempFile ("patch" , ".png" );
200179 imageFile = imagePatch .toString ();
201180 var requestROI = RegionRequest .createInstance (imageData .getServer ().getPath (), 1 , roi );
202181 ImageWriterTools .writeImageRegion (imageData .getServer (), requestROI , imageFile );
203182 }
204183
184+ ArrayList <Point2 > fg = new ArrayList <>();
185+ ArrayList <Point2 > bg = new ArrayList <>();
186+ if (isNuClick ) {
187+ fg = getClicks ("" , imageData , roi , offsetX , offsetY );
188+ } else {
189+ fg = getClicks ("Positive" , imageData , roi , offsetX , offsetY );
190+ bg = getClicks ("Negative" , imageData , roi , offsetX , offsetY );
191+ }
192+
193+ if (validateClicks ) {
194+ if (fg .size () == 0 && bg .size () == 0 ) {
195+ Dialogs .showErrorMessage ("MONAILabel" ,
196+ "Need atleast one Postive/Negative annotation/click point within the ROI" );
197+ return ;
198+ }
199+ if (roi .getBoundsHeight () < 128 || roi .getBoundsWidth () < 128 ) {
200+ Dialogs .showErrorMessage ("MONAILabel" ,
201+ "Min Height/Width of ROI should be more than 128" );
202+ return ;
203+ }
204+ }
205+ req .params .addClicks (fg , true );
206+ req .params .addClicks (bg , false );
207+
208+
205209 Document dom = MonaiLabelClient .infer (model , image , imageFile , sessionId , req );
206210 NodeList annotation_list = dom .getElementsByTagName ("Annotation" );
207211 int count = updateAnnotations (labels , annotation_list , roi , imageData , override , offsetX , offsetY );
@@ -227,6 +231,20 @@ private int updateAnnotations(Set<String> labels, NodeList annotation_list, ROI
227231 }
228232 }
229233 }
234+ } else {
235+ List <PathObject > objs = imageData .getHierarchy ().getFlattenedObjectList (null );
236+ for (int i = 0 ; i < objs .size (); i ++) {
237+ var obj = objs .get (i );
238+ ROI r = obj .getROI ();
239+ if (r instanceof PointsROI ) {
240+ String pname = obj .getPathClass () == null ? "" : obj .getPathClass ().getName ();
241+ if (pname .equalsIgnoreCase ("Positive" ) || pname .equalsIgnoreCase ("Negative" )) {
242+ continue ;
243+ }
244+ imageData .getHierarchy ().removeObjectWithoutUpdate (obj , false );
245+ }
246+ }
247+ QP .fireHierarchyUpdate (imageData .getHierarchy ());
230248 }
231249
232250 int count = 0 ;
0 commit comments