writer: save ROI bitmap and definitions in the master file

Persist regions of interest so an acquisition's ROI layout can be
recovered from the master (_master.h5 / _process.h5):

- /entry/roi/roi_map: uint16 per-pixel bitmask (bit i == ROI i).
- /entry/roi/<name>: logical definition (type + geometry params, incl.
  azimuthal phi sector) plus bit_index tying it to the bitmap plane.

The bitmap rides along in the StartMessage (CBOR, mirroring az_int_map)
and is filled both online (JFJochReceiver::SendStartMessage) and offline
(jfjoch_process). Definitions come from the already-transmitted rois.
Both are dataset-wide metadata, so they are written by the NXmx master
writer (new NXmx::ROI), not the per-image data-file plugin.

Documented the /entry/roi layout in docs/HDF5.md and the master-vs-data
writer convention in CLAUDE.md; added a CBOR roi_map round-trip test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 09:41:26 +02:00
co-authored by Claude Opus 4.8
parent 1d04656dc8
commit 03814b1425
10 changed files with 137 additions and 2 deletions
+18
View File
@@ -446,6 +446,23 @@ inline void CBOR_ENC_AZINT_MAP(CborEncoder &encoder, const StartMessage &msg) {
CBOR_ENC_2D_TYPED_ARRAY(encoder, image);
}
inline void CBOR_ENC_ROI_MAP(CborEncoder &encoder, const StartMessage &msg) {
if (msg.roi_map.empty())
return;
if (msg.roi_map.size() != msg.image_size_x * msg.image_size_y)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Mismatch in size of ROI map");
JFJochBitShuffleCompressor compressor(CompressionAlgorithm::BSHUF_LZ4);
auto mask_compressed = compressor.Compress(msg.roi_map);
CompressedImage image(mask_compressed.data(), mask_compressed.size(),
msg.image_size_x, msg.image_size_y,
CompressedImageMode::Uint16,
CompressionAlgorithm::BSHUF_LZ4, "roi_map");
CBOR_ENC_2D_TYPED_ARRAY(encoder, image);
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const UnitCell &val) {
CborEncoder mapEncoder;
@@ -667,6 +684,7 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC_PIXEL_MASK(mapEncoder, message);
CBOR_ENC_AZINT_MAP(mapEncoder, message);
CBOR_ENC_ROI_MAP(mapEncoder, message);
CBOR_ENC(mapEncoder, "channels", message.channels);
CBOR_ENC(mapEncoder, "max_spot_count", message.max_spot_count);