diff --git a/RandomCrops/.classpath b/RandomCrops/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..f2bb7c149cb50235dc6957d066a14a70470cf398 --- /dev/null +++ b/RandomCrops/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="var" path="ICY_JAR"/> + <classpathentry kind="var" path="ICY_PLUGINS/adufour/ezplug/EzPlug.jar"/> + <classpathentry kind="var" path="ICY_PLUGINS/adufour/blocks/Blocks.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/RandomCrops/.gitignore b/RandomCrops/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c40361ab5730cdf273a697c604d32f221c515f6a --- /dev/null +++ b/RandomCrops/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/.settings/ +*.jar \ No newline at end of file diff --git a/RandomCrops/.project b/RandomCrops/.project new file mode 100644 index 0000000000000000000000000000000000000000..f437f6bb2a633451958c290c644cd6df93b4f381 --- /dev/null +++ b/RandomCrops/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>RandomCrops</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/RandomCrops/export.jardesc b/RandomCrops/export.jardesc new file mode 100644 index 0000000000000000000000000000000000000000..5052a61c81748920d2266bbf13f67390fa21ed7d --- /dev/null +++ b/RandomCrops/export.jardesc @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?> +<jardesc> + <jar path="RandomCrops/RandomCrops.jar"/> + <options buildIfNeeded="true" compress="true" descriptionLocation="/RandomCrops/export.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/> + <storedRefactorings deprecationInfo="true" structuralOnly="false"/> + <selectedProjects/> + <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true"> + <sealing sealJar="false"> + <packagesToSeal/> + <packagesToUnSeal/> + </sealing> + </manifest> + <selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false"> + <javaElement handleIdentifier="=RandomCrops/src\/main\/java"/> + <file path="/RandomCrops/.classpath"/> + <file path="/RandomCrops/.project"/> + </selectedElements> +</jardesc> diff --git a/RandomCrops/src/main/java/danyfel80/randomcrops/RandomRectangleGenerator.java b/RandomCrops/src/main/java/danyfel80/randomcrops/RandomRectangleGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..99c8a6d51157432e32e9fe06c4067b7afbe868cc --- /dev/null +++ b/RandomCrops/src/main/java/danyfel80/randomcrops/RandomRectangleGenerator.java @@ -0,0 +1,120 @@ +package danyfel80.randomcrops; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.function.Supplier; + +import icy.roi.ROI2D; +import plugins.kernel.roi.roi2d.ROI2DRectangle; + +public class RandomRectangleGenerator implements Callable<List<ROI2DRectangle>> +{ + + public static class Builder + { + + private Dimension rectangleSize; + private int rectangleCount; + private List<ROI2D> limitingRois; + + public Builder(Dimension rectangleSize, int rectangleCount, List<ROI2D> limitingRois) + { + Objects.requireNonNull(rectangleSize); + Objects.requireNonNull(limitingRois); + if (limitingRois.isEmpty()) + throw new IllegalArgumentException("limitingRois is empty. At least one roi is needed"); + + this.rectangleSize = rectangleSize; + this.rectangleCount = rectangleCount; + this.limitingRois = limitingRois; + } + + public RandomRectangleGenerator build() + { + RandomRectangleGenerator generator = new RandomRectangleGenerator(); + generator.rectangleSize = rectangleSize; + generator.rectangleCount = rectangleCount; + generator.limitingRois = limitingRois; + return generator; + } + + } + + private Random randomValueGenerator; + private Dimension rectangleSize; + private int rectangleCount; + private List<ROI2D> limitingRois; + + private RandomRectangleGenerator() + { + randomValueGenerator = new Random(); + } + + @Override + public List<ROI2DRectangle> call() throws Exception + { + computeValueBoundary(); + if (valueBoundary.getWidth() < rectangleSize.width || valueBoundary.getHeight() < rectangleSize.height) + throw new IllegalArgumentException("Rectangle"); + + List<ROI2DRectangle> rectangles = new ArrayList<>(rectangleCount); + for (int count = 0; count < rectangleCount; count++) + { + if (Thread.interrupted()) + throw new InterruptedException(); + + rectangles.add(getValidRandomRectangle()); + } + return rectangles; + } + + private Rectangle2D valueBoundary; + private Supplier<Integer> xGenerator; + private Supplier<Integer> yGenerator; + + private void computeValueBoundary() + { + Rectangle2D seedBounds = limitingRois.get(0).getBounds2D(); + valueBoundary = new Rectangle2D.Double(seedBounds.getX(), seedBounds.getY(), seedBounds.getWidth(), + seedBounds.getHeight()); + limitingRois.stream().map(ROI2D::getBounds2D) + .forEach(rect2d -> Rectangle2D.union(valueBoundary, rect2d, valueBoundary)); + + int minX = (int) Math.floor(valueBoundary.getMinX()); + int maxX = (int) Math.floor(valueBoundary.getMaxX()); + int xLength = maxX - minX; + xGenerator = () -> minX + randomValueGenerator.nextInt(xLength); + + int minY = (int) Math.floor(valueBoundary.getMinY()); + int maxY = (int) Math.floor(valueBoundary.getMaxY()); + int yLength = maxY - minY; + yGenerator = () -> minY + randomValueGenerator.nextInt(yLength); + } + + private ROI2DRectangle getValidRandomRectangle() throws InterruptedException + { + Rectangle rect = new Rectangle(rectangleSize); + do + { + if (Thread.interrupted()) + throw new InterruptedException(); + + rect.x = xGenerator.get(); + rect.y = yGenerator.get(); + } + while (!isValidRectangle(rect)); + return new ROI2DRectangle(rect); + } + + private boolean isValidRectangle(Rectangle rect) + { + return limitingRois.stream().anyMatch(roi -> roi.getBounds2D().contains(rect) && roi.contains(rect)); + } + +} diff --git a/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomCrops.java b/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomCrops.java new file mode 100644 index 0000000000000000000000000000000000000000..f499637e600febfbb0c70d6aa5b5fb4f33b7a233 --- /dev/null +++ b/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomCrops.java @@ -0,0 +1,142 @@ +package plugins.danyfel80.randomcrops; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import danyfel80.randomcrops.RandomRectangleGenerator; +import icy.roi.ROI2D; +import icy.sequence.Sequence; +import icy.sequence.SequenceUtil; +import icy.system.IcyHandledException; +import plugins.adufour.blocks.lang.Block; +import plugins.adufour.blocks.util.VarList; +import plugins.adufour.ezplug.EzGroup; +import plugins.adufour.ezplug.EzPlug; +import plugins.adufour.ezplug.EzStoppable; +import plugins.adufour.ezplug.EzVarBoolean; +import plugins.adufour.ezplug.EzVarInteger; +import plugins.adufour.ezplug.EzVarSequence; +import plugins.adufour.vars.lang.VarSequenceArray; +import plugins.kernel.roi.roi2d.ROI2DRectangle; + +public class GenerateRandomCrops extends EzPlug implements Block, EzStoppable +{ + + private EzVarSequence varInSequence; + private EzVarInteger varInRectangleWidth; + private EzVarInteger varInRectangleHeight; + private EzVarInteger varInNumberOfRectangles; + private EzVarBoolean varInLimitRectanglesToROIs; + + @Override + protected void initialize() + { + initializeInputVars(); + addEzComponent(varInSequence); + addEzComponent(new EzGroup("Generated rectangles", varInRectangleWidth, varInRectangleHeight, + varInNumberOfRectangles)); + addEzComponent(varInLimitRectanglesToROIs); + } + + private void initializeInputVars() + { + varInSequence = new EzVarSequence("Sequence"); + varInRectangleWidth = new EzVarInteger("Rectangle width (px)", 512, 1, 10000, 1); + varInRectangleHeight = new EzVarInteger("Rectangle height (px)", 512, 1, 10000, 1); + varInNumberOfRectangles = new EzVarInteger("Number of rectangles", 10, 0, 10000000, 1); + varInLimitRectanglesToROIs = new EzVarBoolean("Limit rectangles to ROIs", false); + } + + @Override + public void declareInput(VarList inputMap) + { + initializeInputVars(); + inputMap.add(varInSequence.name, varInSequence.getVariable()); + inputMap.add(varInRectangleWidth.name, varInRectangleWidth.getVariable()); + inputMap.add(varInRectangleHeight.name, varInRectangleHeight.getVariable()); + inputMap.add(varInNumberOfRectangles.name, varInNumberOfRectangles.getVariable()); + inputMap.add(varInLimitRectanglesToROIs.name, varInLimitRectanglesToROIs.getVariable()); + } + + private VarSequenceArray varOutSequences; + + @Override + public void declareOutput(VarList outputMap) + { + varOutSequences = new VarSequenceArray("Random crops"); + outputMap.add(varOutSequences.getName(), varOutSequences); + } + + @Override + protected void execute() + { + readParameters(); + try + { + generateRandomRectangles(); + } + catch (Exception e) + { + throw new IcyHandledException("Error generating random rectangles: " + e.getMessage(), e); + } + setOutput(); + } + + private Sequence sequence; + private Dimension rectangleSize; + private Integer rectangleCount; + private Boolean limitRectanglesToRois; + private List<ROI2D> limitingRois; + + private void readParameters() + { + sequence = varInSequence.getValue(true); + rectangleSize = new Dimension(varInRectangleWidth.getValue(), varInRectangleHeight.getValue()); + rectangleCount = varInNumberOfRectangles.getValue(); + limitRectanglesToRois = varInLimitRectanglesToROIs.getValue(); + limitingRois = new ArrayList<>(); + List<ROI2D> sequenceRois = sequence.getROI2Ds(); + if (!limitRectanglesToRois || sequenceRois.isEmpty()) + { + limitingRois.add(new ROI2DRectangle(new Rectangle(sequence.getWidth(), sequence.getHeight()))); + } + else + { + + limitingRois.addAll(sequenceRois); + } + } + + private List<Sequence> croppedSequences; + + private void generateRandomRectangles() throws Exception + { + RandomRectangleGenerator rectGenerator = new RandomRectangleGenerator.Builder(rectangleSize, rectangleCount, + limitingRois).build(); + List<ROI2DRectangle> rectangles = rectGenerator.call(); + croppedSequences = rectangles.stream().map(roi -> SequenceUtil.getSubSequence(sequence, roi)) + .collect(Collectors.toList()); + } + + private void setOutput() + { + if (isHeadLess()) + { + varOutSequences.setValue(croppedSequences.stream().toArray(Sequence[]::new)); + } + else + + { + croppedSequences.stream().forEach(seq -> addSequence(seq)); + } + } + + @Override + public void clean() + {// Nothing to do here + } + +} diff --git a/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomRectangleRois.java b/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomRectangleRois.java new file mode 100644 index 0000000000000000000000000000000000000000..a7bc96e29ca51d16b4e424661929e290edc8d93d --- /dev/null +++ b/RandomCrops/src/main/java/plugins/danyfel80/randomcrops/GenerateRandomRectangleRois.java @@ -0,0 +1,138 @@ +package plugins.danyfel80.randomcrops; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.List; + +import danyfel80.randomcrops.RandomRectangleGenerator; +import icy.roi.ROI; +import icy.roi.ROI2D; +import icy.sequence.Sequence; +import icy.system.IcyHandledException; +import plugins.adufour.blocks.lang.Block; +import plugins.adufour.blocks.util.VarList; +import plugins.adufour.ezplug.EzGroup; +import plugins.adufour.ezplug.EzPlug; +import plugins.adufour.ezplug.EzVarBoolean; +import plugins.adufour.ezplug.EzVarInteger; +import plugins.adufour.ezplug.EzVarSequence; +import plugins.adufour.vars.lang.VarROIArray; +import plugins.kernel.roi.roi2d.ROI2DRectangle; + +public class GenerateRandomRectangleRois extends EzPlug implements Block +{ + + private EzVarSequence varInSequence; + private EzVarInteger varInRectangleWidth; + private EzVarInteger varInRectangleHeight; + private EzVarInteger varInNumberOfRectangles; + private EzVarBoolean varInLimitRectanglesToROIs; + + @Override + protected void initialize() + { + initializeInputVars(); + addEzComponent(varInSequence); + addEzComponent(new EzGroup("Generated rectangles", varInRectangleWidth, varInRectangleHeight, + varInNumberOfRectangles)); + addEzComponent(varInLimitRectanglesToROIs); + } + + private void initializeInputVars() + { + varInSequence = new EzVarSequence("Sequence"); + varInRectangleWidth = new EzVarInteger("Rectangle width (px)", 512, 1, 10000, 1); + varInRectangleHeight = new EzVarInteger("Rectangle height (px)", 512, 1, 10000, 1); + varInNumberOfRectangles = new EzVarInteger("Number of rectangles", 10, 0, 10000000, 1); + varInLimitRectanglesToROIs = new EzVarBoolean("Limit rectangles to ROIs", false); + } + + @Override + public void declareInput(VarList inputMap) + { + initializeInputVars(); + inputMap.add(varInSequence.name, varInSequence.getVariable()); + inputMap.add(varInRectangleWidth.name, varInRectangleWidth.getVariable()); + inputMap.add(varInRectangleHeight.name, varInRectangleHeight.getVariable()); + inputMap.add(varInNumberOfRectangles.name, varInNumberOfRectangles.getVariable()); + inputMap.add(varInLimitRectanglesToROIs.name, varInLimitRectanglesToROIs.getVariable()); + } + + private VarROIArray varOutRectangles; + + @Override + public void declareOutput(VarList outputMap) + { + varOutRectangles = new VarROIArray("Random rectangles"); + outputMap.add(varOutRectangles.getName(), varOutRectangles); + } + + @Override + protected void execute() + { + readParameters(); + try + { + generateRandomRectangles(); + } + catch (Exception e) + { + throw new IcyHandledException("Error generating random rectangles: " + e.getMessage(), e); + } + setOutput(); + } + + private Sequence sequence; + private Dimension rectangleSize; + private Integer rectangleCount; + private Boolean limitRectanglesToRois; + private List<ROI2D> limitingRois; + + private void readParameters() + { + sequence = varInSequence.getValue(true); + rectangleSize = new Dimension(varInRectangleWidth.getValue(), varInRectangleHeight.getValue()); + rectangleCount = varInNumberOfRectangles.getValue(); + limitRectanglesToRois = varInLimitRectanglesToROIs.getValue(); + limitingRois = new ArrayList<>(); + List<ROI2D> sequenceRois = sequence.getROI2Ds(); + if (!limitRectanglesToRois || sequenceRois.isEmpty()) + { + limitingRois.add(new ROI2DRectangle(new Rectangle(sequence.getWidth(), sequence.getHeight()))); + } + else + { + + limitingRois.addAll(sequenceRois); + } + } + + private List<ROI2DRectangle> rectangles; + + private void generateRandomRectangles() throws Exception + { + RandomRectangleGenerator rectGenerator = new RandomRectangleGenerator.Builder(rectangleSize, rectangleCount, + limitingRois).build(); + rectangles = rectGenerator.call(); + } + + private void setOutput() + { + if (isHeadLess()) + { + varOutRectangles.setValue(rectangles.stream().toArray(ROI[]::new)); + } + else + { + sequence.addROIs(rectangles, true); + } + + } + + @Override + public void clean() + {// Nothing to do here + } + +} diff --git a/icon100px.png b/icon100px.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b9c1701760295ef4aeeb86276303461a41ef19 Binary files /dev/null and b/icon100px.png differ