From 1a136a53e7eb33729f911a0edf3683fe5d05da6c Mon Sep 17 00:00:00 2001 From: Alessandra Trapani <55453048+alessandratrapani@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:26:17 +0100 Subject: [PATCH] Add function to extract ROIs metadata from ScanImage tiff (#272) * add function to extract ROIs metadata from ScanImage tiff * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * implement requested changes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update test_parse_metadata accordingly * correct wrong value for expected_metadata * update to work with versions v3.8.0 * minor fix --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../scanimagetiff_utils.py | 14 +- tests/test_scanimage_utils.py | 167 ++++++++++++++++++ 2 files changed, 179 insertions(+), 2 deletions(-) diff --git a/src/roiextractors/extractors/tiffimagingextractors/scanimagetiff_utils.py b/src/roiextractors/extractors/tiffimagingextractors/scanimagetiff_utils.py index 691722dc..7d9900d6 100644 --- a/src/roiextractors/extractors/tiffimagingextractors/scanimagetiff_utils.py +++ b/src/roiextractors/extractors/tiffimagingextractors/scanimagetiff_utils.py @@ -1,5 +1,6 @@ """Utility functions for ScanImage TIFF Extractors.""" import numpy as np +import json from ...extraction_tools import PathType, get_package @@ -33,12 +34,16 @@ def extract_extra_metadata( io = ScanImageTiffReader(str(file_path)) extra_metadata = {} for metadata_string in (io.description(iframe=0), io.metadata()): - metadata_dict = { + system_metadata_dict = { x.split("=")[0].strip(): x.split("=")[1].strip() for x in metadata_string.replace("\n", "\r").split("\r") if "=" in x } - extra_metadata = dict(**extra_metadata, **metadata_dict) + extra_metadata = dict(**extra_metadata, **system_metadata_dict) + if "\n\n" in io.metadata(): + additional_metadata_string = io.metadata().split("\n\n")[1] + additional_metadata = json.loads(additional_metadata_string) + extra_metadata = dict(**extra_metadata, **additional_metadata) return extra_metadata @@ -115,12 +120,17 @@ def parse_metadata(metadata: dict) -> dict: channel_names = np.array(metadata["SI.hChannels.channelName"].split("'")[1::2]) channel_names = channel_names[channel_indices].tolist() num_channels = len(channel_names) + if "RoiGroups" in metadata.keys(): + roi_metadata = metadata["RoiGroups"] + else: + roi_metadata = None metadata_parsed = dict( sampling_frequency=sampling_frequency, num_channels=num_channels, num_planes=num_planes, frames_per_slice=frames_per_slice, channel_names=channel_names, + roi_metadata=roi_metadata, ) return metadata_parsed diff --git a/tests/test_scanimage_utils.py b/tests/test_scanimage_utils.py index fd55c671..3d1e60c0 100644 --- a/tests/test_scanimage_utils.py +++ b/tests/test_scanimage_utils.py @@ -63,6 +63,73 @@ def test_parse_matlab_vector_invalid(): "num_planes": 20, "frames_per_slice": 24, "channel_names": ["Channel 1"], + "roi_metadata": { + "imagingRoiGroup": { + "ver": 1, + "classname": "scanimage.mroi.RoiGroup", + "name": "Default Imaging ROI Group", + "UserData": None, + "roiUuid": "E9CD2A60E29A5EDE", + "roiUuiduint64": 1.684716838e19, + "rois": { + "ver": 1, + "classname": "scanimage.mroi.Roi", + "name": "Default Imaging Roi", + "UserData": { + "imagingSystem": "Imaging_RGG", + "fillFractionSpatial": 0.9, + "forceSquarePixelation": 1, + "forceSquarePixels": 1, + "scanZoomFactor": 1, + "scanAngleShiftFast": 0, + "scanAngleMultiplierSlow": 1, + "scanAngleShiftSlow": 0, + "scanRotation": 0, + "pixelsPerLine": 1024, + "linesPerFrame": 1024, + }, + "roiUuid": "1B54BED0B8A25D87", + "roiUuiduint64": 1.969408741e18, + "zs": 0, + "scanfields": { + "ver": 1, + "classname": "scanimage.mroi.scanfield.fields.RotatedRectangle", + "name": "Default Imaging Scanfield", + "UserData": None, + "roiUuid": "4309FD6B19453539", + "roiUuiduint64": 4.830670712e18, + "centerXY": [0, 0], + "sizeXY": [18, 18], + "rotationDegrees": 0, + "enable": 1, + "pixelResolutionXY": [1024, 1024], + "pixelToRefTransform": [ + [0.017578125, 0, -9.008789063], + [0, 0.017578125, -9.008789063], + [0, 0, 1], + ], + "affine": [[18, 0, -9], [0, 18, -9], [0, 0, 1]], + }, + "discretePlaneMode": 0, + "powers": None, + "pzAdjust": [], + "Lzs": None, + "interlaceDecimation": None, + "interlaceOffset": None, + "enable": 1, + }, + }, + "photostimRoiGroups": None, + "integrationRoiGroup": { + "ver": 1, + "classname": "scanimage.mroi.RoiGroup", + "name": "", + "UserData": None, + "roiUuid": "9FC266E57D28670D", + "roiUuiduint64": 1.151187673e19, + "rois": {"_ArrayType_": "double", "_ArraySize_": [1, 0], "_ArrayData_": None}, + }, + }, }, ), ( @@ -73,6 +140,106 @@ def test_parse_matlab_vector_invalid(): "num_planes": 2, "frames_per_slice": 2, "channel_names": ["Channel 1", "Channel 4"], + "roi_metadata": { + "imagingRoiGroup": { + "ver": 1, + "classname": "scanimage.mroi.RoiGroup", + "name": "MROI Imaging ROI Group", + "UserData": None, + "roiUuid": "4118A30BD7393EFF", + "roiUuiduint64": 4.690678283e18, + "rois": [ + { + "ver": 1, + "classname": "scanimage.mroi.Roi", + "name": "ROI 1", + "UserData": None, + "roiUuid": "8C08C657736FBC6C", + "roiUuiduint64": 1.009053304e19, + "zs": -11178.45, + "scanfields": { + "ver": 1, + "classname": "scanimage.mroi.scanfield.fields.RotatedRectangle", + "name": "", + "UserData": None, + "roiUuid": "2B42EE3A0B039B9E", + "roiUuiduint64": 3.117315825e18, + "centerXY": [0.2141430948, -6.019800333], + "sizeXY": [3.616638935, 3.521464226], + "rotationDegrees": 0, + "enable": 1, + "pixelResolutionXY": [256, 256], + "pixelToRefTransform": [ + [0.01412749584, 0, -1.601240121], + [0, 0.01375571963, -7.787410306], + [0, 0, 1], + ], + "affine": [ + [3.616638935, 0, -1.594176373], + [0, 3.521464226, -7.780532446], + [0, 0, 1], + ], + }, + "discretePlaneMode": 0, + "powers": None, + "pzAdjust": [], + "Lzs": None, + "interlaceDecimation": None, + "interlaceOffset": None, + "enable": 1, + }, + { + "ver": 1, + "classname": "scanimage.mroi.Roi", + "name": "ROI 2", + "UserData": None, + "roiUuid": "7C9E605DC6951B29", + "roiUuiduint64": 8.979720663e18, + "zs": -11178.45, + "scanfields": { + "ver": 1, + "classname": "scanimage.mroi.scanfield.fields.RotatedRectangle", + "name": "", + "UserData": None, + "roiUuid": "A02889BA5E5501AB", + "roiUuiduint64": 1.154062548e19, + "centerXY": [2.664891847, 6.376705491], + "sizeXY": [3.616638935, 3.759400998], + "rotationDegrees": 0, + "enable": 1, + "pixelResolutionXY": [256, 256], + "pixelToRefTransform": [ + [0.01412749584, 0, 0.8495086314], + [0, 0.01468516015, 4.489662412], + [0, 0, 1], + ], + "affine": [ + [3.616638935, 0, 0.8565723794], + [0, 3.759400998, 4.497004992], + [0, 0, 1], + ], + }, + "discretePlaneMode": 0, + "powers": None, + "pzAdjust": [], + "Lzs": None, + "interlaceDecimation": None, + "interlaceOffset": None, + "enable": 1, + }, + ], + }, + "photostimRoiGroups": None, + "integrationRoiGroup": { + "ver": 1, + "classname": "scanimage.mroi.RoiGroup", + "name": "", + "UserData": None, + "roiUuid": "1B4D989071535CF3", + "roiUuiduint64": 1.967396358e18, + "rois": {"_ArrayType_": "double", "_ArraySize_": [1, 0], "_ArrayData_": None}, + }, + }, }, ), ],