"""
Author: Ismael Seidel (ismael.seidel@ufsc.br)
Affiliation: Embedded Computing Lab (ECL), Federal University of Santa Catarina (UFSC)
Description:
The class LightfieldConverter handles conversion for all of the currently
supported formats in the LFC Toolkit (e. g, PPM->PGX, PGX->YUV...)
"""
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Optional, Union
from lfc_toolkit.src.converters.ffmpeg import FFMPEGLightFieldFormatConverter
from lfc_toolkit.src.converters.pgx_from_yuv import generate_pgx_from_yuv
from lfc_toolkit.src.converters.png_from_ppm import generate_png_from_ppm
from lfc_toolkit.src.converters.ppm_from_png import generate_ppm_from_png
from lfc_toolkit.src.converters.ppm_from_yuv import generate_ppm_from_yuv
from lfc_toolkit.src.converters.yuv_from_pgx import generate_yuv_from_pgx
from lfc_toolkit.src.data_handlers.lightfield import RAWLightFieldData
[docs]
class LightfieldConverter:
@staticmethod
def __resolve_decoded_raw_path(path: Path, destination_type: str) -> Path:
"""Resolves the output path for decoded raw data based on parent structure.
:param path: Path to the source raw data
:type path: Path
:param destination_type: Destination format type (e.g. PGX, YUV)
:type destination_type: str
:return: Resolved path for the destination type
:rtype: Path
"""
before_type = path.parent.parent
return before_type / destination_type
[docs]
@staticmethod
def convert(
source: RAWLightFieldData,
destination_type: str,
output_path: Optional[Union[str, Path]] = None,
remove_after_using: bool = False,
) -> Optional[RAWLightFieldData]:
"""
Light field converter method
:param source: Input raw light field
:type source: RAWLightFieldData
:param destination_type: Output file format (e.g, PGX, YUV, PNG)
:type destination_type: str
:param output_path: Output path for converted files
:type output_path: Optional[Union[str, Path]]
:param remove_after_using: Whether to remove intermediate files
:return: Converted light field
:rtype: RAWLightFieldData | None
"""
print(source)
if destination_type == source.type:
return source
if not output_path:
output_path = LightfieldConverter.__resolve_decoded_raw_path(
path=source.raw_path, destination_type=destination_type
)
if source.type.lower() == "yuv":
if destination_type.lower() == "pgx":
return generate_pgx_from_yuv(
raw_light_field_data=source,
pgx_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_after_using,
)
if destination_type.lower() == "ppm":
return generate_ppm_from_yuv(
raw_light_field_data=source,
ppm_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_after_using,
)
if destination_type.lower() == "png":
with TemporaryDirectory() as tmpdir:
tmp_ppm_path = Path(tmpdir) / "temp.ppm"
ppm_lf = generate_ppm_from_yuv(
raw_light_field_data=source,
ppm_path=tmp_ppm_path,
scan_order=source.scan_order,
remove_after_using=False,
)
png_lf = generate_png_from_ppm(
raw_light_field_data=ppm_lf,
png_path=output_path,
scan_order=ppm_lf.scan_order,
remove_after_using=remove_after_using,
)
return png_lf
raise Exception(f"Cannot convert from yuv to {destination_type}")
if source.type.lower() == "pgx":
remove_yuv = (destination_type.lower() == "ppm") or remove_after_using
yuv_from_pgx = generate_yuv_from_pgx(
raw_light_field_data=source,
yuv_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_yuv,
)
if destination_type.lower() == "yuv":
return yuv_from_pgx
if destination_type.lower() == "ppm":
converted_yuv = generate_ppm_from_yuv(
raw_light_field_data=yuv_from_pgx,
ppm_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_after_using,
)
return converted_yuv
if destination_type.lower() == "png":
with TemporaryDirectory() as tmpdir:
tmp_ppm_path = Path(tmpdir) / "temp.ppm"
ppm_lf = generate_ppm_from_yuv(
raw_light_field_data=yuv_from_pgx,
ppm_path=tmp_ppm_path,
scan_order=source.scan_order,
remove_after_using=False,
)
png_lf = generate_png_from_ppm(
raw_light_field_data=ppm_lf,
png_path=output_path,
scan_order=ppm_lf.scan_order,
remove_after_using=remove_after_using,
)
return png_lf
raise Exception(f"Cannot convert from pgx to {destination_type}")
if source.type.lower() == "ppm":
remove_yuv = (destination_type.lower() == "pgx") or remove_after_using
yuv_lf = FFMPEGLightFieldFormatConverter.convert_rgb_ppm_lf_to_bt709fr_yuv(
raw_light_field_rgb_ppm=source,
yuv_path=output_path,
remove_after_using=remove_yuv,
)
if destination_type.lower() == "yuv":
return yuv_lf
if destination_type.lower() == "pgx":
pgx_lf = generate_pgx_from_yuv(
raw_light_field_data=yuv_lf,
pgx_path=output_path,
scan_order=yuv_lf.scan_order,
remove_after_using=remove_after_using,
)
return pgx_lf
if destination_type.lower() == "png":
png_lf = generate_png_from_ppm(
raw_light_field_data=source,
ppm_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_after_using,
)
return png_lf
if source.type.lower() == "png":
if destination_type.lower() == "ppm":
return generate_ppm_from_png(
raw_light_field_data=source,
ppm_path=output_path,
scan_order=source.scan_order,
remove_after_using=remove_after_using,
)
if destination_type.lower() == "pgx":
with TemporaryDirectory() as tmpdir:
tmp_ppm_path = Path(tmpdir) / "temp.ppm"
tmp_yuv_path = Path(tmpdir) / "temp.yuv"
ppm_lf = generate_ppm_from_png(
raw_light_field_data=source,
ppm_path=tmp_ppm_path,
scan_order=source.scan_order,
remove_after_using=False,
)
yuv_lf = FFMPEGLightFieldFormatConverter.convert_rgb_ppm_lf_to_bt709fr_yuv(
raw_light_field_rgb_ppm=ppm_lf,
yuv_path=tmp_yuv_path,
remove_after_using=False,
)
pgx_lf = generate_pgx_from_yuv(
raw_light_field_data=yuv_lf,
pgx_path=output_path,
scan_order=yuv_lf.scan_order,
remove_after_using=remove_after_using,
)
return pgx_lf
if destination_type.lower() == "yuv":
with TemporaryDirectory() as tmpdir:
tmp_ppm_path = Path(tmpdir) / "temp.ppm"
ppm_lf = generate_ppm_from_png(
raw_light_field_png=source,
ppm_path=tmp_ppm_path,
scan_order=source.scan_order,
remove_after_using=False,
)
yuv_lf = FFMPEGLightFieldFormatConverter.convert_rgb_ppm_lf_to_bt709fr_yuv(
raw_light_field_rgb_ppm=ppm_lf,
yuv_path=output_path,
remove_after_using=remove_yuv,
)
return yuv_lf
raise Exception("I should not be here (end of LFConverter.convert)")
[docs]
def main():
import argparse
# 1. Create the ArgumentParser object with a description
parser = argparse.ArgumentParser(description="Convert a single YUV LF to PPM.")
# 2. Add a positional argument (required input, no dashes)
parser.add_argument(
"--name", "-n", required=True, type=str, help="The name of the light field."
)
parser.add_argument("--n-views-height", "-t", required=True, type=int, help="T")
parser.add_argument("--n-views-width", "-s", required=True, type=int, help="S")
parser.add_argument("--view-height", "-v", required=True, type=int, help="V")
parser.add_argument("--view-width", "-u", required=True, type=int, help="U")
parser.add_argument(
"--bits-per-sample", "-b", required=True, type=int, help="Bits per sample"
)
parser.add_argument(
"--input_path", "-i", required=True, type=str, help="Input path"
)
parser.add_argument(
"--output_path", "-o", required=True, type=str, help="Output path"
)
parser.add_argument(
"--from-format", "-from", required=True, type=str, help="Input format"
)
parser.add_argument(
"--to-format", "-to", required=True, type=str, help="Output format"
)
# 3. Parse the arguments from the command line
args = parser.parse_args()
# from lfc_toolkit.src.data_handlers.lightfield import LightField
input_format = args.from_format
print(input_format)
match input_format:
case "pgx":
raw_type="pgx",
raw_pix_fmt="PGX",
raw_colour_space="BT.709 Full Range",
case "png":
raw_type="png"
raw_pix_fmt="rgb24"
raw_colour_space="sRGB"
case "ppm":
raw_type="ppm"
raw_pix_fmt="PPM"
raw_colour_space="sRGB"
case "yuv":
raw_type="yuv",
raw_pix_fmt="yuv444p10le",
raw_colour_space="BT.709 Full Range",
case _:
raise Exception("Unknown input format", input_format)
from lfc_toolkit.src.data_handlers.encoding_orders import get_serpentine_scan_list
from lfc_toolkit.src.data_handlers.lightfield import LightField
input_lf = RAWLightFieldData(
lightfield=LightField(
name=args.name,
view_width=args.view_width,
view_height=args.view_height,
n_views_width=args.n_views_width,
n_views_height=args.n_views_height,
),
raw_path=args.input_path,
bits_per_sample=args.bits_per_sample,
type=raw_type,
pix_fmt=raw_pix_fmt,
colour_space=raw_colour_space,
initial_width=0,
initial_height=0,
step_width=1,
step_height=1,
#bpp_for_naming=bpp_for_naming,
scan_order=get_serpentine_scan_list,
remove_after_using=False
)
LightfieldConverter.convert(
source=input_lf,
destination_type=args.to_format,
output_path=args.output_path,
remove_after_using= False,
)
if __name__ == "__main__":
main()