简体   繁体   English

使用颜色校正矩阵在 Opencv 中进行颜色校正

[英]Color correction in Opencv with color correction matrix

I have 4 raspberry pi cameras which takes photos of the same scene, from different positions.我有 4 个树莓派相机,它们从不同的位置拍摄同一场景的照片。 I want to make them as similar as possible in terms of colors.我想让它们在颜色方面尽可能相似。 I've tried some histogram equalization without much success.我尝试了一些直方图均衡化,但没有太大成功。 Searching on the internet, color correction matrix (CCM) came up a lot so I thought to give it a try in Opencv, C++.在互联网上搜索,颜色校正矩阵(CCM)出现了很多,所以我想在Opencv,C++中尝试一下。 I know there is an entire theory about colour correction and colour calibration, however I want to try only CCM and see its results in Opencv too, not just Matlab or other software.我知道有一个关于颜色校正和颜色校准的完整理论,但是我只想尝试 CCM 并在 Opencv 中查看其结果,而不仅仅是 Matlab 或其他软件。

I took 2 photos of a MacBeth color chart and manually get the samples colors.我拍了 2 张 MacBeth 颜色图表的照片并手动获取样本颜色。 (I know I can do this automatically, but before I do this I want to make sure is worth the effort). (我知道我可以自动执行此操作,但在执行此操作之前,我想确保值得付出努力)。

Here is my code:这是我的代码:

//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);

And here are the images of a MacBeth color chart: source image ;这是 MacBeth 颜色图表的图像源图像 target image ;目标图像 result结果

My CCM looks something like this: ccm values我的 CCM 看起来像这样: ccm values

Clearly something is wrong!很明显有问题! The result image doesn't looks nothing like the input images.结果图像看起来不像输入图像。 I took inspiration from here , but opencv kind of makes things more difficult when it comes to matrix multiplication (the images must be float, the order is cols x rows, not rows x cols..).我从这里获得灵感,但是当涉及到矩阵乘法时,opencv 使事情变得更加困难(图像必须是浮点数,顺序是列 x 行,而不是行 x 列......)。 I want to have a result at least as the one in the link above.我希望至少得到上面链接中的结果。 At least the input and output display the same thing.至少输入和输出显示相同的东西。

I hope you can help me.我希望你能帮助我。 I haven't found much support with this using opencv.. Thanks!我没有找到太多支持使用 opencv ..谢谢!

I reproduced above result(pinkish background), found one line of bug and reported here (I was not allow to comment) so that other people can save some time.我转载了上面的结果(粉红色背景),发现了一行错误并在这里报告(我不允许发表评论),以便其他人可以节省一些时间。

After changing改变后

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

to

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

I got perfect result image.我得到了完美的结果图像。

Thanks to @Catree I've managed to obtain a similar result to the other answer .感谢@Catree,我设法获得了与其他答案类似的结果。

This is the corrected code:这是更正后的代码:

//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);

And here are the CCM and the result after the multiplication.这是CCM和乘法后的结果 I think a better sampling of the colours will improve the output.我认为更好的颜色采样会提高输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM