ZEISS / pylibczirw

A simple and easy-to-use Python wrapper for libCZI - a cross-platform C++ library intended for providing read and write access to CZI documents.
https://zeiss.github.io/pylibczirw/
GNU Lesser General Public License v3.0
11 stars 3 forks source link

Access CZI "attachments" (i.e. slide label image, slide / tissue preview, etc.) #38

Open alexbaras opened 3 weeks ago

alexbaras commented 3 weeks ago

From my perspective the pylibczirw module is one of the only modules that allows for writing czi files. As such, I think it would be important to enable both reading and writing of czi files to include various associated images like slide label and slide / tissue preview.

For now I use czifile for access to the "attachments". I've posted that code example below. I suspect this example and the czifile module code base could be put together to achieve the desired effect.

-Alex

get czi attachments

with czifile.CziFile(czi_files[i_file]) as czi:

get attachment objects

attachments = {a.attachment_entry.name: {'obj': a} for a in czi.attachments()}

# get label img
attachments['Label']['obj']._fh.seek(attachments['Label']['obj'].data_offset)
with BytesIO(attachments['Label']['obj']._fh.read(attachments['Label']['obj'].data_size)) as fh:
    attachments['Label']['img'] = czifile.CziFile(fh).asarray()
    attachments['Label']['img'] = 255. * attachments['Label']['img'][0].astype(np.float32) / 4096.
    attachments['Label']['img'] = np.clip(np.round(attachments['Label']['img'], 0), a_min=0, a_max=255).astype(np.uint8)

# get label img
attachments['SlidePreview']['obj']._fh.seek(attachments['SlidePreview']['obj'].data_offset)
with BytesIO(attachments['SlidePreview']['obj']._fh.read(attachments['SlidePreview']['obj'].data_size)) as fh:
    attachments['SlidePreview']['img'] = czifile.CziFile(fh).asarray()
    attachments['SlidePreview']['img'] = 255. * attachments['SlidePreview']['img'][0].astype(np.float32) / 4096.
    attachments['SlidePreview']['img'] = np.clip(np.round(attachments['SlidePreview']['img'], 0), a_min=0, a_max=255).astype(np.uint8)
horsto commented 1 week ago

Hi Alex, I followed your example above to get timestamp information from my czi file. At least I think this might be the only way to retrieve that data for every frame.

from io import BytesIO
import czifile

with czifile.CziFile(czi_file.as_posix()) as f:

    # get attachment objects
    attachments = {a.attachment_entry.name: {'obj': a} for a in f.attachments()}
    attachments['TimeStamps']['obj']._fh.seek(attachments['TimeStamps']['obj'].data_offset)
    with BytesIO(attachments['TimeStamps']['obj']._fh.read(attachments['TimeStamps']['obj'].data_size)) as fh:
        attachments['TimeStamps']['img'] = czifile.CziFile(fh).asarray()
Screenshot 2024-09-08 at 10 40 46

However I am running into this error

ValueError                                Traceback (most recent call last)
Cell In[1422], line 8
      5 attachments['TimeStamps']['obj']._fh.seek(attachments['TimeStamps']['obj'].data_offset)
      6 with BytesIO(attachments['TimeStamps']['obj']._fh.read(attachments['TimeStamps']['obj'].data_size)) as fh:
----> 8     attachments['TimeStamps']['img'] = czifile.CziFile(fh).asarray()

File [~/miniconda3/envs/suite2p/lib/python3.9/site-packages/czifile/czifile.py:266](http://localhost:8888/lab/tree/octo_code/calcium_imaging_slices/~/miniconda3/envs/suite2p/lib/python3.9/site-packages/czifile/czifile.py#line=265), in CziFile.__init__(self, arg, multifile, filesize, detectmosaic)
    264 try:
    265     if self._fh.read(10) != b'ZISRAWFILE':
--> 266         raise ValueError('not a CZI file')
    267     self.header = Segment(self._fh, 0).data()
    268 except Exception:

ValueError: not a CZI file

Do you have any ideas on how to solve that?