"""
Network - Graphs
================
Define a collection of :class:`colour.utilities.PortGraph` graphs for raw and
HDR image processing.
"""
from __future__ import annotations
import os
import typing
if typing.TYPE_CHECKING:
from colour import RGB_Colourspace
from colour.hints import Any, Dict, List, Tuple
from colour.utilities import (
ExecutionNode,
ParallelForMultiprocess,
PortGraph,
)
from colour_hdri.generation import double_sigmoid_anchored_function
from colour_hdri.network import (
InputTransform,
NodeApplyInputTransformCameraSensitivities,
NodeApplyInputTransformDNG,
NodeComputeInputTransformCameraSensitivities,
NodeComputeInputTransformDNG,
NodeConvertRawFileToDNGFile,
NodeCorrectLensAberrationLensFun,
NodeCreateBatches,
NodeCreateImageStack,
NodeDownsample,
NodeMergeImageStack,
NodeNormaliseExposure,
NodeOrient,
NodeProcessingMetadata,
NodeProcessRawFileRawpy,
NodeReadFileMetadataDNG,
NodeRemoveFile,
NodeWatermark,
NodeWriteImage,
NodeWritePreviewImage,
)
from colour_hdri.utilities import notify_process_state
__author__ = "Colour Developers"
__copyright__ = "Copyright 2015 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"
__all__ = [
"GraphRawProcessingDNG",
"GraphRawProcessingCameraSensitivities",
"GraphMergeHDRI",
"GraphPostMergeHDRI",
"GraphBatchMergeHDRI",
"GraphHDRI",
]
[docs]
class GraphRawProcessingDNG(ExecutionNode, PortGraph):
"""
Process given raw file, e.g., *CR2*, *CR3*, *NEF*, using the *DNG* method.
Methods
-------
- :meth:`~colour_hdri.GraphRawProcessingDNG.__init__`
- :meth:`~colour_hdri.GraphRawProcessingDNG.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = (
'Process given raw file, e.g., "CR2", "CR3", "NEF", using the"DNG" method'
)
self.add_input_port("index")
self.add_input_port("element")
self.add_input_port("raw_file_path", None)
self.add_input_port("output_file_path", None)
self.add_input_port("output_colourspace", "sRGB")
self.add_input_port("CCT_D_uv", [6500, 0])
self.add_input_port("correct_vignette", True)
self.add_input_port("correct_chromatic_aberration", True)
self.add_input_port("correct_distortion", True)
self.add_input_port("downsample", 1)
self.add_input_port("orientation")
self.add_input_port("bypass_input_transform", False)
self.add_input_port("bypass_correct_lens_aberration", False)
self.add_input_port("bit_depth", "float32")
self.add_input_port("bypass_watermark", False)
self.add_input_port("bypass_orient", False)
self.add_output_port("output")
for node in [
NodeConvertRawFileToDNGFile("ConvertRawFileToDNGFile"),
NodeReadFileMetadataDNG("ReadFileMetadataDNG"),
NodeComputeInputTransformDNG("ComputeInputTransformDNG"),
NodeProcessRawFileRawpy("ProcessRawFileRawpy"),
NodeRemoveFile("RemoveDNGFile"),
NodeCorrectLensAberrationLensFun("CorrectLensAberrationLensFun"),
NodeDownsample("Downsample"),
NodeApplyInputTransformDNG("ApplyInputTransformDNG"),
NodeProcessingMetadata("ProcessingMetadata"),
NodeWatermark("Watermark"),
NodeOrient("Orient"),
NodeWriteImage("WriteImage"),
]:
self.add_node(node)
for connection in [
(
("ConvertRawFileToDNGFile", "execution_output"),
("ReadFileMetadataDNG", "execution_input"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ReadFileMetadataDNG", "dng_file_path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ProcessRawFileRawpy", "raw_file_path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("RemoveDNGFile", "path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ProcessingMetadata", "sources"),
),
(
("ReadFileMetadataDNG", "execution_output"),
("ComputeInputTransformDNG", "execution_input"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ComputeInputTransformDNG", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ComputeInputTransformDNG", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("CorrectLensAberrationLensFun", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ProcessingMetadata", "input_metadata"),
),
(
("ComputeInputTransformDNG", "execution_output"),
("ProcessRawFileRawpy", "execution_input"),
),
(
("ComputeInputTransformDNG", "input_transform"),
("ProcessRawFileRawpy", "input_transform"),
),
(
("ComputeInputTransformDNG", "input_transform"),
("ApplyInputTransformDNG", "input_transform"),
),
(
("ComputeInputTransformDNG", "input_transform"),
("ProcessingMetadata", "input_transform"),
),
(
("ProcessRawFileRawpy", "execution_output"),
("RemoveDNGFile", "execution_input"),
),
(
("ProcessRawFileRawpy", "image"),
("CorrectLensAberrationLensFun", "input_image"),
),
(
("RemoveDNGFile", "execution_output"),
("CorrectLensAberrationLensFun", "execution_input"),
),
(
("CorrectLensAberrationLensFun", "execution_output"),
("Downsample", "execution_input"),
),
(
("CorrectLensAberrationLensFun", "output_image"),
("Downsample", "input_image"),
),
(
("Downsample", "execution_output"),
("ApplyInputTransformDNG", "execution_input"),
),
(
("Downsample", "output_image"),
("ApplyInputTransformDNG", "input_image"),
),
(
("ApplyInputTransformDNG", "execution_output"),
("ProcessingMetadata", "execution_input"),
),
(
("ApplyInputTransformDNG", "output_image"),
("Watermark", "input_image"),
),
(
("ProcessingMetadata", "execution_output"),
("Watermark", "execution_input"),
),
(
("ProcessingMetadata", "output_metadata"),
("Watermark", "metadata"),
),
(
("ProcessingMetadata", "output_metadata"),
("WriteImage", "metadata"),
),
(
("Watermark", "execution_output"),
("Orient", "execution_input"),
),
(
("Watermark", "output_image"),
("Orient", "input_image"),
),
(
("Orient", "execution_output"),
("WriteImage", "execution_input"),
),
(
("Orient", "output_image"),
("WriteImage", "image"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self.nodes[input_node].connect(
input_port,
self.nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["ConvertRawFileToDNGFile"],
"execution_input",
)
self.connect(
"raw_file_path",
self.nodes["ConvertRawFileToDNGFile"],
"raw_file_path",
)
self.connect(
"output_colourspace",
self.nodes["ApplyInputTransformDNG"],
"output_colourspace",
)
self.connect(
"output_colourspace",
self.nodes["ProcessingMetadata"],
"output_colourspace",
)
self.connect(
"output_colourspace",
self.nodes["WriteImage"],
"output_colourspace",
)
self.connect(
"CCT_D_uv",
self.nodes["ComputeInputTransformDNG"],
"CCT_D_uv",
)
self.connect(
"correct_vignette",
self.nodes["CorrectLensAberrationLensFun"],
"correct_vignette",
)
self.connect(
"correct_chromatic_aberration",
self.nodes["CorrectLensAberrationLensFun"],
"correct_chromatic_aberration",
)
self.connect(
"correct_distortion",
self.nodes["CorrectLensAberrationLensFun"],
"correct_distortion",
)
self.connect(
"downsample",
self.nodes["Downsample"],
"factor",
)
self.connect(
"orientation",
self.nodes["Orient"],
"orientation",
)
self.connect(
"orientation",
self.nodes["ProcessingMetadata"],
"orientation",
)
self.connect(
"bypass_correct_lens_aberration",
self.nodes["CorrectLensAberrationLensFun"],
"bypass",
)
self.connect(
"bypass_input_transform",
self.nodes["ComputeInputTransformDNG"],
"bypass",
)
self.connect(
"bypass_input_transform",
self.nodes["ApplyInputTransformDNG"],
"bypass",
)
self.connect(
"bypass_watermark",
self.nodes["Watermark"],
"bypass",
)
self.connect(
"bypass_orient",
self.nodes["Orient"],
"bypass",
)
self.connect(
"output_file_path",
self.nodes["WriteImage"],
"path",
)
self.connect(
"bit_depth",
self.nodes["WriteImage"],
"bit_depth",
)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
if self.get_input("element") is not None:
self.set_input("raw_file_path", self.get_input("element"))
extension = os.path.splitext(self.get_input("raw_file_path"))[-1]
self.set_input(
"output_file_path",
self.get_input("raw_file_path").replace(extension, ".exr"),
)
super().process(**kwargs)
self.set_output("output", self.get_input("output_file_path"))
[docs]
class GraphRawProcessingCameraSensitivities(ExecutionNode, PortGraph):
"""
Process given raw file, e.g., *CR2*, *CR3*, *NEF*, using the
*Camera Sensitivities* method.
Methods
-------
- :meth:`~colour_hdri.GraphRawProcessingCameraSensitivities.__init__`
- :meth:`~colour_hdri.GraphRawProcessingCameraSensitivities.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = (
'Process given raw file, e.g., "CR2", "CR3", "NEF", using the'
'"Camera Sensitivities" method'
)
self.add_input_port("index")
self.add_input_port("element")
self.add_input_port("raw_file_path", None)
self.add_input_port("output_file_path", None)
self.add_input_port("output_colourspace", "sRGB")
self.add_input_port("CCT_D_uv", [6500, 0])
self.add_input_port("camera_sensitivities")
self.add_input_port("correct_vignette", True)
self.add_input_port("correct_chromatic_aberration", True)
self.add_input_port("correct_distortion", True)
self.add_input_port("downsample", 1)
self.add_input_port("orientation")
self.add_input_port("bit_depth", "float32")
self.add_input_port("bypass_input_transform", False)
self.add_input_port("bypass_correct_lens_aberration", False)
self.add_input_port("bypass_watermark", False)
self.add_input_port("bypass_orient", False)
self.add_output_port("output")
for node in [
NodeConvertRawFileToDNGFile("ConvertRawFileToDNGFile"),
NodeReadFileMetadataDNG("ReadFileMetadataDNG"),
NodeComputeInputTransformCameraSensitivities(
"ComputeInputTransformCameraSensitivities"
),
NodeProcessRawFileRawpy("ProcessRawFileRawpy"),
NodeRemoveFile("RemoveDNGFile"),
NodeCorrectLensAberrationLensFun("CorrectLensAberrationLensFun"),
NodeDownsample("Downsample"),
NodeApplyInputTransformCameraSensitivities(
"ApplyInputTransformCameraSensitivities"
),
NodeProcessingMetadata("ProcessingMetadata"),
NodeWatermark("Watermark"),
NodeOrient("Orient"),
NodeWriteImage("WriteImage"),
]:
self.add_node(node)
for connection in [
(
("ConvertRawFileToDNGFile", "execution_output"),
("ReadFileMetadataDNG", "execution_input"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ReadFileMetadataDNG", "dng_file_path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ProcessRawFileRawpy", "raw_file_path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("RemoveDNGFile", "path"),
),
(
("ConvertRawFileToDNGFile", "dng_file_path"),
("ProcessingMetadata", "sources"),
),
(
("ReadFileMetadataDNG", "execution_output"),
("ComputeInputTransformCameraSensitivities", "execution_input"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ComputeInputTransformCameraSensitivities", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ComputeInputTransformCameraSensitivities", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("CorrectLensAberrationLensFun", "metadata"),
),
(
("ReadFileMetadataDNG", "metadata"),
("ProcessingMetadata", "input_metadata"),
),
(
("ComputeInputTransformCameraSensitivities", "execution_output"),
("ProcessRawFileRawpy", "execution_input"),
),
(
("ComputeInputTransformCameraSensitivities", "input_transform"),
("ProcessRawFileRawpy", "input_transform"),
),
(
("ComputeInputTransformCameraSensitivities", "input_transform"),
("ApplyInputTransformCameraSensitivities", "input_transform"),
),
(
("ComputeInputTransformCameraSensitivities", "input_transform"),
("ProcessingMetadata", "input_transform"),
),
(
("ProcessRawFileRawpy", "execution_output"),
("RemoveDNGFile", "execution_input"),
),
(
("ProcessRawFileRawpy", "image"),
("CorrectLensAberrationLensFun", "input_image"),
),
(
("RemoveDNGFile", "execution_output"),
("CorrectLensAberrationLensFun", "execution_input"),
),
(
("CorrectLensAberrationLensFun", "execution_output"),
("Downsample", "execution_input"),
),
(
("CorrectLensAberrationLensFun", "output_image"),
("Downsample", "input_image"),
),
(
("Downsample", "execution_output"),
("ApplyInputTransformCameraSensitivities", "execution_input"),
),
(
("Downsample", "output_image"),
("ApplyInputTransformCameraSensitivities", "input_image"),
),
(
("ApplyInputTransformCameraSensitivities", "execution_output"),
("ProcessingMetadata", "execution_input"),
),
(
("ApplyInputTransformCameraSensitivities", "output_image"),
("Watermark", "input_image"),
),
(
("ProcessingMetadata", "execution_output"),
("Watermark", "execution_input"),
),
(
("ProcessingMetadata", "output_metadata"),
("Watermark", "metadata"),
),
(
("ProcessingMetadata", "output_metadata"),
("WriteImage", "metadata"),
),
(
("Watermark", "execution_output"),
("Orient", "execution_input"),
),
(
("Watermark", "output_image"),
("Orient", "input_image"),
),
(
("Orient", "execution_output"),
("WriteImage", "execution_input"),
),
(
("Orient", "output_image"),
("WriteImage", "image"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self.nodes[input_node].connect(
input_port,
self.nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["ConvertRawFileToDNGFile"],
"execution_input",
)
self.connect(
"raw_file_path",
self.nodes["ConvertRawFileToDNGFile"],
"raw_file_path",
)
self.connect(
"output_colourspace",
self.nodes["ApplyInputTransformCameraSensitivities"],
"output_colourspace",
)
self.connect(
"output_colourspace",
self.nodes["ProcessingMetadata"],
"output_colourspace",
)
self.connect(
"output_colourspace",
self.nodes["WriteImage"],
"output_colourspace",
)
self.connect(
"CCT_D_uv",
self.nodes["ComputeInputTransformCameraSensitivities"],
"CCT_D_uv",
)
self.connect(
"camera_sensitivities",
self.nodes["ComputeInputTransformCameraSensitivities"],
"camera_sensitivities",
)
self.connect(
"correct_vignette",
self.nodes["CorrectLensAberrationLensFun"],
"correct_vignette",
)
self.connect(
"correct_chromatic_aberration",
self.nodes["CorrectLensAberrationLensFun"],
"correct_chromatic_aberration",
)
self.connect(
"correct_distortion",
self.nodes["CorrectLensAberrationLensFun"],
"correct_distortion",
)
self.connect(
"downsample",
self.nodes["Downsample"],
"factor",
)
self.connect(
"orientation",
self.nodes["Orient"],
"orientation",
)
self.connect(
"orientation",
self.nodes["ProcessingMetadata"],
"orientation",
)
self.connect(
"bypass_correct_lens_aberration",
self.nodes["CorrectLensAberrationLensFun"],
"bypass",
)
self.connect(
"bypass_input_transform",
self.nodes["ComputeInputTransformCameraSensitivities"],
"bypass",
)
self.connect(
"bypass_input_transform",
self.nodes["ApplyInputTransformCameraSensitivities"],
"bypass",
)
self.connect(
"bypass_watermark",
self.nodes["Watermark"],
"bypass",
)
self.connect(
"bypass_orient",
self.nodes["Orient"],
"bypass",
)
self.connect(
"output_file_path",
self.nodes["WriteImage"],
"path",
)
self.connect(
"bit_depth",
self.nodes["WriteImage"],
"bit_depth",
)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
if self.get_input("element") is not None:
self.set_input("raw_file_path", self.get_input("element"))
extension = os.path.splitext(self.get_input("raw_file_path"))[-1]
self.set_input(
"output_file_path",
self.get_input("raw_file_path").replace(extension, ".exr"),
)
super().process(**kwargs)
self.set_output("output", self.get_input("output_file_path"))
[docs]
class GraphMergeHDRI(ExecutionNode, PortGraph):
"""
Merge the given *EXR* files to HDRI.
Methods
-------
- :meth:`~colour_hdri.GraphMergeHDRI.__init__`
- :meth:`~colour_hdri.GraphMergeHDRI.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = 'Merge the given "EXR" files to HDRI'
self.add_input_port("index")
self.add_input_port("element")
self.add_input_port("exr_file_paths", None)
self.add_input_port("metadata", None)
self.add_input_port("input_transform", InputTransform())
self.add_input_port("weighting_function", double_sigmoid_anchored_function)
self.add_input_port("output_colourspace", "sRGB")
self.add_input_port("output_file_path", None)
self.add_input_port("bypass_watermark", False)
self.add_output_port("output")
for node in [
NodeCreateImageStack("CreateImageStack"),
NodeMergeImageStack("MergeImageStack"),
NodeDownsample("Downsample"),
NodeProcessingMetadata("ProcessingMetadata"),
NodeWatermark("Watermark"),
NodeWriteImage("WriteImage"),
]:
self.add_node(node)
for connection in [
(
("CreateImageStack", "execution_output"),
("MergeImageStack", "execution_input"),
),
(
("CreateImageStack", "image_stack"),
("MergeImageStack", "image_stack"),
),
(
("MergeImageStack", "execution_output"),
("Downsample", "execution_input"),
),
(
("MergeImageStack", "image"),
("Downsample", "input_image"),
),
(
("Downsample", "execution_output"),
("ProcessingMetadata", "execution_input"),
),
(
("Downsample", "output_image"),
("Watermark", "input_image"),
),
(
("ProcessingMetadata", "execution_output"),
("Watermark", "execution_input"),
),
(
("ProcessingMetadata", "output_metadata"),
("Watermark", "metadata"),
),
(
("ProcessingMetadata", "output_metadata"),
("WriteImage", "metadata"),
),
(
("Watermark", "execution_output"),
("WriteImage", "execution_input"),
),
(
("Watermark", "output_image"),
("WriteImage", "image"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self._nodes[input_node].connect(
input_port,
self._nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["CreateImageStack"],
"execution_input",
)
self.connect(
"exr_file_paths",
self.nodes["CreateImageStack"],
"paths",
)
self.connect(
"metadata",
self.nodes["ProcessingMetadata"],
"input_metadata",
)
self.connect(
"exr_file_paths",
self.nodes["ProcessingMetadata"],
"sources",
)
self.connect(
"input_transform",
self.nodes["ProcessingMetadata"],
"input_transform",
)
self.connect(
"weighting_function",
self.nodes["MergeImageStack"],
"weighting_function",
)
self.connect(
"output_colourspace",
self.nodes["ProcessingMetadata"],
"output_colourspace",
)
self.connect(
"output_colourspace",
self.nodes["WriteImage"],
"output_colourspace",
)
self.connect(
"bypass_watermark",
self.nodes["Watermark"],
"bypass",
)
self.connect(
"output_file_path",
self.nodes["WriteImage"],
"path",
)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
if self.get_input("element") is not None:
element = self.get_input("element")
exr_file_paths = [item[0] for item in element]
metadata = [item[1] for item in element]
input_transform = [item[2] for item in element]
output_colourspace = [item[3] for item in element]
self.set_input("exr_file_paths", exr_file_paths)
self.set_input("metadata", next(iter(metadata)))
self.set_input("input_transform", next(iter(input_transform)))
self.set_input("output_colourspace", next(iter(output_colourspace)))
filename = os.path.basename(exr_file_paths[0])
filename, _extension = os.path.splitext(filename)
self.set_input(
"output_file_path",
os.path.join(
os.path.dirname(exr_file_paths[0]),
f"{filename}_{len(exr_file_paths)}_HDR.exr",
),
)
self.nodes["ProcessingMetadata"].set_input("type", "hdr")
self.nodes["Watermark"].set_input("include_exposure_information", False)
super().process(**kwargs)
self.set_output("output", self.get_input("output_file_path"))
def _task_multiprocess_post_merge_hdr(args: List) -> Tuple[int, str]:
i, element, sub_graph, node = args
node.log(f"Index {i}, Element {element}", "info")
node.set_output("index", i)
node.set_output("element", element)
sub_graph.process()
return i, sub_graph.get_output("preview_path")
[docs]
class GraphPostMergeHDRI(ExecutionNode, PortGraph):
"""
Normalise the exposure of the input *EXR* files at once and write
corresponding preview image files.
Methods
-------
- :meth:`~colour_hdri.GraphPostMergeHDRI.__init__`
- :meth:`~colour_hdri.GraphPostMergeHDRI.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = (
'Normalise the exposure of the input "EXR" files at once and write '
"corresponding preview image files"
)
self.add_input_port("array", [])
self.add_input_port("exposure_normalisation_factor", None)
self.add_input_port("processes")
self.add_input_port("bypass_exposure_normalisation", False)
self.add_input_port("bypass_preview_image", False)
self.add_output_port("output")
for node in [
NodeNormaliseExposure("NormaliseExposure"),
ParallelForMultiprocess("ParallelForMultiprocess"),
NodeWritePreviewImage("WritePreviewImage"),
]:
self.add_node(node)
for connection in [
(
("NormaliseExposure", "execution_output"),
("ParallelForMultiprocess", "execution_input"),
),
(
("ParallelForMultiprocess", "loop_output"),
("WritePreviewImage", "execution_input"),
),
(
("ParallelForMultiprocess", "element"),
("WritePreviewImage", "path"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self._nodes[input_node].connect(
input_port,
self._nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["NormaliseExposure"],
"execution_input",
)
self.connect(
"array",
self.nodes["NormaliseExposure"],
"image_paths",
)
self.connect(
"array",
self.nodes["ParallelForMultiprocess"],
"array",
)
self.connect(
"exposure_normalisation_factor",
self.nodes["NormaliseExposure"],
"normalisation_factor",
)
self.connect(
"processes",
self.nodes["ParallelForMultiprocess"],
"processes",
)
self.connect(
"bypass_exposure_normalisation",
self.nodes["NormaliseExposure"],
"bypass",
)
self.connect(
"bypass_preview_image",
self.nodes["WritePreviewImage"],
"bypass",
)
self.nodes["ParallelForMultiprocess"].set_input(
"task", _task_multiprocess_post_merge_hdr
)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
super().process(**kwargs)
self.set_output(
"output", self.nodes["ParallelForMultiprocess"].get_output("results")
)
[docs]
class GraphBatchMergeHDRI(ExecutionNode, PortGraph):
"""
Batch-merge to HDRI the input files.
Methods
-------
- :meth:`~colour_hdri.GraphBatchMergeHDRI.__init__`
- :meth:`~colour_hdri.GraphBatchMergeHDRI.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = "Batch-merge to HDRI the input files"
self.add_input_port("array", [])
self.add_input_port("batch_size", 3)
self.add_input_port("weighting_function", double_sigmoid_anchored_function)
self.add_input_port("exposure_normalisation_factor", None)
self.add_input_port("bypass_watermark", False)
self.add_input_port("bypass_exposure_normalisation", False)
self.add_input_port("bypass_preview_image", False)
self.add_input_port("processes")
self.add_output_port("output")
for node in [
NodeCreateBatches("CreateBatches"),
ParallelForMultiprocess("ParallelForMultiprocess"),
GraphMergeHDRI("GraphMergeHDRI"),
GraphPostMergeHDRI("GraphPostMergeHDRI"),
]:
self.add_node(node)
for connection in [
(
("CreateBatches", "execution_output"),
("ParallelForMultiprocess", "execution_input"),
),
(
("CreateBatches", "batches"),
("ParallelForMultiprocess", "array"),
),
(
("ParallelForMultiprocess", "loop_output"),
("GraphMergeHDRI", "execution_input"),
),
(
("ParallelForMultiprocess", "index"),
("GraphMergeHDRI", "index"),
),
(
("ParallelForMultiprocess", "element"),
("GraphMergeHDRI", "element"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self._nodes[input_node].connect(
input_port,
self._nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["CreateBatches"],
"execution_input",
)
self.connect(
"array",
self.nodes["CreateBatches"],
"array",
)
self.connect(
"batch_size",
self.nodes["CreateBatches"],
"batch_size",
)
self.connect(
"weighting_function",
self.nodes["GraphMergeHDRI"],
"weighting_function",
)
self.connect(
"exposure_normalisation_factor",
self.nodes["GraphPostMergeHDRI"],
"exposure_normalisation_factor",
)
self.connect(
"bypass_watermark",
self.nodes["GraphMergeHDRI"],
"bypass_watermark",
)
self.connect(
"bypass_exposure_normalisation",
self.nodes["GraphPostMergeHDRI"],
"bypass_exposure_normalisation",
)
self.connect(
"bypass_preview_image",
self.nodes["GraphPostMergeHDRI"],
"bypass_preview_image",
)
self.connect(
"processes",
self.nodes["ParallelForMultiprocess"],
"processes",
)
self.connect(
"processes",
self.nodes["GraphPostMergeHDRI"],
"processes",
)
self.nodes["ParallelForMultiprocess"].connect(
"execution_output", self.nodes["GraphPostMergeHDRI"], "execution_input"
)
self.nodes["ParallelForMultiprocess"].connect(
"results", self.nodes["GraphPostMergeHDRI"], "array"
)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
super().process(**kwargs)
self.set_output(
"output",
list(
zip(
self.nodes["ParallelForMultiprocess"].get_output("results"),
self.nodes["GraphPostMergeHDRI"].get_output("output"),
strict=False,
)
),
)
def _task_multiprocess_graph_hdri(
args: List,
) -> Tuple[int, Tuple[str, Dict, InputTransform, str | RGB_Colourspace]]:
i, element, sub_graph, node = args
node.log(f"Index {i}, Element {element}", "info")
node.set_output("index", i)
node.set_output("element", element)
sub_graph.process()
return (
i,
(
sub_graph.get_input("output_file_path"),
sub_graph.nodes["ProcessingMetadata"].get_input("input_metadata"),
sub_graph.nodes["ProcessingMetadata"].get_input("input_transform"),
sub_graph.nodes["ProcessingMetadata"].get_input("output_colourspace"),
),
)
[docs]
class GraphHDRI(ExecutionNode, PortGraph):
"""
Merge to HDRI the input files using the *Camera Sensitivities* method.
Methods
-------
- :meth:`~colour_hdri.GraphHDRI.__init__`
- :meth:`~colour_hdri.GraphHDRI.process`
"""
[docs]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.description = (
'Merge to HDRI the input files using the "Camera Sensitivities" method'
)
self.add_input_port("array", [])
self.add_input_port("camera_sensitivities")
self.add_input_port("output_colourspace")
self.add_input_port("CCT_D_uv", [6500, 0])
self.add_input_port("exposure_normalisation_factor", None)
self.add_input_port("downsample", 1)
self.add_input_port("correct_vignette", True)
self.add_input_port("correct_chromatic_aberration", True)
self.add_input_port("correct_distortion", True)
self.add_input_port("orientation", None)
self.add_input_port("bit_depth", "float32")
self.add_input_port("bypass_input_transform", False)
self.add_input_port("bypass_correct_lens_aberration", False)
self.add_input_port("bypass_watermark", False)
self.add_input_port("bypass_orient", False)
self.add_input_port("bypass_exposure_normalisation", False)
self.add_input_port("bypass_preview_image", False)
self.add_input_port("batch_size", 3)
self.add_input_port("weighting_function", double_sigmoid_anchored_function)
self.add_input_port("processes")
self.add_output_port("output")
for node in [
ParallelForMultiprocess("ParallelForMultiprocess"),
GraphRawProcessingCameraSensitivities(
"GraphRawProcessingCameraSensitivities"
),
GraphBatchMergeHDRI("GraphBatchMergeHDRI"),
]:
self.add_node(node)
for connection in [
(
("ParallelForMultiprocess", "execution_output"),
("GraphBatchMergeHDRI", "execution_input"),
),
(
("ParallelForMultiprocess", "results"),
("GraphBatchMergeHDRI", "array"),
),
(
("ParallelForMultiprocess", "loop_output"),
("GraphRawProcessingCameraSensitivities", "execution_input"),
),
(
("ParallelForMultiprocess", "index"),
("GraphRawProcessingCameraSensitivities", "index"),
),
(
("ParallelForMultiprocess", "element"),
("GraphRawProcessingCameraSensitivities", "element"),
),
]:
(input_node, input_port), (output_node, output_port) = connection
self._nodes[input_node].connect(
input_port,
self._nodes[output_node],
output_port,
)
self.connect(
"execution_input",
self.nodes["ParallelForMultiprocess"],
"execution_input",
)
self.connect(
"array",
self.nodes["ParallelForMultiprocess"],
"array",
)
self.connect(
"camera_sensitivities",
self.nodes["GraphRawProcessingCameraSensitivities"],
"camera_sensitivities",
)
self.connect(
"output_colourspace",
self.nodes["GraphRawProcessingCameraSensitivities"],
"output_colourspace",
)
self.connect(
"CCT_D_uv",
self.nodes["GraphRawProcessingCameraSensitivities"],
"CCT_D_uv",
)
self.connect(
"exposure_normalisation_factor",
self.nodes["GraphBatchMergeHDRI"],
"exposure_normalisation_factor",
)
self.connect(
"downsample",
self.nodes["GraphRawProcessingCameraSensitivities"],
"downsample",
)
self.connect(
"correct_vignette",
self.nodes["GraphRawProcessingCameraSensitivities"],
"correct_vignette",
)
self.connect(
"correct_chromatic_aberration",
self.nodes["GraphRawProcessingCameraSensitivities"],
"correct_chromatic_aberration",
)
self.connect(
"correct_distortion",
self.nodes["GraphRawProcessingCameraSensitivities"],
"correct_distortion",
)
self.connect(
"orientation",
self.nodes["GraphRawProcessingCameraSensitivities"],
"orientation",
)
self.connect(
"bit_depth",
self.nodes["GraphRawProcessingCameraSensitivities"],
"bit_depth",
)
self.connect(
"bypass_input_transform",
self.nodes["GraphRawProcessingCameraSensitivities"],
"bypass_input_transform",
)
self.connect(
"bypass_correct_lens_aberration",
self.nodes["GraphRawProcessingCameraSensitivities"],
"bypass_correct_lens_aberration",
)
self.connect(
"bypass_watermark",
self.nodes["GraphRawProcessingCameraSensitivities"],
"bypass_watermark",
)
self.connect(
"bypass_watermark",
self.nodes["GraphBatchMergeHDRI"],
"bypass_watermark",
)
self.connect(
"bypass_orient",
self.nodes["GraphRawProcessingCameraSensitivities"],
"bypass_orient",
)
self.connect(
"bypass_exposure_normalisation",
self.nodes["GraphBatchMergeHDRI"],
"bypass_exposure_normalisation",
)
self.connect(
"bypass_preview_image",
self.nodes["GraphBatchMergeHDRI"],
"bypass_preview_image",
)
self.connect(
"batch_size",
self.nodes["GraphBatchMergeHDRI"],
"batch_size",
)
self.connect(
"weighting_function",
self.nodes["GraphBatchMergeHDRI"],
"weighting_function",
)
self.connect(
"processes",
self.nodes["ParallelForMultiprocess"],
"processes",
)
self.connect(
"processes",
self.nodes["GraphBatchMergeHDRI"],
"processes",
)
self.nodes["ParallelForMultiprocess"].set_input(
"task", _task_multiprocess_graph_hdri
)
self.nodes["GraphRawProcessingCameraSensitivities"].nodes[ # pyright: ignore
"Watermark"
].set_input("include_exposure_information", False)
@notify_process_state
def process(self, **kwargs: Any) -> None:
"""
Process the node-graph.
"""
super().process(**kwargs)
self.set_output(
"output", self.nodes["GraphBatchMergeHDRI"].get_output("output")
)