From 0ba0d1b4d5ba8d339fc9c62223a95dc6b64702dc Mon Sep 17 00:00:00 2001 From: Florian M Date: Tue, 16 Apr 2024 11:45:11 +0200 Subject: [PATCH 1/2] Fix reading CompressedSegmentation with uint32 data --- .../scalableminds/util/tools/ByteUtils.scala | 15 +++++++++++++++ .../CompressedSegmentation.scala | 18 +++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/util/src/main/scala/com/scalableminds/util/tools/ByteUtils.scala b/util/src/main/scala/com/scalableminds/util/tools/ByteUtils.scala index 9583051b704..8a0ff93f002 100644 --- a/util/src/main/scala/com/scalableminds/util/tools/ByteUtils.scala +++ b/util/src/main/scala/com/scalableminds/util/tools/ByteUtils.scala @@ -20,4 +20,19 @@ trait ByteUtils { } result.reverse } + + /** + * + * @param i a 32 bit number + * @return i as array of 8 bytes, little endian + */ + def intToBytes(i: Int): Array[Byte] = { + var w = i + val result = new Array[Byte](4) + for (i <- 3 to 0 by -1) { + result(i) = (w & 0xFF).toByte + w >>= 4 + } + result.reverse + } } diff --git a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/datareaders/precomputed/compressedsegmentation/CompressedSegmentation.scala b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/datareaders/precomputed/compressedsegmentation/CompressedSegmentation.scala index 3633bbcd925..c742f5d4c5a 100644 --- a/webknossos-datastore/app/com/scalableminds/webknossos/datastore/datareaders/precomputed/compressedsegmentation/CompressedSegmentation.scala +++ b/webknossos-datastore/app/com/scalableminds/webknossos/datastore/datareaders/precomputed/compressedsegmentation/CompressedSegmentation.scala @@ -48,11 +48,11 @@ trait CompressedSegmentation[T <: AnyVal] extends ByteUtils { val bitmask = (1 << encodedBits) - 1 for (z <- zmin until zmax) { for (y <- ymin until ymax) { - var outindex = (z * (volumeSize(1)) + y) * volumeSize(0) + xmin - var bitpos = blockSize.x * ((z - zmin) * (blockSize.y) + (y - ymin)) * encodedBits - for (x <- xmin until xmax) { + var outindex = (z * volumeSize(1) + y) * volumeSize(0) + xmin + var bitpos = blockSize.x * ((z - zmin) * blockSize.y + (y - ymin)) * encodedBits + for (_ <- xmin until xmax) { val bitshift = bitpos % 32 - val arraypos = bitpos / (32) + val arraypos = bitpos / 32 var bitval = 0 if (encodedBits > 0) { bitval = (input(encodedValueStart + arraypos) >> bitshift) & bitmask @@ -76,7 +76,7 @@ trait CompressedSegmentation[T <: AnyVal] extends ByteUtils { .flatMap(channel => decompressChannel(input.drop(input(channel)), volumeSize, blockSize)) .toArray - def valueAsLong(v: T): Long + def valueToBytes(v: T): Array[Byte] def decompress(encodedBytes: Array[Byte], volumeSize: Array[Int], blockSize: Vec3Int)( implicit c: ClassTag[T]): Array[Byte] = { @@ -87,8 +87,8 @@ trait CompressedSegmentation[T <: AnyVal] extends ByteUtils { } val input32 = new Array[Int](encodedBytes.length / 4) ByteBuffer.wrap(encodedBytes).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get(input32) - val values = decompressChannels(input32, vs, blockSize) - values.flatMap(v => longToBytes(valueAsLong(v))) + val values: Array[T] = decompressChannels(input32, vs, blockSize) + values.flatMap(v => valueToBytes(v)) } } @@ -101,7 +101,7 @@ object CompressedSegmentation32 extends CompressedSegmentation[Int] { override def readValue(input: Array[Int], position: Int): Int = input(position) - override def valueAsLong(v: Int): Long = v.toLong + def valueToBytes(v: Int): Array[Byte] = intToBytes(v) } object CompressedSegmentation64 extends CompressedSegmentation[Long] { @@ -113,5 +113,5 @@ object CompressedSegmentation64 extends CompressedSegmentation[Long] { override def readValue(input: Array[Int], position: Int): Long = ByteBuffer.wrap(ByteBuffer.allocate(8).putInt(input(position + 1)).putInt(input(position)).array()).getLong - override def valueAsLong(v: Long): Long = v + def valueToBytes(v: Long): Array[Byte] = longToBytes(v) } From 6146eeb75c41ae858ffa3415bba58b166f730522 Mon Sep 17 00:00:00 2001 From: Florian M Date: Tue, 16 Apr 2024 11:49:54 +0200 Subject: [PATCH 2/2] changelog --- CHANGELOG.unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 64501ba90c7..5b86ca25a04 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -33,6 +33,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released - Fixed a bug where users that have no team memberships were omitted from the user list. [#7721](https://github.com/scalableminds/webknossos/pull/7721) - Added an appropriate placeholder to be rendered in case the timetracking overview is otherwise empty. [#7736](https://github.com/scalableminds/webknossos/pull/7736) - The overflow menu in the layer settings tab for layers with long names can now be opened comfortably. [#7747](https://github.com/scalableminds/webknossos/pull/7747) +- Fixed a bug where segmentation data looked scrambled when reading uint32 segmentation layers with CompressedSegmentation codec. [#7757](https://github.com/scalableminds/webknossos/pull/7757) ### Removed