CCM算法

517 阅读2分钟

1、CCM矩阵的作用是矫正整张图片的色彩表现,利用现象变换使图片的表现更接近理想状态。使用测试机在标准光源环境下拍摄24色卡,获取24个色块的三通道均值,矫正过程如下:

[A00A01A02A10A11A12A20A21A22][RGB]=[RGB]\begin{bmatrix} A_{00} & A_{01} & A_{02} \\ A_{10} & A_{11} & A_{12} \\ A_{20} & A_{21} &A_{22} \end{bmatrix} * \begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} R' \\ G' \\ B' \end{bmatrix}

2、收集调试机和target图片的24色卡数据,取前18个色块进行计算,针对R分量矫正误差如下:

err=i=017(RiA00+GiA01+BiA02Ri)2err= \displaystyle\sum_{i=0}^{17} \left(R_i A_{00}+G_iA_{01}+B_iA_{02}-R'_i\right)^{\smash{2}}

问题就变成了在约束条件:A00+A01+A02=1A_{00}+A_{01}+A_{02}=1下求上式的极值点,构建拉格朗日函数:

L=i=017(RiA00+GiA01+BiA02Ri)2+λ(A00+A01+A021)L=\displaystyle\sum_{i=0}^{17} \left(R_i A_{00}+G_iA_{01}+B_iA_{02}-R'_i\right)^{\smash{2}} + \lambda\left(A_{00}+A_{01}+A_{02}-1\right)

于是对四个未知数求偏导数:

LA00=i=017(2Ri2A00+2GiRiA01+2BiRiA022RiRi)+λ=0\frac{\partial L}{\partial A_{00}}=\displaystyle\sum_{i=0}^{17} \left(2R_i^2 A_{00}+2G_iR_iA_{01}+2B_iR_iA_{02}-2R_iR'_i\right) + \lambda=0

LA01=i=017(2RiGiA00+2Gi2A01+2BiGiA022GiRi)+λ=0\frac{\partial L}{\partial A_{01}}=\displaystyle\sum_{i=0}^{17} \left(2R_iG_i A_{00}+2G_i^2A_{01}+2B_iG_iA_{02}-2G_iR'_i\right) + \lambda=0

LA02=i=017(2RiBiA00+2GiBiA01+2Bi2A022BiRi)+λ=0\frac{\partial L}{\partial A_{02}}=\displaystyle\sum_{i=0}^{17} \left(2R_iB_i A_{00}+2G_iB_iA_{01}+2B_i^2A_{02}-2B_iR'_i\right) + \lambda=0

Lλ=A00+A01+A02=1\frac{\partial L}{\partial \lambda}=A_{00}+A_{01}+A_{02}=1

对应的矩阵方程为:

i=017[Ri2GiRiBiRi0.5RiGiGi2BiGi0.5RiBiGiBiBi20.51110][A00A01A02λ]=i=017[RiRiGiRiBiRi1]\displaystyle\sum_{i=0}^{17} \begin{bmatrix} R_i^2 & G_iR_i & B_iR_i & 0.5 \\ R_iG_i & G_i^2 & B_iG_i & 0.5 \\ R_iB_i & G_iB_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{bmatrix} \begin{bmatrix} A_{00} \\ A_{01} \\ A_{02} \\ \lambda \end{bmatrix}=\displaystyle\sum_{i=0}^{17} \begin{bmatrix} R_iR'_i \\ G_iR'_i \\ B_iR'_i \\ 1 \end{bmatrix}

由克莱姆法则可知方程的解如下:

A00=i=017RiRiGiRiBiRi0.5GiRiGi2BiGi0.5BiRiGiBiBi20.51110i=017Ri2GiRiBiRi0.5RiGiGi2BiGi0.5RiBiGiBiBi20.51110A_{00}=\frac{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_iR'_i & G_iR_i & B_iR_i & 0.5 \\ G_iR'_i & G_i^2 & B_iG_i & 0.5 \\ B_iR'_i & G_iB_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_i^2 & G_iR_i & B_iR_i & 0.5 \\ R_iG_i & G_i^2 & B_iG_i & 0.5 \\ R_iB_i & G_iB_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}

A01=i=017Ri2RiRiBiRi0.5RiGiGiRiBiGi0.5RiBiBiRiBi20.51110i=017Ri2GiRiBiRi0.5RiGiGi2BiGi0.5RiBiGiBiBi20.51110A_{01}=\frac{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_i^2 & R_iR'_i & B_iR_i & 0.5 \\ R_iG_i & G_iR'_i & B_iG_i & 0.5 \\ R_iB_i & B_iR'_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_i^2 & G_iR_i & B_iR_i & 0.5 \\ R_iG_i & G_i^2 & B_iG_i & 0.5 \\ R_iB_i & G_iB_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}

A02=i=017Ri2GiRiRiRi0.5RiGiGi2GiRi0.5RiBiGiBiBiRi0.51110i=017Ri2GiRiBiRi0.5RiGiGi2BiGi0.5RiBiGiBiBi20.51110A_{02}=\frac{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_i^2 & G_iR_i & R_iR'_i & 0.5 \\ R_iG_i & G_i^2 & G_iR'_i & 0.5 \\ R_iB_i & G_iB_i & B_iR'_i & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}{\displaystyle\sum_{i=0}^{17} \begin{vmatrix} R_i^2 & G_iR_i & B_iR_i & 0.5 \\ R_iG_i & G_i^2 & B_iG_i & 0.5 \\ R_iB_i & G_iB_i & B_i^2 & 0.5 \\ 1 & 1 & 1 & 0 \end{vmatrix}}

3、同理可以求出:[A10A11A12][A20A21A22] \begin{bmatrix} A_{10} & A_{11} & A_{12} \end{bmatrix} \begin{bmatrix} A_{20} & A_{21} & A_{22} \end{bmatrix}

4、代码实现如下:

 #从excel导入标准环境下的测试机拍摄的色卡数据以及理想状态色卡数据

workBook = xlrd.open_workbook( 'D:/develop_simulate_tool/CCM.xls' )

allSheetNames = workBook.sheet_names()



#读取相关数据

sheet1_content1 = workBook.sheet_by_name( 'original' )

sheet1_content2 = workBook.sheet_by_name( 'target' )

original = np.zeros((24, 3), np.float)

target = np.zeros((24, 3), np.float)

for i in range(sheet1_content1.nrows):

    for j in range(sheet1_content1.ncols):

        original[i, j] = sheet1_content1.cell_value(i, j)

        target[i, j] = sheet1_content2.cell_value(i, j)



#根据上述公式准备矩阵中的各项数值,最后计算结果保存在result数组中

result = np.zeros((3, 3), np.float)

for m in range(3):

    coe = np.zeros((4, 4), np.float)

    coe_x = np.zeros((4, 4), np.float)

    coe_y = np.zeros((4, 4), np.float)

    coe_z = np.zeros((4, 4), np.float)

    for i in range(sheet1_content1.nrows * 3 // 4):

        coe[0, 0] = coe[0, 0] + sheet1_content1.cell_value(i, 0) * sheet1_content1.cell_value(i, 0)    #R*R

 coe[0, 1] = coe[0, 1] + sheet1_content1.cell_value(i, 0) * sheet1_content1.cell_value(i, 1)    #R*G

 coe[0, 2] = coe[0, 2] + sheet1_content1.cell_value(i, 0) * sheet1_content1.cell_value(i, 2)    #R*B

 coe[1, 1] = coe[1, 1] + sheet1_content1.cell_value(i, 1) * sheet1_content1.cell_value(i, 1)    #G*G

 coe[1, 2] = coe[1, 2] + sheet1_content1.cell_value(i, 1) * sheet1_content1.cell_value(i, 2)    #B*G

 coe[2, 2] = coe[2, 2] + sheet1_content1.cell_value(i, 2) * sheet1_content1.cell_value(i, 2)    #G*G

 coe[1, 0] = coe[1, 0] + sheet1_content1.cell_value(i, 0) * sheet1_content2.cell_value(i, m)    #R*R1

 coe[2, 0] = coe[2, 0] + sheet1_content1.cell_value(i, 1) * sheet1_content2.cell_value(i, m)    #G*R1

 coe[2, 1] = coe[2, 1] + sheet1_content1.cell_value(i, 2) * sheet1_content2.cell_value(i, m)    #B*R1



 rr = coe[1, 0]

    gr = coe[2, 0]

    br = coe[2, 1]

    coe[0, 3] = 0.5

    coe[1, 0] = coe[0, 1]

    coe[1, 3] = 0.5

    coe[2, 0] = coe[0, 2]

    coe[2, 1] = coe[1, 2]

    coe[2, 3] = 0.5

    coe[3, 0] = 1

    coe[3, 1] = 1

    coe[3, 2] = 1



    coe_x = copy.deepcopy(coe)

    coe_x[0, 0] = rr

    coe_x[1, 0] = gr

    coe_x[2, 0] = br



    coe_y = copy.deepcopy(coe)

    coe_y[0, 1] = rr

    coe_y[1, 1] = gr

    coe_y[2, 1] = br



    coe_z = copy.deepcopy(coe)

    coe_z[0, 2] = rr

    coe_z[1, 2] = gr

    coe_z[2, 2] = br

    

    result[m, 0] = np.linalg.det(coe_x) / np.linalg.det(coe)

    result[m, 1] = np.linalg.det(coe_y) / np.linalg.det(coe)

    result[m, 2] = np.linalg.det(coe_z) / np.linalg.det(coe)

5、运行结果如下: