diff --git a/.gitignore b/.gitignore
index 0f33221ba14c994d1054744f7a310805a27ac78d..57f16fb67c1b1589981416b323d7a9debc728665 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,41 @@
-.idea/
-.settings/
-bin/
-build/
+/build*
+/workspace
+setting.xml
+release/
 target/
-workspace/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+icy.log
+
+### IntelliJ IDEA ###
+.idea/
+*.iws
 *.iml
-*.jar
+*.ipr
+
+### Eclipse ###
+.apt_generated
 .classpath
+.factorypath
 .project
-export.jardesc
-setting.xml
-**/.DS_Store
\ No newline at end of file
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+**/.DS_Store
+Icon?
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ead22e35eb3aabd014d4ca56628b0fea88bdd849..02ef00b45202ec3ecf88bb23a6853aa569993f21 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,11 +5,11 @@
 	<parent>
 		<groupId>org.bioimageanalysis.icy</groupId>
 		<artifactId>pom-icy</artifactId>
-		<version>2.2.0</version>
+		<version>3.0.0-a.1</version>
 	</parent>
 
 	<artifactId>roi-statistics</artifactId>
-	<version>6.0.0</version>
+	<version>6.0.0-a.1</version>
 
 	<name>ROI Statistics</name>
 	<description>
@@ -18,36 +18,68 @@
     </description>
 
 	<dependencies>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>kernel-extensions</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>quickhull</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>3d-mesh-roi</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
 			<artifactId>vecmath</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
-			<artifactId>active-contours</artifactId>
+			<artifactId>jama</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
-			<artifactId>convexify</artifactId>
+			<artifactId>ezplug</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
-			<artifactId>sequence-blocks</artifactId>
+			<artifactId>convexify</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
-			<artifactId>spot-tracking</artifactId>
+			<artifactId>protocols</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.bioimageanalysis.icy</groupId>
 			<artifactId>workbooks</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>icy-jmath</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>track-manager</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>active-contours</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>spot-detection-utilities</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bioimageanalysis.icy</groupId>
+			<artifactId>spot-tracking</artifactId>
+		</dependency>
 	</dependencies>
 
 	<repositories>
 		<repository>
 			<id>icy</id>
-			<url>https://icy-nexus.pasteur.fr/repository/Icy/</url>
+			<url>https://nexus-icy.pasteur.cloud/repository/icy/</url>
 		</repository>
 	</repositories>
 </project>
\ No newline at end of file
diff --git a/src/main/java/plugins/adufour/roi/ROIConvexHullDescriptor.java b/src/main/java/plugins/adufour/roi/ROIConvexHullDescriptor.java
index cae4e71671ab09681b3c7913552290e94696571c..13791ba8c0baaf47c205b2eee0c4e4c63df2860a 100644
--- a/src/main/java/plugins/adufour/roi/ROIConvexHullDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROIConvexHullDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,20 +18,22 @@
 
 package plugins.adufour.roi;
 
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DRectShape;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROI2D;
+import org.bioimageanalysis.icy.model.roi.ROI3D;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
 import plugins.adufour.quickhull.QuickHull2D;
 import plugins.adufour.quickhull.QuickHull3D;
 import plugins.adufour.roi.mesh.Vertex3D;
 import plugins.adufour.roi.mesh.polygon.ROI3DPolygonalMesh;
-import plugins.kernel.roi.roi2d.ROI2DRectShape;
 
 import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
@@ -42,7 +44,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Convex Hull Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescriptor {
     public static class ROIConvexity extends ROIDescriptor {
         protected ROIConvexity() {
             super("Convexity", Double.class);
@@ -85,9 +89,7 @@ public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescript
             if (roi.getNumberOfPoints() < 4)
                 return 100;
 
-            if (roi instanceof ROI2D) {
-                final ROI2D r2 = (ROI2D) roi;
-
+            if (roi instanceof final ROI2D r2) {
                 final Point[] pts = r2.getBooleanMask(true).getContourPoints();
 
                 if (pts.length < 4)
@@ -105,7 +107,7 @@ public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescript
                 // contour = sum( sqrt[ (x[i] - x[i-1])^2 + (y[i] - y[i-1])^2 ] )
                 // area = 0.5 * sum( (x[i-1] * y[i]) - (y[i-1] * x[i]) )
 
-                Point2D p1 = points.get(points.size() - 1), p2;
+                Point2D p1 = points.getLast(), p2;
 
                 for (final Point2D point : points) {
                     p2 = point;
@@ -118,8 +120,7 @@ public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescript
             else if (roi instanceof ROI3D) {
                 final Point3d[] points;
 
-                if (roi instanceof ROI3DPolygonalMesh) {
-                    final ROI3DPolygonalMesh mesh = (ROI3DPolygonalMesh) roi;
+                if (roi instanceof final ROI3DPolygonalMesh mesh) {
                     // Tuple3d res = mesh.getPixelSize();
                     points = new Point3d[mesh.getNumberOfVertices(true)];
 
@@ -174,11 +175,11 @@ public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescript
                     }
                 }
                 catch (final RuntimeException e) {
-                    System.err.println("Warning while computing the convexity of " + roi.getName() + ": " + e.getMessage());
+                    IcyLogger.warn(ROIConvexity.class, e, "Warning while computing the convexity of " + roi.getName());
                 }
             }
             else {
-                System.err.println("WARNING: cannot compute the convexity of a " + roi.getClassName());
+                IcyLogger.warn(ROIConvexity.class, "WARNING: cannot compute the convexity of a " + roi.getClassName());
                 return Double.NaN;
             }
 
@@ -202,9 +203,4 @@ public class ROIConvexHullDescriptor extends Plugin implements PluginROIDescript
         map.put(convexity, convexity.compute(roi, sequence));
         return map;
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROIEllipsoidFittingDescriptor.java b/src/main/java/plugins/adufour/roi/ROIEllipsoidFittingDescriptor.java
index 7a0b1b99628fec681dddf16aa644a3fb18ebe094..0bc83ab72ad511352c5ad588f69a064d92c3d2f6 100644
--- a/src/main/java/plugins/adufour/roi/ROIEllipsoidFittingDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROIEllipsoidFittingDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -20,19 +20,19 @@ package plugins.adufour.roi;
 
 import Jama.EigenvalueDecomposition;
 import Jama.Matrix;
-import icy.math.MathUtil;
-import icy.math.UnitUtil;
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.common.math.MathUtil;
+import org.bioimageanalysis.icy.common.math.UnitUtil;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.*;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
 import plugins.adufour.vars.lang.VarDouble;
-import plugins.kernel.roi.descriptor.measure.ROIMassCenterDescriptorsPlugin;
 
 import javax.vecmath.*;
 import java.awt.*;
@@ -40,7 +40,9 @@ import java.awt.geom.Point2D;
 import java.util.List;
 import java.util.*;
 
-public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Ellipsoid Fitting Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDescriptor {
     public static class ROIFirstDiameter extends ROIDescriptor {
         protected ROIFirstDiameter() {
             super("1st Diameter", Double.class);
@@ -175,7 +177,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
          * @return The first (or major) principle axis of the best fitting ellipse
          * @throws InterruptedException if thread was interrupted
          */
-        public static Vector3d computeFirstAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
+        public static @NotNull Vector3d computeFirstAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
             final double[] ellipse = computeOrientation(roi, sequence);
             return new Vector3d(ellipse[3], ellipse[4], ellipse[5]);
         }
@@ -210,7 +212,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
          * @return The second principle axis of the best fitting ellipse
          * @throws InterruptedException if thread was interrupted
          */
-        public static Vector3d computeSecondAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
+        public static @NotNull Vector3d computeSecondAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
             final double[] ellipse = computeOrientation(roi, sequence);
             return new Vector3d(ellipse[6], ellipse[7], ellipse[8]);
         }
@@ -245,7 +247,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
          * @return The third principle axis of the best fitting ellipse
          * @throws InterruptedException if thread was interrupted
          */
-        public static Vector3d computeThirdAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
+        public static @NotNull Vector3d computeThirdAxis(final ROI roi, final Sequence sequence) throws InterruptedException {
             if (roi instanceof ROI2D)
                 return new Vector3d();
 
@@ -457,6 +459,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
          * @param ellipse ellipse orientation
          * @return The elongation ratio of the X-Y plane
          */
+        @Contract(pure = true)
         public static double computeElongation(final double[] ellipse) {
             if (ellipse == null)
                 return Double.NaN;
@@ -503,6 +506,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
          * @param ellipse ellipse orientation
          * @return The 3D flatness ratio of the Y-Z plane
          */
+        @Contract(pure = true)
         public static double computeFlatness3D(final double[] ellipse) {
             if (ellipse == null)
                 return Double.NaN;
@@ -567,7 +571,8 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
         return map;
     }
 
-    private static String getUnit(final Sequence sequence) {
+    @Contract(pure = true)
+    private static @NotNull String getUnit(final Sequence sequence) {
         if (sequence == null)
             return "px";
 
@@ -596,7 +601,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
      * </ul>
      * @throws InterruptedException if thread was interrupted
      */
-    public static double[] computeOrientation(final ROI roi, final Sequence sequence) throws InterruptedException {
+    public static double @NotNull [] computeOrientation(final ROI roi, final Sequence sequence) throws InterruptedException {
         final double[] ellipse = new double[12];
 
         if (roi instanceof ROI2D) {
@@ -661,7 +666,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
             }
         }
         else {
-            System.err.println("Cannot compute ellipse dimensions for ROI of type: " + roi.getClassName());
+            IcyLogger.error(ROIEllipsoidFittingDescriptor.class, "Cannot compute ellipse dimensions for ROI of type: " + roi.getClassName());
             Arrays.fill(ellipse, Double.NaN);
         }
 
@@ -695,7 +700,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
      * @throws InterruptedException
      * @throws SingularMatrixException  if the component is flat (i.e. lies in a 2D plane)
      */
-    private static void fitEllipse(final ROI3D cc, final Point3d radii, final Vector3d[] eigenVectors, final double[] equation) throws IllegalArgumentException, InterruptedException {
+    private static void fitEllipse(final @NotNull ROI3D cc, final Point3d radii, final Vector3d[] eigenVectors, final double[] equation) throws IllegalArgumentException, InterruptedException {
         final Point3D.Integer[] points = cc.getBooleanMask(true).getContourPoints();
 
         if (points.length < 9) {
@@ -789,7 +794,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
      * @throws InterruptedException
      */
     private static void fitEllipse(
-            final ROI2D roi,
+            final @NotNull ROI2D roi,
             final Point2d center,
             final Point2d radii,
             final VarDouble angle,
@@ -801,7 +806,7 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
         if (points.length < 4)
             return;
 
-        final Point2D ccenter = ROIMassCenterDescriptorsPlugin.computeMassCenter(roi).toPoint2D();
+        final Point2D ccenter = ROIUtil.computeMassCenter(roi).toPoint2D();
         final double cx = ccenter.getX();
         final double cy = ccenter.getY();
 
@@ -924,7 +929,8 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
         }
     }
 
-    private static Matrix diag(final Matrix matrix) {
+    @Contract("_ -> new")
+    private static @NotNull Matrix diag(final @NotNull Matrix matrix) {
         final int min = Math.min(matrix.getRowDimension(), matrix.getColumnDimension());
         final double[][] diag = new double[min][1];
         for (int i = 0; i < min; i++) {
@@ -933,15 +939,11 @@ public class ROIEllipsoidFittingDescriptor extends Plugin implements PluginROIDe
         return new Matrix(diag);
     }
 
-    private static Matrix ones(final int m, final int n) {
+    @Contract("_, _ -> new")
+    private static @NotNull Matrix ones(final int m, final int n) {
         final double[][] array = new double[m][n];
         for (final double[] row : array)
             Arrays.fill(row, 1.0);
         return new Matrix(array, m, n);
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROIFeretDiameterDescriptor.java b/src/main/java/plugins/adufour/roi/ROIFeretDiameterDescriptor.java
index 859adbbbd24c2450255f8cbecad69ddc92ccd240..49960e391e27238cab596fb10d448aec012750ee 100644
--- a/src/main/java/plugins/adufour/roi/ROIFeretDiameterDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROIFeretDiameterDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,19 +18,21 @@
 
 package plugins.adufour.roi;
 
-import icy.math.UnitUtil;
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DRectShape;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.common.math.UnitUtil;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROI2D;
+import org.bioimageanalysis.icy.model.roi.ROI3D;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
 import plugins.adufour.roi.mesh.Vertex3D;
 import plugins.adufour.roi.mesh.polygon.ROI3DPolygonalMesh;
-import plugins.kernel.roi.roi2d.ROI2DRectShape;
 
 import javax.vecmath.Point3d;
 import java.awt.*;
@@ -41,7 +43,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class ROIFeretDiameterDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Feret Diameter Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROIFeretDiameterDescriptor extends Plugin implements PluginROIDescriptor {
     public static class ROIFeretDiameter extends ROIDescriptor {
         protected ROIFeretDiameter() {
             super("Max Feret diameter", Double.class);
@@ -153,7 +157,7 @@ public class ROIFeretDiameterDescriptor extends Plugin implements PluginROIDescr
                 maxDistance = Math.sqrt(maxDistance);
             }
             else {
-                System.err.println("Cannot compute Max. Feret diameter for ROI of type: " + roi.getClassName());
+                IcyLogger.error(ROIFeretDiameter.class, "Cannot compute Max. Feret diameter for ROI of type: " + roi.getClassName());
                 maxDistance = 0.0d;
             }
 
@@ -176,9 +180,4 @@ public class ROIFeretDiameterDescriptor extends Plugin implements PluginROIDescr
         map.put(feretDiameter, feretDiameter.compute(roi, sequence));
         return map;
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROIHaralickTextureDescriptor.java b/src/main/java/plugins/adufour/roi/ROIHaralickTextureDescriptor.java
index cb2273e4658354da269f4adaec7ff496aa35c1f4..514218d691696226af1781e28aec7755392aeebb 100644
--- a/src/main/java/plugins/adufour/roi/ROIHaralickTextureDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROIHaralickTextureDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,25 +18,29 @@
 
 package plugins.adufour.roi;
 
-import icy.image.IcyBufferedImage;
-import icy.image.IcyBufferedImageUtil;
-import icy.math.ArrayMath;
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.BooleanMask2D;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.DataType;
+import org.bioimageanalysis.icy.common.math.ArrayMath;
+import org.bioimageanalysis.icy.common.type.DataType;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.image.IcyBufferedImage;
+import org.bioimageanalysis.icy.model.image.IcyBufferedImageUtil;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROI2D;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.mask.BooleanMask2D;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class ROIHaralickTextureDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Haralick Texture Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROIHaralickTextureDescriptor extends Plugin implements PluginROIDescriptor {
     private static abstract class ROIHaralickDescriptor extends ROIDescriptor {
         protected final int step;
 
@@ -211,7 +215,7 @@ public class ROIHaralickTextureDescriptor extends Plugin implements PluginROIDes
      * (see {@link #getDescriptors()}) for a full list
      * @throws InterruptedException
      */
-    public static Map<ROIDescriptor, Object> computeHaralickFeatures(final Sequence sequence, final ROI2D roi, final int step) throws InterruptedException {
+    public static @NotNull Map<ROIDescriptor, Object> computeHaralickFeatures(final Sequence sequence, final @NotNull ROI2D roi, final int step) throws InterruptedException {
         final int c = roi.getC();
         if (c == -1)
             throw new UnsupportedOperationException("Texture can only be calculated on a single channel");
@@ -295,10 +299,10 @@ public class ROIHaralickTextureDescriptor extends Plugin implements PluginROIDes
      * input region of interest (ROI)
      * @throws InterruptedException
      */
-    private static IcyBufferedImage buildGLCM(final IcyBufferedImage image, final ROI2D roi, final int step) throws InterruptedException {
+    private static @NotNull IcyBufferedImage buildGLCM(final @NotNull IcyBufferedImage image, final ROI2D roi, final int step) throws InterruptedException {
         // Rescale to [0-255] if necessary
         IcyBufferedImage imByte = null;
-        if (image.getDataType_() == DataType.UBYTE) {
+        if (image.getDataType() == DataType.UBYTE) {
             imByte = image;
         }
         else {
@@ -372,9 +376,4 @@ public class ROIHaralickTextureDescriptor extends Plugin implements PluginROIDes
 
         return coocImage;
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROIMeasures.java b/src/main/java/plugins/adufour/roi/ROIMeasures.java
index 15a2b8ddbfff02fabcf3eaa7f389f20cc5bce63f..aeb14a080833245e3ddc223e89bca872d4f0f0ca 100644
--- a/src/main/java/plugins/adufour/roi/ROIMeasures.java
+++ b/src/main/java/plugins/adufour/roi/ROIMeasures.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,31 +18,35 @@
 
 package plugins.adufour.roi;
 
-import icy.file.FileUtil;
-import icy.gui.main.GlobalSequenceListener;
-import icy.main.Icy;
-import icy.plugin.PluginLauncher;
-import icy.plugin.PluginLoader;
-import icy.preferences.XMLPreferences;
-import icy.roi.*;
-import icy.roi.ROIEvent.ROIEventType;
-import icy.sequence.Sequence;
-import icy.sequence.SequenceDataIterator;
-import icy.sequence.SequenceEvent;
-import icy.sequence.SequenceEvent.SequenceEventSourceType;
-import icy.sequence.SequenceListener;
-import icy.system.IcyExceptionHandler;
-import icy.system.SystemUtil;
-import icy.system.thread.Processor;
-import icy.system.thread.ThreadUtil;
-import icy.type.point.Point3D;
-import icy.type.point.Point5D;
-import icy.type.rectangle.Rectangle5D;
-import icy.util.StringUtil;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.util.WorkbookUtil;
+import org.bioimageanalysis.extension.kernel.roi.descriptor.measure.ROIContourDescriptor;
+import org.bioimageanalysis.extension.kernel.roi.descriptor.measure.ROIInteriorDescriptor;
+import org.bioimageanalysis.icy.Icy;
+import org.bioimageanalysis.icy.common.geom.point.Point5D;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.rectangle.Rectangle5D;
+import org.bioimageanalysis.icy.common.string.StringUtil;
+import org.bioimageanalysis.icy.extension.plugin.PluginLauncher;
+import org.bioimageanalysis.icy.extension.plugin.PluginLoader;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.gui.listener.GlobalSequenceListener;
+import org.bioimageanalysis.icy.io.FileUtil;
+import org.bioimageanalysis.icy.model.roi.*;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.model.sequence.SequenceDataIterator;
+import org.bioimageanalysis.icy.model.sequence.SequenceEvent;
+import org.bioimageanalysis.icy.model.sequence.SequenceListener;
+import org.bioimageanalysis.icy.system.SystemUtil;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
+import org.bioimageanalysis.icy.system.preferences.XMLPreferences;
+import org.bioimageanalysis.icy.system.thread.Processor;
+import org.bioimageanalysis.icy.system.thread.ThreadUtil;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
 import plugins.adufour.blocks.tools.roi.ROIBlock;
 import plugins.adufour.blocks.util.VarList;
 import plugins.adufour.ezplug.EzDialog;
@@ -65,8 +69,6 @@ import plugins.adufour.vars.util.VarReferencingPolicy;
 import plugins.adufour.workbooks.IcySpreadSheet;
 import plugins.adufour.workbooks.Workbooks;
 import plugins.kernel.roi.descriptor.measure.ROIBasicMeasureDescriptorsPlugin;
-import plugins.kernel.roi.descriptor.measure.ROIContourDescriptor;
-import plugins.kernel.roi.descriptor.measure.ROIInteriorDescriptor;
 import plugins.kernel.roi.descriptor.measure.ROIMassCenterDescriptorsPlugin;
 
 import javax.swing.*;
@@ -85,8 +87,9 @@ import java.util.concurrent.Future;
  * @author Alexandre Dufour
  * @author Daniel Gonzalez
  */
+@IcyPluginName("ROI Measures")
+@IcyPluginIcon(path = "/roi-stat.png")
 public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListener, SequenceListener, ROIListener {
-
     /**
      * Measures available for this plugin.
      * <b>Note:</b> The id is used when loading and saving parameters.
@@ -121,6 +124,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
         final int id;
         final String unit;
 
+        @Contract(pure = true)
         Measures(final String name, final int id, final String unit) {
             this.name = name;
             this.id = id;
@@ -129,31 +133,39 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
 
         boolean selected = true;
 
+        @SuppressWarnings("UnstableApiUsage")
+        @Contract(mutates = "this")
         public void toggleSelection() {
             selected = !selected;
         }
 
+        @SuppressWarnings("UnstableApiUsage")
+        @Contract(mutates = "this")
         public void setSelected(final boolean value) {
             selected = value;
         }
 
+        @Contract(pure = true)
         @Override
         public String toString() {
             return name;
         }
 
-        public String toHeader() {
+        public @NotNull String toHeader() {
             return name + (hasUnit() ? " (" + getUnit() + ")" : "");
         }
 
+        @Contract(pure = true)
         public boolean hasUnit() {
             return unit != null && !unit.isEmpty();
         }
 
+        @Contract(pure = true)
         public String getUnit() {
             return unit;
         }
 
+        @Contract(pure = true)
         public boolean isSelected() {
             return selected;
         }
@@ -226,7 +238,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     }
 
     @Override
-    public void declareInput(final VarList inputMap) {
+    public void declareInput(final @NotNull VarList inputMap) {
         measureSelector.setReferencingPolicy(VarReferencingPolicy.NONE);
         inputMap.add("measures", measureSelector);
         inputMap.add("Regions of interest", rois);
@@ -234,7 +246,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     }
 
     @Override
-    public void declareOutput(final VarList outputMap) {
+    public void declareOutput(final @NotNull VarList outputMap) {
         outputMap.add("Workbook", book);
     }
 
@@ -271,7 +283,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                 book.setValue(wbs);
             }
             catch (final IOException e) {
-                IcyExceptionHandler.showErrorMessage(e, true);
+                IcyLogger.error(this.getClass(), e);
             }
             //book.setValue(wb = Workbooks.createEmptyWorkbook());
         }
@@ -293,7 +305,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
             // try retrieving the sequence attached to the first ROI
             final List<Sequence> sequences = rois.getValue()[0].getSequences();
             if (!sequences.isEmpty())
-                sequenceOfInterest = sequences.get(0);
+                sequenceOfInterest = sequences.getFirst();
         }
 
         if (sequenceOfInterest == null) {
@@ -418,7 +430,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                 return;
             }
             catch (final Exception e) {
-                IcyExceptionHandler.showErrorMessage(e, true);
+                IcyLogger.error(this.getClass(), e);
                 return;
             }
 
@@ -433,7 +445,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
         }
     }
 
-    private void updateStatistics(final ROI roi) {
+    private void updateStatistics(final @NotNull ROI roi) {
         final Workbook wb = book.getValue();
 
         for (final Sequence sequenceOfInterest : roi.getSequences())
@@ -452,13 +464,13 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                 }
     }
 
-    private static String colorToString(final Color color) {
+    private static @NotNull String colorToString(final @NotNull Color color) {
         return (StringUtil.toHexaString(color.getAlpha(), 2) + StringUtil.toHexaString(color.getRed(), 2)
                 + StringUtil.toHexaString(color.getGreen(), 2) + StringUtil.toHexaString(color.getBlue(), 2))
                 .toUpperCase();
     }
 
-    private void updateWorkbook(final Workbook wb, final IcySpreadSheet sheet, final int rowID, final List<Object> measures, final boolean updateInterface) {
+    private void updateWorkbook(final Workbook wb, final IcySpreadSheet sheet, final int rowID, final @NotNull List<Object> measures, final boolean updateInterface) {
         for (int colID = 0; colID < measures.size(); colID++) {
             final Object value = measures.get(colID);
 
@@ -474,7 +486,9 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
             book.valueChanged(book, null, book.getValue());
     }
 
-    private Callable<List<Object>> createUpdater(final Sequence sequenceOfInterest, final ROI roi2Update) {
+    @SuppressWarnings("resource")
+    @Contract(pure = true)
+    private @NotNull Callable<List<Object>> createUpdater(final Sequence sequenceOfInterest, final ROI roi2Update) {
         return () -> {
             final List<Object> measures = new ArrayList<>();
             final List<Measures> measuresToCalculate = new ArrayList<>();
@@ -493,7 +507,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                     || Measures.T_CENTER.isSelected() || Measures.C_CENTER.isSelected()
                     || Measures.X_GLOBAL_CENTER.isSelected() || Measures.Y_GLOBAL_CENTER.isSelected()
                     || Measures.Z_GLOBAL_CENTER.isSelected()) {
-                center = ROIMassCenterDescriptorsPlugin.computeMassCenter(roi);
+                center = ROIUtil.computeMassCenter(roi);
                 globalCenter = center.toPoint3D();
                 if (sequenceOfInterest != null) {
                     globalCenter.setX(sequenceOfInterest.getPositionX()
@@ -596,7 +610,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                             // we don't want to spam output with these errors
                             if (!haralickErrors.contains(mess)) {
                                 haralickErrors.add(mess);
-                                System.err.println(mess);
+                                IcyLogger.error(this.getClass(), ex);
                             }
                         }
                     }
@@ -866,8 +880,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                             if (sequenceOfInterest == null)
                                 measures.add("NA");
                             else {
-                                final double mul = ROIBasicMeasureDescriptorsPlugin
-                                        .getMultiplierFactor(sequenceOfInterest, roi, 2);
+                                final double mul = ROIUtil.getMultiplierFactor(sequenceOfInterest, roi, 2);
 
                                 // 0 means the operation is not supported for this ROI
                                 if (mul == 0d)
@@ -888,8 +901,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                             if (sequenceOfInterest == null)
                                 measures.add("NA");
                             else {
-                                final double mul1 = ROIBasicMeasureDescriptorsPlugin
-                                        .getMultiplierFactor(sequenceOfInterest, roi, 3);
+                                final double mul1 = ROIUtil.getMultiplierFactor(sequenceOfInterest, roi, 3);
 
                                 // 0 means the operation is not supported for this ROI
                                 if (mul1 == 0d)
@@ -902,16 +914,19 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                             }
                             break;
                         case INTENSITY_X:
+                            Objects.requireNonNull(intensityCenters);
                             for (int c = 0; c < sizeC; c++) {
                                 measures.add(intensityCenters[c].getX());
                             }
                             break;
                         case INTENSITY_Y:
+                            Objects.requireNonNull(intensityCenters);
                             for (int c = 0; c < sizeC; c++) {
                                 measures.add(intensityCenters[c].getY());
                             }
                             break;
                         case INTENSITY_Z:
+                            Objects.requireNonNull(intensityCenters);
                             for (int c = 0; c < sizeC; c++) {
                                 measures.add(intensityCenters[c].getZ());
                             }
@@ -931,7 +946,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     // MAIN LISTENER //
 
     @Override
-    public void sequenceOpened(final Sequence openedSequence) {
+    public void sequenceOpened(final @NotNull Sequence openedSequence) {
         openedSequence.addListener(this);
         for (final ROI roi : openedSequence.getROIs())
             roi.addListener(this);
@@ -944,7 +959,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     }
 
     @Override
-    public void sequenceClosed(final Sequence closedSequence) {
+    public void sequenceClosed(final @NotNull Sequence closedSequence) {
         closedSequence.removeListener(this);
         for (final ROI roi : closedSequence.getROIs())
             roi.removeListener(this);
@@ -963,12 +978,12 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     // SEQUENCE LISTENER //
 
     @Override
-    public void sequenceChanged(final SequenceEvent sequenceEvent) {
-        if (sequenceEvent.getSourceType() == SequenceEventSourceType.SEQUENCE_DATA) {
+    public void sequenceChanged(final @NotNull SequenceEvent sequenceEvent) {
+        if (sequenceEvent.getSourceType() == SequenceEvent.SequenceEventSourceType.SEQUENCE_DATA) {
 
             updateStatistics(sequenceEvent.getSequence());
         }
-        else if (sequenceEvent.getSourceType() == SequenceEventSourceType.SEQUENCE_ROI) {
+        else if (sequenceEvent.getSourceType() == SequenceEvent.SequenceEventSourceType.SEQUENCE_ROI) {
             final ROI roi = (ROI) sequenceEvent.getSource();
 
             switch (sequenceEvent.getType()) {
@@ -991,7 +1006,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
 
                     if (roi == null) {
                         // multiple ROIs have been removed
-                        System.err.println("[ROI Statistics] Warning: potential memory leak");
+                        IcyLogger.warn(this.getClass(), "Warning: potential memory leak");
                     }
                     else {
                         roi.removeListener(this);
@@ -1021,9 +1036,9 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
     }
 
     @Override
-    public void roiChanged(final ROIEvent event) {
-        if (event.getType() == ROIEventType.ROI_CHANGED
-                || event.getType() == ROIEventType.PROPERTY_CHANGED && (event.getPropertyName().equalsIgnoreCase("name")
+    public void roiChanged(final @NotNull ROIEvent event) {
+        if (event.getType() == ROIEvent.ROIEventType.ROI_CHANGED
+                || event.getType() == ROIEvent.ROIEventType.PROPERTY_CHANGED && (event.getPropertyName().equalsIgnoreCase("name")
                 || event.getPropertyName().equalsIgnoreCase("color"))) {
             updateStatistics(event.getSource());
             // this is mandatory since sheet modification cannot be detected
@@ -1049,8 +1064,9 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
             setNameVisible(false);
         }
 
+        @Contract(" -> new")
         @Override
-        protected JButton createEditorComponent() {
+        protected @NotNull JButton createEditorComponent() {
             if (getEditorComponent() != null)
                 deactivateListeners();
 
@@ -1074,6 +1090,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
             getEditorComponent().removeActionListener(listener);
         }
 
+        @Contract(pure = true)
         @Override
         protected void updateInterfaceValue() {
             // nothing to do (it's just a button with a name)
@@ -1103,8 +1120,9 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
                 addListener(gui);
         }
 
+        @Contract(" -> new")
         @Override
-        public VarEditor<Long> createVarEditor() {
+        public @NotNull VarEditor<Long> createVarEditor() {
             return new ButtonVarEditor(this);
         }
 
@@ -1241,6 +1259,7 @@ public class ROIMeasures extends EzPlug implements ROIBlock, GlobalSequenceListe
         }
     }
 
+    @SuppressWarnings("resource")
     public static void main(final String[] args) {
         Icy.main(args);
 
diff --git a/src/main/java/plugins/adufour/roi/ROIRoundnessDescriptor.java b/src/main/java/plugins/adufour/roi/ROIRoundnessDescriptor.java
index 2da0b4c20c644619f2e297ea137f7fcce24dd623..ab3da3b883174c5319f4c341af234f5a13073894 100644
--- a/src/main/java/plugins/adufour/roi/ROIRoundnessDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROIRoundnessDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,19 +18,18 @@
 
 package plugins.adufour.roi;
 
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.point.Point3D;
-import icy.type.point.Point5D;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DEllipse;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.point.Point5D;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.*;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
 import plugins.adufour.roi.ROISphericityDescriptor.ROISphericity;
 import plugins.kernel.roi.descriptor.measure.ROIMassCenterDescriptorsPlugin;
-import plugins.kernel.roi.roi2d.ROI2DEllipse;
 
 import javax.vecmath.Point3d;
 import java.awt.*;
@@ -41,7 +40,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class ROIRoundnessDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Roundness Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROIRoundnessDescriptor extends Plugin implements PluginROIDescriptor {
     public static class ROIRoundness extends ROIDescriptor {
         public ROIRoundness() {
             super("Roundness", Double.class);
@@ -111,7 +112,7 @@ public class ROIRoundnessDescriptor extends Plugin implements PluginROIDescripto
         public static double computeRoundness(final ROI roi) throws InterruptedException {
             double minDistance = Double.MAX_VALUE, maxDistance = 0.0d;
 
-            final Point5D center = ROIMassCenterDescriptorsPlugin.computeMassCenter(roi);
+            final Point5D center = ROIUtil.computeMassCenter(roi);
 
             if (roi instanceof ROI2D) {
                 if (roi instanceof ROI2DEllipse) {
@@ -146,7 +147,7 @@ public class ROIRoundnessDescriptor extends Plugin implements PluginROIDescripto
                 }
             }
             else {
-                System.err.println("Cannot compute roundness for ROI of type: " + roi.getClassName());
+                IcyLogger.error(ROIRoundness.class, "Cannot compute roundness for ROI of type: " + roi.getClassName());
                 return Double.NaN;
             }
 
@@ -171,9 +172,4 @@ public class ROIRoundnessDescriptor extends Plugin implements PluginROIDescripto
         map.put(roundness, roundness.compute(roi, sequence));
         return map;
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROISphericityDescriptor.java b/src/main/java/plugins/adufour/roi/ROISphericityDescriptor.java
index ce81dae99ada3e5ace4648070bf8218847e13283..a3edb221c15a602c969df1d16ddba6d9014d29e6 100644
--- a/src/main/java/plugins/adufour/roi/ROISphericityDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/ROISphericityDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,21 +18,25 @@
 
 package plugins.adufour.roi;
 
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROI2D;
+import org.bioimageanalysis.icy.model.roi.ROI3D;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class ROISphericityDescriptor extends Plugin implements PluginROIDescriptor, PluginBundled {
+@IcyPluginName("ROI Sphericity Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROISphericityDescriptor extends Plugin implements PluginROIDescriptor {
     public static class ROISphericity extends ROIDescriptor {
         public ROISphericity() {
             super("Sphericity", Double.class);
@@ -101,7 +105,7 @@ public class ROISphericityDescriptor extends Plugin implements PluginROIDescript
                 dim = 3.0d;
             }
             else {
-                System.err.println("Cannot compute sphericity for ROI of type: " + roi.getClassName());
+                IcyLogger.error(ROISphericity.class, "Cannot compute sphericity for ROI of type: " + roi.getClassName());
                 return Double.NaN;
             }
 
@@ -147,9 +151,4 @@ public class ROISphericityDescriptor extends Plugin implements PluginROIDescript
         map.put(sphericity, sphericity.compute(roi, sequence));
         return map;
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/ROIStatisticsTrackProcessor.java b/src/main/java/plugins/adufour/roi/ROIStatisticsTrackProcessor.java
index 67bab6d97090fb64902dd5d6394fb1cd6515f531..0b799703683c7afdc023d7e9c1a438fa37f29abe 100644
--- a/src/main/java/plugins/adufour/roi/ROIStatisticsTrackProcessor.java
+++ b/src/main/java/plugins/adufour/roi/ROIStatisticsTrackProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,15 +18,14 @@
 
 package plugins.adufour.roi;
 
-import icy.file.FileUtil;
-import icy.gui.dialog.SaveDialog;
-import icy.gui.frame.progress.AnnounceFrame;
-import icy.gui.util.GuiUtil;
-import icy.plugin.interface_.PluginBundled;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.system.IcyExceptionHandler;
 import org.apache.poi.ss.usermodel.Workbook;
+import org.bioimageanalysis.icy.gui.GuiUtil;
+import org.bioimageanalysis.icy.gui.dialog.SaveDialog;
+import org.bioimageanalysis.icy.gui.frame.progress.AnnounceFrame;
+import org.bioimageanalysis.icy.io.FileUtil;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.system.logging.IcyLogger;
 import org.math.plot.Plot2DPanel;
 import plugins.adufour.blocks.tools.io.WorkbookToFile;
 import plugins.adufour.blocks.tools.io.WorkbookToFile.MergePolicy;
@@ -42,12 +41,7 @@ import javax.swing.*;
 import java.awt.*;
 import java.io.IOException;
 
-public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor implements PluginBundled {
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
-
+public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor {
     private final JButton exportButton = new JButton("Export to XLS...");
 
     private final VarSequence sequence = new VarSequence("Sequence", null);
@@ -134,8 +128,13 @@ public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor imp
         final Sequence seq = trackPool.getDisplaySequence();
 
         try {
-            ROITrackStatistics.buildPlot(trackPool.getTrackGroupList(), seq, channel.getValue(),
-                    ROIDescriptor.getDescriptor(roiDescriptor.getValue()), plotPanel);
+            ROITrackStatistics.buildPlot(
+                    trackPool.getTrackGroupList(),
+                    seq,
+                    channel.getValue(),
+                    ROIDescriptor.getDescriptor(roiDescriptor.getValue()),
+                    plotPanel
+            );
 
             if (!plotPanel.getPlots().isEmpty()) {
                 chartPanel.add(plotPanel);
@@ -148,7 +147,7 @@ public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor imp
             }
         }
         catch (final Exception e) {
-            IcyExceptionHandler.showErrorMessage(e, true);
+            IcyLogger.error(this.getClass(), e, "Cannot compute descriptor.");
             chartPanel.add(new JLabel("Cannot compute descriptor: " + e.getMessage()));
             exportButton.setEnabled(false);
         }
@@ -172,7 +171,7 @@ public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor imp
 
             // Restore last used folder
             final String xlsFolder = getPreferencesRoot().get("xlsFolder", null);
-            final String path = SaveDialog.chooseFile("Export statistics", xlsFolder, name, ".xls");
+            final String path = SaveDialog.chooseFile("Export statistics", xlsFolder, name, ".xlsx");
 
             // canceled
             if (path == null)
@@ -191,7 +190,7 @@ public class ROIStatisticsTrackProcessor extends PluginTrackManagerProcessor imp
                 }
             }
             catch (final IOException e) {
-                IcyExceptionHandler.showErrorMessage(e, true);
+                IcyLogger.error(this.getClass(), e, "Cannot export statistics.");
             }
             finally {
                 message.close();
diff --git a/src/main/java/plugins/adufour/roi/ROITrackStatistics.java b/src/main/java/plugins/adufour/roi/ROITrackStatistics.java
index 6cf461327622b5e244c5e29dbc6c6a6844046d9a..0e49661fd2f3ac703549af816da7e0571e5e664f 100644
--- a/src/main/java/plugins/adufour/roi/ROITrackStatistics.java
+++ b/src/main/java/plugins/adufour/roi/ROITrackStatistics.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,15 +18,21 @@
 
 package plugins.adufour.roi;
 
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginBundled;
-import icy.roi.ROI;
-import icy.roi.ROI2D;
-import icy.roi.ROI3D;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.type.collection.CollectionUtil;
 import org.apache.poi.ss.usermodel.Workbook;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DArea;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DPoint;
+import org.bioimageanalysis.extension.kernel.roi.roi3d.ROI3DArea;
+import org.bioimageanalysis.extension.kernel.roi.roi3d.ROI3DPoint;
+import org.bioimageanalysis.icy.common.collection.CollectionUtil;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROI2D;
+import org.bioimageanalysis.icy.model.roi.ROI3D;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.jetbrains.annotations.NotNull;
 import org.math.plot.Plot2DPanel;
 import org.math.plot.plots.Plot;
 import plugins.adufour.activecontours.ActiveContour;
@@ -39,10 +45,6 @@ import plugins.adufour.workbooks.IcySpreadSheet;
 import plugins.adufour.workbooks.Workbooks;
 import plugins.fab.trackmanager.TrackGroup;
 import plugins.fab.trackmanager.TrackSegment;
-import plugins.kernel.roi.roi2d.ROI2DArea;
-import plugins.kernel.roi.roi2d.ROI2DPoint;
-import plugins.kernel.roi.roi3d.ROI3DArea;
-import plugins.kernel.roi.roi3d.ROI3DPoint;
 import plugins.nchenouard.particletracking.DetectionSpotTrack;
 import plugins.nchenouard.particletracking.legacytracker.SpotTrack;
 import plugins.nchenouard.spot.Detection;
@@ -55,15 +57,22 @@ import java.util.List;
  *
  * @author Stephane Dallongeville
  */
-public class ROITrackStatistics extends Plugin implements ROIBlock, PluginBundled {
+@IcyPluginName("ROI Track Statistics")
+@IcyPluginIcon(path = "/roi-stat.png")
+public class ROITrackStatistics extends Plugin implements ROIBlock {
     /**
      * Build the plot describing the {@link ROIDescriptor} evolution along given input tracks
      *
      * @throws InterruptedException
      * @throws UnsupportedOperationException
      */
-    public static void buildPlot(final List<TrackGroup> trackGroups, final Sequence sequence, final int channel, final ROIDescriptor descriptor, final Plot2DPanel plotPanel)
-            throws UnsupportedOperationException, InterruptedException {
+    public static void buildPlot(
+            final @NotNull List<TrackGroup> trackGroups,
+            final Sequence sequence,
+            final int channel,
+            final @NotNull ROIDescriptor descriptor,
+            final @NotNull Plot2DPanel plotPanel
+    ) throws UnsupportedOperationException, InterruptedException {
         final int sizeZ = (sequence != null) ? sequence.getSizeZ() : 1;
         final double timeInterval = (sequence != null) ? sequence.getTimeInterval() : 1d;
 
@@ -178,7 +187,7 @@ public class ROITrackStatistics extends Plugin implements ROIBlock, PluginBundle
     /**
      * Build and return the workbook describing the {@link ROIDescriptor} evolution along given input tracks
      */
-    public static Workbook getWorkBook(final Sequence sequence, final String name, final Plot2DPanel plotPanel) {
+    public static @NotNull Workbook getWorkBook(final Sequence sequence, final String name, final Plot2DPanel plotPanel) {
         final Workbook wb = Workbooks.createEmptyWorkbook();
         final IcySpreadSheet sheet = Workbooks.getSheet(wb, name);
 
@@ -225,7 +234,7 @@ public class ROITrackStatistics extends Plugin implements ROIBlock, PluginBundle
     }
 
     @Override
-    public void declareInput(final VarList inputMap) {
+    public void declareInput(final @NotNull VarList inputMap) {
         inputMap.add("trackgroup", tracks);
         inputMap.add("sequence", sequence);
         inputMap.add("channel", channel);
@@ -233,7 +242,7 @@ public class ROITrackStatistics extends Plugin implements ROIBlock, PluginBundle
     }
 
     @Override
-    public void declareOutput(final VarList outputMap) {
+    public void declareOutput(final @NotNull VarList outputMap) {
         outputMap.add("workbook", workbook);
     }
 
@@ -268,9 +277,4 @@ public class ROITrackStatistics extends Plugin implements ROIBlock, PluginBundle
             Thread.currentThread().interrupt();
         }
     }
-
-    @Override
-    public String getMainPluginClassName() {
-        return ROIMeasures.class.getName();
-    }
 }
diff --git a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterDescriptorsPlugin.java b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterDescriptorsPlugin.java
index ea06b9881703bf3b7ff3926994d650bee18a2496..b60eb673452e624321c2f97f3b75e94979948b78 100644
--- a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterDescriptorsPlugin.java
+++ b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterDescriptorsPlugin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,16 +18,20 @@
 
 package plugins.adufour.roi.intensitycenter;
 
-import icy.plugin.abstract_.Plugin;
-import icy.plugin.interface_.PluginROIDescriptor;
-import icy.roi.ROI;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.sequence.SequenceDataIterator;
-import icy.type.point.Point3D;
-import icy.type.rectangle.Rectangle5D;
-import plugins.kernel.roi.roi2d.ROI2DPoint;
-import plugins.kernel.roi.roi3d.ROI3DPoint;
+import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DPoint;
+import org.bioimageanalysis.extension.kernel.roi.roi3d.ROI3DPoint;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.rectangle.Rectangle5D;
+import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon;
+import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName;
+import org.bioimageanalysis.icy.extension.plugin.interface_.PluginROIDescriptor;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.model.sequence.SequenceDataIterator;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -41,6 +45,8 @@ import java.util.Map;
  *
  * @author Daniel Felipe Gonzalez Obando
  */
+@IcyPluginName("ROI Intensity Center Descriptor")
+@IcyPluginIcon(path = "/roi-stat.png")
 public class ROIIntensityCenterDescriptorsPlugin extends Plugin implements PluginROIDescriptor {
     public static final String ID_MASS_CENTER_X = ROIIntensityCenterXDescriptor.ID;
     public static final String ID_MASS_CENTER_Y = ROIIntensityCenterYDescriptor.ID;
@@ -58,7 +64,8 @@ public class ROIIntensityCenterDescriptorsPlugin extends Plugin implements Plugi
      * @return Position of the intensity center.
      * @throws InterruptedException If the thread is interrupted during the descriptors computation.
      */
-    public static Point3D computeIntensityCenter(final ROI roi, final Sequence sequence) throws InterruptedException {
+    @Contract("_, _ -> new")
+    public static @NotNull Point3D computeIntensityCenter(final @NotNull ROI roi, final Sequence sequence) throws InterruptedException {
         final Rectangle5D bounds = roi.getBounds5D();
 
         // special case of empty bounds ? --> return position
@@ -142,5 +149,4 @@ public class ROIIntensityCenterDescriptorsPlugin extends Plugin implements Plugi
 
         return result;
     }
-
 }
diff --git a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterXDescriptor.java b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterXDescriptor.java
index f97178f8c9708d866172dad3b69d9ce3b49bfb20..fd462e2268f2dac04c747371e7ed814afac5e0a1 100644
--- a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterXDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterXDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,12 +18,12 @@
 
 package plugins.adufour.roi.intensitycenter;
 
-import icy.roi.ROI;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.sequence.SequenceEvent;
-import icy.sequence.SequenceEvent.SequenceEventSourceType;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.model.sequence.SequenceEvent;
+import org.jetbrains.annotations.NotNull;
 
 public class ROIIntensityCenterXDescriptor extends ROIDescriptor {
     public static final String ID = "Intensity center X";
@@ -48,8 +48,8 @@ public class ROIIntensityCenterXDescriptor extends ROIDescriptor {
     }
 
     @Override
-    public boolean needRecompute(final SequenceEvent change) {
-        return (change.getSourceType() == SequenceEventSourceType.SEQUENCE_DATA);
+    public boolean needRecompute(final @NotNull SequenceEvent change) {
+        return (change.getSourceType() == SequenceEvent.SequenceEventSourceType.SEQUENCE_DATA);
     }
 
     @Override
diff --git a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterYDescriptor.java b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterYDescriptor.java
index 8e55be667384fcaa4084a688976b7203e742082d..b6eab030f6737e1e4310ccd900f5843f3f72163b 100644
--- a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterYDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterYDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,12 +18,12 @@
 
 package plugins.adufour.roi.intensitycenter;
 
-import icy.roi.ROI;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.sequence.SequenceEvent;
-import icy.sequence.SequenceEvent.SequenceEventSourceType;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.model.sequence.SequenceEvent;
+import org.jetbrains.annotations.NotNull;
 
 public class ROIIntensityCenterYDescriptor extends ROIDescriptor {
     public static final String ID = "Intensity center Y";
@@ -48,8 +48,8 @@ public class ROIIntensityCenterYDescriptor extends ROIDescriptor {
     }
 
     @Override
-    public boolean needRecompute(final SequenceEvent change) {
-        return (change.getSourceType() == SequenceEventSourceType.SEQUENCE_DATA);
+    public boolean needRecompute(final @NotNull SequenceEvent change) {
+        return (change.getSourceType() == SequenceEvent.SequenceEventSourceType.SEQUENCE_DATA);
     }
 
     @Override
diff --git a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterZDescriptor.java b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterZDescriptor.java
index 55ad85310f11b58f306b439bb47eee5ca0c2ccec..ecae5f7d67dc588f250bd8fc520cda24262d1a42 100644
--- a/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterZDescriptor.java
+++ b/src/main/java/plugins/adufour/roi/intensitycenter/ROIIntensityCenterZDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2023. Institut Pasteur.
+ * Copyright (c) 2010-2024. Institut Pasteur.
  *
  * This file is part of Icy.
  * Icy is free software: you can redistribute it and/or modify
@@ -18,12 +18,12 @@
 
 package plugins.adufour.roi.intensitycenter;
 
-import icy.roi.ROI;
-import icy.roi.ROIDescriptor;
-import icy.sequence.Sequence;
-import icy.sequence.SequenceEvent;
-import icy.sequence.SequenceEvent.SequenceEventSourceType;
-import icy.type.point.Point3D;
+import org.bioimageanalysis.icy.common.geom.point.Point3D;
+import org.bioimageanalysis.icy.model.roi.ROI;
+import org.bioimageanalysis.icy.model.roi.ROIDescriptor;
+import org.bioimageanalysis.icy.model.sequence.Sequence;
+import org.bioimageanalysis.icy.model.sequence.SequenceEvent;
+import org.jetbrains.annotations.NotNull;
 
 public class ROIIntensityCenterZDescriptor extends ROIDescriptor {
     public static final String ID = "Intensity center Z";
@@ -48,8 +48,8 @@ public class ROIIntensityCenterZDescriptor extends ROIDescriptor {
     }
 
     @Override
-    public boolean needRecompute(final SequenceEvent change) {
-        return (change.getSourceType() == SequenceEventSourceType.SEQUENCE_DATA);
+    public boolean needRecompute(final @NotNull SequenceEvent change) {
+        return (change.getSourceType() == SequenceEvent.SequenceEventSourceType.SEQUENCE_DATA);
     }
 
     @Override
diff --git a/src/main/resources/roi-stat.png b/src/main/resources/roi-stat.png
new file mode 100644
index 0000000000000000000000000000000000000000..cefa2397373f100d897d68f81231284f3e2aaccc
Binary files /dev/null and b/src/main/resources/roi-stat.png differ