From ab6a824521db5560a669221f5f03428cd0c55142 Mon Sep 17 00:00:00 2001 From: Rui-Jesus Date: Sat, 2 Mar 2024 18:59:11 +0000 Subject: [PATCH] Reworked bulk annotation to be compliant with the standard. Applied code suggestions. --- .../core/mlprovider/PrepareDatastoreTask.java | 15 ++-- .../server/web/dicom/ROIExtractor.java | 41 +++++----- .../server/web/servlets/ROIServlet.java | 17 ++-- .../web/servlets/mlprovider/InferServlet.java | 81 +++++++++---------- .../sdk/datastructs/dim/BulkAnnotation.java | 62 +++++++++----- .../dicoogle/sdk/mlprovider/ImageEntry.java | 4 +- .../dicoogle/sdk/mlprovider/MLCSVDataset.java | 30 ------- .../dicoogle/sdk/mlprovider/MLDataType.java | 19 ++++- .../ua/dicoogle/sdk/mlprovider/MLDataset.java | 6 +- .../sdk/mlprovider/MLImageDataset.java | 2 +- 10 files changed, 143 insertions(+), 134 deletions(-) delete mode 100644 sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLCSVDataset.java diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/mlprovider/PrepareDatastoreTask.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/mlprovider/PrepareDatastoreTask.java index b6ee0e81d..ca00d90ca 100644 --- a/dicoogle/src/main/java/pt/ua/dicoogle/core/mlprovider/PrepareDatastoreTask.java +++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/mlprovider/PrepareDatastoreTask.java @@ -27,6 +27,7 @@ import pt.ua.dicoogle.plugins.PluginController; import pt.ua.dicoogle.sdk.datastructs.SearchResult; import pt.ua.dicoogle.sdk.datastructs.dim.BulkAnnotation; +import pt.ua.dicoogle.sdk.datastructs.dim.Point2D; import pt.ua.dicoogle.sdk.mlprovider.*; import pt.ua.dicoogle.server.web.dicom.ROIExtractor; import pt.ua.dicoogle.server.web.utils.cache.WSICache; @@ -109,12 +110,14 @@ public MLDataset call() throws Exception { dcm.putString(Tag.TransferSyntaxUID, VR.CS, "1.2.840.10008.1.2.4.50"); for(BulkAnnotation annotation: entry.getValue()){ - BufferedImage roi = roiExtractor.extractROI(image.get("SOPInstanceUID").toString(), annotation); - String roiFileName = annotation.getLabel().getName() + c++; - classes.add(annotation.getLabel().getName()); - File output = new File(path + File.separator + roiFileName + ".jpeg"); - ImageIO.write(roi, "jpeg", output); - dataset.put(new ImageEntry(dcm, output.toURI()), annotation.getLabel()); + for(List points: annotation.getAnnotations()){ + BufferedImage roi = roiExtractor.extractROI(image.get("SOPInstanceUID").toString(), annotation.getAnnotationType(), points); + String roiFileName = annotation.getLabel().getName() + c++; + classes.add(annotation.getLabel().getName()); + File output = new File(path + File.separator + roiFileName + ".jpeg"); + ImageIO.write(roi, "jpeg", output); + dataset.put(new ImageEntry(dcm, output.toURI()), annotation.getLabel()); + } } } diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/ROIExtractor.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/ROIExtractor.java index fd4275b61..e9cf8ab10 100644 --- a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/ROIExtractor.java +++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/ROIExtractor.java @@ -27,6 +27,7 @@ import pt.ua.dicoogle.sdk.datastructs.dim.Point2D; import pt.ua.dicoogle.sdk.datastructs.wsi.WSIFrame; import pt.ua.dicoogle.server.web.utils.cache.WSICache; +import sun.reflect.annotation.AnnotationType; import javax.imageio.ImageIO; import javax.imageio.ImageReader; @@ -37,6 +38,8 @@ import java.util.*; import java.util.List; +import static pt.ua.dicoogle.sdk.datastructs.dim.BulkAnnotation.AnnotationType.*; + public class ROIExtractor { private static final Logger logger = LoggerFactory.getLogger(ROIExtractor.class); @@ -49,7 +52,7 @@ public ROIExtractor() { this.wsiCache = WSICache.getInstance(); } - public BufferedImage extractROI(String sopInstanceUID, BulkAnnotation bulkAnnotation) { + public BufferedImage extractROI(String sopInstanceUID, BulkAnnotation.AnnotationType type, List annotation) { DicomMetaData metaData; try { metaData = getDicomMetadata(sopInstanceUID); @@ -57,10 +60,10 @@ public BufferedImage extractROI(String sopInstanceUID, BulkAnnotation bulkAnnota logger.error("Could not extract metadata", e); return null; } - return extractROI(metaData, bulkAnnotation); + return extractROI(metaData, type, annotation); } - public BufferedImage extractROI(DicomMetaData dicomMetaData, BulkAnnotation bulkAnnotation) { + public BufferedImage extractROI(DicomMetaData dicomMetaData, BulkAnnotation.AnnotationType type, List annotation) { ImageReader imageReader = getImageReader(); @@ -84,7 +87,7 @@ public BufferedImage extractROI(DicomMetaData dicomMetaData, BulkAnnotation bulk descriptor.extractData(dicomMetaData.getAttributes()); try { - return getROIFromAnnotation(bulkAnnotation, descriptor, imageReader, param); + return getROIFromAnnotation(type, annotation, descriptor, imageReader, param); } catch (IllegalArgumentException e) { logger.error("Error writing ROI", e); } @@ -105,19 +108,20 @@ private static ImageReader getImageReader() { /** * Given an annotation and an image, return the section of the image the annotation intersects. * It only works with rectangle type annotations. - * @param annotation the annotation to intersect + * @param type the annotation type + * @param annotation a list of points defining the annotation to extract * @param descriptor descriptor of the WSI pyramid, contains information about the dimensions of the image. * @param imageReader * @param param * @return the intersection of the annotation on the image. * @throws IllegalArgumentException when the annotation is not one of the supported types. */ - private BufferedImage getROIFromAnnotation(BulkAnnotation annotation, WSISopDescriptor descriptor, ImageReader imageReader, DicomImageReadParam param) throws IllegalArgumentException { - if(notSupportedTypes.contains(annotation.getAnnotationType())){ + private BufferedImage getROIFromAnnotation(BulkAnnotation.AnnotationType type, List annotation, WSISopDescriptor descriptor, ImageReader imageReader, DicomImageReadParam param) throws IllegalArgumentException { + if(notSupportedTypes.contains(type)){ throw new IllegalArgumentException("Trying to build a ROI with an unsupported annotation type"); } - List constructionPoints = annotation.getBoundingBox(); //Points that will be used to construct the ROI. + List constructionPoints = BulkAnnotation.getBoundingBox(type, annotation); //Points that will be used to construct the ROI. Point2D annotationPoint1 = constructionPoints.get(0); Point2D annotationPoint2 = constructionPoints.get(3); @@ -134,8 +138,8 @@ private BufferedImage getROIFromAnnotation(BulkAnnotation annotation, WSISopDesc // We need to perform clipping if annotation is not a rectangle Shape clippingShape = null; - if(annotation.getAnnotationType() != BulkAnnotation.AnnotationType.RECTANGLE){ - clippingShape = getClippingShape(annotation, constructionPoints.get(0)); + if(type != BulkAnnotation.AnnotationType.RECTANGLE){ + clippingShape = getClippingShape(type, annotation, constructionPoints.get(0)); if (clippingShape != null) g.setClip(clippingShape); } @@ -199,25 +203,26 @@ private BufferedImage getROIFromAnnotation(BulkAnnotation annotation, WSISopDesc * Given an annotation, get it as a Shape to apply as a clipping shape for the ROIs. * The points of this shape are normalized according to the starting point. * This is only needed when dealing with non-rectangle annotations. - * @param annotation + * @param type the type of annotation + * @param annotation the list of points of the annotation * @param startingPoint starting point of the rectangle that contains the annotation * @return a shape to use to clip the ROI */ - private Shape getClippingShape(BulkAnnotation annotation, Point2D startingPoint){ - switch (annotation.getAnnotationType()){ + private Shape getClippingShape(BulkAnnotation.AnnotationType type, List annotation, Point2D startingPoint){ + switch (type){ case POLYLINE: case POLYGON: Polygon polygon = new Polygon(); - for(Point2D p : annotation.getPoints()){ + for(Point2D p : annotation){ polygon.addPoint((int) (p.getX() - startingPoint.getX()), (int) (p.getY() - startingPoint.getY())); } return polygon; case ELLIPSE: - double minX = annotation.getPoints().get(0).getX(); - double maxX = annotation.getPoints().get(1).getX(); + double minX = annotation.get(0).getX(); + double maxX = annotation.get(1).getX(); - double minY = annotation.getPoints().get(2).getY(); - double maxY = annotation.getPoints().get(3).getY(); + double minY = annotation.get(2).getY(); + double maxY = annotation.get(3).getY(); return new Ellipse2D.Double(minX - startingPoint.getX(), minY - startingPoint.getY(), Math.abs(maxX - minX), Math.abs(maxY - minY)); diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ROIServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ROIServlet.java index 1fa54eb67..f2621f5c6 100644 --- a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ROIServlet.java +++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ROIServlet.java @@ -78,21 +78,18 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) return; } - BulkAnnotation annotation; + List annotation; + BulkAnnotation.AnnotationType annotationType = BulkAnnotation.AnnotationType.RECTANGLE; try{ int nX = Integer.parseInt(x); int nY = Integer.parseInt(y); int nWidth = Integer.parseInt(width); int nHeight = Integer.parseInt(height); - annotation = new BulkAnnotation(); Point2D tl = new Point2D(nX, nY); Point2D tr = new Point2D(nX + nWidth, nY); Point2D bl = new Point2D(nX, nY + nHeight); Point2D br = new Point2D(nX + nWidth, nY + nHeight); - List points = new ArrayList<>(); - points.add(tl); points.add(tr); points.add(bl); points.add(br); - annotation.setPoints(points); - annotation.setAnnotationType(BulkAnnotation.AnnotationType.RECTANGLE); + annotation = Arrays.asList(tl, tr, bl, br); } catch (NumberFormatException e){ response.sendError(Status.CLIENT_ERROR_BAD_REQUEST.getCode(), "ROI provided was invalid"); return; @@ -100,7 +97,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) DicomMetaData metaData = getDicomMetadata(sopInstanceUID); - BufferedImage bi = roiExtractor.extractROI(metaData, annotation); + BufferedImage bi = roiExtractor.extractROI(metaData, annotationType, annotation); if(bi != null){ response.setContentType("image/jpeg"); @@ -136,13 +133,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) String type = body.get("type").asText(); List points = mapper.readValue(body.get("points").toString(), new TypeReference>(){}); - BulkAnnotation annotation = new BulkAnnotation(); - annotation.setPoints(points); - annotation.setAnnotationType(BulkAnnotation.AnnotationType.valueOf(type)); - DicomMetaData dicomMetaData = this.getDicomMetadata(sopInstanceUID); - BufferedImage bi = roiExtractor.extractROI(dicomMetaData, annotation); + BufferedImage bi = roiExtractor.extractROI(dicomMetaData, BulkAnnotation.AnnotationType.valueOf(type), points); if(bi != null){ response.setContentType("image/jpeg"); diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/mlprovider/InferServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/mlprovider/InferServlet.java index 43a616fef..5d9f58c73 100644 --- a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/mlprovider/InferServlet.java +++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/mlprovider/InferServlet.java @@ -48,10 +48,7 @@ import java.awt.image.BufferedImage; import java.io.*; import java.nio.file.Files; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ExecutionException; public class InferServlet extends HttpServlet { @@ -150,8 +147,8 @@ private Task sendWSIRequest(String provider, String modelID, String ObjectMapper mapper = new ObjectMapper(); MLInferenceRequest predictionRequest = new MLInferenceRequest(true, DimLevel.INSTANCE, uid, modelID); predictionRequest.setParameters(parameters); - BulkAnnotation annotation = new BulkAnnotation(); - annotation.setPoints(roi); + BulkAnnotation annotation = new BulkAnnotation(roiType, BulkAnnotation.PixelOrigin.VOLUME); + annotation.setAnnotations(Collections.singletonList(roi)); annotation.setAnnotationType(roiType); try { @@ -171,11 +168,11 @@ private Task sendWSIRequest(String provider, String modelID, String } // Verify dimensions of annotation, reject if too big. In the future, adopt a sliding window strategy to process large processing windows. - double area = annotation.getArea(); + double area = annotation.getArea(annotation.getAnnotations().get(0)); if(area > 16000000) // This equates to a maximum of 4000x4000 which represents in RGB an image of 48MB return null; - BufferedImage bi = roiExtractor.extractROI(dicomMetaData, annotation); + BufferedImage bi = roiExtractor.extractROI(dicomMetaData, annotation.getAnnotationType(), annotation.getAnnotations().get(0)); predictionRequest.setRoi(bi); Task task = PluginController.getInstance().infer(provider, predictionRequest); if(task != null){ @@ -191,7 +188,7 @@ private Task sendWSIRequest(String provider, String modelID, String // Coordinates need to be converted if we're working with WSI if(!prediction.getAnnotations().isEmpty()){ - Point2D tl = annotation.getBoundingBox().get(0); + Point2D tl = annotation.getBoundingBox(annotation.getAnnotations().get(0)).get(0); convertCoordinates(prediction, tl, scale); } @@ -199,7 +196,6 @@ private Task sendWSIRequest(String provider, String modelID, String PrintWriter out = response.getWriter(); mapper.writeValue(out, prediction); out.close(); - out.flush(); } catch (InterruptedException | ExecutionException e) { log.error("Could not make prediction", e); try { @@ -247,39 +243,36 @@ private Task sendRequest(String provider, String modelID, DimLevel String boundary = UUID.randomUUID().toString(); response.setContentType("multipart/form-data; boundary=" + boundary); - ServletOutputStream out = response.getOutputStream(); - - out.print("--" + boundary); - out.println(); - out.print("Content-Disposition: form-data; name=\"params\""); - out.println(); - out.print("Content-Type: application/json"); - out.println(); out.println(); - out.print(mapper.writeValueAsString(prediction)); - out.println(); - out.print("--" + boundary); - out.println(); - out.print("Content-Disposition: form-data; name=\"dicomseg\"; filename=\"dicomseg.dcm\""); - out.println(); - out.print("Content-Type: application/dicom"); - out.println(); out.println(); - - try (InputStream fi = Files.newInputStream(prediction.getDicomSEG())) { - IOUtils.copy(fi, out); - out.flush(); + try (ServletOutputStream out = response.getOutputStream()){ + out.print("--" + boundary); + out.println(); + out.print("Content-Disposition: form-data; name=\"params\""); + out.println(); + out.print("Content-Type: application/json"); + out.println(); out.println(); + out.print(mapper.writeValueAsString(prediction)); + out.println(); + out.print("--" + boundary); + out.println(); + out.print("Content-Disposition: form-data; name=\"dicomseg\"; filename=\"dicomseg.dcm\""); + out.println(); + out.print("Content-Type: application/dicom"); + out.println(); out.println(); + + try (InputStream fi = Files.newInputStream(prediction.getDicomSEG())) { + IOUtils.copy(fi, out); + out.flush(); + } + + out.println(); + out.print("--" + boundary + "--"); } - out.println(); - out.print("--" + boundary + "--"); - out.flush(); - out.close(); - } else { response.setContentType("application/json"); PrintWriter out = response.getWriter(); mapper.writeValue(out, prediction); out.close(); - out.flush(); } try{ @@ -320,9 +313,11 @@ private DicomMetaData getDicomMetadata(String sop) throws IOException{ */ private void convertCoordinates(MLInference prediction, Point2D tl, double scale){ for(BulkAnnotation ann : prediction.getAnnotations()){ - for(Point2D p : ann.getPoints()){ - p.setX((p.getX() + tl.getX()) * scale); - p.setY((p.getY() + tl.getY()) * scale); + for(List points : ann.getAnnotations()){ + for(Point2D p : points){ + p.setX((p.getX() + tl.getX()) * scale); + p.setY((p.getY() + tl.getY()) * scale); + } } } } @@ -334,9 +329,11 @@ private void convertCoordinates(MLInference prediction, Point2D tl, double scale * @return the ml prediction with the converted coordinates. */ private void scaleAnnotation(BulkAnnotation annotation, double scale){ - for(Point2D p : annotation.getPoints()){ - p.setX((p.getX()) * scale); - p.setY((p.getY()) * scale); + for(List ann : annotation.getAnnotations()){ + for(Point2D p : ann){ + p.setX((p.getX()) * scale); + p.setY((p.getY()) * scale); + } } } } diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/dim/BulkAnnotation.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/dim/BulkAnnotation.java index 4997252e5..abb0d5313 100644 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/dim/BulkAnnotation.java +++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/dim/BulkAnnotation.java @@ -20,6 +20,7 @@ import pt.ua.dicoogle.sdk.mlprovider.MLlabel; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -27,6 +28,10 @@ * A bulk annotation object denotes a group of annotations from a DICOM file generated by third-party services like AI algorithms. * It follows the supplement 222 of the DICOM standard. * Annotations in a bulk annotation object share common attributes such as shape type, label, pixel origin, etc. + * Check the module C.37.1.2 Microscopy Bulk Simple Annotations for more information on annotation bulks. + * This object only maps certain parts of the standard, not the whole of it, as it is quite extensive. + * For ease of use, this object maps annotations as a list of lists. + * The standard stores all the annotations on a single list and uses a secondary list of indices to delimit the annotations. */ public class BulkAnnotation { @@ -73,9 +78,18 @@ public enum CoordinateType { private MLlabel label; - private List points; + private List> annotations; - private double confidence; + public BulkAnnotation(AnnotationType type, PixelOrigin origin){ + this.annotationType = type; + this.pixelOrigin = origin; + this.annotations = new ArrayList<>(); + } + + public BulkAnnotation(AnnotationType type, PixelOrigin origin, List> annotations){ + this(type, origin); + this.annotations = annotations; + } public PixelOrigin getPixelOrigin() { return pixelOrigin; @@ -109,40 +123,39 @@ public void setLabel(MLlabel label) { this.label = label; } - public double getConfidence() { - return confidence; + public List> getAnnotations() { + return annotations; } - public void setConfidence(double confidence) { - this.confidence = confidence; + public void setAnnotations(List> annotations) { + this.annotations = annotations; } - public List getPoints() { - return points; + public void addAnnotation(List annotation){ + this.annotations.add(annotation); } - public void setPoints(List points) { - this.points = points; + public List getBoundingBox(List points){ + return BulkAnnotation.getBoundingBox(this.annotationType, points); } - /** - * Calculate the bounding box of this annotation. + * Calculate the bounding box of an annotation from this bulk. * @return a list of 4 points, representing a rectangle that contains the provided annotation. */ - public List getBoundingBox(){ + public static List getBoundingBox(AnnotationType type, List points){ double minX = Double.MAX_VALUE; double minY = Double.MAX_VALUE; double maxX = Double.MIN_VALUE; double maxY = Double.MIN_VALUE; - switch (annotationType){ + switch (type){ case RECTANGLE: - return this.getPoints(); + return points; // In case of rectangles, annotations are already coded as the corners of the rectangle case POLYGON: case POLYLINE: - for(Point2D p : this.getPoints()){ + for(Point2D p : points){ if(p.getX() > maxX) maxX = p.getX(); if(p.getX() < minX) @@ -155,10 +168,10 @@ public List getBoundingBox(){ } break; case ELLIPSE: - minX = this.getPoints().get(0).getX(); - maxX = this.getPoints().get(1).getX(); - minY = this.getPoints().get(2).getY(); - maxY = this.getPoints().get(3).getY(); + minX = points.get(0).getX(); + maxX = points.get(1).getX(); + minY = points.get(2).getY(); + maxY = points.get(3).getY(); break; } @@ -170,8 +183,13 @@ public List getBoundingBox(){ return Arrays.asList(tl, tr, bl, br); } - public double getArea(){ - List bbox = this.getBoundingBox(); + /** + * Given a list of points from this bulk, calculate its area. + * @param points + * @return + */ + public double getArea(List points){ + List bbox = this.getBoundingBox(points); double width = bbox.get(1).getX() - bbox.get(0).getX(); double height = bbox.get(0).getY() - bbox.get(2).getY(); return Math.abs(width * height); diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/ImageEntry.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/ImageEntry.java index 816aa5637..c0a618268 100644 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/ImageEntry.java +++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/ImageEntry.java @@ -24,7 +24,9 @@ import java.util.Objects; /** - * Used to map the metadata of regions of interest. + * This object is used in {@see MLImageDataset} to map the image objects. + * Each entry is defined by a physical file and a set of DICOM metadata containing information such as + * the transfer syntax of the image, and other relevant information to process this image. */ public class ImageEntry { diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLCSVDataset.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLCSVDataset.java deleted file mode 100644 index 50b657542..000000000 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLCSVDataset.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (C) 2014 Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/ - * - * This file is part of Dicoogle/dicoogle-sdk. - * - * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Dicoogle. If not, see . - */ -package pt.ua.dicoogle.sdk.mlprovider; - -import java.io.InputStream; - -public class MLCSVDataset extends MLDataset { - - private InputStream csvFile; - - public MLCSVDataset(){ - super("", MLDataType.CSV); - } -} diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataType.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataType.java index 3b42a4985..7862d3130 100644 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataType.java +++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataType.java @@ -18,6 +18,23 @@ */ package pt.ua.dicoogle.sdk.mlprovider; +/** + * This enum maps the supported data types used in the MLProviderInterface. + * Data in this context always refers to data objects, labelled or unlabelled, used throughout the ML pipeline, + * for example in training or inference jobs. + * The data types listed here are not exhaustive, meaning future releases and iterations might add or remove new data types. + */ public enum MLDataType { - CSV, IMAGE, DICOM + /** + * CSV data objects refers to data that can be mapped in a tabular format. + */ + CSV, + /** + * IMAGE data objects refer explicitly to pixel data objects. + */ + IMAGE, + /** + * DICOM data objects refer to one: Study, Series or Instance. + */ + DICOM } diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataset.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataset.java index 3958f476f..69faf0aae 100644 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataset.java +++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLDataset.java @@ -18,10 +18,14 @@ */ package pt.ua.dicoogle.sdk.mlprovider; +/** + * ML dataset objects map a collection of labelled data, to be used in the training and generation of models. + * ML datasets have a type, defined by {@see MLDataType} and an identifier, to be used by the providers to internally manage this dataset. + * This data object is used in datastore requests to construct annotated datasets. + */ public abstract class MLDataset { protected String name; - protected MLDataType dataType; public MLDataset(String name, MLDataType dataType) { diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLImageDataset.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLImageDataset.java index 272f61561..14ef9740e 100644 --- a/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLImageDataset.java +++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/mlprovider/MLImageDataset.java @@ -22,7 +22,7 @@ /** * An ML dataset of image objects. - * Optionally an array of labels can be given to create a labelled dataset. + * Images are defined by {@see ImageEntry} objects and must have a label associated. */ public class MLImageDataset extends MLDataset {