Exemple #1
0
def write_LUT_ResolveCube(LUT, path, decimals=7):
    """
    Writes given *LUT* to given  *Resolve* *.cube* *LUT* file.

    Parameters
    ----------
    LUT : LUT1D or LUT3x1D or LUT3D or LUTSequence
        :class:`LUT1D`, :class:`LUT3x1D` or :class:`LUT3D` or
        :class:`LUTSequence` class instance to write at given path.
    path : unicode
        *LUT* path.
    decimals : int, optional
        Formatting decimals.

    Returns
    -------
    bool
        Definition success.

    References
    ----------
    :cite:`Chamberlain2015`

    Examples
    --------
    Writing a 3x1D *Resolve* *.cube* *LUT*:

    >>> from colour.algebra import spow
    >>> domain = np.array([[-0.1, -0.1, -0.1], [3.0, 3.0, 3.0]])
    >>> LUT = LUT3x1D(
    ...     spow(LUT3x1D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_ResolveCube(LUT, 'My_LUT.cube')  # doctest: +SKIP

    Writing a 3D *Iridas* *.cube* *LUT*:

    >>> domain = np.array([[-0.1, -0.1, -0.1], [3.0, 3.0, 3.0]])
    >>> LUT = LUT3D(
    ...     spow(LUT3D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_ResolveCube(LUT, 'My_LUT.cube')  # doctest: +SKIP
    """

    has_3D, has_3x1D = False, False

    if isinstance(LUT, LUTSequence):
        assert (len(LUT) == 2 and isinstance(LUT[0], (LUT1D, LUT3x1D))
                and isinstance(LUT[1], LUT3D)), (
                    'LUTSequence must be 1D + 3D or 3x1D + 3D!')

        if isinstance(LUT[0], LUT1D):
            LUT[0] = LUT[0].as_LUT(LUT3x1D)

        has_3x1D = True
        has_3D = True
        name = LUT[1].name
    elif isinstance(LUT, LUT1D):
        name = LUT.name
        LUT = LUTSequence(LUT.as_LUT(LUT3x1D), LUT3D())
        has_3x1D = True
    elif isinstance(LUT, LUT3x1D):
        name = LUT.name
        LUT = LUTSequence(LUT, LUT3D())
        has_3x1D = True
    elif isinstance(LUT, LUT3D):
        name = LUT.name
        LUT = LUTSequence(LUT3x1D(), LUT)
        has_3D = True
    else:
        raise ValueError('LUT must be 1D, 3x1D, 3D, 1D + 3D or 3x1D + 3D!')

    for i in range(2):
        assert not LUT[i].is_domain_explicit(), (
            '"LUT" domain must be implicit!')

    assert (len(np.unique(LUT[0].domain)) == 2
            and len(np.unique(LUT[1].domain)) == 2), 'LUT domain must be 1D!'

    if has_3x1D:
        assert 2 <= LUT[0].size <= 65536, (
            'Shaper size must be in domain [2, 65536]!')
    if has_3D:
        assert 2 <= LUT[1].size <= 256, 'Cube size must be in domain [2, 256]!'

    def _format_array(array):
        """
        Formats given array as a *Resolve* *.cube* data row.
        """

        return '{1:0.{0}f} {2:0.{0}f} {3:0.{0}f}'.format(decimals, *array)

    def _format_tuple(array):
        """
        Formats given array as 2 space separated values to *decimals*
        precision.
        """

        return '{1:0.{0}f} {2:0.{0}f}'.format(decimals, *array)

    with open(path, 'w') as cube_file:
        cube_file.write('TITLE "{0}"\n'.format(name))

        if LUT[0].comments:
            for comment in LUT[0].comments:
                cube_file.write('# {0}\n'.format(comment))

        if LUT[1].comments:
            for comment in LUT[1].comments:
                cube_file.write('# {0}\n'.format(comment))

        default_domain = np.array([[0, 0, 0], [1, 1, 1]])

        if has_3x1D:
            cube_file.write('{0} {1}\n'.format('LUT_1D_SIZE',
                                               LUT[0].table.shape[0]))
            if not np.array_equal(LUT[0].domain, default_domain):
                cube_file.write('LUT_1D_INPUT_RANGE {0}\n'.format(
                    _format_tuple([LUT[0].domain[0][0], LUT[0].domain[1][0]])))

        if has_3D:
            cube_file.write('{0} {1}\n'.format('LUT_3D_SIZE',
                                               LUT[1].table.shape[0]))
            if not np.array_equal(LUT[1].domain, default_domain):
                cube_file.write('LUT_3D_INPUT_RANGE {0}\n'.format(
                    _format_tuple([LUT[1].domain[0][0], LUT[1].domain[1][0]])))

        if has_3x1D:
            table = LUT[0].table
            for row in table:
                cube_file.write('{0}\n'.format(_format_array(row)))
            cube_file.write('\n')

        if has_3D:
            table = LUT[1].table.reshape([-1, 3], order='F')
            for row in table:
                cube_file.write('{0}\n'.format(_format_array(row)))

    return True
Exemple #2
0
def write_LUT_Cinespace(LUT, path, decimals=7):
    """
    Writes given *LUT* to given  *Cinespace* *.csp* *LUT* file.

    Parameters
    ----------
    LUT : LUT1D or LUT3x1D or LUT3D or LUTSequence
        :class:`LUT1D`, :class:`LUT3x1D` or :class:`LUT3D` or
        :class:`LUTSequence` class instance to write at given path.
    path : unicode
        *LUT* path.
    decimals : int, optional
        Formatting decimals.

    Returns
    -------
    bool
        Definition success.

    References
    ----------
    :cite:`RisingSunResearch`

    Examples
    --------
    Writing a 3x1D *Cinespace* *.csp* *LUT*:

    >>> from colour.algebra import spow
    >>> domain = np.array([[-0.1, -0.2, -0.4], [1.5, 3.0, 6.0]])
    >>> LUT = LUT3x1D(
    ...     spow(LUT3x1D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_Cinespace(LUT, 'My_LUT.cube')  # doctest: +SKIP

    Writing a 3D *Cinespace* *.csp* *LUT*:

    >>> domain = np.array([[-0.1, -0.2, -0.4], [1.5, 3.0, 6.0]])
    >>> LUT = LUT3D(
    ...     spow(LUT3D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_Cinespace(LUT, 'My_LUT.cube')  # doctest: +SKIP
    """

    has_3D, has_3x1D, non_uniform = False, False, False

    if isinstance(LUT, LUTSequence):
        assert (len(LUT) == 2 and
                (isinstance(LUT[0], LUT1D) or isinstance(LUT[0], LUT3x1D)) and
                isinstance(LUT[1],
                           LUT3D)), 'LUTSequence must be 1D+3D or 3x1D+3D!'
        has_3x1D = True
        has_3D = True
        name = LUT[1].name
        if isinstance(LUT[0], LUT1D):
            LUT[0] = LUT[0].as_LUT(LUT3x1D)

    elif isinstance(LUT, LUT1D):
        if LUT.is_domain_explicit():
            non_uniform = True
        name = LUT.name
        LUT = LUTSequence(LUT.as_LUT(LUT3x1D), LUT3D())
        has_3x1D = True

    elif isinstance(LUT, LUT3x1D):
        if LUT.is_domain_explicit():
            non_uniform = True
        name = LUT.name
        LUT = LUTSequence(LUT, LUT3D())
        has_3x1D = True

    elif isinstance(LUT, LUT3D):
        name = LUT.name
        LUT = LUTSequence(LUT3x1D(), LUT)
        has_3D = True

    else:
        assert False, 'LUT must be 1D, 3x1D, 3D, 1D+3D or 3x1D+3D!'

    if has_3x1D:
        assert 2 <= LUT[0].size <= 65536, (
            'Shaper size must be in domain [2, 65536]!')
    if has_3D:
        assert 2 <= LUT[1].size <= 256, 'Cube size must be in domain [2, 256]!'

    def _ragged_size(table):
        """
        Return the ragged size of given table.
        """

        r, g, b = tsplit(table)
        r_len = r.shape[-1] - np.sum(np.isnan(r))
        g_len = g.shape[-1] - np.sum(np.isnan(g))
        b_len = b.shape[-1] - np.sum(np.isnan(b))

        return [r_len, g_len, b_len]

    def _format_array(array):
        """
        Formats given array as a *Cinespace* *.cube* data row.
        """

        return '{1:0.{0}f} {2:0.{0}f} {3:0.{0}f}'.format(decimals, *array)

    def _format_tuple(array):
        """
        Formats given array as 2 space separated values to *decimals*
        precision.
        """

        return '{1:0.{0}f} {2:0.{0}f}'.format(decimals, *array)

    with open(path, 'w') as csp_file:
        csp_file.write('CSPLUTV100\n')

        if has_3D:
            csp_file.write('3D\n\n')
        else:
            csp_file.write('1D\n\n')

        csp_file.write('BEGIN METADATA\n')
        csp_file.write('{0}\n'.format(name))

        if LUT[0].comments:
            for comment in LUT[0].comments:
                csp_file.write('{0}\n'.format(comment))

        if LUT[1].comments:
            for comment in LUT[1].comments:
                csp_file.write('{0}\n'.format(comment))

        csp_file.write('END METADATA\n\n')

        if has_3D or non_uniform:
            if has_3x1D:
                for i in range(3):
                    if LUT[0].is_domain_explicit():
                        size = _ragged_size(LUT[0].domain)[i]
                        table_min = np.nanmin(LUT[0].table)
                        table_max = np.nanmax(LUT[0].table)
                    else:
                        size = LUT[0].size

                    csp_file.write('{0}\n'.format(size))

                    for j in range(size):
                        if LUT[0].is_domain_explicit():
                            entry = LUT[0].domain[j][i]
                        else:
                            entry = (
                                LUT[0].domain[0][i] + j *
                                (LUT[0].domain[1][i] - LUT[0].domain[0][i]) /
                                (LUT[0].size - 1))
                        csp_file.write('{0:.{1}f} '.format(entry, decimals))

                    csp_file.write('\n')

                    for j in range(size):
                        entry = LUT[0].table[j][i]
                        if non_uniform:
                            entry -= table_min
                            entry /= (table_max - table_min)
                        csp_file.write('{0:.{1}f} '.format(entry, decimals))

                    csp_file.write('\n')
            else:
                for i in range(3):
                    csp_file.write('2\n')
                    csp_file.write('{0}\n'.format(
                        _format_tuple(
                            [LUT[1].domain[0][i], LUT[1].domain[1][i]])))
                    csp_file.write('{0:.{2}f} {1:.{2}f}\n'.format(
                        0, 1, decimals))
            if non_uniform:
                csp_file.write('\n{0}\n'.format(2))
                row = [table_min, table_min, table_min]
                csp_file.write('{0}\n'.format(_format_array(row)))
                row = [table_max, table_max, table_max]
                csp_file.write('{0}\n'.format(_format_array(row)))
            else:
                csp_file.write('\n{0} {1} {2}\n'.format(
                    LUT[1].table.shape[0], LUT[1].table.shape[1],
                    LUT[1].table.shape[2]))
                table = LUT[1].table.reshape((-1, 3), order='F')

                for row in table:
                    csp_file.write('{0}\n'.format(_format_array(row)))

        else:
            for i in range(3):
                csp_file.write('2\n')
                csp_file.write('{0}\n'.format(
                    _format_tuple([LUT[0].domain[0][i], LUT[0].domain[1][i]])))
                csp_file.write('0.0 1.0\n')
            csp_file.write('\n{0}\n'.format(LUT[0].size))
            table = LUT[0].table

            for row in table:
                csp_file.write('{0}\n'.format(_format_array(row)))

    return True
def write_LUT_ResolveCube(LUT, path, decimals=7):
    """
    Writes given *LUT* to given  *Resolve* *.cube* *LUT* file.

    Parameters
    ----------
    LUT : LUT1D or LUT3x1D or LUT3D or LUTSequence
        :class:`LUT1D`, :class:`LUT3x1D` or :class:`LUT3D` or
        :class:`LUTSequence` class instance to write at given path.
    path : unicode
        *LUT* path.
    decimals : int, optional
        Formatting decimals.

    Returns
    -------
    bool
        Definition success.

    References
    ----------
    :cite:`Chamberlain2015`

    Examples
    --------
    Writing a 3x1D *Resolve* *.cube* *LUT*:

    >>> from colour.algebra import spow
    >>> domain = np.array([[-0.1, -0.1, -0.1], [3.0, 3.0, 3.0]])
    >>> LUT = LUT3x1D(
    ...     spow(LUT3x1D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_ResolveCube(LUT, 'My_LUT.cube')  # doctest: +SKIP

    Writing a 3D *Iridas* *.cube* *LUT*:

    >>> domain = np.array([[-0.1, -0.1, -0.1], [3.0, 3.0, 3.0]])
    >>> LUT = LUT3D(
    ...     spow(LUT3D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_ResolveCube(LUT, 'My_LUT.cube')  # doctest: +SKIP
    """

    has_3D, has_3x1D = False, False

    if isinstance(LUT, LUTSequence):
        assert (len(LUT) == 2 and isinstance(LUT[0], (LUT1D, LUT3x1D)) and
                isinstance(LUT[1], LUT3D)), (
                    'LUTSequence must be 1D + 3D or 3x1D + 3D!')

        if isinstance(LUT[0], LUT1D):
            LUT[0] = LUT[0].as_LUT(LUT3x1D)

        has_3x1D = True
        has_3D = True
        name = LUT[1].name
    elif isinstance(LUT, LUT1D):
        name = LUT.name
        LUT = LUTSequence(LUT.as_LUT(LUT3x1D), LUT3D())
        has_3x1D = True
    elif isinstance(LUT, LUT3x1D):
        name = LUT.name
        LUT = LUTSequence(LUT, LUT3D())
        has_3x1D = True
    elif isinstance(LUT, LUT3D):
        name = LUT.name
        LUT = LUTSequence(LUT3x1D(), LUT)
        has_3D = True
    else:
        raise ValueError('LUT must be 1D, 3x1D, 3D, 1D + 3D or 3x1D + 3D!')

    for i in range(2):
        assert not LUT[i].is_domain_explicit(), (
            '"LUT" domain must be implicit!')

    assert (len(np.unique(LUT[0].domain)) == 2 and
            len(np.unique(LUT[1].domain)) == 2), 'LUT domain must be 1D!'

    if has_3x1D:
        assert 2 <= LUT[0].size <= 65536, (
            'Shaper size must be in domain [2, 65536]!')
    if has_3D:
        assert 2 <= LUT[1].size <= 256, 'Cube size must be in domain [2, 256]!'

    def _format_array(array):
        """
        Formats given array as a *Resolve* *.cube* data row.
        """

        return '{1:0.{0}f} {2:0.{0}f} {3:0.{0}f}'.format(decimals, *array)

    def _format_tuple(array):
        """
        Formats given array as 2 space separated values to *decimals*
        precision.
        """

        return '{1:0.{0}f} {2:0.{0}f}'.format(decimals, *array)

    with open(path, 'w') as cube_file:
        cube_file.write('TITLE "{0}"\n'.format(name))

        if LUT[0].comments:
            for comment in LUT[0].comments:
                cube_file.write('# {0}\n'.format(comment))

        if LUT[1].comments:
            for comment in LUT[1].comments:
                cube_file.write('# {0}\n'.format(comment))

        default_domain = np.array([[0, 0, 0], [1, 1, 1]])

        if has_3x1D:
            cube_file.write('{0} {1}\n'.format('LUT_1D_SIZE',
                                               LUT[0].table.shape[0]))
            if not np.array_equal(LUT[0].domain, default_domain):
                cube_file.write('LUT_1D_INPUT_RANGE {0}\n'.format(
                    _format_tuple([LUT[0].domain[0][0], LUT[0].domain[1][0]])))

        if has_3D:
            cube_file.write('{0} {1}\n'.format('LUT_3D_SIZE',
                                               LUT[1].table.shape[0]))
            if not np.array_equal(LUT[1].domain, default_domain):
                cube_file.write('LUT_3D_INPUT_RANGE {0}\n'.format(
                    _format_tuple([LUT[1].domain[0][0], LUT[1].domain[1][0]])))

        if has_3x1D:
            table = LUT[0].table
            for row in table:
                cube_file.write('{0}\n'.format(_format_array(row)))
            cube_file.write('\n')

        if has_3D:
            table = LUT[1].table.reshape([-1, 3], order='F')
            for row in table:
                cube_file.write('{0}\n'.format(_format_array(row)))

    return True
def write_LUT_Cinespace(LUT, path, decimals=7):
    """
    Writes given *LUT* to given  *Cinespace* *.csp* *LUT* file.

    Parameters
    ----------
    LUT : LUT1D or LUT3x1D or LUT3D or LUTSequence
        :class:`LUT1D`, :class:`LUT3x1D` or :class:`LUT3D` or
        :class:`LUTSequence` class instance to write at given path.
    path : unicode
        *LUT* path.
    decimals : int, optional
        Formatting decimals.

    Returns
    -------
    bool
        Definition success.

    References
    ----------
    :cite:`RisingSunResearch`

    Examples
    --------
    Writing a 3x1D *Cinespace* *.csp* *LUT*:

    >>> from colour.algebra import spow
    >>> domain = np.array([[-0.1, -0.2, -0.4], [1.5, 3.0, 6.0]])
    >>> LUT = LUT3x1D(
    ...     spow(LUT3x1D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_Cinespace(LUT, 'My_LUT.cube')  # doctest: +SKIP

    Writing a 3D *Cinespace* *.csp* *LUT*:

    >>> domain = np.array([[-0.1, -0.2, -0.4], [1.5, 3.0, 6.0]])
    >>> LUT = LUT3D(
    ...     spow(LUT3D.linear_table(16, domain), 1 / 2.2),
    ...     'My LUT',
    ...     domain,
    ...     comments=['A first comment.', 'A second comment.'])
    >>> write_LUT_Cinespace(LUT, 'My_LUT.cube')  # doctest: +SKIP
    """

    has_3D, has_3x1D, non_uniform = False, False, False

    if isinstance(LUT, LUTSequence):
        assert (len(LUT) == 2 and
                (isinstance(LUT[0], LUT1D) or isinstance(LUT[0], LUT3x1D)) and
                isinstance(LUT[1],
                           LUT3D)), 'LUTSequence must be 1D+3D or 3x1D+3D!'
        has_3x1D = True
        has_3D = True
        name = LUT[1].name
        if isinstance(LUT[0], LUT1D):
            LUT[0] = LUT[0].as_LUT(LUT3x1D)

    elif isinstance(LUT, LUT1D):
        if LUT.is_domain_explicit():
            non_uniform = True
        name = LUT.name
        LUT = LUTSequence(LUT.as_LUT(LUT3x1D), LUT3D())
        has_3x1D = True

    elif isinstance(LUT, LUT3x1D):
        if LUT.is_domain_explicit():
            non_uniform = True
        name = LUT.name
        LUT = LUTSequence(LUT, LUT3D())
        has_3x1D = True

    elif isinstance(LUT, LUT3D):
        name = LUT.name
        LUT = LUTSequence(LUT3x1D(), LUT)
        has_3D = True

    else:
        assert False, 'LUT must be 1D, 3x1D, 3D, 1D+3D or 3x1D+3D!'

    if has_3x1D:
        assert 2 <= LUT[0].size <= 65536, (
            'Shaper size must be in domain [2, 65536]!')
    if has_3D:
        assert 2 <= LUT[1].size <= 256, 'Cube size must be in domain [2, 256]!'

    def _ragged_size(table):
        """
        Return the ragged size of given table.
        """

        r, g, b = tsplit(table)
        r_len = r.shape[-1] - np.sum(np.isnan(r))
        g_len = g.shape[-1] - np.sum(np.isnan(g))
        b_len = b.shape[-1] - np.sum(np.isnan(b))

        return [r_len, g_len, b_len]

    def _format_array(array):
        """
        Formats given array as a *Cinespace* *.cube* data row.
        """

        return '{1:0.{0}f} {2:0.{0}f} {3:0.{0}f}'.format(decimals, *array)

    def _format_tuple(array):
        """
        Formats given array as 2 space separated values to *decimals*
        precision.
        """

        return '{1:0.{0}f} {2:0.{0}f}'.format(decimals, *array)

    with open(path, 'w') as csp_file:
        csp_file.write('CSPLUTV100\n')

        if has_3D:
            csp_file.write('3D\n\n')
        else:
            csp_file.write('1D\n\n')

        csp_file.write('BEGIN METADATA\n')
        csp_file.write('{0}\n'.format(name))

        if LUT[0].comments:
            for comment in LUT[0].comments:
                csp_file.write('{0}\n'.format(comment))

        if LUT[1].comments:
            for comment in LUT[1].comments:
                csp_file.write('{0}\n'.format(comment))

        csp_file.write('END METADATA\n\n')

        if has_3D or non_uniform:
            if has_3x1D:
                for i in range(3):
                    if LUT[0].is_domain_explicit():
                        size = _ragged_size(LUT[0].domain)[i]
                        table_min = np.nanmin(LUT[0].table)
                        table_max = np.nanmax(LUT[0].table)
                    else:
                        size = LUT[0].size

                    csp_file.write('{0}\n'.format(size))

                    for j in range(size):
                        if LUT[0].is_domain_explicit():
                            entry = LUT[0].domain[j][i]
                        else:
                            entry = (
                                LUT[0].domain[0][i] + j *
                                (LUT[0].domain[1][i] - LUT[0].domain[0][i]) /
                                (LUT[0].size - 1))
                        csp_file.write('{0:.{1}f} '.format(entry, decimals))

                    csp_file.write('\n')

                    for j in range(size):
                        entry = LUT[0].table[j][i]
                        if non_uniform:
                            entry -= table_min
                            entry /= (table_max - table_min)
                        csp_file.write('{0:.{1}f} '.format(entry, decimals))

                    csp_file.write('\n')
            else:
                for i in range(3):
                    csp_file.write('2\n')
                    csp_file.write('{0}\n'.format(
                        _format_tuple(
                            [LUT[1].domain[0][i], LUT[1].domain[1][i]])))
                    csp_file.write('{0:.{2}f} {1:.{2}f}\n'.format(
                        0, 1, decimals))
            if non_uniform:
                csp_file.write('\n{0}\n'.format(2))
                row = [table_min, table_min, table_min]
                csp_file.write('{0}\n'.format(_format_array(row)))
                row = [table_max, table_max, table_max]
                csp_file.write('{0}\n'.format(_format_array(row)))
            else:
                csp_file.write('\n{0} {1} {2}\n'.format(
                    LUT[1].table.shape[0], LUT[1].table.shape[1],
                    LUT[1].table.shape[2]))
                table = LUT[1].table.reshape([-1, 3], order='F')

                for row in table:
                    csp_file.write('{0}\n'.format(_format_array(row)))

        else:
            for i in range(3):
                csp_file.write('2\n')
                csp_file.write('{0}\n'.format(
                    _format_tuple([LUT[0].domain[0][i], LUT[0].domain[1][i]])))
                csp_file.write('0.0 1.0\n')
            csp_file.write('\n{0}\n'.format(LUT[0].size))
            table = LUT[0].table

            for row in table:
                csp_file.write('{0}\n'.format(_format_array(row)))

    return True