Reading a video#
VideoReader is the single entry point for every
supported recording format. It hides the difference between a Photron header
plus raw file, a proprietary camera container, a folder of TIFFs and an MP4 —
downstream, every identification method sees the same interface.
from pyidi import VideoReader
video = VideoReader('measurement.cih')
Supported formats#
Source |
Extensions |
Notes |
|---|---|---|
Photron |
|
Point at the header file; the |
Phantom |
|
Read through the |
Pharsighted |
|
Read by the bundled |
Image sequence |
|
See Image sequences below. |
Video file |
|
Decoded with PyAV. Currently 8-bit only. |
In memory |
Shape |
# Photron
video = VideoReader('data/data_synthetic.cih')
# Phantom
video = VideoReader('data/data_small_cine.cine')
# an image sequence: point at any image in the folder
video = VideoReader('frames/im_0000.png')
# a numpy array already in memory
video = VideoReader(array, root='analysis_output')
Image sequences#
Give the path to any image in the sequence. All images must be in the same
directory and named so that a plain sort puts them in the right order — pad
the numbers: im_0000.png ... im_9999.png, not im_0.png ... im_9999.png.
Multi-image containers (.gif, multi-page .tif) are read as a sequence
from the single file.
Frame rate#
The frame rate is what turns a displacement history into a frequency, so it is worth checking rather than assuming.
pyIDI reads it from the file where the format carries it (Photron headers,
.cine setup blocks, and video-container metadata). Where it does not — a
numpy array, most image sequences, and any container whose metadata is missing
or wrong — set it yourself:
video = VideoReader('frames/im_0000.png', fps=10000)
# or later
video.configure(fps=10000)
Warning
Ordinary video containers frequently report a playback rate rather than the capture rate — a 6000 fps recording exported to MP4 will often claim 30 fps. If you did not record the file yourself, verify the rate against the acquisition settings.
The value is available as video.fps, and format-specific metadata is in
video.info.
Colour and bit depth#
Frames come back as a 2-D numpy.ndarray of shape
(image_height, image_width), uint8 or uint16 depending on the
source. Colour material is converted to grayscale (the luma channel) by
default. To use a single channel or your own weights instead:
# one channel
video.configure(video_format='rgb24', channel='R')
# custom weights
video.configure(video_format='rgb24', channel_weights=[0.299, 0.587, 0.114])
channel and channel_weights only take effect if video_format is set
to an RGB format matching the source bit depth (rgb24, rgb48le,
rgb48be); the default formats (gray, gray16be, gray16le)
already deliver a monochrome frame.
Reading frames#
frame = video.get_frame(0) # a single frame, (height, width)
frames = video.get_frames() # every frame, (n, height, width)
frames = video.get_frames(500) # frames 0..500
frames = video.get_frames((100, 400)) # frames 100..400
Useful attributes:
|
number of frames |
|
frame size in pixels |
|
frame rate in Hz |
|
metadata dictionary from the source file |
|
directory where the analysis results will be written |
Call video.close() when you are done with a .cine or memory-mapped
source, or let the object go out of scope.
Viewing the recording#
video.gui()
opens the napari viewer on the recording (requires the [qt] extra — see
Napari image viewer).
Next#
Point selection UI (deprecated) — choosing where to track.
Displacement identification methods — choosing how to track.