首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Opencv中利用色彩校正矩阵进行色彩校正

Opencv中利用色彩校正矩阵进行色彩校正
EN

Stack Overflow用户
提问于 2017-12-22 17:59:27
回答 2查看 7.4K关注 0票数 1

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

我拍摄了两张MacBeth颜色表的照片,并手动获取了样本颜色。(我知道我可以自动做到这一点,但在我这样做之前,我想确保付出的努力是值得的)。

下面是我的代码:

代码语言:javascript
复制
//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 imagetarget imageresult

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

显然有什么地方不对劲!结果图像看起来与输入图像一点也不像。我从here中获得了灵感,但opencv在矩阵乘法方面让事情变得更加困难(图像必须是浮点型的,顺序是cols×rows,而不是rows×cols)。我希望有一个结果,至少在上面的链接之一。至少输入和输出显示的是相同的东西。

我希望你能帮助我。我还没有发现使用opencv对此有多少支持。谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-22 21:48:09

多亏了@Catree,我设法获得了与其他answer类似的结果。

这是更正后的代码:

代码语言:javascript
复制
//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。我认为更好的颜色采样会提高输出效果。

票数 1
EN

Stack Overflow用户

发布于 2018-02-22 06:05:13

我复制了上面的结果(粉色背景),找到了一行错误并在这里报告(我不被允许评论),这样其他人就可以节省一些时间。

更换后

代码语言:javascript
复制
cv::Mat ccm = trgFloat.t() * srcFloat * (trgFloat.t() * trgFloat).inv();

代码语言:javascript
复制
cv::Mat ccm = (srcFloat.t() * srcFloat).inv()* srcFloat.t() * trgFloat;

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47939482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档