顏色空間系列代碼下載鏈接:http://files.cnblogs.com/Imageshop/ImageInfo.rar (同文章同步更新)
在顏色感知的研究中,CIE 1931 XYZ 色彩空間(也叫做 CIE 1931 色彩空間)是其中一個最先采用數學方式來定義的色彩空間,它由國際照明委員會(CIE)於1931年創立。CIE XYZ 色彩空間是從 1920 年代后期 W. David Wright (Wright 1928) 和 John Guild (Guild 1931) 做的一系列實驗中得出的。他們的實驗結果合並到了 CIE RGB 色彩空間的規定中,CIE XYZ 色彩空間再從它得出。
更過具體的關於XYZ空間的理論解釋可見:點擊打開鏈接
本文的重點是如何優化這個RGB<->XYZ相互轉換的過程。
從相關的文獻包括OpenCv的文檔中可找到兩者的理論轉換算式如下:
[X] [0.412453 0.357580 0.180423] [R]
[Y] = [0.212671 0.715160 0.072169] [G] (1)
[Z] [0.019334 0.119193 0.950227] [B]
[R] [3.240479 -1.537150 -0.498535] [X]
[G] = [-0.969256 1.875992 0.041556] [Y] (2)
[B] [0.055648 -0.204043 1.057311] [Z]
仔細觀察式(1),其中 X = 0.412453 * R + 0.412453 *G+ 0.412453B ; 各系數相加之和為0.950456,非常接近於1,我們知道R/G/B的取值范圍為[ 0,255 ],如果系數和等於1,則X的取值范圍也必然在[ 0,255 ]之間,因此我們可以考慮等比修改各系數,使其之和等於1,這樣就做到了XYZ和RGB在同等范圍的映射,因此第一行的系數應分別修改為 [0.412453 0.357580 0.180423] / [0.950456] = [0.433953 0.376219 0.189828]。
式(1)的第二行,三個系數之和恰為1,因此無需修正。
式(1)的第三行,三個系數之和為1.088754,修正算式為 [0.019334 0.119193 0.950227] / [1.088754] = [0.017758 0.109477 0.872765]
由於式(1)的變化,式(2)必須做相應的調整,考慮式(1)關於X的各分量都除以了 0.950456,因此,只需在式2的對應分量上乘以 0.950456即可,同理,關於Z的各分量由於都除以了1.088754,式(2)各分量必須對應乘以1.088754。得到最終的變換式(3)(4)。
[X] [0.433953 0.376219 0.189828] [R]
[Y] = [0.212671 0.715160 0.072169] [G] (3)
[Z] [0.017758 0.109477 0.872765] [B]
[R] [3.0799327 -1.537150 -0.542782] [X]
[G] = [-0.921235 1.875992 0.0452442] [Y] (4)
[B] [0.0528909 -0.204043 1.1511515] [Z]
如果有朋友查閱過OpenCv的RGB到LAB空間的轉換,就可以發現Cv就是用的上述矩陣先將RGB轉到XYZ,再由XYZ轉為LAB的。
由以上數式可以看出RGB和XYZ顏色空間的轉換時線性的,因此,兩個系數矩陣之間的成績必為一個E矩陣(對角線為1,其他元素都為0),讀者可以用matlab測試下。
由於各小數的存在,理論上說,RGB顏色空間的顏色對應的XYZ分量的數值一般都為浮點數,之前說過經過調整系數矩陣后其有效范圍在[0,255]之間,這和RGB的范圍是一致的,因此我們更感興趣的可能是用整數表示XYZ的值,此時,如果先用上述計算式計算,最后在用(int) 強制取整,則效率很低下,因此,很有必要做點的優化。
優化的原理基本就是用整數的乘除法來替代浮點運算,比如,對各系數乘以一個很大的數,計算出結果在整除這個數,則得到的數字和之前的浮點算式取整結果是一致的。
如何取放大系數,也有着一定的講究,比如0.433953 ,很多朋友的第一反應應該是乘以1000000得到433953 ,不錯,這是個很好的優化,卻不是最好的,因為最后的整除1000000相對來說也是個慢的過程,如果我們能夠整除一個2的N次冪數,則可以用整數的移位來代替整除。眾所周知,移位的速度非常快。
那這個N如何取呢,比方說取1可行嗎,分析下馬上得到的結果是絕對不行,因為很多系數乘以2再取整就變為0了。我對這個N的取值建議是在保證整個算式的每個部分的計算結果不超過int(對於64位CPU,則是long類型)類型的最大范圍時,N越大越好。像我們這種情況,由於RGB的取值范圍是[255],因此N的取值最大只能是23。
假定我們取N的值為20,則RGB轉XYZ的算式可以寫為如下:
X = (Blue * 199049 + Green * 394494 + Red * 455033 + 524288) >> 20; // 這些系數是按照RGBLAB類里的labXr_32f放大2^20后得到的 Y = (Blue * 75675 + Green * 749900 + Red * 223002 + 524288) >> 20; Z = (Blue * 915161 + Green * 114795 + Red * 18621 + 524288) >> 20; // 這里無需驗證結果是否在[0,255]之間,必然在。
注意算式中的524288,這個值等於(2^20)/2,加上他的作用是使整個算式能夠做到四舍五入。
另外,還要注意各系數小數點后數字的累積,那X一行來說事,0.433953 * 2^20 = 455032.700928,我們取值455033 ,0.376219 * 2^20= 394494.214144 ,則取值394494 ,那么最后一個系數其實可以不用計算,直接拿 2^20-455033 -394494 =199049 。
對應的XYZ轉RGB空間算式為:
Blue = (X * 55460 - Y * 213955 + Z * 1207070) >> 20; Green = (X * -965985 + Y * 1967119 + Z * 47442) >> 20; // x * -965985 和 -x * 965985 在反匯編后是不一樣的,后者多了個neg指令 Red = (X * 3229543 - Y * 1611819 - Z * 569148) >> 20; if (Red > 255) Red = 255; else if (Red < 0) Red = 0; // 這里需要判斷,因為RGB空間所有的顏色轉換到XYZ后,並不是填充滿了0-255的范圍的,反轉過去就會存在一些溢出的點。 if (Green > 255) Green = 255; else if (Green < 0) Green = 0; // 編譯后比三目運算符的效率高 if (Blue > 255) Blue = 255; else if (Blue < 0) Blue = 0;
正如代碼中的注釋一樣,XYZ-RGB的轉換必須判斷轉換的顏色是否在有效范圍內。
另外對上述算式提一點點優化方面的是事情:
Green = (X * -965985 + Y * 1967119 + Z * 47442) >> 20; // x * -965985 和 -x * 965985 在反匯編后是不一樣的,后者多了個neg指令 00000048 imul ebx,edi,0FFF1429Fh 0000004e imul eax,dword ptr [ebp-10h],1E040Fh 00000055 add ebx,eax 00000057 imul eax,dword ptr [ebp-14h],0B952h 0000005e add ebx,eax 00000060 sar ebx,14h
Green = (-X * 965985 + Y * 1967119 + Z * 47442) >> 20; // x * -965985 和 -x * 965985 在反匯編后是不一樣的,后者多了個neg指令 00000048 mov ebx,edi 0000004a neg ebx 0000004c imul ebx,ebx,0EBD61h 00000052 imul eax,dword ptr [ebp-10h],1E040Fh 00000059 add ebx,eax 0000005b imul eax,dword ptr [ebp-14h],0B952h 00000062 add ebx,eax 00000064 sar ebx,14h






轉載請保留以下信息:
作者: laviewpbt
時間:2013.1.31 7點於辦公室
QQ:33184777
E-Mail : laviewpbt@sina.com