diff --git a/src/main/java/ai/nets/samj/ij/ui/Consumer.java b/src/main/java/ai/nets/samj/ij/ui/Consumer.java new file mode 100644 index 0000000..9976617 --- /dev/null +++ b/src/main/java/ai/nets/samj/ij/ui/Consumer.java @@ -0,0 +1,180 @@ +package ai.nets.samj.ij.ui; + +import java.awt.Polygon; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; +import java.util.stream.Collectors; + +import javax.swing.SwingUtilities; + +import ai.nets.samj.annotation.Mask; +import ai.nets.samj.gui.components.ComboBoxItem; +import ai.nets.samj.ui.ConsumerInterface; +import ij.IJ; +import ij.ImagePlus; +import ij.Prefs; +import ij.gui.ImageCanvas; +import ij.gui.ImageWindow; +import ij.gui.PolygonRoi; +import ij.gui.Roi; +import ij.plugin.frame.RoiManager; +import net.imglib2.Localizable; +import net.imglib2.RandomAccessibleInterval; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.type.numeric.integer.UnsignedShortType; + +public class Consumer extends ConsumerInterface { + /** + * The image being processed + */ + private final ImagePlus activeImage; + /** + * Canvas of the image selected. Used to record the prompts drawn by the user + */ + private final ImageCanvas activeCanvas; + /** + * Window of the selected image. Used to record the prompts drawn by the user + */ + private final ImageWindow activeWindow; + /** + * Instance of the ROI manager to save the ROIs created + */ + private final RoiManager roiManager; + /** + * Whether to add the ROIs created to the ROI manager or not + */ + private boolean isAddingToRoiManager = true; + /** + * A list to save several ROIs that are being created for the same prompt. + * Whenever the prompt is sent to the model, this list is emptied + */ + private List temporalROIs = new ArrayList(); + /** + * A list to save several ROIs that are being created from the same prompt. + * This list saves only the "negative" ROIs, those that are not part of the instance of interest, + * but part of the background. + * Whenever the prompt is sent to the model, this list is emptied. + */ + private List temporalNegROIs = new ArrayList(); + /** + * For the point prompts, whether if hte user is collecting several prompts (pressing the ctrl key) + * or just one + */ + private boolean isCollectingPoints = false; + /** + * All the points being collected that reference the instance of interest + */ + private List collectedPoints = new ArrayList(); + /** + * All the points being collected that reference the background (ctrl + alt) + */ + private List collecteNegPoints = new ArrayList(); + /** + * Save lists of rois that have been added at the same time to delete them if necessary + */ + private Stack> undoStack = new Stack<>(); + /** + * Save lists of polygons deleted at the same time to undo their deleting + */ + private Stack> redoStack = new Stack<>(); + /** + * List of the annotated masks on an image + */ + private Stack> annotatedMask = new Stack>(); + /** + * List that keeps track of the annotated masks + */ + private Stack> redoAnnotatedMask = new Stack>(); + /** + * Tracks if Ctrl+Z has already been handled + */ + private boolean undoPressed = false; + /** + * Tracks if Ctrl+Y has already been handled + */ + private boolean redoPressed = false; + /** + * Whether the SAMJ specific listeners are registered or not. + */ + private boolean registered = false; + + @Override + public List getListOfOpenImages() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getPolygonsFromRoiManager() { + return Arrays.stream(roiManager.getRoisAsArray()).map(i -> i.getPolygon()).collect(Collectors.toList()); + } + + @Override + public void enableAddingToRoiManager(boolean shouldBeAdding) { + this.isAddingToRoiManager = shouldBeAdding; + } + + @Override + public void exportImageLabeling() { + int width = activeImage.getWidth(); + int height = activeImage.getHeight(); + List masks = new ArrayList(); + this.annotatedMask.stream().forEach(mm -> masks.addAll(mm)); + RandomAccessibleInterval raiMask = Mask.getMask(width, height, masks); + ImagePlus impMask = ImageJFunctions.show(raiMask); + impMask.setTitle(activeImage.getTitle() + "-labeling"); + impMask.getProcessor().setMinAndMax(0, annotatedMask.size()); + } + + @Override + public void activateListeners() { + if (registered) return; + SwingUtilities.invokeLater(() -> { + IJ.addEventListener(this); + activeCanvas.removeKeyListener(IJ.getInstance()); + activeWindow.removeKeyListener(IJ.getInstance()); + activeCanvas.addMouseListener(this); + activeCanvas.addKeyListener(this); + activeWindow.addWindowListener(this); + activeWindow.addKeyListener(this); + }); + registered = true; + } + + @Override + public void deactivateListeners() { + if (!registered) return; + SwingUtilities.invokeLater(() -> { + IJ.removeEventListener(this); + activeCanvas.removeMouseListener(this); + activeCanvas.removeKeyListener(this); + activeWindow.removeWindowListener(this); + activeWindow.removeKeyListener(this); + + activeWindow.addKeyListener(IJ.getInstance()); + activeCanvas.addKeyListener(IJ.getInstance()); + }); + registered = false; + } + + @Override + public void setFocusedImage(Object image) { + activeImage = (ImagePlus) image; + } + + private RoiManager startRoiManager() { + RoiManager roiManager = RoiManager.getInstance(); + if (roiManager == null) { + roiManager = new RoiManager(); + } + roiManager.reset(); + roiManager.setVisible(true); + roiManager.setTitle("SAM Roi Manager"); + Prefs.useNamesAsLabels = true; + roiManager.setEditMode(activeImage, true); + return roiManager; + } + +}