Source code for lvpyioTools.frame
"""
Helper class for working lvpyio frames retrieved from a set.
"""
from typing import TYPE_CHECKING
from enum import StrEnum
import matplotlib.pyplot as plt
from matplotlib.colors import Colormap
from lvpyio.types.frame import ImageFrame
from lvpyio.types.scale import Scales
from .attribute import FrameAttribute
if TYPE_CHECKING:
from .set import LVSet
[docs]
class LVFrame():
"""
Wrapper class for working with lvpyio frames retrieved from a set. This class provides a convenient interface to access frame attributes, image data, and scale information.
"""
def __init__(self, frame: ImageFrame, set: 'LVSet'):
self.frame = frame
self.set = set
[docs]
def replace_frame(self, new_frame: ImageFrame):
"""
Update the current frame with a new frame. Notably used for performance reasons to not create a new LVFrame object for each frame in a set.
Args:
new_frame (ImageFrame): The new frame to update with.
"""
self.frame = new_frame
def __len__(self):
return len(self.frame.images)
def __repr__(self):
return f"<LVFrame: {len(self.frame.images)} images, shape={self.frame.shape}>"
[docs]
def shape(self):
"""
Get the images and masks shapes.
Returns:
tuple: A tuple containing the shapes of the images and masks.
"""
return self.frame.shape
[docs]
def get(self, image_number: int = 0):
"""
Read the image data from a specific frame and image number.
Args:
image_number (int, optional): The index of the image to retrieve. Defaults to 0.
Raises:
IndexError: If the image_number is out of range.
Returns:
numpy.ndarray: The image data as a NumPy array.
"""
if image_number < 0 or image_number >= len(self.frame.images):
raise IndexError(f"Image number {image_number} is out of range. Available images: 0 to {len(self.frame.images)-1}.")
return self.frame.images[image_number]
[docs]
def show(self, image_number: int = 0,
vmin: float | None = None, vmax: float | None = None,
cmap: str | Colormap | None = 'gray',
_show: bool = True):
"""
Display the image data from a specific frame and image number using the default image viewer.
Args:
image_number (int, optional): The index of the image to display. Defaults to 0.
"""
image_data = self.get(image_number)
fig, ax = plt.subplots()
ax.imshow(image_data, cmap=cmap, vmin=vmin, vmax=vmax)
ax.axis('off')
plt.tight_layout()
if _show:
plt.show()
return fig, ax
[docs]
def scale(self) -> Scales:
"""
Read the scale information from the frame, that is a class containing the following attributes:
- ``x``: The scale in the x-direction (in meters per pixel).
- ``y``: The scale in the y-direction (in meters per pixel).
- ``z``: The scale in the z-direction (in meters per pixel).
- ``i``: The scale in the intensity direction (generally with a slope of 1).
Each attributes are ``Scale`` objects, which contain the following attributes:
- ``slope``: The slope of the scale
- ``offset``: The offset of the scale
- ``unit``: The unit of the scale (mm, counts, etc.)
- ``description``: Mostly just empty
Returns:
Scales: A ``Scales`` object containing the scale information for the frame.
"""
return self.frame.scales
[docs]
def get_attribute(self, attribute: FrameAttribute):
"""
Get a specific attribute from the frame.
Args:
attribute (FrameAttribute): The attribute to retrieve.
Returns:
Any: The value of the requested attribute, or ``None`` if the attribute is not found in the frame.
"""
return self.frame.attributes.get(attribute.value, None)
[docs]
def get_max_intensity(self):
"""
Get the maximum intensity of the pixel values from the frame.
Raises:
ValueError: If the CAMERA_MAX_INTENSITY attribute is not found or is invalid.
Returns:
float: The maximum intensity value of the pixel values from the frame.
"""
max_intensity = self.get_attribute(FrameAttribute.CAMERA_MAX_INTENSITY)
if max_intensity is not None:
try:
return float(max_intensity)
except ValueError:
raise ValueError(f"Invalid CAMERA_MAX_INTENSITY value: {max_intensity}")
else:
raise ValueError("CAMERA_MAX_INTENSITY attribute not found in frame.")