From a461f3cc94c27120ea9ddc024746a87f892172a8 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 15 Nov 2022 12:09:43 -0600 Subject: [PATCH 1/4] Allow the `--rgb` flag when there are multiple timepoints and/or Z sections --- .../com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 9f59909..844fdcc 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -679,7 +679,7 @@ else if (layoutVersion != 3) { s.dimensionLengths[s.dimensionOrder.indexOf("T") - 2] = s.t; s.dimensionLengths[s.dimensionOrder.indexOf("C") - 2] = s.c; - s.rgb = rgb && (s.c == 3) && (s.z * s.t == 1); + s.rgb = rgb && (s.c == 3); if (!s.rgb) { s.planeCount *= s.c; } From d1fb6711f90aec7e91d6284a9ea420eeeb2a8fd3 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 15 Nov 2022 13:31:38 -0600 Subject: [PATCH 2/4] Expand --rgb support to include all multiples of 3 channels This allows writing e.g. 12 channel input data as 4 RGB planes. --- .../pyramid/PyramidFromDirectoryWriter.java | 51 ++++++++++++++----- .../raw2ometiff/test/ConversionTest.java | 25 +++++++++ 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 844fdcc..50c4885 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -183,7 +183,8 @@ public class PyramidFromDirectoryWriter implements Callable { @Option( names = "--rgb", - description = "Attempt to write channels as RGB; channel count must be 3" + description = "Attempt to write channels as RGB; " + + "channel count must be a multiple of 3" ) boolean rgb = false; @@ -679,21 +680,42 @@ else if (layoutVersion != 3) { s.dimensionLengths[s.dimensionOrder.indexOf("T") - 2] = s.t; s.dimensionLengths[s.dimensionOrder.indexOf("C") - 2] = s.c; - s.rgb = rgb && (s.c == 3); - if (!s.rgb) { - s.planeCount *= s.c; - } - else { + int rgbChannels = 1; + int effectiveChannels = s.c; + + // --rgb flag only respected if the number of channels in the source data + // is a multiple of 3 + // this assumes that channels should be grouped by 3s (not 2s or 4s) + // into RGB planes + // this could be made configurable later? + s.rgb = rgb && (s.c % 3 == 0); + if (s.rgb) { + rgbChannels = 3; + effectiveChannels = s.c / rgbChannels; + LOG.debug("Merging {} original channels into {} RGB channels", + s.c, effectiveChannels); + OMEXMLMetadataRoot root = (OMEXMLMetadataRoot) metadata.getRoot(); Pixels pixels = root.getImage(seriesIndex).getPixels(); - while (pixels.sizeOfChannelList() > 1) { - Channel ch = pixels.getChannel(pixels.sizeOfChannelList() - 1); + for (int index=pixels.sizeOfChannelList()-1; index>0; index--) { + if (index % rgbChannels == 0) { + continue; + } + Channel ch = pixels.getChannel(index); pixels.removeChannel(ch); } - Channel onlyChannel = pixels.getChannel(0); - onlyChannel.setSamplesPerPixel(new PositiveInteger(s.c)); + for (int index=0; index Date: Fri, 2 Dec 2022 11:16:23 -0600 Subject: [PATCH 3/4] Fix plane indexing to handle RGB with multiple Z and/or T --- .../pyramid/PyramidFromDirectoryWriter.java | 151 ++++++++++-------- 1 file changed, 86 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 50c4885..6ebf500 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -708,6 +708,16 @@ else if (layoutVersion != 3) { Channel channel = pixels.getChannel(index); channel.setSamplesPerPixel(new PositiveInteger(rgbChannels)); } + + // RGB data needs to have XYC* dimension order + if (!s.dimensionOrder.startsWith("XYC")) { + if (s.dimensionOrder.indexOf("Z") < s.dimensionOrder.indexOf("T")) { + s.dimensionOrder = "XYCZT"; + } + else { + s.dimensionOrder = "XYCTZ"; + } + } } else if (rgb) { LOG.warn( @@ -826,77 +836,88 @@ private void convertPyramid(PyramidSeries s) pb = null; } - for (int plane=0; plane { - Slf4JStopWatch t1 = new Slf4JStopWatch("writeTile"); - try { - if (tileBytes != null) { - if (region.width == descriptor.tileSizeX && - region.height == descriptor.tileSizeY) - { - writeTile(s, currentPlane, tileBytes, - currentIndex, currentResolution); + final int currentIndex = tileCount * ch + tileIndex; + final int currentPlane = plane; + final int currentResolution = resolution; + executor.execute(() -> { + Slf4JStopWatch t1 = new Slf4JStopWatch("writeTile"); + try { + if (tileBytes != null) { + if (region.width == descriptor.tileSizeX && + region.height == descriptor.tileSizeY) + { + writeTile(s, currentPlane, tileBytes, + currentIndex, currentResolution); + } + else { + // padded tile, use descriptor X and Y tile size + int tileX = descriptor.tileSizeX; + int tileY = descriptor.tileSizeY; + byte[] realTile = + new byte[tileX * tileY * bytesPerPixel]; + int totalRows = region.height; + int inRowLen = region.width * bytesPerPixel; + int outRowLen = tileX * bytesPerPixel; + for (int row=0; row Date: Tue, 6 Dec 2022 08:47:20 -0600 Subject: [PATCH 4/4] Clarify dimension order comment --- .../com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 6ebf500..4df255a 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -861,7 +861,7 @@ private void convertPyramid(PyramidSeries s) StopWatch t0 = new Slf4JStopWatch("getInputTileBytes"); byte[] tileBytes; try { - // assumes TCZXY order consistent with OME-NGFF spec + // assumes TCZYX order consistent with bioformats2raw int planeIndex = FormatTools.positionToRaster( s.dimensionLengths, new int[] {z, c * rgbChannels + ch, t});