From 698daa9b0ee1c172578700a3128633e140850c51 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 15 Nov 2013 16:06:03 +0100 Subject: [PATCH 01/19] Add colors helper #7 --- utils/colors_helper.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 utils/colors_helper.py diff --git a/utils/colors_helper.py b/utils/colors_helper.py new file mode 100644 index 0000000..69c2028 --- /dev/null +++ b/utils/colors_helper.py @@ -0,0 +1,24 @@ +""" Colors helpers + +.. moduleauthor:: `Marie FETIVEAU `_ + +""" + + +def xy_to_XYZ(xy, Y=1): + """Convert xyY into XYZ + + Args: + xy ([float, float]): x, y input values + + Kwargs: + Y (float): Y input value + + Returns: + .[float, float, float] + + """ + x, y = xy + X = (x*Y)/y + Z = ((1-x-y)*Y)/y + return [X, Y, Z] From d842c42059b25064a38292bda79031fa3c2d4fc1 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 15 Nov 2013 16:06:35 +0100 Subject: [PATCH 02/19] Add rec709 definition #7 --- utils/colorspaces.py | 109 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 utils/colorspaces.py diff --git a/utils/colorspaces.py b/utils/colorspaces.py new file mode 100644 index 0000000..633796a --- /dev/null +++ b/utils/colorspaces.py @@ -0,0 +1,109 @@ +""" Colorspace definitions + +.. moduleauthor:: `Marie FETIVEAU `_ + +""" +from abc import ABCMeta, abstractmethod + + +class AbstractColorspace: + __metaclass__ = ABCMeta + + @abstractmethod + def get_red_primaries(self): + """Return colorspace primaries + + Returns: + .float, float + + """ + pass + + @abstractmethod + def get_green_primaries(self): + """Return colorspace primaries + + Returns: + .float, float + + """ + pass + + @abstractmethod + def get_blue_primaries(self): + """Return colorspace primaries + + Returns: + .float, float + + """ + pass + + @abstractmethod + def get_white_point(self): + """Return white coords + + Returns: + .numpy.matrix (3x1) + + """ + pass + + @abstractmethod + def lin_to_gamma(self, value): + """Convert value from lin to gamma + + Args: + value (float): value to transform + + Returns: + .float + + """ + pass + + @abstractmethod + def gamma_to_lin(self, value): + """Convert value from lin to gamma + + Args: + value (float): value to transform + + Returns: + .float + + """ + pass + + +class Rec709(AbstractColorspace): + """rec709 colorspace + + """ + def get_red_primaries(self): + return 0.64, 0.33 + + def get_green_primaries(self): + return 0.30, 0.60 + + def get_blue_primaries(self): + return 0.15, 0.06 + + def get_white_point(self): + return 0.3127, 0.3290 + + def lin_to_gamma(self, value): + if value < 0.018: + value *= 4.5 + else: + value = float(pow(value, 0.45)*1.099 - 0.099) + return value + + def gamma_to_lin(self, value): + if value < 0.081: + value *= 1.0/4.5 + else: + value = float(pow((value + 0.099) * (1.0/1.099), 1.0/0.45)) + return value + +REC709 = Rec709() From 5ee056cc843b81f8bb229064507133717d3cd413 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 15 Nov 2013 16:07:09 +0100 Subject: [PATCH 03/19] rgb_to_xyz initial commit #7 --- lutLab/rgb_to_xyz_matrix.py | 160 ++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 lutLab/rgb_to_xyz_matrix.py diff --git a/lutLab/rgb_to_xyz_matrix.py b/lutLab/rgb_to_xyz_matrix.py new file mode 100644 index 0000000..afd2289 --- /dev/null +++ b/lutLab/rgb_to_xyz_matrix.py @@ -0,0 +1,160 @@ +""" Display RGB colorspaces to XYZ conversion matrixes + +.. moduleauthor:: `Marie FETIVEAU `_ + +""" +from utils.colors_helper import xy_to_XYZ +from utils.colorspaces import REC709 +import numpy +import argparse + + +class RGBToXYZMatrixException(Exception): + pass + + +def get_primaries_matrix(xy_red, xy_green, xy_blue): + """Return primaries XYZ matrix form xy coords + + Args: + xy_red (float, float): red primary coords + + xy_green (float, float): green primary coords + + xy_blue (float, float): blue primary coords + + Returns: + .numpy.matrix (3x3) + + """ + XYZ_red = xy_to_XYZ(xy_red) + XYZ_green = xy_to_XYZ(xy_green) + XYZ_blue = xy_to_XYZ(xy_blue) + primaries_matrix = numpy.matrix( + [ + [XYZ_red[0], XYZ_green[0], XYZ_blue[0]], + [XYZ_red[1], XYZ_green[1], XYZ_blue[1]], + [XYZ_red[2], XYZ_green[2], XYZ_blue[2]], + ]) + return primaries_matrix + + +def get_white_matrix(xy_white): + """Return white point XYZ matrix form xy coords + + Args: + xy_white (float, float): white point coords + + Returns: + .numpy.matrix (3x1) + + """ + XYZ_white = xy_to_XYZ(xy_white) + white_matrix = numpy.matrix( + [ + [XYZ_white[0]], + [XYZ_white[1]], + [XYZ_white[2]], + ]) + return white_matrix + + +def get_RGB_to_XYZ_matrix(xy_red, xy_green, xy_blue, xy_white): + """Compute RGB to XYZ matrix + See Bruce Lindbloom page : + http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + + Args: + xy_red (float, float): red primary coords + + xy_green (float, float): green primary coords + + xy_blue (float, float): blue primary coords + + xy_white (float, float): white point coords + + Returns: + .numpy.matrix (3x3) + + """ + primaries_matrix = get_primaries_matrix(xy_red, xy_green, xy_blue) + white_matrix = get_white_matrix(xy_white) + s = primaries_matrix ** -1 * white_matrix + s_r, s_g, s_b = s.item(0, 0), s.item(1, 0), s.item(2, 0) + RGB_to_XYZ = numpy.matrix([ + [s_r * primaries_matrix.item(0, 0), s_g * primaries_matrix.item(0, 1), + s_b * primaries_matrix.item(0, 2)], + [s_r * primaries_matrix.item(1, 0), s_g * primaries_matrix.item(1, 1), + s_b * primaries_matrix.item(1, 2)], + [s_r * primaries_matrix.item(2, 0), s_g * primaries_matrix.item(2, 1), + s_b * primaries_matrix.item(2, 2)]]) + return RGB_to_XYZ + + +def display_matrix(colorspace, format): + """Display RGB to XYZ matrix corresponding to colorspace and formatting + as format + + Args: + colorspace (str): input colorspace. For now, REC709 is the only option. + + format (str): output format. simple, matrix, spimtx. + + """ + print "{0} to XYZ matrix ({1} output):\n".format(colorspace, format) + if colorspace == "REC709": + colorspace = REC709 + matrix = get_RGB_to_XYZ_matrix(colorspace.get_red_primaries(), + colorspace.get_green_primaries(), + colorspace.get_blue_primaries(), + colorspace.get_white_point()) + if format == 'simple': + print ("{0} {1} {2}\n" + "{3} {4} {5}\n" + "{6} {7} {8}\n").format(matrix.item(0, 0), matrix.item(0, 1), + matrix.item(0, 2), matrix.item(1, 0), + matrix.item(1, 1), matrix.item(1, 2), + matrix.item(2, 0), matrix.item(2, 1), + matrix.item(2, 2)) + elif format == 'spimtx': + print ("{0} {1} {2} 0\n" + "{3} {4} {5} 0\n" + "{6} {7} {8} 0\n").format(matrix.item(0, 0), matrix.item(0, 1), + matrix.item(0, 2), matrix.item(1, 0), + matrix.item(1, 1), matrix.item(1, 2), + matrix.item(2, 0), matrix.item(2, 1), + matrix.item(2, 2)) + else: + print matrix + + +def __get_options(): + """ Return rgb_to_xyz option parser + + Returns: + .argparse.ArgumentParser.args + + """ + ## Define parser + description = 'Print RGB -> XYZ matrix' + parser = argparse.ArgumentParser(description=description) + # RGB colorspace + parser.add_argument("-c", "--colorspace", + help=("Input RGB Colorspace."), + type=str, + choices=['REC709'], + default='REC709') + # Output format + parser.add_argument("-f", "--format", + help=("Output formatting."), + type=str, + choices=['matrix', 'spimtx', 'simple'], + default='matrix') + return parser.parse_args() + + +if __name__ == '__main__': + """ Command line interface + """ + args = __get_options() + display_matrix(args.colorspace, args.format) From c5fb848178097c3e5f5cce0a6673aa1545d04884 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 15 Nov 2013 16:08:12 +0100 Subject: [PATCH 04/19] Update README #7 --- lutLab/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lutLab/README.md b/lutLab/README.md index f05b257..1d8584e 100644 --- a/lutLab/README.md +++ b/lutLab/README.md @@ -12,6 +12,8 @@ Available scripts : - **ext_1d_lut**: extract the tone mapping curve of a 3D LUT using a bicubic interpolation (or not) +- **rgb_to_xyz_matrix**: generate RGB colorspace to XYZ conversion matrix + Supported input LUT formats : 3dl, csp, cub, cube, hdl, look, mga/m3d, spid1d, spi3d, spimtx, vf. See [OpenColorIO FAQ](http://opencolorio.org/FAQ.html) for more informations. @@ -33,6 +35,7 @@ Command line usage See command line help : `lut_to_lut.py -h` `ext_1d_lut.py -h` +`rgb_to_xyz_matrix.py -h` Screenshots ----------- From deab27c6fa3ca85dddac5a14cc9aa28a11ebdf07 Mon Sep 17 00:00:00 2001 From: mfe Date: Tue, 3 Dec 2013 16:07:33 +0100 Subject: [PATCH 05/19] Add AlexaLogCV3 colorspace #8 --- utils/colorspaces.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index 633796a..ddbeba8 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -4,6 +4,7 @@ """ from abc import ABCMeta, abstractmethod +import math class AbstractColorspace: @@ -106,4 +107,38 @@ def gamma_to_lin(self, value): value = float(pow((value + 0.099) * (1.0/1.099), 1.0/0.45)) return value + +class AlexaLogCV3(AbstractColorspace): + """AlexaLogCV3 colorspace + + """ + def get_red_primaries(self): + return 0.6840, 0.3130 + + def get_green_primaries(self): + return 0.2210, 0.8480 + + def get_blue_primaries(self): + return 0.0861, -0.1020 + + def get_white_point(self): + return 0.3127, 0.3290 + + def lin_to_gamma(self, value): + if value > 0.010591: + value = (0.247190 * math.log10(5.555556 * value + 0.052272) + + 0.385537) + else: + value = 5.367655 * value + 0.092809 + return value + + def gamma_to_lin(self, value): + if value > 0.1496582: + value = (math.pow(10.0, (value - 0.385537) / 0.2471896) * 0.18 + - 0.00937677) + else: + value = (value / 0.9661776 - 0.04378604) * 0.18 - 0.00937677 + return value + REC709 = Rec709() +ALEXALOGCV3 = AlexaLogCV3() From 5a806af0258a7ea002681cf4578e0dda5f85c5b2 Mon Sep 17 00:00:00 2001 From: mfe Date: Thu, 5 Dec 2013 19:13:28 +0100 Subject: [PATCH 06/19] PlotThatLut : display several curves For now only available in command line and for curves (not for cubes) --- plotThatLut/plot_that_lut.py | 156 +++++++++++++++++++++++++---------- plotThatLut/ptlut.py | 17 ++-- 2 files changed, 123 insertions(+), 50 deletions(-) diff --git a/plotThatLut/plot_that_lut.py b/plotThatLut/plot_that_lut.py index 747f759..e4c5624 100755 --- a/plotThatLut/plot_that_lut.py +++ b/plotThatLut/plot_that_lut.py @@ -15,6 +15,7 @@ ) # matplotlib import matplotlib +import itertools web_mode = False @@ -39,6 +40,11 @@ def set_matplotlib_backend(): DEFAULT_SAMPLE = 256 DEFAULT_CUBE_SIZE = 17 +MARKERS = ['o', '*', 'H', 'D', '8', 's', 'p', 'h', 'd'] +REDS = ['r', 'c', '#990000', '#660000'] +GREENS = ['g', 'm', '#009900', '#006600'] +BLUES = ['b', 'y', '#000099', '#000066'] + def show_plot(fig, filename): """Plot the figure depending on the backend @@ -68,16 +74,26 @@ def show_plot(fig, filename): return "" -def plot_curve(lutfile, samples_count, processor): +def plot_curve(lutfiles, samples_count, processors, draw_red_curve=True, + draw_green_curve=True, draw_blue_curve=True, + display_markers=False): """Plot a lutfile as a curve Args: - lutfile (str): path to a color transformation file (lut, matrix...) + lutfiles ([str]): pathes to color transformation files (lut, matrix...) samples_count (int): number of points for the displayed curve - processor (PyOpenColorIO.config.Processor): an OpenColorIO processor - for lutfile + processors ([PyOpenColorIO.config.Processor]): OpenColorIO processors + for lutfiles + + draw_red_curve (bool): plot red curve only + + draw_green_curve (bool): plot green curve only + + draw_blue_curve (bool): plot blue curve only + + display_markers (bool): should display markers on curve Returns: str. @@ -86,32 +102,55 @@ def plot_curve(lutfile, samples_count, processor): # matplotlib : general plot from matplotlib.pyplot import (title, plot, xlabel, ylabel, grid, figure) - # init vars - max_value = samples_count - 1.0 - red_values = [] - green_values = [] - blue_values = [] - input_range = [] - # process color values - for n in range(0, samples_count): - x = n/max_value - res = processor.applyRGB([x, x, x]) - red_values.append(res[0]) - green_values.append(res[1]) - blue_values.append(res[2]) - input_range.append(x) + # init plot fig = figure() fig.canvas.set_window_title('Plot That 1D LUT') - filename = os.path.basename(lutfile) - title(filename) + figure_title = "" + for lutfile in lutfiles: + filename = os.path.basename(lutfile) + figure_title = "{0}\n{1}".format(figure_title, filename) + title(figure_title) xlabel("Input") ylabel("Output") grid(True) - # plot curves - plot(input_range, red_values, 'r-', label='Red values', linewidth=1) - plot(input_range, green_values, 'g-', label='Green values', linewidth=1) - plot(input_range, blue_values, 'b-', label='Blue values', linewidth=1) + index = 0 + markers_it = itertools.cycle(MARKERS) + reds_it = itertools.cycle(REDS) + greens_it = itertools.cycle(GREENS) + blues_it = itertools.cycle(BLUES) + for lutfile, processor in itertools.izip(lutfiles, processors): + # init vars + max_value = samples_count - 1.0 + red_values = [] + green_values = [] + blue_values = [] + input_range = [] + # process color values + for n in range(0, samples_count): + x = n/max_value + res = processor.applyRGB([x, x, x]) + red_values.append(res[0]) + green_values.append(res[1]) + blue_values.append(res[2]) + input_range.append(x) + # markers + marker = markers_it.next() + markersize = 0 + if display_markers: + markersize = 4 + # plot curves + if draw_red_curve: + plot(input_range, red_values, color=reds_it.next(), marker=marker, + label='Red values', linewidth=1, markersize=markersize) + if draw_green_curve: + plot(input_range, green_values, color=greens_it.next(), + marker=marker, label='Green values', linewidth=1, + markersize=markersize) + if draw_blue_curve: + plot(input_range, blue_values, color=blues_it.next(), marker=marker, + label='Blue values', linewidth=1, markersize=markersize) + index += 1 return show_plot(fig, filename) @@ -187,12 +226,12 @@ def supported_formats(): return "Supported LUT formats : {0}".format(', '.join(OCIO_LUTS_FORMATS)) -def plot_that_lut(lutfile, plot_type=None, count=None, inverse=False, - prelutfile=None, postlutfile=None): +def plot_that_lut(lutfiles, plot_type=None, count=None, inverse=False, + prelutfile=None, postlutfile=None, display_markers=False): """Plot a lut depending on its type and/or args Args: - lutfile (str): path to a color transformation file (lut, matrix...) + lutfiles (str): pathes to color transformation files (lut, matrix...) kwargs: plot_type (str): possible values are 'curve' or 'cube' @@ -203,43 +242,70 @@ def plot_that_lut(lutfile, plot_type=None, count=None, inverse=False, postlutfile (str): path to a post LUT + display_markers (bool): should display markers on curve + Raises: PlotThatLutException Exception from OpenColorIO binding """ + if not isinstance(lutfiles, list): + lutfiles = [lutfiles] set_matplotlib_backend() - # check if LUT format is supported - fileext = os.path.splitext(lutfile)[1] - if not fileext: - raise PlotThatLutException(( - "Error: Couldn't extract extension in this\n" - "path : {0}" - ).format(lutfile)) - if fileext not in OCIO_LUTS_FORMATS: - raise PlotThatLutException("Error: {0} file aren't supported.\n{1}" - .format(fileext, supported_formats())) - # create OCIO processor - processor = create_ocio_processor(lutfile, INTERP_LINEAR, inverse, - prelutfile, postlutfile) + processors = [] + for lutfile in lutfiles: + # check if LUT format is supported + fileext = os.path.splitext(lutfile)[1] + if not fileext: + raise PlotThatLutException(( + "Error: Couldn't extract extension in this\n" + "path : {0}" + ).format(lutfile)) + if fileext not in OCIO_LUTS_FORMATS: + raise PlotThatLutException("Error: {0} file aren't supported.\n{1}" + .format(fileext, supported_formats())) + # create OCIO processor + processors.append(create_ocio_processor(lutfile, INTERP_LINEAR, inverse, + prelutfile, postlutfile)) # init args if not plot_type or plot_type == 'auto': - if is_3d_lut(processor, lutfile): + # deduce plot type considering first lutfile + if is_3d_lut(processors[0], lutfiles[0]): plot_type = 'cube' else: plot_type = 'curve' if not count or count == 'auto': # set plot_type from the command line and init default count - if plot_type == 'curve': + if 'curve' in plot_type: count = DEFAULT_SAMPLE else: count = DEFAULT_CUBE_SIZE # plot print "Plotting a {0} with {1} samples...".format(plot_type, count) - if plot_type == 'curve': - return plot_curve(lutfile, count, processor) + if 'curve' in plot_type: + draw_red_curve = True + draw_green_curve = True + draw_blue_curve = True + if 'red' in plot_type: + #red_curve option + draw_green_curve = False + draw_blue_curve = False + elif 'green' in plot_type: + #green_curve option + draw_red_curve = False + draw_blue_curve = False + elif 'blue' in plot_type: + #blue_curve option + draw_red_curve = False + draw_green_curve = False + return plot_curve(lutfiles, count, processors, + draw_red_curve=draw_red_curve, + draw_green_curve=draw_green_curve, + draw_blue_curve=draw_blue_curve, + display_markers=display_markers) elif plot_type == 'cube': - return plot_cube(lutfile, count, processor) + # TODO support multiple cubes display + return plot_cube(lutfiles[0], count, processors[0]) else: raise PlotThatLutException(( "Unknown plot type : {0}\n" diff --git a/plotThatLut/ptlut.py b/plotThatLut/ptlut.py index a466aef..380fdd5 100755 --- a/plotThatLut/ptlut.py +++ b/plotThatLut/ptlut.py @@ -20,12 +20,16 @@ def __get_options(): description = 'PlotThatLUT command line tool' parser = argparse.ArgumentParser(description=description) # main lut - parser.add_argument("lutfile", help=( + parser.add_argument("lutfiles", help=( "path to the main LUT to plot.\n{0}" - ).format(plot_that_lut.supported_formats()), type=str) + ).format(plot_that_lut.supported_formats()), type=str, nargs='+') # inverse parser.add_argument("-i", "--inverse", help="inverse main lut", action="store_true") + # display markers + parser.add_argument("-m", "--markers", + help="display markers on curves (useless on cubes)", + action="store_true") # pre lut parser.add_argument("-pre", "--prelutfile", help=( "path to a pre LUT.{0}" @@ -39,7 +43,9 @@ def __get_options(): help=("Plot type. By default, a curve for a 1D/2D LUT " "and a cube for a 3D LUT."), type=str, - choices=['auto', 'curve', 'cube'], default='auto') + choices=['auto', 'curve', 'red_curve', 'blue_curve', + 'green_curve', 'cube'], + default='auto') # samples count parser.add_argument("-s", "--samples-count", help=( "Samples count. Ex : {0} for a curve or {1} for a cube." @@ -55,11 +61,12 @@ def __get_options(): """ args = __get_options() try: - plot_that_lut.plot_that_lut(args.lutfile, + plot_that_lut.plot_that_lut(args.lutfiles, args.plot_type, args.samples_count, args.inverse, args.prelutfile, - args.postlutfile) + args.postlutfile, + args.markers) except Exception, e: print "Watch out !\n%s" % e From 2da137338cb3aac4892b1aef9198875d4b76a647 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 6 Dec 2013 16:48:33 +0100 Subject: [PATCH 07/19] Factorize 3d values process #9 --- plotThatLut/plot_that_lut.py | 33 ++++++---------------- utils/lut_utils.py | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/plotThatLut/plot_that_lut.py b/plotThatLut/plot_that_lut.py index e4c5624..61592d5 100755 --- a/plotThatLut/plot_that_lut.py +++ b/plotThatLut/plot_that_lut.py @@ -13,6 +13,7 @@ from utils.ocio_helper import ( OCIO_LUTS_FORMATS, create_ocio_processor, is_3d_lut ) +from utils.lut_utils import get_3d_list_values # matplotlib import matplotlib import itertools @@ -175,30 +176,13 @@ def plot_cube(lutfile, cube_size, processor): # matplotlib : for 3D plot # mplot3d has to be imported for 3d projection import mpl_toolkits.mplot3d - from matplotlib.colors import rgb2hex # init vars - input_range = range(0, cube_size) - max_value = cube_size - 1.0 - red_values = [] - green_values = [] - blue_values = [] - colors = [] - # process color values - for r in input_range: - for g in input_range: - for b in input_range: - # get a value between [0..1] - norm_r = r/max_value - norm_g = g/max_value - norm_b = b/max_value - # apply correction via OCIO - res = processor.applyRGB([norm_r, norm_g, norm_b]) - # append values - red_values.append(res[0]) - green_values.append(res[1]) - blue_values.append(res[2]) - # append corresponding color - colors.append(rgb2hex([norm_r, norm_g, norm_b])) + processed_values = get_3d_list_values(cube_size, processor, + hexa_values=True) + red_values = processed_values['red_values'] + green_values = processed_values['green_values'] + blue_values = processed_values['blue_values'] + input_colors = processed_values['input_colors'] # init plot fig = figure() fig.canvas.set_window_title('Plot That 3D LUT') @@ -212,7 +196,8 @@ def plot_cube(lutfile, cube_size, processor): filename = os.path.basename(lutfile) title(filename) # plot 3D values - ax.scatter(red_values, green_values, blue_values, c=colors, marker="o") + ax.scatter(red_values, green_values, blue_values, c=input_colors, + marker="o") return show_plot(fig, filename) diff --git a/utils/lut_utils.py b/utils/lut_utils.py index 5feda8b..9bec2e4 100644 --- a/utils/lut_utils.py +++ b/utils/lut_utils.py @@ -40,3 +40,57 @@ def get_default_out_path(filepath, ext): """ split_filename = os.path.splitext(filepath) return "{0}_export{1}".format(split_filename[0], ext) + + +def get_3d_list_values(cubesize, processor, hexa_values=False): + """Process cube values + + Args: + filepath (str): out LUT path + + cubesize (int): cube size. Ex: 17, 32... + + processor (PyOpenColorIO.config.Processor): an OpenColorIO processor + + Kwargs: + hexa_values (bool): if true, input colors will be hexa values and rgb + float triplets if false + + Returns: + .dict containing cubesize and red, green, blue, input color values + as lists + + """ + input_range = range(0, cubesize) + max_value = cubesize - 1.0 + red_values = [] + green_values = [] + blue_values = [] + input_colors = [] + if hexa_values: + from matplotlib.colors import rgb2hex + # process color values + for b in input_range: + for g in input_range: + for r in input_range: + # get a value between [0..1] + norm_r = r/max_value + norm_g = g/max_value + norm_b = b/max_value + # apply correction via OCIO + res = processor.applyRGB([norm_r, norm_g, norm_b]) + red_values.append(res[0]) + green_values.append(res[1]) + blue_values.append(res[2]) + # append corresponding input color + if hexa_values: + color = rgb2hex([norm_r, norm_g, norm_b]) + else: + color = [norm_r, norm_g, norm_b] + input_colors.append(color) + return {'cubesize': cubesize, + 'red_values': red_values, + 'green_values': green_values, + 'blue_values': blue_values, + 'input_colors': input_colors + } From 7f684dd1f6610a66f0e0e146eb58758ba4185949 Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 6 Dec 2013 16:49:51 +0100 Subject: [PATCH 08/19] Add 3d json export #9 In lut_utils and lut_to_lut --- lutLab/lut_to_lut.py | 8 ++++++-- utils/lut_utils.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lutLab/lut_to_lut.py b/lutLab/lut_to_lut.py index bff1ce0..4d1f27d 100755 --- a/lutLab/lut_to_lut.py +++ b/lutLab/lut_to_lut.py @@ -9,7 +9,7 @@ from utils.ocio_helper import OCIO_LUTS_FORMATS, create_ocio_processor from utils.csp_helper import write_2d_csp_lut from utils.cube_helper import write_2d_cube_lut, write_3d_cube_lut -from utils.lut_utils import get_default_out_path +from utils.lut_utils import get_default_out_path, write_3d_json_file from PyOpenColorIO.Constants import ( INTERP_LINEAR, INTERP_TETRAHEDRAL ) @@ -49,6 +49,10 @@ def lut_to_lut(inlutfile, outlutfile=None, type='1D_CUBE', ext = ".csp" write_function = write_2d_csp_lut interp = INTERP_LINEAR + elif type == '3D_JSON': + ext = ".json" + write_function = write_3d_json_file + interp = INTERP_TETRAHEDRAL else: raise LutToLutException("Unsupported export format!") if not outlutfile: @@ -97,7 +101,7 @@ def __get_options(): parser.add_argument("-t", "--out-type", help=("Output LUT type."), type=str, - choices=['1D_CSP', '1D_CUBE', '3D_CUBE'], + choices=['1D_CSP', '1D_CUBE', '3D_CUBE', '3D_JSON'], default='1D_CUBE') # out lut size parser.add_argument("-os", "--out-lut-size", help=( diff --git a/utils/lut_utils.py b/utils/lut_utils.py index 9bec2e4..845ab60 100644 --- a/utils/lut_utils.py +++ b/utils/lut_utils.py @@ -94,3 +94,21 @@ def get_3d_list_values(cubesize, processor, hexa_values=False): 'blue_values': blue_values, 'input_colors': input_colors } + + +def write_3d_json_file(filepath, cubesize, processor): + """Export cube into a json file + + Args: + filepath (str): out LUT path + + cubesize (int): cube size. Ex: 17, 32... + + processor (PyOpenColorIO.config.Processor): an OpenColorIO processor + + """ + processed_values = get_3d_list_values(cubesize, processor) + import json + f = open(filepath, 'w+') + json.dump(processed_values, f) + f.close() From f60d1d6b7d98e7a19556a0e9fce334b5b3cb68fb Mon Sep 17 00:00:00 2001 From: mfe Date: Fri, 6 Dec 2013 16:52:22 +0100 Subject: [PATCH 09/19] Add missing documentation --- utils/lut_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/lut_utils.py b/utils/lut_utils.py index 845ab60..dbd3c2c 100644 --- a/utils/lut_utils.py +++ b/utils/lut_utils.py @@ -34,6 +34,10 @@ def check_arrays_length(array1, array2, array3): def get_default_out_path(filepath, ext): """ Return a defaut output LUT path from an input LUT path + Args: + filepath (str): input LUT file path + ext (str): output file extension + Returns: .str From ddb964cbfea2558102ea0712d890a7ee5d9b4e77 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 13:44:37 +0100 Subject: [PATCH 10/19] Add private colorspaces feature --- lutLab/rgb_to_xyz_matrix.py | 11 +++++--- utils/colorspaces.py | 4 +++ utils/private_colorspaces.py | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 utils/private_colorspaces.py diff --git a/lutLab/rgb_to_xyz_matrix.py b/lutLab/rgb_to_xyz_matrix.py index afd2289..ec068f6 100644 --- a/lutLab/rgb_to_xyz_matrix.py +++ b/lutLab/rgb_to_xyz_matrix.py @@ -4,7 +4,8 @@ """ from utils.colors_helper import xy_to_XYZ -from utils.colorspaces import REC709 +from utils.colorspaces import COLORSPACES +from utils.private_colorspaces import PRIVATE_COLORSPACES import numpy import argparse @@ -102,8 +103,10 @@ def display_matrix(colorspace, format): """ print "{0} to XYZ matrix ({1} output):\n".format(colorspace, format) - if colorspace == "REC709": - colorspace = REC709 + try: + colorspace = COLORSPACES[colorspace] + except KeyError: + colorspace = PRIVATE_COLORSPACES[colorspace] matrix = get_RGB_to_XYZ_matrix(colorspace.get_red_primaries(), colorspace.get_green_primaries(), colorspace.get_blue_primaries(), @@ -142,7 +145,7 @@ def __get_options(): parser.add_argument("-c", "--colorspace", help=("Input RGB Colorspace."), type=str, - choices=['REC709'], + choices= COLORSPACES.keys()+PRIVATE_COLORSPACES.keys(), default='REC709') # Output format parser.add_argument("-f", "--format", diff --git a/utils/colorspaces.py b/utils/colorspaces.py index ddbeba8..9329b23 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -142,3 +142,7 @@ def gamma_to_lin(self, value): REC709 = Rec709() ALEXALOGCV3 = AlexaLogCV3() +COLORSPACES = { + 'REC709': REC709, + 'ALEXALOGCV3': ALEXALOGCV3 +} diff --git a/utils/private_colorspaces.py b/utils/private_colorspaces.py new file mode 100644 index 0000000..0d2dc42 --- /dev/null +++ b/utils/private_colorspaces.py @@ -0,0 +1,49 @@ +""" Private colorspace definitions + These colorspaces don't have public specifications. + To add a colorspace, see example below. + +.. moduleauthor:: `Marie FETIVEAU `_ + +""" +from utils.colorspaces import AbstractColorspace + +# class DCI(AbstractColorspace): +# """DCI colorspace + +# """ +# def get_red_primaries(self): +# # See DCI specifications +# pass + +# def get_green_primaries(self): +# # See DCI specifications +# pass + +# def get_blue_primaries(self): +# # See DCI specifications +# pass + +# def get_white_point(self): +# # See DCI specifications +# pass + +# def lin_to_gamma(self, value): +# # See DCI specifications +# pass + +# def gamma_to_lin(self, value): +# # See DCI specifications +# pass + + +# class DCID60(DCI): +# """DCI colorspace with D60 white point + +# """ +# def get_white_point(self): +# return 0.3217, 0.3378 + +PRIVATE_COLORSPACES = { + # 'DCI': DCI(), + # 'DCI_D60': DCID60() +} From 77a15eea518743920eccea94758ba0067f89d41a Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 14:01:04 +0100 Subject: [PATCH 11/19] Reformat matrices display --- lutLab/rgb_to_xyz_matrix.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/lutLab/rgb_to_xyz_matrix.py b/lutLab/rgb_to_xyz_matrix.py index ec068f6..0f2aa1f 100644 --- a/lutLab/rgb_to_xyz_matrix.py +++ b/lutLab/rgb_to_xyz_matrix.py @@ -112,21 +112,29 @@ def display_matrix(colorspace, format): colorspace.get_blue_primaries(), colorspace.get_white_point()) if format == 'simple': - print ("{0} {1} {2}\n" - "{3} {4} {5}\n" - "{6} {7} {8}\n").format(matrix.item(0, 0), matrix.item(0, 1), - matrix.item(0, 2), matrix.item(1, 0), - matrix.item(1, 1), matrix.item(1, 2), - matrix.item(2, 0), matrix.item(2, 1), - matrix.item(2, 2)) + print ("{0:.10f} {1:.10f} {2:.10f}\n" + "{3:.10f} {4:.10f} {5:.10f}\n" + "{6:.10f} {7:.10f} {8:.10f}\n").format(matrix.item(0, 0), + matrix.item(0, 1), + matrix.item(0, 2), + matrix.item(1, 0), + matrix.item(1, 1), + matrix.item(1, 2), + matrix.item(2, 0), + matrix.item(2, 1), + matrix.item(2, 2)) elif format == 'spimtx': - print ("{0} {1} {2} 0\n" - "{3} {4} {5} 0\n" - "{6} {7} {8} 0\n").format(matrix.item(0, 0), matrix.item(0, 1), - matrix.item(0, 2), matrix.item(1, 0), - matrix.item(1, 1), matrix.item(1, 2), - matrix.item(2, 0), matrix.item(2, 1), - matrix.item(2, 2)) + print ("{0:.10f} {1:.10f} {2:.10f} 0\n" + "{3:.10f} {4:.10f} {5:.10f} 0\n" + "{6:.10f} {7:.10f} {8:.10f} 0\n").format(matrix.item(0, 0), + matrix.item(0, 1), + matrix.item(0, 2), + matrix.item(1, 0), + matrix.item(1, 1), + matrix.item(1, 2), + matrix.item(2, 0), + matrix.item(2, 1), + matrix.item(2, 2)) else: print matrix From 18db59f14722c4929b8dbd7e0749ff894ae73e24 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 14:03:32 +0100 Subject: [PATCH 12/19] Add simple gamma function --- utils/colors_helper.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/utils/colors_helper.py b/utils/colors_helper.py index 69c2028..170a311 100644 --- a/utils/colors_helper.py +++ b/utils/colors_helper.py @@ -3,6 +3,7 @@ .. moduleauthor:: `Marie FETIVEAU `_ """ +import math def xy_to_XYZ(xy, Y=1): @@ -22,3 +23,33 @@ def xy_to_XYZ(xy, Y=1): X = (x*Y)/y Z = ((1-x-y)*Y)/y return [X, Y, Z] + + +def lin_to_gamma(self, value, gamma): + """Simple lin to Gamma function + + Args: + value (float): input value + + gamma (float): gamma value + + Returns: + .float + + """ + return math.pow(value, 1/gamma) + + +def gamma_to_lin(self, value, gamma): + """Simple gamma to lin function + + Args: + value (float): input value + + gamma (float): gamma value + + Returns: + .float + + """ + return math.pow(value, gamma) From 50188b63df6445745ef598dd2572c90dd4fb2e3c Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 14:11:17 +0100 Subject: [PATCH 13/19] Add WideGamut colorspace --- utils/colorspaces.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index 9329b23..c52b282 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -3,6 +3,7 @@ .. moduleauthor:: `Marie FETIVEAU `_ """ +from utils import colors_helper from abc import ABCMeta, abstractmethod import math @@ -140,9 +141,37 @@ def gamma_to_lin(self, value): value = (value / 0.9661776 - 0.04378604) * 0.18 - 0.00937677 return value + +class WideGamut(AbstractColorspace): + """WideGamut colorspace + + """ + def __init__(self): + self._gamma = 2.2 + + def get_red_primaries(self): + return 0.7347, 0.2653 + + def get_green_primaries(self): + return 0.1152, 0.8264 + + def get_blue_primaries(self): + return 0.1566, 0.0177 + + def get_white_point(self): + return 0.3457, 0.3585 + + def lin_to_gamma(self, value): + return colors_helper.lin_to_gamma(value, self._gamma) + + def gamma_to_lin(self, value): + return colors_helper.gamma_to_lin(value, self._gamma) + REC709 = Rec709() ALEXALOGCV3 = AlexaLogCV3() +WIDEGAMUT = WideGamut() COLORSPACES = { 'REC709': REC709, - 'ALEXALOGCV3': ALEXALOGCV3 + 'ALEXALOGCV3': ALEXALOGCV3, + 'WIDEGAMUT': WIDEGAMUT } From 142a48f9b452837beef645e4208fa436c3819ff4 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 15:36:06 +0100 Subject: [PATCH 14/19] Refactor Rec709 Colorspace To prepare Rec2020 addition --- utils/colorspaces.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index c52b282..f86cbd6 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -82,6 +82,11 @@ class Rec709(AbstractColorspace): """rec709 colorspace """ + def __init__(self): + self._alpha = 1.099 + self._beta = 0.018 + self._round_depth = 3 + def get_red_primaries(self): return 0.64, 0.33 @@ -95,18 +100,17 @@ def get_white_point(self): return 0.3127, 0.3290 def lin_to_gamma(self, value): - if value < 0.018: - value *= 4.5 + if value < self._beta: + return value * 4.5 else: - value = float(pow(value, 0.45)*1.099 - 0.099) - return value + return pow(value, 0.45)*self._alpha - (self._alpha - 1) def gamma_to_lin(self, value): - if value < 0.081: - value *= 1.0/4.5 + inv_beta = round(self.lin_to_gamma(self._beta), self._round_depth) + if value < inv_beta: + return value * 1/4.5 else: - value = float(pow((value + 0.099) * (1.0/1.099), 1.0/0.45)) - return value + return pow((value + (self._alpha - 1)) * (1/self._alpha), 1/0.45) class AlexaLogCV3(AbstractColorspace): From 54e634164e6efbd7d33c70b3e1348b9ee5bfc498 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 15:37:25 +0100 Subject: [PATCH 15/19] Add Rec2020 Colorspace --- utils/colorspaces.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index f86cbd6..f85df1b 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -113,6 +113,37 @@ def gamma_to_lin(self, value): return pow((value + (self._alpha - 1)) * (1/self._alpha), 1/0.45) +class Rec2020(Rec709): + """Rec2020 colorspace (10 and 12 bits) + """ + def __init__(self, is_ten_bits=True): + """ Ctor + + Kwargs: + is_ten_bits (bool): if true, 10 bits Rec709 constants will be used, + else 12 bits ones are defined + + """ + Rec709.__init__(self) + if not is_ten_bits: + # define value for 12 bits per sample display + self._alpha = 1.0993 + self._beta = 0.0181 + self._round_depth = 4 + + def get_red_primaries(self): + return 0.708, 0.292 + + def get_green_primaries(self): + return 0.170, 0.797 + + def get_blue_primaries(self): + return 0.131, 0.046 + + def get_white_point(self): + return 0.3127, 0.3290 + + class AlexaLogCV3(AbstractColorspace): """AlexaLogCV3 colorspace @@ -171,11 +202,16 @@ def lin_to_gamma(self, value): def gamma_to_lin(self, value): return colors_helper.gamma_to_lin(value, self._gamma) + REC709 = Rec709() ALEXALOGCV3 = AlexaLogCV3() WIDEGAMUT = WideGamut() +REC2020_10B = Rec2020(is_ten_bits=True) +REC2020_12B = Rec2020(is_ten_bits=False) COLORSPACES = { 'REC709': REC709, 'ALEXALOGCV3': ALEXALOGCV3, - 'WIDEGAMUT': WIDEGAMUT + 'WIDEGAMUT': WIDEGAMUT, + 'REC2020_10bits': REC2020_10B, + 'REC2020_12bits': REC2020_12B, } From 0c20efcd89f7d82b4f7c809c52e7c14d547836a6 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 15:49:41 +0100 Subject: [PATCH 16/19] Sort colorspace list --- lutLab/rgb_to_xyz_matrix.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lutLab/rgb_to_xyz_matrix.py b/lutLab/rgb_to_xyz_matrix.py index 0f2aa1f..684843d 100644 --- a/lutLab/rgb_to_xyz_matrix.py +++ b/lutLab/rgb_to_xyz_matrix.py @@ -153,7 +153,8 @@ def __get_options(): parser.add_argument("-c", "--colorspace", help=("Input RGB Colorspace."), type=str, - choices= COLORSPACES.keys()+PRIVATE_COLORSPACES.keys(), + choices= sorted(COLORSPACES.keys() + + PRIVATE_COLORSPACES.keys()), default='REC709') # Output format parser.add_argument("-f", "--format", From 85a3f68c2ee4d77bbd58933ef90de76828e127cc Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 16:46:04 +0100 Subject: [PATCH 17/19] Add ACES Colorspace --- utils/colorspaces.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index f85df1b..83a73db 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -203,15 +203,37 @@ def gamma_to_lin(self, value): return colors_helper.gamma_to_lin(value, self._gamma) +class ACES(AbstractColorspace): + def get_red_primaries(self): + return 0.73470, 0.26530 + + def get_green_primaries(self): + return 0.00000, 1.00000 + + def get_blue_primaries(self): + return 0.00010, -0.07700 + + def get_white_point(self): + return 0.32168, 0.33767 + + def lin_to_gamma(self, value): + return value + + def gamma_to_lin(self, value): + return value + + REC709 = Rec709() ALEXALOGCV3 = AlexaLogCV3() WIDEGAMUT = WideGamut() REC2020_10B = Rec2020(is_ten_bits=True) REC2020_12B = Rec2020(is_ten_bits=False) +ACES = ACES() COLORSPACES = { 'REC709': REC709, 'ALEXALOGCV3': ALEXALOGCV3, 'WIDEGAMUT': WIDEGAMUT, 'REC2020_10bits': REC2020_10B, 'REC2020_12bits': REC2020_12B, + 'ACES': ACES, } From 0d0182471dde6135341618bd5b28aa0ad0b5a0cb Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 17:07:10 +0100 Subject: [PATCH 18/19] Add sRGB colorspace Now Rec709 is a child of sRGB. --- utils/colorspaces.py | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/utils/colorspaces.py b/utils/colorspaces.py index 83a73db..2eecf4f 100644 --- a/utils/colorspaces.py +++ b/utils/colorspaces.py @@ -78,15 +78,10 @@ def gamma_to_lin(self, value): pass -class Rec709(AbstractColorspace): - """rec709 colorspace +class sRGB(AbstractColorspace): + """sRGB colorspace """ - def __init__(self): - self._alpha = 1.099 - self._beta = 0.018 - self._round_depth = 3 - def get_red_primaries(self): return 0.64, 0.33 @@ -99,6 +94,28 @@ def get_blue_primaries(self): def get_white_point(self): return 0.3127, 0.3290 + def lin_to_gamma(self, value): + if value > 0.0031308: + return 1.055 * pow(value, 1.0 / 2.4) - 0.055 + else: + return 12.92 * value + + def gamma_to_lin(self, value): + if value > 0.04045: + return pow((value + 0.055) / 1.055, 2.4) + else: + return value / 12.92 + + +class Rec709(sRGB): + """rec709 colorspace + + """ + def __init__(self): + self._alpha = 1.099 + self._beta = 0.018 + self._round_depth = 3 + def lin_to_gamma(self, value): if value < self._beta: return value * 4.5 @@ -229,6 +246,7 @@ def gamma_to_lin(self, value): REC2020_10B = Rec2020(is_ten_bits=True) REC2020_12B = Rec2020(is_ten_bits=False) ACES = ACES() +sRGB = sRGB() COLORSPACES = { 'REC709': REC709, 'ALEXALOGCV3': ALEXALOGCV3, @@ -236,4 +254,5 @@ def gamma_to_lin(self, value): 'REC2020_10bits': REC2020_10B, 'REC2020_12bits': REC2020_12B, 'ACES': ACES, + 'sRGB': sRGB, } From c934b3e660372ed4a63170cd9fdec6df98250236 Mon Sep 17 00:00:00 2001 From: mfe Date: Wed, 11 Dec 2013 18:47:04 +0100 Subject: [PATCH 19/19] Inverted matrices (XYZ to RGB) --- lutLab/rgb_to_xyz_matrix.py | 65 +++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/lutLab/rgb_to_xyz_matrix.py b/lutLab/rgb_to_xyz_matrix.py index 684843d..f81ddcb 100644 --- a/lutLab/rgb_to_xyz_matrix.py +++ b/lutLab/rgb_to_xyz_matrix.py @@ -1,4 +1,4 @@ -""" Display RGB colorspaces to XYZ conversion matrixes +""" Display RGB colorspaces to XYZ conversion matrices and their inverses .. moduleauthor:: `Marie FETIVEAU `_ @@ -92,6 +92,23 @@ def get_RGB_to_XYZ_matrix(xy_red, xy_green, xy_blue, xy_white): return RGB_to_XYZ +def matrix_to_string(matrix, extra=""): + return ("{0:.10f} {1:.10f} {2:.10f} {9}\n" + "{3:.10f} {4:.10f} {5:.10f} {10}\n" + "{6:.10f} {7:.10f} {8:.10f} {11} \n").format(matrix.item(0, 0), + matrix.item(0, 1), + matrix.item(0, 2), + matrix.item(1, 0), + matrix.item(1, 1), + matrix.item(1, 2), + matrix.item(2, 0), + matrix.item(2, 1), + matrix.item(2, 2), + extra, + extra, + extra) + + def display_matrix(colorspace, format): """Display RGB to XYZ matrix corresponding to colorspace and formatting as format @@ -102,41 +119,27 @@ def display_matrix(colorspace, format): format (str): output format. simple, matrix, spimtx. """ - print "{0} to XYZ matrix ({1} output):\n".format(colorspace, format) try: - colorspace = COLORSPACES[colorspace] + colorspace_obj = COLORSPACES[colorspace] except KeyError: - colorspace = PRIVATE_COLORSPACES[colorspace] - matrix = get_RGB_to_XYZ_matrix(colorspace.get_red_primaries(), - colorspace.get_green_primaries(), - colorspace.get_blue_primaries(), - colorspace.get_white_point()) + colorspace_obj = PRIVATE_COLORSPACES[colorspace] + matrix = get_RGB_to_XYZ_matrix(colorspace_obj.get_red_primaries(), + colorspace_obj.get_green_primaries(), + colorspace_obj.get_blue_primaries(), + colorspace_obj.get_white_point()) if format == 'simple': - print ("{0:.10f} {1:.10f} {2:.10f}\n" - "{3:.10f} {4:.10f} {5:.10f}\n" - "{6:.10f} {7:.10f} {8:.10f}\n").format(matrix.item(0, 0), - matrix.item(0, 1), - matrix.item(0, 2), - matrix.item(1, 0), - matrix.item(1, 1), - matrix.item(1, 2), - matrix.item(2, 0), - matrix.item(2, 1), - matrix.item(2, 2)) + matrix_dump = matrix_to_string(matrix) + inv_matrix_dump = matrix_to_string(matrix.I) elif format == 'spimtx': - print ("{0:.10f} {1:.10f} {2:.10f} 0\n" - "{3:.10f} {4:.10f} {5:.10f} 0\n" - "{6:.10f} {7:.10f} {8:.10f} 0\n").format(matrix.item(0, 0), - matrix.item(0, 1), - matrix.item(0, 2), - matrix.item(1, 0), - matrix.item(1, 1), - matrix.item(1, 2), - matrix.item(2, 0), - matrix.item(2, 1), - matrix.item(2, 2)) + matrix_dump = matrix_to_string(matrix, "0") + inv_matrix_dump = matrix_to_string(matrix.I, "0") else: - print matrix + matrix_dump = "{0}".format(matrix) + inv_matrix_dump = "{0}".format(matrix.I) + print "{0} to XYZ matrix ({1} output):\n".format(colorspace, format) + print matrix_dump + print "XYZ to {0} matrix ({1} output):\n".format(colorspace, format) + print inv_matrix_dump def __get_options():