Source code for src.generate_11x11_ppm_for_lenslets

"""
Author: Ismael Seidel
Affiliation: Embedded Computing Lab (ECL), Federal University of Santa Catarina (UFSC)

Description:
    This module renames PPM files to select a subset of the views and starts counting from view 000_000.
    This implementation is for JPEG Pleno CE 14.
"""

import json
import os
import shutil
import sys
from hashlib import md5

# Add the parent directory to the Python path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from lfc_toolkit.src.converters.ffmpeg import FFMPEGLightFieldFormatConverter
from lfc_toolkit.src.data_handlers.lightfield import (
    LightField, RAW_BT709_FR_YUV444p10le_LightField_Data, RAWLightFieldData)


[docs] def get_lenslet_lf(name: str) -> LightField: """Create a LightField object for a lenslet configuration (11x11 views). :param name: Light field name :type name: str :return: Light field object with lenslet specifications :rtype: LightField """ return LightField( name=name, view_width=625, view_height=434, n_views_width=11, n_views_height=11 )
[docs] def get_raw_lenslet_lf_ppm(name: str, raw_ppm_path: str) -> RAWLightFieldData: """Create a raw light field data object for lenslet PPM files. :param name: Light field name :type name: str :param raw_ppm_path: Path to the raw PPM files :type raw_ppm_path: str :return: Raw light field data object :rtype: RAWLightFieldData """ return RAWLightFieldData( lightfield=get_lenslet_lf(name), initial_width=0, initial_height=0, raw_path=f"{raw_ppm_path}/{name}", pix_fmt="PPM", colour_space="sRGB", )
[docs] def load_paths_from_json(cfg_file: str) -> dict: """Load paths configuration from a JSON file. Loads the raw_ppm_path, selected_ppm_path, and other paths from a JSON configuration file. :param cfg_file: Path to the JSON configuration file :type cfg_file: str :return: Dictionary containing paths from the JSON file :rtype: dict """ with open(cfg_file, "r") as file: data = json.load(file) return data
[docs] def copy_and_rename_files( raw_ppm_path: str, selected_ppm_path: str, xxx: int, yyy: int, limit_xxx: int, limit_yyy: int ) -> None: """Copy and rename PPM files from source to destination with view indexing. Copies files from raw_ppm_path to selected_ppm_path, renaming them from xxx_yyy.ppm to 000_000.ppm format, within the specified view limits. :param raw_ppm_path: Path to the raw source files :type raw_ppm_path: str :param selected_ppm_path: Path to the output folder :type selected_ppm_path: str :param xxx: Offset for the first view index dimension :type xxx: int :param yyy: Offset for the second view index dimension :type yyy: int :param limit_xxx: Maximum value for first dimension before stopping :type limit_xxx: int :param limit_yyy: Maximum value for second dimension before resetting :type limit_yyy: int :return: None :rtype: None """ # Create output folder if it doesn't exist if not os.path.exists(selected_ppm_path): os.makedirs(selected_ppm_path) # Loop to rename and copy files source_xxx = xxx source_yyy = yyy target_xxx = 0 target_yyy = 0 while target_xxx < limit_xxx: # Format the source file name with source_xxx and source_yyy source_file = f"{source_xxx:03d}_{source_yyy:03d}.ppm" source_path = os.path.join(raw_ppm_path, source_file) # Check if the file exists in the source folder if not os.path.exists(source_path): print(f"File {source_file} not found. Stopping.") break # Format the target file name with target_xxx and target_yyy target_file = f"{target_xxx:03d}_{target_yyy:03d}.ppm" target_path = os.path.join(selected_ppm_path, target_file) # Copy the file to the output folder with the new name shutil.copy(source_path, target_path) print(f"Copied {source_file} to {target_file}") target_yyy += 1 source_yyy += 1 if target_yyy >= limit_yyy: target_yyy = 0 source_yyy = yyy target_xxx += 1 source_xxx += 1
[docs] def main() -> None: """Generate 11x11 PPM files for lenslet light fields. Processes lenslet light fields to extract and rename views into 11x11 grid format, starting from view 000_000. Performs validation by converting to YUV and comparing with previously generated YUV files. Usage: python generate_11x11_ppm_for_lenslets.py <configuration.json> :return: None :rtype: None """ if not len(sys.argv) == 2: print( "Error. Expecting a parameter with the name of the JSON configuration file with the paths (ppm, yuv, and pgx)." ) exit(1) cfg_file = sys.argv[1] print("Using the paths from", cfg_file) # Open and read the JSON file configuration = load_paths_from_json(cfg_file) # Extract paths raw_paths = configuration["raw_paths"] raw_ppm_path = raw_paths["ppm"] selected_ppm_path = raw_paths["ppm11x11"] print(f"{selected_ppm_path =}") # using the raw_yuv_from_pgx_path to cross check raw_yuv_from_pgx_path = raw_paths["yuv_check"] remove_yuv_from_pgx_after_check = configuration["remove_yuv_from_pgx_after_check"] # the ideia is to compare with already generated YUV files that should be in this path raw_yuv_path = raw_paths["yuv"] # TODO: use this! output_log_filename = configuration["logs"]["generate_11x11_ppm"] lenslets = configuration["lightfields"]["lenslets"] # Set offsets and limits xxx = 2 # Set the offset for xxx yyy = 2 # Set the offset for yyy limit_xxx = 11 # Maximum value for xxx limit_yyy = 11 # Maximum value for yyy matches = dict() # Call the function to copy and rename files for lenslet in lenslets: print(f"Creating 11x11 version for {lenslet} with PPM files.") copy_and_rename_files( f"{raw_ppm_path}/{lenslet}", f"{selected_ppm_path}/{lenslet}", xxx, yyy, limit_xxx, limit_yyy, ) # performing cross check by generating yuv file print(f"Generating YUV for validation with previously generated YUV") already_existing_yuv = RAW_BT709_FR_YUV444p10le_LightField_Data( lightfield=get_lenslet_lf(lenslet), yuv_path=raw_yuv_path ) md5_of_already_existing_yuv = md5( open(already_existing_yuv.raw_path, "rb").read() ).hexdigest() print("MD5 from existing YUV:", md5_of_already_existing_yuv) print("Converting the new PPM to YUV for crosscheck") yuv_from_ppm: RAW_BT709_FR_YUV444p10le_LightField_Data = ( FFMPEGLightFieldFormatConverter.convert_rgb_ppm_lf_to_bt709fr_yuv( get_raw_lenslet_lf_ppm(lenslet, os.path.abspath(selected_ppm_path)), yuv_path=raw_yuv_from_pgx_path, ) ) md5_of_yuv_from_ppm = md5(yuv_from_ppm.raw_path.read_bytes()).hexdigest() matches[lenslet] = md5_of_yuv_from_ppm == md5_of_already_existing_yuv print("MD5 from new YUV:", md5_of_yuv_from_ppm) if matches[lenslet]: print( "Already existing YUV file matches an YUV created from the 11x11 PPM." ) else: print( "Something went wrong! Already existing YUV file does not match the YUV created from the 11x11 PPM." ) if remove_yuv_from_pgx_after_check and os.path.exists(yuv_from_ppm.raw_path): print("Removing the YUV generated from 11x11 PPM (created to crosscheck).") os.remove(yuv_from_ppm.raw_path) print("") print("Finished for all lenslets. Summary: ") for lenslet, match in matches.items(): print(lenslet, "OK" if match else "Error")
if __name__ == "__main__": main()