writer#

Custom OME.TIFF + MP4 writers for MDASequences.

CustomWriter extends pymmcore-plus’s public OMETiffWriter with two additions:

  1. bigtiff=True on the underlying tifffile call – mesoscope acquisitions routinely exceed the classic-TIFF 4 GiB ceiling.

  2. A per-frame <filename>_frame_metadata.json sidecar emitted from finalize_metadata(), containing the same metadata pymmcore-plus accumulates internally. This is the legacy mesofield contract every downstream parser already reads.

The sidecar JSON is the current source of truth for per-frame metadata. The broader goal (tracked separately) is to push the same fields into the OME-XML embedded in the TIFF itself so the JSON becomes supplementary and redundant; see the TODO in OMETiffWriter._sequence_metadata() upstream.

CV2Writer subclasses the public OMETiffWriter purely to reuse its inherited frameReady plumbing (the machinery that turns MMCamera/MDA signals into new_array / write_frame / store_frame_metadata calls and accumulates pymmcore-plus metadata). It overrides every TIFF-specific method to emit MP4/AVI instead – there is no public MP4 handler in pymmcore-plus to inherit from, and inheriting the public OMETiffWriter avoids depending on pymmcore-plus’s private _5d_writer_base module.

class mesofield.data.writer.CustomWriter[source]#

Bases: OMETiffWriter

OME-TIFF writer extending pymmcore-plus’s OMETiffWriter.

Two divergences from the public base:

  • Uses bigtiff=True so multi-GiB mesoscope acquisitions write cleanly.

  • Emits the per-frame metadata JSON sidecar mesofield’s downstream parsers (and the AcquisitionManifest’s metadata_path) depend on.

Everything else – filename validation, frame writing, OME-XML sequence metadata, memmap handling – is inherited from OMETiffWriter.

__init__(filename)[source]#
Parameters:

filename (Path | str)

Return type:

None

new_array(position_key, dtype, sizes)[source]#

Mirror OMETiffWriter.new_array() but with bigtiff=True.

Upstream’s implementation hardcodes the imwrite call; we duplicate it here to flip the bigtiff flag. Keep the bodies in sync if a pymmcore-plus bump changes the upstream version.

Parameters:
Return type:

memmap

finalize_metadata()[source]#

Write the per-frame metadata sidecar.

Called by OMETiffWriter.sequenceFinished after the last frame. Serialises self.frame_metadatas (the dict pymmcore-plus accumulates for us in frameReady) to JSON at <filename>_frame_metadata.json.

Return type:

None

class mesofield.data.writer.CustomJSONEncoder[source]#

Bases: JSONEncoder

default(object)[source]#

Implement this method in a subclass such that it returns a serializable object for o, or calls the base implementation (to raise a TypeError).

For example, to support arbitrary iterators, you could implement default like this:

def default(self, o):
    try:
        iterable = iter(o)
    except TypeError:
        pass
    else:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return super().default(o)
Parameters:

object (Any)

Return type:

Any

mesofield.data.writer.configure_opencv_codec()[source]#

Configure environment so OpenCV can locate the bundled OpenH264 DLL.

Safe to call repeatedly. Silences OpenCV/FFMPEG logging and prepends the project’s external/video-codecs directory to PATH / DLL search.

Return type:

None

class mesofield.data.writer.CV2Writer[source]#

Bases: OMETiffWriter

Write frames to an mp4/avi video using OpenCV.

Subclasses the public OMETiffWriter only to reuse its inherited MDA-signal handling (frameReady / sequenceStarted / sequenceFinished / store_frame_metadata and the frame_metadatas accumulation). Every TIFF-specific method (__init__ / new_array / write_frame / finalize_metadata) is overridden below to emit video instead, so none of OMETiffWriter’s tifffile machinery is ever reached.

Two usage modes share the same codec/fourcc/metadata logic:

  • MDA-driven (new_array / write_frame / finalize_metadata) when handed to CMMCorePlus.run_mda as an output handler.

  • Direct (begin / add_frame / finish) for cameras that run their own capture loop (e.g. OpenCVCamera).

__init__(filename, fps=30, fourcc='H264')[source]#
Parameters:
Return type:

None

new_array(position_key, dtype, sizes)[source]#

Create a new tifffile file and memmap for this position.

Parameters:
write_frame(ary, index, frame)[source]#

Write a frame to the file.

Parameters:
Return type:

None

finalize_metadata()[source]#

Called during sequenceFinished before clearing sequence metadata.

Subclasses may override this method to flush any accumulated frame metadata to disk at the end of the sequence.

Return type:

None

begin(width, height, is_color=True)[source]#

Open the underlying cv2.VideoWriter for a self-driven loop.

Parameters:
Return type:

None

add_frame(frame)[source]#

Write one frame to the direct-mode video (uint8 frames pass through).

Parameters:

frame (ndarray)

Return type:

None

finish(extra_metadata=None)[source]#

Release the direct-mode writer and write the metadata sidecar.

Parameters:

extra_metadata (dict | None)

Return type:

None