首页 文章

Opencv中的色彩校正与色彩校正矩阵

提问于
浏览
0

我有4个覆盆子pi相机,从不同的位置拍摄同一场景的照片 . 我想让它们在颜色方面尽可能相似 . 我尝试过一些直方图均衡而没有太大的成功 . 在互联网上搜索,颜色校正矩阵(CCM)出现了很多,所以我想在Opencv,C中试一试 . 我知道有关于色彩校正和色彩校准的整个理论,但是我想只尝试CCM并在Opencv中看到它的结果,而不仅仅是Matlab或其他软件 .

我拍了2张MacBeth颜色图表的照片并手动获取样品颜色 . (我知道我可以自动执行此操作,但在此之前我想确保值得付出努力) .

这是我的代码:

//input images
CameraInfo c1, c2;
cv::Mat inputImgCam1 = cv::imread("color_c1.jpeg");
cv::Mat inputImgCam2 = cv::imread("color_c3.jpeg");

//convert them to float for multiplication
cv::Mat3f cam1F, cam2F;
inputImgCam1.convertTo(cam1F, CV_32FC3, 1 / 255.0);
inputImgCam2.convertTo(cam2F, CV_32FC3, 1 / 255.0);

//take manually the source and target colours
c1.Initialize(inputImgCam1, cv::Size(14, 8), false);
c2.Initialize(inputImgCam2, cv::Size(14, 8), false);

std::vector<cv::Vec3b> colors1 = c1.GetColors();
std::vector<cv::Vec3b> colors2 = c2.GetColors();

//convert them to Mat - 3 ch, 1 col, 4 rows
cv::Mat source(colors1);// = Convert(colors1);
cv::Mat target(colors2);// = Convert(colors2);

//reshape them - 1 ch, 3 cols, 4 rows
cv::Mat src = source.reshape(1, source.size().height);
cv::Mat trg = target.reshape(1, target.size().height);

//convert them to float
cv::Mat srcFloat, trgFloat;
src.convertTo(srcFloat, CV_32FC1, 1 / 255.0);
trg.convertTo(trgFloat, CV_32FC1, 1 / 255.0);

std::cout << srcFloat.size() << " " << srcFloat.t().size() << " " << trgFloat.size() << " " << trgFloat.t().size();

//compute the colour correction matrix: A*M = B => M = (A' * A).inv() * A' * B
cv::Mat ccm = (trgFloat.t() * trgFloat).inv() * trgFloat.t() * srcFloat;

//reshape the source image to 1 ch, width * height cols, 3 rows
cv::Mat cam1Reshaped = cam1F.reshape(1, 3);

//perform correction
cv::Mat result = cam1Reshaped.t() * ccm;

//reshape back, 3 ch, width cols, height rows
cv::Mat resultR = result.reshape(3, inputImgCam1.size().height);

//convert to uchar for saving
cv::Mat out;
resultR.convertTo(out, CV_8UC3, 255);

cv::imwrite("ccm_c1.jpg", out);

以下是MacBeth颜色图表的图像:source image; target image; result

我的CCM看起来像这样:ccm values

显然有些不对劲!结果图像看起来与输入图像不同 . 我从here中获取灵感,但是当涉及矩阵乘法时,opencv会使事情变得更加困难(图像必须是浮点数,顺序是cols x行,而不是行x cols ..) . 我希望得到一个至少与上面链接中的结果相同的结果 . 至少输入和输出显示相同的东西 .

我希望你能帮助我 . 使用opencv我没有找到太多的支持..谢谢!

2 回答

  • 0

    我复制了上面的结果(粉红色的背景),发现了一行bug并在这里报告(我不允许发表评论),以便其他人可以节省一些时间 .

    改变之后

    cv::Mat ccm = trgFloat.t() * srcFloat * (trgFloat.t() * trgFloat).inv();
    

    cv::Mat ccm = (srcFloat.t() * srcFloat).inv()* srcFloat.t() * trgFloat;
    

    我得到了完美的结果图像 .

  • 1

    感谢@Catree,我设法获得了与其他answer类似的结果 .

    这是更正后的代码:

    //input images
    CameraInfo c1, c2;
    cv::Mat inputImgCam1 = cv::imread("color_c1.jpeg");
    cv::Mat inputImgCam2 = cv::imread("color_c3.jpeg");
    
    //convert them to float for multiplication
    cv::Mat3f cam1F, cam2F;
    inputImgCam1.convertTo(cam1F, CV_32FC3, 1 / 255.0);
    inputImgCam2.convertTo(cam2F, CV_32FC3, 1 / 255.0);
    
    //take manually the source and target colours
    c1.Initialize(inputImgCam1, cv::Size(14, 8), false);
    c2.Initialize(inputImgCam2, cv::Size(14, 8), false);
    
    std::vector<cv::Vec3b> colors1 = c1.GetColors();
    std::vector<cv::Vec3b> colors2 = c2.GetColors();
    
    //convert them to Mat - 3 ch, 4 rows, 1 col
    cv::Mat source(colors1);// = Convert(colors1);
    cv::Mat target(colors2);// = Convert(colors2);
    
    //reshape them - 1 ch, 4 rows, 3 cols
    cv::Mat src = source.reshape(1, source.size().height);
    cv::Mat trg = target.reshape(1, target.size().height);
    
    //convert them to float
    cv::Mat srcFloat, trgFloat;
    src.convertTo(srcFloat, CV_32FC1, 1 / 255.0);
    trg.convertTo(trgFloat, CV_32FC1, 1 / 255.0);
    
    std::cout << srcFloat.size() << " " << srcFloat.t().size() << " " << trgFloat.size() << " " << trgFloat.t().size();
    
    //compute the colour correction matrix: A*M = B => M = (A' * A).inv() * A' * B
    cv::Mat ccm = trgFloat.t() * srcFloat * (trgFloat.t() * trgFloat).inv();
    
    //reshape the source image to 1 ch, width * height rows, 3 cols
    cv::Mat cam1Reshaped = cam1F.reshape(1, cam1F.size().height * cam1F.size().width);
    
    //perform correction
    cv::Mat result = cam1Reshaped * ccm;
    
    //reshape back, 3 ch, height rows, width cols
    cv::Mat resultR = result.reshape(3, inputImgCam1.size().height);
    
    //convert to uchar for saving
    cv::Mat out;
    resultR.convertTo(out, CV_8UC3, 255);
    
    cv::imwrite("ccm_c1.jpg", out);
    

    以下是乘法后的CCMresult . 我认为更好的颜色采样将改善输出 .

相关问题