forked from AcademySoftwareFoundation/OpenColorIO
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial visuals and chromaticity diagram inspector.
Signed-off-by: Thomas Mansencal <thomas.mansencal@gmail.com>
- Loading branch information
Showing
10 changed files
with
1,070 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
# Copyright Contributors to the OpenColorIO Project. | ||
|
||
from .chromaticities_inspector import ChromaticitiesInspector | ||
from .code_inspector import CodeInspector | ||
from .curve_inspector import CurveInspector | ||
from .log_inspector import LogInspector |
101 changes: 101 additions & 0 deletions
101
src/apps/ocioview/ocioview/inspect/chromaticities_inspector.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
# Copyright Contributors to the OpenColorIO Project. | ||
|
||
import numpy as np | ||
import pygfx as gfx | ||
import OpenImageIO as oiio | ||
import PyOpenColorIO as ocio | ||
from PySide6 import QtCore, QtGui, QtWidgets | ||
from typing import Optional | ||
from wgpu.gui.qt import WgpuWidget | ||
|
||
from ..message_router import MessageRouter | ||
from ..utils import get_glyph_icon | ||
from .visuals import VisualChromaticityDiagramCIE1931, VisualGrid | ||
|
||
|
||
class ChromaticitiesInspector(QtWidgets.QWidget): | ||
@classmethod | ||
def label(cls) -> str: | ||
return "Chromaticities" | ||
|
||
@classmethod | ||
def icon(cls) -> QtGui.QIcon: | ||
return get_glyph_icon("mdi6.grain") | ||
|
||
def __init__(self, parent: Optional[QtCore.QObject] = None): | ||
super().__init__(parent=parent) | ||
|
||
self._cpu_proc = None | ||
self._image_buf = None | ||
|
||
# Scene | ||
self.canvas = WgpuWidget(parent=self) | ||
self.renderer = gfx.WgpuRenderer(self.canvas) | ||
self.scene = gfx.Scene() | ||
self.grid = VisualGrid() | ||
self.grid.local.position = np.array([0, 0, -1e-3]) | ||
self.chromaticity_diagram = VisualChromaticityDiagramCIE1931( | ||
kwargs_visual_chromaticity_diagram={"opacity": 0.25} | ||
) | ||
self.scene.add(self.grid, self.chromaticity_diagram) | ||
self.camera = gfx.PerspectiveCamera(45) | ||
self.camera.show_object( | ||
self.chromaticity_diagram, up=np.array([0, 0, 1]), scale=1.5 | ||
) | ||
self.controller = gfx.OrbitController(register_events=self.renderer) | ||
self.controller.add_camera(self.camera) | ||
|
||
self.canvas.request_draw(self.draw) | ||
|
||
# Layout | ||
layout = QtWidgets.QHBoxLayout() | ||
self.setLayout(layout) | ||
layout.addWidget(self.canvas) | ||
|
||
msg_router = MessageRouter.get_instance() | ||
# msg_router.processor_ready.connect(self._on_processor_ready) | ||
# msg_router.image_ready.connect(self._on_image_ready) | ||
|
||
def draw(self): | ||
self.renderer.render(self.scene, self.camera) | ||
|
||
def reset(self) -> None: | ||
raise NotImplementedError() | ||
|
||
def showEvent(self, event: QtGui.QShowEvent) -> None: | ||
"""Start listening for processor updates, if visible.""" | ||
super().showEvent(event) | ||
|
||
msg_router = MessageRouter.get_instance() | ||
# msg_router.set_processor_updates_allowed(True) | ||
# msg_router.set_image_updates_allowed(True) | ||
|
||
def hideEvent(self, event: QtGui.QHideEvent) -> None: | ||
"""Stop listening for processor updates, if not visible.""" | ||
super().hideEvent(event) | ||
|
||
msg_router = MessageRouter.get_instance() | ||
# msg_router.set_processor_updates_allowed(False) | ||
# msg_router.set_image_updates_allowed(False) | ||
|
||
@QtCore.Slot(ocio.CPUProcessor) | ||
def _on_processor_ready(self, cpu_proc: ocio.CPUProcessor) -> None: | ||
self._cpu_proc = cpu_proc | ||
|
||
print("_on_processor_ready") | ||
|
||
@QtCore.Slot(np.ndarray) | ||
def _on_image_ready(self, image_buf: oiio.ImageBuf) -> None: | ||
self._image_buf = image_buf | ||
|
||
print("_on_image_ready") | ||
|
||
|
||
if __name__ == "__main__": | ||
application = QtWidgets.QApplication([]) | ||
chromaticity_inspector = ChromaticitiesInspector() | ||
chromaticity_inspector.resize(800, 600) | ||
chromaticity_inspector.show() | ||
|
||
application.exec() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from .diagrams import ( | ||
VisualChromaticityDiagramCIE1931, | ||
VisualChromaticityDiagramCIE1960UCS, | ||
VisualChromaticityDiagramCIE1976UCS, | ||
) | ||
from .grid import VisualGrid | ||
from .rgb_colorspace import VisualRGBColorspace2D, VisualRGBColorspace3D | ||
from .rgb_scatter import VisualRGBScatter3d |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
# Copyright Contributors to the OpenColorIO Project. | ||
|
||
""" | ||
Common Utilities | ||
================ | ||
Defines the common utilities objects that don't fall in any specific category. | ||
""" | ||
|
||
import numpy as np | ||
from colour import ( | ||
Luv_to_uv, | ||
Luv_uv_to_xy, | ||
UCS_to_uv, | ||
UCS_uv_to_xy, | ||
XYZ_to_Jzazbz, | ||
XYZ_to_Luv, | ||
XYZ_to_OSA_UCS, | ||
XYZ_to_UCS, | ||
XYZ_to_xy, | ||
convert, | ||
xy_to_XYZ, | ||
) | ||
from colour.hints import ArrayLike, NDArray, NDArrayFloat, NDArrayInt, Tuple | ||
from colour.utilities import full | ||
|
||
from ocioview.constants import DEFAULT_FLOAT_DTYPE, DEFAULT_INT_DTYPE | ||
|
||
__all__ = [ | ||
"METHODS_CHROMATICITY_DIAGRAM", | ||
"XYZ_to_colourspace_model", | ||
"as_float_array", | ||
"as_int_array", | ||
"as_contiguous_array", | ||
"conform_primitive_dtype", | ||
"append_alpha_channel", | ||
] | ||
|
||
METHODS_CHROMATICITY_DIAGRAM = { | ||
"CIE 1931": { | ||
"XYZ_to_ij": lambda a, i: XYZ_to_xy(a), | ||
"ij_to_XYZ": lambda a, i: xy_to_XYZ(a), | ||
}, | ||
"CIE 1960 UCS": { | ||
"XYZ_to_ij": lambda a, i: UCS_to_uv(XYZ_to_UCS(a)), | ||
"ij_to_XYZ": lambda a, i: xy_to_XYZ(UCS_uv_to_xy(a)), | ||
}, | ||
"CIE 1976 UCS": { | ||
"XYZ_to_ij": lambda a, i: Luv_to_uv(XYZ_to_Luv(a, i), i), | ||
"ij_to_XYZ": lambda a, i: xy_to_XYZ(Luv_uv_to_xy(a)), | ||
}, | ||
} | ||
""" | ||
Chromaticity diagram specific helper conversion objects. | ||
""" | ||
|
||
|
||
def XYZ_to_colourspace_model( | ||
XYZ: ArrayLike, illuminant: ArrayLike, model: str, **kwargs | ||
) -> NDArray: | ||
""" | ||
Converts from *CIE XYZ* tristimulus values to given colourspace model while | ||
normalising for visual convenience some of the models. | ||
""" | ||
|
||
ijk = convert( | ||
XYZ, | ||
"CIE XYZ", | ||
model, | ||
illuminant=illuminant, | ||
verbose={"mode": "Short"}, | ||
**kwargs | ||
) | ||
|
||
# TODO: ICtCp? | ||
if model == "JzAzBz": | ||
ijk /= XYZ_to_Jzazbz([1, 1, 1])[0] | ||
elif model == "OSA UCS": | ||
ijk /= XYZ_to_OSA_UCS([1, 1, 1])[0] | ||
|
||
return ijk | ||
|
||
|
||
def as_float_array(a: ArrayLike) -> NDArrayFloat: | ||
from colour.utilities import as_float_array | ||
|
||
return as_float_array(a, DEFAULT_FLOAT_DTYPE) | ||
|
||
|
||
def as_int_array(a: ArrayLike) -> NDArrayInt: | ||
from colour.utilities import as_int_array | ||
|
||
return as_int_array(a, DEFAULT_INT_DTYPE) | ||
|
||
|
||
def as_contiguous_array(a, dtype=DEFAULT_FLOAT_DTYPE): | ||
return np.ascontiguousarray(a.astype(dtype)) | ||
|
||
|
||
def conform_primitive_dtype( | ||
primitive: Tuple[NDArray, NDArray, NDArray] | ||
) -> Tuple[NDArray, NDArray, NDArray]: | ||
""" | ||
Conform the given primitive to the required dtype. | ||
""" | ||
|
||
vertices, faces, outline = primitive | ||
|
||
return ( | ||
vertices.astype( | ||
[ | ||
("position", DEFAULT_FLOAT_DTYPE, (3,)), | ||
("uv", DEFAULT_FLOAT_DTYPE, (2,)), | ||
("normal", DEFAULT_FLOAT_DTYPE, (3,)), | ||
("colour", DEFAULT_FLOAT_DTYPE, (4,)), | ||
] | ||
), | ||
faces.astype(DEFAULT_INT_DTYPE), | ||
outline.astype(DEFAULT_INT_DTYPE), | ||
) | ||
|
||
|
||
def append_alpha_channel(a: ArrayLike, alpha: float = 1) -> NDArray: | ||
a = np.copy(a) | ||
|
||
return np.hstack([a, full(list(a.shape[:-1]) + [1], alpha, dtype=a.dtype)]) |
Oops, something went wrong.