Source code for ddd_pylib._base._image_operator
from ._base_operator import BaseOperator
from ddd_pylib import ImageUtils
import xarray as xr
from typing import List, Tuple
from abc import abstractmethod
[docs]
class ImageOperator(BaseOperator):
"""
Gives all the common functions that all Operator that use images will use.
It provides an image attribute which stock the main image used and a
result attribute which stock the result of the function used.
:param _mainImage: Take a DataArray defining the image
:param _result: Store the result of the function used, its form may vary depending of the function
"""
def __init__(self):
super().__init__()
self._mainImage = None
[docs]
def getMainImage(self) -> xr.DataArray:
"""
Return the main image as a DataArray
"""
if self._mainImage is None:
raise ValueError("Main image is not set")
return self._mainImage
[docs]
def setMainImage(self, image: xr.DataArray):
"""
Take an image and store it in the _mainImage attribute
Args:
image: An image as a DataArray
"""
self._mainImage = image
[docs]
def makeResultName(self, t=None) -> str:
"""
Create the result name using the image name and the getPrefix function of the used operator
"""
if self._mainImage is None:
raise ValueError("Main image is not set")
name = f"{self.getPrefix()}{self._mainImage.name if self._mainImage.name is not None else ''}"
if t is not None:
name = f"{name}[{t+1}]"
return name
[docs]
def sanityCheck(self):
"""
Simple check to prevent simple error, it may be implemented in subclasses
to check more precise stuff
"""
if self._mainImage is None:
raise ValueError("Main image is not set")
currentAxes = set([str(a) for a in self._mainImage.dims])
if not currentAxes.issubset(self.getValidAxes()):
raise ValueError(f"Main image dimensions {self._mainImage.dims} are not valid. Valid axes are {self.getValidAxes()}")
@abstractmethod
def _applyToFrame(self, frameData: Tuple[xr.DataArray, ...], t: int, nT: int):
raise NotImplementedError("Subclasses should implement this method")
[docs]
def getNTimePoints(self) -> int:
"""
Return the size of the T axis if it exist, if not then just 1
"""
img = self.getMainImage()
return img.sizes.get('T', 1)
def _zipInputs(self) -> List[Tuple[xr.DataArray, ...]]:
img = self.getMainImage()
if 'T' in img.dims:
return [(img.isel(T=t),) for t in range(self.getNTimePoints())]
else:
return [(img,)]
[docs]
def getOutputDims(self) -> List[str]:
img = self.getMainImage()
return [str(a) for a in img.dims]
def _bundleResultsBuffer(self, buffer: List):
"""
Bundle the results in the buffer into a single DataArray or DataFrame.
If the main image has a T dimension, concatenate along that dimension.
Otherwise, return the first element of the buffer.
"""
img = self.getMainImage()
result = (
xr.concat(buffer, dim='T').transpose(*self.getOutputDims())
if 'T' in img.dims
else buffer[0]
)
result.name = self.makeResultName()
ImageUtils.completeCalibrationFrom(img, result)
return result