Source code for src.quality.quality_tool_wrapper
import abc
import os
from pathlib import Path
from typing import Optional, Tuple, Union
from lfc_toolkit.src.converters.lightfield_converter import LightfieldConverter
from lfc_toolkit.src.data_handlers.lightfield import RAWLightFieldData
[docs]
class QualityToolWrapper(abc.ABC):
"""Abstract base class for quality metric tool wrappers."""
[docs]
def __init__(self, reports_path: Union[str, Path], required_format: str) -> None:
"""Initializes the quality tool wrapper with reports path and required format.
:param reports_path: Path to store metric reports
:type reports_path: Union[str, Path]
:param required_format: Required lightfield format for the tool (e.g., "yuv")
:type required_format: str
:return: None
:rtype: None
"""
self.__reports_path = reports_path
os.makedirs(reports_path, exist_ok=True)
self._required_format = required_format
@property
def reports_path(self) -> Union[str, Path]:
"""Gets the path where quality reports are stored.
:return: Reports path
:rtype: Union[str, Path]
"""
return self.__reports_path
def _ensure_compatible(
self,
original_lightfield: RAWLightFieldData,
decoded_lightfield: RAWLightFieldData,
) -> None:
"""Ensures original and decoded light fields have compatible properties for metrics.
:param original_lightfield: Original light field data
:type original_lightfield: RAWLightFieldData
:param decoded_lightfield: Decoded light field data
:type decoded_lightfield: RAWLightFieldData
:return: None
:rtype: None
"""
assert original_lightfield.type == decoded_lightfield.type
assert original_lightfield.name == decoded_lightfield.name
assert original_lightfield.pix_fmt == decoded_lightfield.pix_fmt
assert original_lightfield.colour_space == decoded_lightfield.colour_space
assert original_lightfield.view_width == decoded_lightfield.view_width
assert original_lightfield.view_height == decoded_lightfield.view_height
assert original_lightfield.n_views_width == decoded_lightfield.n_views_width
assert original_lightfield.n_views_height == decoded_lightfield.n_views_height
def _get_raw_lfs_in_the_required_format(
self,
destination_type: str,
original_lightfield: RAWLightFieldData,
decoded_lightfield: RAWLightFieldData,
remove_after_using: bool = False
) -> Tuple[RAWLightFieldData, RAWLightFieldData]:
"""Converts original and decoded light fields to the required format for metrics.
:param destination_type: Target format type (e.g., "yuv", "pgx")
:type destination_type: str
:param original_lightfield: Original light field data
:type original_lightfield: RAWLightFieldData
:param decoded_lightfield: Decoded light field data
:type decoded_lightfield: RAWLightFieldData
:param remove_after_using: Whether to remove converted files after use, defaults to False
:type remove_after_using: bool, optional
:return: Tuple of (converted_original, converted_decoded)
:rtype: Tuple[RAWLightFieldData, RAWLightFieldData]
"""
converted_original = original_lightfield
converted_decoded = decoded_lightfield
if original_lightfield.type.lower() != destination_type.lower():
print("converting original...", original_lightfield.type, destination_type)
converted_original = LightfieldConverter.convert(
source=original_lightfield, destination_type=destination_type,
remove_after_using=remove_after_using
)
print(original_lightfield.raw_path)
if decoded_lightfield.type.lower() != destination_type.lower():
print("converting decoded...", decoded_lightfield.type, destination_type)
converted_decoded = LightfieldConverter.convert(
source=decoded_lightfield, destination_type=destination_type,
remove_after_using=remove_after_using
)
self._ensure_compatible(converted_original, converted_decoded)
return (
converted_original,
converted_decoded
)
[docs]
def get_metrics(
self,
original_lightfield: RAWLightFieldData,
decoded_lightfield: RAWLightFieldData,
remove_converted_lfs_after_using: bool = False
) -> Union[str, Path]:
"""Computes quality metrics between original and decoded light fields.
:param original_lightfield: Original light field data
:type original_lightfield: RAWLightFieldData
:param decoded_lightfield: Decoded light field data
:type decoded_lightfield: RAWLightFieldData
:param remove_converted_lfs_after_using: Whether to remove converted files after use, defaults to False
:type remove_converted_lfs_after_using: bool, optional
:return: Path to the metrics report
:rtype: Union[str, Path]
"""
(
converted_original,
converted_decoded
) = self._get_raw_lfs_in_the_required_format(
destination_type=self._required_format,
original_lightfield=original_lightfield,
decoded_lightfield=decoded_lightfield,
remove_after_using=remove_converted_lfs_after_using
)
report_path = self._call_metrics(converted_original, converted_decoded)
return report_path
@abc.abstractmethod
def _call_metrics(
self,
original_lightfield: RAWLightFieldData,
decoded_lightfield: RAWLightFieldData,
) -> Union[str, Path]:
"""Computes metrics between original and decoded lightfields. Must be implemented by subclasses.
:param original_lightfield: Original (reference) lightfield
:type original_lightfield: RAWLightFieldData
:param decoded_lightfield: Decoded lightfield to evaluate
:type decoded_lightfield: RAWLightFieldData
:return: Path to the metrics report file
:rtype: Union[str, Path]
"""
pass