Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[METEOR-1230][fix] store power correctly for each channel in metadata #2947

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/odemis/dataio/test/tiff_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2156,6 +2156,7 @@ def testFindImageGroupsAcquiredMultiChannelZStack(self):
model.MD_EXP_TIME: 1.2, # s
model.MD_IN_WL: (500e-9, 522e-9), # m
model.MD_OUT_WL: (400e-9, 450e-9), # m
model.MD_LIGHT_POWER: 0.140, # W
},
{model.MD_SW_VERSION: "1.0-test",
model.MD_HW_NAME: "fake hw",
Expand All @@ -2165,9 +2166,10 @@ def testFindImageGroupsAcquiredMultiChannelZStack(self):
model.MD_BINNING: (1, 1), # px, px
model.MD_PIXEL_SIZE: (1e-6, 1e-6), # m/px
model.MD_POS: (13.7e-3, -30e-3), # m
model.MD_EXP_TIME: 1, # s
model.MD_EXP_TIME: 2, # s
model.MD_IN_WL: (590e-9, 620e-9), # m
model.MD_OUT_WL: (520e-9, 550e-9), # m
model.MD_LIGHT_POWER: 0.240, # W
},
{model.MD_SW_VERSION: "1.0-test",
model.MD_HW_NAME: "fake hw",
Expand All @@ -2177,9 +2179,10 @@ def testFindImageGroupsAcquiredMultiChannelZStack(self):
model.MD_BINNING: (1, 1), # px, px
model.MD_PIXEL_SIZE: (1e-6, 1e-6), # m/px
model.MD_POS: (13.7e-3, -30e-3), # m
model.MD_EXP_TIME: 1, # s
model.MD_EXP_TIME: 1.5, # s
model.MD_IN_WL: (600e-9, 630e-9), # m
model.MD_OUT_WL: (620e-9, 650e-9), # m
model.MD_LIGHT_POWER: 0.350, # W
},
]
# create 3 greyscale images with Z stacks of same size
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can further improve this test by having 2 Z stacks, with something like:

        for md in metadata.copy():
            md2 = md.copy()
            md2[model.MD_POS] = (1.7e-3, -97e-3)
            md2[model.MD_LIGHT_POWER] += 1
            metadata.append(md2)

It fails due to the LightSource ID being incorrect, as you can see in the TIFF metadata:

        <LightEmittingDiode ID="LightSource:0" Power="140.000000000000000" PowerUnit="mW" />
        <LightEmittingDiode ID="LightSource:1" Power="240.000000000000000" PowerUnit="mW" />
        <LightEmittingDiode ID="LightSource:2" Power="350.000000000000000" PowerUnit="mW" />
        <LightEmittingDiode ID="LightSource:0" Power="1140.000000000000227" PowerUnit="mW" />
        <LightEmittingDiode ID="LightSource:1" Power="1240.000000000000000" PowerUnit="mW" />
        <LightEmittingDiode ID="LightSource:2" Power="1350.000000000000000" PowerUnit="mW" />
        <Detector ID="Detector:0" Model="fake hw" />
        <Detector ID="Detector:9" Model="fake hw" />

Expand Down Expand Up @@ -2219,7 +2222,7 @@ def testFindImageGroupsAcquiredMultiChannelZStack(self):
for k in range(nb_t):
combinations_zc.append((i, j, k))

tiff_data_elements = root.findall('.//{http://www.openmicroscopy.org/Schemas/OME/2012-06}TiffData')
tiff_data_elements = root.findall('.//{http://www.openmicroscopy.org/Schemas/OME/2016-06}TiffData')
for ind, element in enumerate(tiff_data_elements):
tiffdata = element.attrib
if int(tiffdata["IFD"]) < ifd_max:
Expand All @@ -2243,6 +2246,22 @@ def testFindImageGroupsAcquiredMultiChannelZStack(self):
res = (1,) * (5 - len(shape)) + shape
self.assertEqual(im.shape, res)

# validate the metadata after re-opening the file
exclude_keys = [model.MD_SW_VERSION, model.MD_ACQ_DATE] # md that is not saved in the file
# note: acq_date causes timezone issues when comparing, so skipped in this test
for i, md in enumerate(metadata):
for key, value in md.items():
if key in exclude_keys:
continue
self.assertIn(key, rdata[i].metadata)

if isinstance(value, (tuple, list)):
numpy.testing.assert_array_almost_equal(value, rdata[i].metadata[key])
elif isinstance(value, float):
self.assertAlmostEqual(value, rdata[i].metadata[key], delta=1e-5)
else:
self.assertEqual(value, rdata[i].metadata[key])

def testAcquisitionDataTIFFLargerFile(self):

def getSubData(dast, zoom, rect):
Expand Down
25 changes: 23 additions & 2 deletions src/odemis/dataio/tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,23 @@ def _convertToOMEMD(images, multiple_files=False, findex=None, fname=None, uuids
description.text = da0.metadata[model.MD_HW_NOTE]

# light source must come before detector for valid ome-xml
if (model.MD_LIGHT_POWER in da0.metadata or
# meteor multi-channel lightsource
if model.MD_LIGHT_POWER in da0.metadata and (
model.MD_IN_WL in da0.metadata or model.MD_OUT_WL in da0.metadata
):
# TODO: what is the best way to check if image is meteor?
# add a light source for each channel, as they can have different power
for gdid, gr in enumerate(g):

obj = ET.Element("LightEmittingDiode",
attrib={"ID": "LightSource:%d" % gdid})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using just the gdid here is incorrect, as there can be several groups of zstacks. So, something like did + gdid would more likely work in every case.

if model.MD_LIGHT_POWER in gr.metadata:
pwr = gr.metadata[model.MD_LIGHT_POWER] * 1e3 # in mW
obj.attrib["Power"] = "%.15f" % pwr
obj.attrib["PowerUnit"] = "mW"
light_sources.append(obj)

elif (model.MD_LIGHT_POWER in da0.metadata or
model.MD_EBEAM_CURRENT in da0.metadata or
model.MD_EBEAM_CURRENT_TIME in da0.metadata
):
Expand Down Expand Up @@ -1611,7 +1627,12 @@ def _addImageElement(root, das, ifd, rois, fname=None, fuuid=None):

# TODO: non-standard metadata, treat it differently for different detectors
cot = da.metadata.get(model.MD_EBEAM_CURRENT_TIME)
if attrib or cot or model.MD_LIGHT_POWER in da.metadata:

# support light source per channel (meteor)
if not (attrib and cot) and model.MD_LIGHT_POWER in da.metadata:
attrib["ID"] = "LightSource:%d" % subid
ds = ET.SubElement(chan, "LightSourceSettings", attrib=attrib)
elif attrib or cot or model.MD_LIGHT_POWER in da.metadata:
attrib["ID"] = "LightSource:%d" % ifd
ds = ET.SubElement(chan, "LightSourceSettings", attrib=attrib)
# This is a non-standard metadata, it defines the emitter, which
Expand Down
Loading