Преобразование матрицы 3х3 без петли (преобразование цвета RGB) - PullRequest
3 голосов
/ 04 ноября 2011

У меня есть изображение RGB, загруженное в массив numpy через PIL.Я получаю массив строк x cols x 3.Повозившись, я пришел к следующему коду.Я хотел бы научиться делать такие манипуляции с массивом / матрицей без цикла.

# Note using matrix not array.
rgb_to_ycc = np.matrix(
     (0.2990,  0.5870,  0.1140,
    -0.1687, -0.3313,  0.5000,
     0.5000, -0.4187, -0.0813,)
).reshape( 3,3 )

ycc_to_rgb = np.matrix(
    ( 1.0, 0.0, 1.4022,
      1.0, -0.3456, -0.7145,
      1.0, 1.7710, 0, )
).reshape( 3, 3 )

def convert_ycc_to_rgb( ycc ) :
    # convert back to RGB
    rgb = np.zeros_like( ycc )
    for row in range(ycc.shape[0]) :
        rgb[row] = ycc[row] * ycc_to_rgb.T
    return rgb

def convert_rgb_to_ycc( rgb ) :
    ycc = np.zeros_like( rgb )
    for row in range(rgb.shape[0]):
        ycc[row] = rgb[row] * rgb_to_ycc.T
    return ycc

Я мог бы использовать http://pypi.python.org/pypi/colormath (через Использование Python для преобразования цветовых форматов? ), но я использую это как упражнение, чтобы выучить numpy.

Вышеупомянутая библиотека Colormath использует точечное произведение.

# Perform the adaptation via matrix multiplication.
result_matrix = numpy.dot(var_matrix, rgb_matrix)

Моя математика не там, где она должна быть.Является ли np.dot () моей лучшей ставкой?

РЕДАКТИРОВАТЬ.После более глубокого чтения colormath's apply_RGB_matrix () - color_conversions.py, я обнаружил, что np.dot () работает, если мои конверсии 3x3 являются , а не матрицами.Weird.

def convert_rgb_to_ycc( rgb ) :
    return np.dot( rgb, np.asarray( rgb_to_ycc ).T )

Ответы [ 2 ]

4 голосов
/ 04 ноября 2011

Я не уверен насчет формулы, которую вы используете для преобразования RGB в YCC , поэтому я не хочу утверждать, что это полный расчет, но чтобы упростить опубликованную вами функцию, да, используйте np.dot с массивами вместо цифровых матриц.

np.dot является более общим, чем * с пустыми матрицами. При использовании * с пустыми матрицами две матрицы должны быть 2-мерными. Но np.dot может дать результат с массивами различной формы. Это важно для вашего приложения, поскольку rgb является трехмерным (например, когда оно имеет форму (1470, 2105, 3)).

Документы для np.dot говорят:

    For N dimensions it is a sum product over the last axis of `a` and
    the second-to-last of `b`::

        dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

Это обобщение умножения регулярных матриц.


Я предлагаю назвать вашу конечную функцию rgb_to_ycc, вместо того, чтобы назначать это обозначение постоянной матрице. (Это короче и говорит, что именно вы хотите, чтобы функция делала.)

Так что ниже, rgb_to_ycc - моя предложенная функция, и я сделал несколько незначительных изменений, чтобы convert_rgb_to_ycc не вызывал исключения и выполнял вычисления, которые, я думаю, вы намереваетесь.

Последняя строка np.allclose(...) показывает, что две функции возвращают одинаковый результат.

import numpy as np

def rgb_to_ycc(rgb):
    M = np.array(
         (0.2990,  0.5870,  0.1140,
        -0.1687, -0.3313,  0.5000,
         0.5000, -0.4187, -0.0813,)
        ).reshape( 3,3 )
    return np.dot(rgb, M.T)

def convert_rgb_to_ycc( rgb ) :
    M = np.matrix(
         (0.2990,  0.5870,  0.1140,
        -0.1687, -0.3313,  0.5000,
         0.5000, -0.4187, -0.0813,)
        ).reshape( 3,3 )
    shape=rgb.shape
    rgb=rgb.reshape((-1,3))
    ycc = np.zeros_like( rgb )
    for i in range(len(rgb)):
        ycc[i] = rgb[i] * M.T
    return ycc.reshape(shape)

rgb=np.random.random((100,100,3))
assert np.allclose(rgb_to_ycc(rgb),convert_rgb_to_ycc(rgb))
3 голосов
/ 04 ноября 2011
def convert_ycc_to_rgb(ycc):
    return ycc * ycc_to_rgb.T

def convert_rgb_to_ycc(rgb):
    return rgb * rgb_to_ycc.T

все так просто, помните, как умножение матриц определяется в терминах внутренних произведений строк и столбцов.

edit:

Я предполагалчто матрицы rgb и ycc были просто матрицей, в которой было столько строк, сколько пикселей и столбцов на компонент цвета.Итак, что нам нужно сделать, это изменить их на (rows*cols,3), а затем снова на (rows, cols, 3).

Итак, код наконец-то:

def convert_ycc_to_rgb(ycc):
    shape = ycc.shape
    return np.array(ycc.reshape(-1,3) * ycc_to_rgb.T).reshape(shape)

def convert_rgb_to_ycc(rgb):
    shape = rgb.shape
    return np.array(rgb.reshape(-1,3) * rgb_to_ycc.T).reshape(shape)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...