使用C ++和OpenCV将RGB转换为LMS模型

时间:2018-01-26 20:34:21

标签: c++ opencv image-processing rgb

我正在尝试将带有RGB色彩空间的图像转换为LMS模型。我从this paper得到的变换矩阵值。我读了这篇Question : RGB to LMS color space conversion with OpenCV,我们提到了同一篇论文,我已经按照答案中的所有说明进行了阅读。

为了确保我的代码运行良好,我将原始RGB转换为LMS,然后使用第一个矩阵的逆矩阵将LMS转换回RGB,并查看输出是否与原始图像匹配。 enter image description here

但输出与原始图像源不匹配。 这是我的代码: 的 [增订]

void test(const Mat &original, Mat &pic, int rows, int cols)
{
    for (int i = 0; i < original.rows; i++) {
        for (int j = 0; j < original.cols; j++) {
        //RGB into LMS
            pic.at<Vec3b>(i, j)[0] =    original.at<Vec3b>(i, j)[0] * 1.4671 + 
                                        original.at<Vec3b>(i, j)[1] * 0.1843 + 
                                        original.at<Vec3b>(i, j)[2] * 0.003;   //B-->S
            pic.at<Vec3b>(i, j)[1] =    original.at<Vec3b>(i, j)[0] * 3.8671 + 
                                        original.at<Vec3b>(i, j)[1] * 27.1554 + 
                                        original.at<Vec3b>(i, j)[2] * 3.4557;   //G-->M
            pic.at<Vec3b>(i, j)[2] =    original.at<Vec3b>(i, j)[0] * 4.1194 + 
                                        original.at<Vec3b>(i, j)[1] * 43.5161 + 
                                        original.at<Vec3b>(i, j)[2] * 17.8824;  //R-->L


            //LMS back into RGB
            pic.at<Vec3b>(i, j)[0] = pic.at<Vec3b>(i, j)[0] * 0.6935 + pic.at<Vec3b>(i, j)[1] * -0.0041 + pic.at<Vec3b>(i, j)[2] * -0.0004;   //S-->B
            pic.at<Vec3b>(i, j)[1] = pic.at<Vec3b>(i, j)[0] * -0.1136 + pic.at<Vec3b>(i, j)[1] * 0.0540 + pic.at<Vec3b>(i, j)[2] * -0.0102;   //M-->G
            pic.at<Vec3b>(i, j)[2] = pic.at<Vec3b>(i, j)[0] * 0.1167 + pic.at<Vec3b>(i, j)[1] * -0.1305 + pic.at<Vec3b>(i, j)[2] * 0.0809;   //L-->R

        }
    }
}

主要

int main(int argv, char** argc){
Mat original= imread("original.png", CV_LOAD_IMAGE_COLOR);
int rows = original.rows;
int cols = original.cols;

Mat pic(rows, cols, CV_8UC3);

test(original, pic, rows, cols);
imwrite("pic.png", pic);
}

有什么建议吗?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

需要注意的事项:

  1. OpenCV按照BGR的顺序订购频道,而不是RGB。
  2. 新频道的值是前一频道所有3个频道的加权值。
  3. 因此,您的转化不正确。请考虑以下用于获取通道S的代码

    //B-->S    
    pic.at<Vec3b>(i, j)[0] = original.at<Vec3b>(i, j)[0] * (0.0030, 0.1843, 1.4671);
    

    应该是

    pic.at<Vec3b>(i, j)[0] = original.at<Vec3b>(i, j)[0] * 1.4671 + 
                             original.at<Vec3b>(i, j)[1] * 0.1843 + 
                             original.at<Vec3b>(i, j)[2] * 0.03
    

    其他频道(即L和M)的转换也应相应更改。

    通常,如果cvtColor无法执行颜色转换,则应考虑使用矩阵乘法执行颜色转换。

    即,将转换矩阵存储为Mat个对象,然后将其与图像的Mat对象相乘,以获得所需的结果。这将比使用for循环执行转换快得多,因为OpenCV可能会使用场景后面的优化BLAS例程来执行乘法。此外,代码将更紧凑和干净。

    this post中的答案应该让您了解如何实现这一点。

    <强>已更新

    在您的更新之后,您的错误是当您从LSM转换回BGR时,pic.at<Vec3b>(i, j)[0]会存储B通道的像素值,因此它不再包含L通道的值。然后,在计算G和R通道的值时继续使用此值。

    同样,当您计算R频道的值时,pic.at<Vec3b>(i, j)[0]pic.at<Vec3b>(i, j)[1]不再是S和M频道的值。

    请注意,BGR图像中的通道是所有3个LMS通道的值的混合,反之亦然。

    您应该为每个新输出(LMS图像和最终BGR图像)创建一个新矩阵并相应地存储值。这应该可以解决你的错误。

    我在帖子中提到了-0.0003678,因为这是该条目的更准确的值。您可以通过反转原始转换矩阵来获得此值。