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