From bc163584e28748bbfbe34e5b3642b5d7adec415b Mon Sep 17 00:00:00 2001 From: Thomas <thomas.musset@pasteur.fr> Date: Thu, 27 Jun 2024 20:28:44 +0200 Subject: [PATCH] updated pom to v5.0.0-a.1, fix classes accordingly to new architecture, added icon, updated .gitignore --- .gitignore | 44 +++- pom.xml | 13 +- .../ConnectedComponent.java | 30 +-- .../ConnectedComponentDescriptor.java | 14 +- .../ConnectedComponents.java | 218 +++++++++--------- .../resources/icon/Connected_Components.png | Bin 0 -> 7851 bytes 6 files changed, 168 insertions(+), 151 deletions(-) create mode 100644 src/main/resources/icon/Connected_Components.png diff --git a/.gitignore b/.gitignore index b2f15ce..57f16fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,41 @@ -.idea/ -.settings/ -build/ +/build* +/workspace +setting.xml +release/ target/ -bin/ +!.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 -**/.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 061aeba..107ccb9 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,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>connected-components</artifactId> - <version>5.0.0</version> - - <packaging>jar</packaging> + <version>5.0.0-a.1</version> <name>ConnectedComponents</name> <description> @@ -48,17 +46,12 @@ <groupId>org.bioimageanalysis.icy</groupId> <artifactId>jama</artifactId> </dependency> - - <dependency> - <groupId>net.sourceforge.jexcelapi</groupId> - <artifactId>jxl</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> diff --git a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponent.java b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponent.java index dfa7b47..fa8fa12 100644 --- a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponent.java +++ b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponent.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,17 @@ package plugins.adufour.connectedcomponents; -import icy.image.IcyBufferedImage; -import icy.roi.ROI; -import icy.sequence.Sequence; -import icy.sequence.SequenceDataIterator; -import icy.type.DataIteratorUtil; -import icy.type.DataType; -import icy.type.collection.array.Array1DUtil; -import plugins.kernel.roi.roi2d.ROI2DArea; -import plugins.kernel.roi.roi3d.ROI3DArea; + +import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DArea; +import org.bioimageanalysis.extension.kernel.roi.roi3d.ROI3DArea; +import org.bioimageanalysis.icy.common.collection.array.Array1DUtil; +import org.bioimageanalysis.icy.common.type.DataIteratorUtil; +import org.bioimageanalysis.icy.common.type.DataType; +import org.bioimageanalysis.icy.model.image.IcyBufferedImage; +import org.bioimageanalysis.icy.model.roi.ROI; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.model.sequence.SequenceDataIterator; +import org.jetbrains.annotations.NotNull; import plugins.nchenouard.spot.Detection; import javax.vecmath.Point3d; @@ -182,7 +184,7 @@ public class ConnectedComponent extends Detection implements Iterable<Point3i> { for (int c = 0; c < intensitySum.length; c++) intensitySum[c] += Array1DUtil.getValue(((Object[]) dataCXY)[c], offsetXY, - sequence.getDataType_().isSigned()); + sequence.getDataType().isSigned()); } for (int i = 0; i < intensitySum.length; i++) @@ -220,7 +222,7 @@ public class ConnectedComponent extends Detection implements Iterable<Point3i> { for (int c = 0; c < minIntensity.length; c++) { final double val = Array1DUtil.getValue(((Object[]) dataCXY)[c], offsetXY, - sequence.getDataType_().isSigned()); + sequence.getDataType().isSigned()); if (val < minIntensity[c]) minIntensity[c] = val; } @@ -257,7 +259,7 @@ public class ConnectedComponent extends Detection implements Iterable<Point3i> { for (int c = 0; c < maxIntensity.length; c++) { final double val = Array1DUtil.getValue(((Object[]) dataCXY)[c], offsetXY, - sequence.getDataType_().isSigned()); + sequence.getDataType().isSigned()); if (val > maxIntensity[c]) maxIntensity[c] = val; } @@ -568,7 +570,7 @@ public class ConnectedComponent extends Detection implements Iterable<Point3i> { } @Override - public Iterator<Point3i> iterator() { + public @NotNull Iterator<Point3i> iterator() { return points.iterator(); } diff --git a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponentDescriptor.java b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponentDescriptor.java index 6c7a7fd..abe0eeb 100644 --- a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponentDescriptor.java +++ b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponentDescriptor.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,11 +20,11 @@ package plugins.adufour.connectedcomponents; import Jama.EigenvalueDecomposition; import Jama.Matrix; -import icy.image.IcyBufferedImage; -import icy.plugin.abstract_.Plugin; -import icy.plugin.interface_.PluginBundled; -import icy.sequence.Sequence; -import icy.type.DataType; +import org.bioimageanalysis.icy.common.type.DataType; +import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin; +import org.bioimageanalysis.icy.extension.plugin.interface_.PluginBundled; +import org.bioimageanalysis.icy.model.image.IcyBufferedImage; +import org.bioimageanalysis.icy.model.sequence.Sequence; import plugins.adufour.blocks.lang.Block; import plugins.adufour.blocks.util.VarList; import plugins.adufour.quickhull.QuickHull2D; @@ -389,7 +389,7 @@ public class ConnectedComponentDescriptor extends Plugin implements PluginBundle // volume = 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 (i = 0; i < points.size(); i++) { p2 = points.get(i); diff --git a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponents.java b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponents.java index baa1be6..f8113aa 100644 --- a/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponents.java +++ b/src/main/java/plugins/adufour/connectedcomponents/ConnectedComponents.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,56 +18,47 @@ package plugins.adufour.connectedcomponents; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import javax.vecmath.Point3d; -import javax.vecmath.Point3i; -import javax.vecmath.Point4d; - -import icy.file.FileUtil; -import icy.gui.frame.progress.FailedAnnounceFrame; -import icy.image.IcyBufferedImage; -import icy.image.colormap.FireColorMap; -import icy.main.Icy; -import icy.roi.ROI; -import icy.sequence.Sequence; -import icy.sequence.SequenceDataIterator; -import icy.sequence.VolumetricImage; -import icy.swimmingPool.SwimmingObject; -import icy.system.IcyHandledException; -import icy.type.DataIteratorUtil; -import icy.type.DataType; -import icy.type.collection.array.Array1DUtil; -import icy.util.StringUtil; -import icy.util.XLSUtil; -import jxl.write.WritableSheet; -import jxl.write.WritableWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.bioimageanalysis.extension.kernel.roi.roi2d.ROI2DArea; +import org.bioimageanalysis.extension.kernel.roi.roi3d.ROI3DArea; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.collection.array.Array1DUtil; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.common.type.DataIteratorUtil; +import org.bioimageanalysis.icy.common.type.DataType; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.gui.frame.progress.FailedAnnounceFrame; +import org.bioimageanalysis.icy.io.FileUtil; +import org.bioimageanalysis.icy.io.xls.XLSXUtil; +import org.bioimageanalysis.icy.model.colormap.FireColorMap; +import org.bioimageanalysis.icy.model.image.IcyBufferedImage; +import org.bioimageanalysis.icy.model.roi.ROI; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.model.sequence.SequenceDataIterator; +import org.bioimageanalysis.icy.model.sequence.VolumetricImage; +import org.bioimageanalysis.icy.model.swimmingPool.SwimmingObject; +import org.bioimageanalysis.icy.system.IcyHandledException; import plugins.adufour.blocks.lang.Block; import plugins.adufour.blocks.util.VarList; -import plugins.adufour.ezplug.EzGroup; -import plugins.adufour.ezplug.EzLabel; -import plugins.adufour.ezplug.EzPlug; -import plugins.adufour.ezplug.EzVarBoolean; -import plugins.adufour.ezplug.EzVarEnum; -import plugins.adufour.ezplug.EzVarFile; -import plugins.adufour.ezplug.EzVarInteger; -import plugins.adufour.ezplug.EzVarSequence; +import plugins.adufour.ezplug.*; import plugins.adufour.vars.lang.VarGenericArray; import plugins.adufour.vars.lang.VarROIArray; import plugins.adufour.vars.lang.VarSequence; import plugins.adufour.vars.util.VarException; -import plugins.kernel.roi.roi2d.ROI2DArea; -import plugins.kernel.roi.roi3d.ROI3DArea; import plugins.nchenouard.spot.DetectionResult; import plugins.nchenouard.spot.Spot; +import javax.vecmath.Point3d; +import javax.vecmath.Point3i; +import javax.vecmath.Point4d; +import java.io.File; +import java.io.IOException; +import java.util.*; + +@IcyPluginName("Connected Components") +@IcyPluginIcon(path = "/icon/Connected_Components.png") public class ConnectedComponents extends EzPlug implements Block { /** * List of extraction methods suitable for the Connected Components plugin @@ -359,17 +350,18 @@ public class ConnectedComponents extends EzPlug implements Block { if (exportExcel.getValue()) { int page = 1; - WritableSheet sheet; - final WritableWorkbook workbook; + Sheet sheet; + final Workbook workbook; + + File f = exportExcelFile.getValue(true); + if (!FileUtil.getFileExtension(f.getPath(), false).equalsIgnoreCase("xlsx")) + f = new File(f.getPath() + ".xlsx"); try { - File f = exportExcelFile.getValue(true); - if (!FileUtil.getFileExtension(f.getPath(), false).equalsIgnoreCase("xls")) - f = new File(f.getPath() + ".xls"); - workbook = XLSUtil.createWorkbook(f); - sheet = XLSUtil.createNewPage(workbook, "Page " + page); + workbook = XLSXUtil.createWorkbook(); + sheet = XLSXUtil.createNewPage(workbook, "Page " + page); } - catch (final Exception e) { + catch (final IOException e) { throw new IcyHandledException(e.getMessage()); } @@ -383,37 +375,37 @@ public class ConnectedComponents extends EzPlug implements Block { res += ", Z=" + StringUtil.toStringEx(resolution.z, 5); res += ", T=" + StringUtil.toStringEx(resolution.w, 5); - XLSUtil.setCellString(sheet, 0, 0, s.getName()); - XLSUtil.setCellString(sheet, 6, 0, res); - XLSUtil.setCellString(sheet, 0, 1, "#"); - XLSUtil.setCellString(sheet, 1, 1, "t"); - XLSUtil.setCellString(sheet, 2, 1, "x"); - XLSUtil.setCellString(sheet, 3, 1, "y"); - XLSUtil.setCellString(sheet, 4, 1, "z"); - XLSUtil.setCellString(sheet, 5, 1, "perimeter"); - XLSUtil.setCellString(sheet, 6, 1, "area"); - XLSUtil.setCellString(sheet, 7, 1, "sphericity"); - XLSUtil.setCellString(sheet, 8, 1, "major axis"); - XLSUtil.setCellString(sheet, 9, 1, "minor axis"); - XLSUtil.setCellString(sheet, 10, 1, "minor Z axis"); - XLSUtil.setCellString(sheet, 11, 1, "eccentricity"); - XLSUtil.setCellString(sheet, 12, 1, "hull fill ratio"); - XLSUtil.setCellString(sheet, 13, 1, "M100"); - XLSUtil.setCellString(sheet, 14, 1, "M010"); - XLSUtil.setCellString(sheet, 15, 1, "M001"); - XLSUtil.setCellString(sheet, 16, 1, "M110"); - XLSUtil.setCellString(sheet, 17, 1, "M101"); - XLSUtil.setCellString(sheet, 18, 1, "M011"); - XLSUtil.setCellString(sheet, 19, 1, "M111"); - XLSUtil.setCellString(sheet, 20, 1, "M200"); - XLSUtil.setCellString(sheet, 21, 1, "M020"); - XLSUtil.setCellString(sheet, 22, 1, "M002"); - XLSUtil.setCellString(sheet, 23, 1, "M220"); - XLSUtil.setCellString(sheet, 24, 1, "M202"); - XLSUtil.setCellString(sheet, 25, 1, "M022"); - XLSUtil.setCellString(sheet, 26, 1, "M222"); - XLSUtil.setCellString(sheet, 27, 1, "convex perimeter"); - XLSUtil.setCellString(sheet, 28, 1, "convex volume"); + XLSXUtil.setCellString(sheet, 0, 0, s.getName()); + XLSXUtil.setCellString(sheet, 6, 0, res); + XLSXUtil.setCellString(sheet, 0, 1, "#"); + XLSXUtil.setCellString(sheet, 1, 1, "t"); + XLSXUtil.setCellString(sheet, 2, 1, "x"); + XLSXUtil.setCellString(sheet, 3, 1, "y"); + XLSXUtil.setCellString(sheet, 4, 1, "z"); + XLSXUtil.setCellString(sheet, 5, 1, "perimeter"); + XLSXUtil.setCellString(sheet, 6, 1, "area"); + XLSXUtil.setCellString(sheet, 7, 1, "sphericity"); + XLSXUtil.setCellString(sheet, 8, 1, "major axis"); + XLSXUtil.setCellString(sheet, 9, 1, "minor axis"); + XLSXUtil.setCellString(sheet, 10, 1, "minor Z axis"); + XLSXUtil.setCellString(sheet, 11, 1, "eccentricity"); + XLSXUtil.setCellString(sheet, 12, 1, "hull fill ratio"); + XLSXUtil.setCellString(sheet, 13, 1, "M100"); + XLSXUtil.setCellString(sheet, 14, 1, "M010"); + XLSXUtil.setCellString(sheet, 15, 1, "M001"); + XLSXUtil.setCellString(sheet, 16, 1, "M110"); + XLSXUtil.setCellString(sheet, 17, 1, "M101"); + XLSXUtil.setCellString(sheet, 18, 1, "M011"); + XLSXUtil.setCellString(sheet, 19, 1, "M111"); + XLSXUtil.setCellString(sheet, 20, 1, "M200"); + XLSXUtil.setCellString(sheet, 21, 1, "M020"); + XLSXUtil.setCellString(sheet, 22, 1, "M002"); + XLSXUtil.setCellString(sheet, 23, 1, "M220"); + XLSXUtil.setCellString(sheet, 24, 1, "M202"); + XLSXUtil.setCellString(sheet, 25, 1, "M022"); + XLSXUtil.setCellString(sheet, 26, 1, "M222"); + XLSXUtil.setCellString(sheet, 27, 1, "convex perimeter"); + XLSXUtil.setCellString(sheet, 28, 1, "convex volume"); final ConnectedComponentDescriptor shapeDescriptor = new ConnectedComponentDescriptor(); int cpt = 2; @@ -424,68 +416,68 @@ public class ConnectedComponents extends EzPlug implements Block { center.x *= resolution.x; center.y *= resolution.y; center.z *= resolution.z; - XLSUtil.setCellNumber(sheet, 0, cpt, cpt - 1); - XLSUtil.setCellNumber(sheet, 1, cpt, time * resolution.w); - XLSUtil.setCellNumber(sheet, 2, cpt, center.x); - XLSUtil.setCellNumber(sheet, 3, cpt, center.y); - XLSUtil.setCellNumber(sheet, 4, cpt, center.z); - XLSUtil.setCellNumber(sheet, 5, cpt, shapeDescriptor.computePerimeter(cc, null, null)); - XLSUtil.setCellNumber(sheet, 6, cpt, cc.getSize() * voxelSize); - XLSUtil.setCellNumber(sheet, 7, cpt, shapeDescriptor.computeSphericity(cc)); + XLSXUtil.setCellNumber(sheet, 0, cpt, (double) (cpt - 1)); + XLSXUtil.setCellNumber(sheet, 1, cpt, time * resolution.w); + XLSXUtil.setCellNumber(sheet, 2, cpt, center.x); + XLSXUtil.setCellNumber(sheet, 3, cpt, center.y); + XLSXUtil.setCellNumber(sheet, 4, cpt, center.z); + XLSXUtil.setCellNumber(sheet, 5, cpt, shapeDescriptor.computePerimeter(cc, null, null)); + XLSXUtil.setCellNumber(sheet, 6, cpt, cc.getSize() * voxelSize); + XLSXUtil.setCellNumber(sheet, 7, cpt, shapeDescriptor.computeSphericity(cc)); final double[] radiuses = shapeDescriptor.computeEllipseDimensions(cc); - XLSUtil.setCellNumber(sheet, 8, cpt, radiuses[0]); - XLSUtil.setCellNumber(sheet, 9, cpt, radiuses[1]); - XLSUtil.setCellNumber(sheet, 10, cpt, radiuses[2]); - XLSUtil.setCellNumber(sheet, 11, cpt, shapeDescriptor.computeEccentricity(cc)); + XLSXUtil.setCellNumber(sheet, 8, cpt, radiuses[0]); + XLSXUtil.setCellNumber(sheet, 9, cpt, radiuses[1]); + XLSXUtil.setCellNumber(sheet, 10, cpt, radiuses[2]); + XLSXUtil.setCellNumber(sheet, 11, cpt, shapeDescriptor.computeEccentricity(cc)); final double[] contour_area = shapeDescriptor.computeConvexAreaAndVolume(cc); - XLSUtil.setCellNumber(sheet, 12, cpt, contour_area[1] == 0.0 ? 0.0 : Math.min(1.0, cc.getSize() / contour_area[1])); - XLSUtil.setCellNumber(sheet, 13, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 0, 0)); - XLSUtil.setCellNumber(sheet, 14, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 1, 0)); + XLSXUtil.setCellNumber(sheet, 12, cpt, contour_area[1] == 0.0 ? 0.0 : Math.min(1.0, cc.getSize() / contour_area[1])); + XLSXUtil.setCellNumber(sheet, 13, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 0, 0)); + XLSXUtil.setCellNumber(sheet, 14, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 1, 0)); if (!is2D) - XLSUtil.setCellNumber(sheet, 15, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 0, 1)); + XLSXUtil.setCellNumber(sheet, 15, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 0, 1)); - XLSUtil.setCellNumber(sheet, 16, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 1, 0)); + XLSXUtil.setCellNumber(sheet, 16, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 1, 0)); if (!is2D) - XLSUtil.setCellNumber(sheet, 17, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 0, 1)); + XLSXUtil.setCellNumber(sheet, 17, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 0, 1)); if (!is2D) - XLSUtil.setCellNumber(sheet, 18, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 1, 1)); + XLSXUtil.setCellNumber(sheet, 18, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 1, 1)); if (!is2D) - XLSUtil.setCellNumber(sheet, 19, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 1, 1)); + XLSXUtil.setCellNumber(sheet, 19, cpt, shapeDescriptor.computeGeometricMoment(cc, 1, 1, 1)); - XLSUtil.setCellNumber(sheet, 20, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 0, 0)); - XLSUtil.setCellNumber(sheet, 21, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 2, 0)); + XLSXUtil.setCellNumber(sheet, 20, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 0, 0)); + XLSXUtil.setCellNumber(sheet, 21, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 2, 0)); if (!is2D) - XLSUtil.setCellNumber(sheet, 22, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 0, 2)); + XLSXUtil.setCellNumber(sheet, 22, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 0, 2)); - XLSUtil.setCellNumber(sheet, 23, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 2, 0)); + XLSXUtil.setCellNumber(sheet, 23, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 2, 0)); if (!is2D) - XLSUtil.setCellNumber(sheet, 24, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 0, 2)); + XLSXUtil.setCellNumber(sheet, 24, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 0, 2)); if (!is2D) - XLSUtil.setCellNumber(sheet, 25, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 2, 2)); + XLSXUtil.setCellNumber(sheet, 25, cpt, shapeDescriptor.computeGeometricMoment(cc, 0, 2, 2)); if (!is2D) - XLSUtil.setCellNumber(sheet, 26, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 2, 2)); + XLSXUtil.setCellNumber(sheet, 26, cpt, shapeDescriptor.computeGeometricMoment(cc, 2, 2, 2)); - XLSUtil.setCellNumber(sheet, 27, cpt, contour_area[0]); - XLSUtil.setCellNumber(sheet, 28, cpt, contour_area[1]); + XLSXUtil.setCellNumber(sheet, 27, cpt, contour_area[0]); + XLSXUtil.setCellNumber(sheet, 28, cpt, contour_area[1]); cpt++; if (cpt == Short.MAX_VALUE) { page++; - sheet = XLSUtil.createNewPage(workbook, "Page " + page); + sheet = XLSXUtil.createNewPage(workbook, "Page " + page); cpt = 1; } } try { - XLSUtil.saveAndClose(workbook); + XLSXUtil.saveAndClose(workbook, f); } catch (final Exception e) { throw new IcyHandledException(e.getMessage()); @@ -761,7 +753,7 @@ public class ConnectedComponents extends EzPlug implements Block { int voxelOffset = 0; final Object inputData = stack.getImage(z).getDataXY(0); - final DataType dataType = stack.getImage(z).getDataType_(); + final DataType dataType = stack.getImage(z).getDataType(); for (int y = 0; y < height; y++) { onEdgeY = (y == 0 || y == height - 1); diff --git a/src/main/resources/icon/Connected_Components.png b/src/main/resources/icon/Connected_Components.png new file mode 100644 index 0000000000000000000000000000000000000000..75d115265fc73272e854d46e26b680d999b78f58 GIT binary patch literal 7851 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 JPDHLkV1iKuR6qa# literal 0 HcmV?d00001 -- GitLab