2011-11-04 169 views
3

我有裝入經由PIL一個numpy的陣列的RGB圖像。我得到了一個行x cols x 3數組。修補後,我得到了下面的代碼。我想學習如何在沒有循環的情況下做這樣的數組/矩陣操作。3x3矩陣轉換而不循環(RGB顏色轉換)

# 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(通過Using Python to convert color formats?),但我用這個作爲一個練習學習numpy的。

上述Colormath庫使用的點積。

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

我的數學不是它應該在的地方。 np.dot()是我最好的選擇嗎?

編輯。更深層次的閱讀colormath的apply_RGB_matrix()之後 - color_conversions.py,我發現np.dot如果轉換3x3s是矩陣()的作品。奇怪的。

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

回答

4

我不知道您使用的是convert RGB to YCC公式,所以我不想聲稱這是完整的計算,而是以簡化功能你發佈,是的,使用np.dot與numpy數組而不是numpy矩陣。

np.dot*與numpy的矩陣更普遍。當使用*與numpy的矩陣,兩個矩陣必須是2維的。 但np.dot可以產生具有不同形狀的陣列的結果。這對您的應用很重要,因爲rgb是三維的(例如,當它具有形狀(1470,2105,5))時。

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)) 
+1

啊!實際上,使用3x3作爲陣列而不是矩陣是解決方案。並且內聯轉換矩陣的確會使代碼更好看。謝謝!而np.allclose()是學習的新東西。 –

3
def convert_ycc_to_rgb(ycc): 
    return ycc * ycc_to_rgb.T 

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

那樣簡單,記住矩陣乘法是如何以行和列的內積來定義。

編輯:

我假定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) 
+0

我原本試過。例如,rgb.shape就是(1470,2105,3)。 rgb_to_ycc是(3,3)。 ValueError:形狀太大而不能成爲矩陣。 –

+0

哦,我明白了,我正在考慮序列化的像素顏色......讓我劈開一點;-) – fortran

+1

+1幫助我想到以新的方式重塑! –