使用颜色校正矩阵中的OpenCV颜色校正
Color correction in Opencv with color correction matrix
我有4个Raspberry Pi摄像机,从不同位置拍摄同一场景的照片。我想让它们在颜色方面尽可能相似。我尝试了一些直方图均衡,但没有太大的成功。在Internet上搜索,色彩校正矩阵(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);
这是麦克白颜色图的图像:源图像;目标图像;结果
我的CCM看起来像这样:CCM值
显然有什么问题!结果图像看起来不像输入图像。我从这里汲取了灵感,但是OpenCV在矩阵乘法方面会使事情变得更加困难(图像必须是浮动,订单为cols x行,而不是行x cols ..)。我想至少作为上面链接中的结果。至少输入和输出显示相同的内容。
我希望你能帮助我。我没有使用OpenCV找到太多支持。谢谢!
我在结果上复制了(粉红色的背景),发现了一行错误,并在此处报告(我不允许发表评论),以便其他人可以节省一些时间。
更改后
cv::Mat ccm = trgFloat.t() * srcFloat * (trgFloat.t() * trgFloat).inv();
to
cv::Mat ccm = (srcFloat.t() * srcFloat).inv()* srcFloat.t() * trgFloat;
我得到了完美的结果图像。
多亏了@catree,我设法获得了与其他答案相似的结果。
这是校正的代码:
//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);
,这是乘法后的CCM和结果。我认为更好的颜色采样将改善输出。
相关文章:
- 如何使用OpenCV同时显示"深度"和"颜色"视频图像
- 访问和更改基于另一个图像的像素颜色-opencv c++
- OpenCV 访问像素的颜色值
- 使用 OpenCV 更改图像的颜色
- 如何使用 openCV 更改图像每个像素的颜色
- OPENCV在实时摄像机供稿中更改颜色
- OpenCV将一种颜色转换为任何其他颜色
- 使用颜色校正矩阵中的OpenCV颜色校正
- 将RGB颜色图像转换为OpenCV C 中的索引颜色图像类型
- RGB颜色图像直方图使用OpenCV C 进行对比度拉伸
- 如何在OpenCV中实现颜色分割以及前景检测
- 将OpenCV中的像素颜色映射到预定的颜色列表中
- 在OpenCV中绘制带有梯度颜色的线
- 根据OPENCV中一个通道中的一个值,查找最大颜色像素
- 如何在opencv中为图像添加边框,边框颜色必须与图像颜色相同
- 检测 OpenCV 中"average"的颜色范围
- 将颜色图像转换为OpenCV中的灰度问题
- opencv c 中的蒙版颜色图像
- openCV中的颜色检测-像素检查问题
- 反转颜色 OpenCV Java API