Skip to content

Commit c0baaec

Browse files
committed
Added new model parameter to allow the specification of a preferred magnification level.
1 parent 48a0ab0 commit c0baaec

File tree

4 files changed

+56
-14
lines changed

4 files changed

+56
-14
lines changed

dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/mlprovider/InferServlet.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,25 @@ private Task<MLInference> sendWSIRequest(String provider, String modelID, String
156156

157157
try {
158158
DicomMetaData dicomMetaData = this.getDicomMetadata(uid);
159+
DicomMetaData baseDicomMetaData = this.getDicomMetadata(baseSopInstanceUID);
160+
161+
WSISopDescriptor descriptor = new WSISopDescriptor();
162+
descriptor.extractData(dicomMetaData.getAttributes());
163+
164+
WSISopDescriptor baseDescriptor = new WSISopDescriptor();
165+
baseDescriptor.extractData(baseDicomMetaData.getAttributes());
166+
167+
double scale = (descriptor.getTotalPixelMatrixRows() * 1.0) / baseDescriptor.getTotalPixelMatrixRows();
168+
169+
if(!uid.equals(baseSopInstanceUID)){
170+
scaleAnnotation(annotation, scale);
171+
}
172+
173+
// Verify dimensions of annotation, reject if too big. In the future, adopt a sliding window strategy to process large processing windows.
174+
double area = annotation.getArea();
175+
if(area > 16000000) // This equates to a maximum of 4000x4000 which represents in RGB an image of 48MB
176+
return null;
177+
159178
BufferedImage bi = roiExtractor.extractROI(dicomMetaData, annotation);
160179
predictionRequest.setRoi(bi);
161180
Task<MLInference> task = PluginController.getInstance().infer(provider, predictionRequest);
@@ -172,12 +191,6 @@ private Task<MLInference> sendWSIRequest(String provider, String modelID, String
172191

173192
// Coordinates need to be converted if we're working with WSI
174193
if(!prediction.getAnnotations().isEmpty()){
175-
WSISopDescriptor descriptor = new WSISopDescriptor();
176-
descriptor.extractData(dicomMetaData.getAttributes());
177-
DicomMetaData base = this.getDicomMetadata(baseSopInstanceUID);
178-
WSISopDescriptor baseDescriptor = new WSISopDescriptor();
179-
baseDescriptor.extractData(base.getAttributes());
180-
double scale = (descriptor.getTotalPixelMatrixRows() * 1.0) / baseDescriptor.getTotalPixelMatrixRows();
181194
Point2D tl = annotation.getBoundingBox().get(0);
182195
convertCoordinates(prediction, tl, scale);
183196
}
@@ -308,9 +321,22 @@ private DicomMetaData getDicomMetadata(String sop) throws IOException{
308321
private void convertCoordinates(MLInference prediction, Point2D tl, double scale){
309322
for(BulkAnnotation ann : prediction.getAnnotations()){
310323
for(Point2D p : ann.getPoints()){
311-
p.setX((p.getX() + tl.getX())/scale);
312-
p.setY((p.getY() + tl.getY())/scale);
324+
p.setX((p.getX() + tl.getX()) * scale);
325+
p.setY((p.getY() + tl.getY()) * scale);
313326
}
314327
}
315328
}
329+
330+
/**
331+
* When working with WSI, it is convenient to have coordinates relative to the base of the pyramid.
332+
* This method takes care of that.
333+
* @param scale to transform coordinates
334+
* @return the ml prediction with the converted coordinates.
335+
*/
336+
private void scaleAnnotation(BulkAnnotation annotation, double scale){
337+
for(Point2D p : annotation.getPoints()){
338+
p.setX((p.getX()) * scale);
339+
p.setY((p.getY()) * scale);
340+
}
341+
}
316342
}

dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/cache/WSICache.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,14 @@
3131
import pt.ua.dicoogle.sdk.datastructs.SearchResult;
3232
import pt.ua.dicoogle.sdk.utils.QueryException;
3333

34-
import java.io.BufferedInputStream;
35-
import java.io.File;
36-
import java.io.FileInputStream;
37-
import java.io.InputStream;
3834
import java.net.URI;
3935
import java.security.InvalidParameterException;
4036
import java.util.List;
4137
import java.util.concurrent.TimeUnit;
42-
import java.util.zip.GZIPInputStream;
4338

4439
/**
4540
* Cache used to store DicomMetadata objects temporarily, as they are quite heavy to build on-demand.
4641
* Used only for WSI instances.
47-
* @author Rui Jesus <r.jesus@ua.pt>
4842
*/
4943
public class WSICache extends MemoryCache<DicomMetaData>{
5044

sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/dim/BulkAnnotation.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,11 @@ public List<Point2D> getBoundingBox(){
170170
return Arrays.asList(tl, tr, bl, br);
171171
}
172172

173+
public double getArea(){
174+
List<Point2D> bbox = this.getBoundingBox();
175+
double width = bbox.get(1).getX() - bbox.get(0).getX();
176+
double height = bbox.get(0).getY() - bbox.get(2).getY();
177+
return Math.abs(width * height);
178+
}
179+
173180
}

sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLModel.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public class MLModel implements Serializable {
3939

4040
private List<MLModelParameter> parameters;
4141

42+
/**
43+
* A number between 1 and n that specifies the magnification level of the images this model supports.
44+
* It is only useful in pathology where algorithms might be trained on lower resolution levels of the pyramid.
45+
*/
46+
private int processMagnification;
47+
4248
public MLModel(String name, String id) {
4349
this.name = name;
4450
this.id = id;
@@ -47,6 +53,7 @@ public MLModel(String name, String id) {
4753
parameters = new ArrayList<>();
4854
dataType = MLDataType.IMAGE;
4955
creationDate = new Date();
56+
processMagnification = 0;
5057
}
5158

5259
public MLModel(String name, String id, List<MLModelParameter> parameters){
@@ -125,4 +132,12 @@ public void removeLabel(MLlabel label){
125132
public void addLabel(MLlabel label){
126133
this.labels.add(label);
127134
}
135+
136+
public int getProcessMagnification() {
137+
return processMagnification;
138+
}
139+
140+
public void setProcessMagnification(int processMagnification) {
141+
this.processMagnification = processMagnification;
142+
}
128143
}

0 commit comments

Comments
 (0)