zoukankan      html  css  js  c++  java
  • 在OpenCV中使用色彩校正

    以下文章来源于OpenCV团队 ,作者华为开源能力中心

    OpenCV团队
    OpenCV团队

    OpenCV在中国的开发团队,非营利目的,致力于OpenCV的开发、维护和推广工作,也即提升OpenCV的软件质量和让更多的人使用OpenCV加快开发效率。

    编者按:今年OpenCV收到了很多来自中国的贡献,比如DNN的ARM后端Tengine、基于深度学习的文本检测识别、对RISC-V的支持等新功能。在即将发布的4.5.1版本,华为开源能力中心的工程师又为OpenCV贡献了一个重要功能 -- 色彩校正。

    作者:张金衡、单晨琪、王龙步 (华为开源能力中心)

    本文将介绍CV领域一个重要应用 -- 色彩校正。该模块收录在opencv_contrib/modules/mcc 模块中,由 PR #2671 贡献。

    色彩校正简介

    一般来说,由于拍摄设备、光线环境等客观因素,或者拍摄者喜好等主观因素影响,人们拍摄到的图片与真实物体的色彩会有一定的偏差。同一个事物在不同的环境下得到的图片颜色是不同的,这样就对接下来进行的图片处理、比较造成了一定影响。色彩校正技术就是为解决这个问题而提出的。

    色彩校正(color calibration),通俗来说,就是使图片还原事物本身的颜色,也就是尽可能接近拍摄时人眼看所看到的事物。如今,色彩校正已经不仅在摄影中使用,而是在影视制作、游戏、医疗、建筑等各行各业中广泛使用。

    图片

    需要注意的是,色彩校正与调色是不同的概念。前者是在图片中使事物的色彩重现,必须遵循一定的标准,不具有随意性,需要一些技术手段实现;后者则是人们对图片色彩的主观喜好而为,不需要遵循任何标准,具有随意性,是艺术性的实现。

    从技术上来说,色彩校正[1]的目的是调整输入输出设备的颜色响应到已知状态。被校准的设备有时被称为校准源 ; 用作标准的色彩空间有时也称为校准目标。由于输入输出设备的制造工艺等,其通道响应存在非线性失真,为了校正该设备输出的图片,必须将其捕捉到的色彩与实际色彩进行校正。

    色彩校正通常分成2个步骤:

    • 一是先将输入色彩空间线性化为与亮度成正比。这个过程是不适定问题[2],因此有许多不同的解决方案;

    • 二是做线性变换,把色彩空间变成绝对RGB色彩空间。所用的线性变换的矩阵称为色彩变换矩阵(color correction matrix,CCM),也称为CCM矩阵。CCM矩阵需要通过非线性优化来求解。

    通常使用的校准色彩叫做色卡(colorchecker),最著名的是麦克白色卡(Macbeth ColorChecker)。色卡提供色彩校正中的参考色,所有的颜色都已经被标定。最流行的标准色卡是 Macbeth色卡,如下图所示。它包括4*6个色块,其中,最后一行的色块是灰色色块,可以用于灰度线性化或是白平衡。

    图片

    Macbeth色卡

    色彩校正的详细理论可查阅以下链接:

    https://github.com/riskiest/color_calibration/tree/v4/doc/pdf/English/Algorithm 

    在OpenCV中使用色彩校正

     

    在对 OpenCV 进行 building 时,运行以下命令来 build 所有 opencv_contrib 模块

    cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/

    或者仅 build 色彩校正所在的 mcc 模块

    cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/mcc

    若使用 cmake-gui(CMake的GUI版本)进行构建,需要检查确认包含 mcc 模块。

    opencv_contrib/modules/mcc 模块主要包含两个部分,

    • 其一是 color checker detector 模型,具体说明可参考

      https://github.com/opencv/opencv_contrib/blob/master/modules/mcc/tutorials/basic_chart_detection/basic_chart_detection.markdown;

    • 其二为本文主要介绍的色彩校正模块。

    色彩校正模块的核心类 -- ColorCorrectionModel:

    声明:

    opencv_contrib/modules/mcc/include/opencv2/mcc/ccm.hpp 

    定义:

    opencv_contrib/modules/mcc/src/ccm.cpp

    ColorCorrectionModel 的参数说明如下:

        src :
                检测到 ColorChecker 色块的颜色(颜色类型是RGB而不是BGR,颜色值在[0, 1]范围内);
        constcolor :
                内置色卡,包括Macbeth、Vinyl、DigitalSG
        Mat colors :
               参考颜色值(颜色值在[0, 1]范围内);
        ref_cs :
               对应颜色值的色彩空间。如果颜色类型是RGB类型,则颜色格式是RGB而不是BGR;
        支持的色彩空间有:RGB色彩空间(如COLOR_SPACE_sRGB)、线性RGB色彩空间(如COLOR_SPACE_sRGBL)、非RGB色彩空间(如COLOR_SPACE_Lab_D50_2)等。

    在本文中,以 samples/color_correction_model.cpp 的示例作为参考,提取关键步骤代码形成如下程序:

    #include <opencv2/imgcodecs.hpp>
    #include <opencv2/mcc.hpp>
    #include <iostream>
    using namespace std;
    using namespace cv;
    using namespace mcc;
    using namespace ccm;
    int main(int argc, char *argv[])
    {
       // [get_messages_of_image]:获取图像消息
       string filepath = "input.png"; // 输入图片路径
       Mat image = imread(filepath, IMREAD_COLOR);
       Mat imageCopy = image.clone();
       Ptr<CCheckerDetector> detector = CCheckerDetector::create();
       // [get_color_checker]:准备ColorChecker检测
       vector<Ptr<mcc::CChecker>> checkers = detector->getListColorChecker();
       for (Ptr<mcc::CChecker> checker : checkers)
       {
           // [create]:创建CCheckerDetector对象,并使用getListColorChecker函数获取ColorChecker信息。
           Ptr<CCheckerDraw> cdraw = CCheckerDraw::create(checker);
           cdraw->draw(image);
           Mat chartsRGB = checker->getChartsRGB();
           Mat src = chartsRGB.col(1).clone().reshape(3, chartsRGB.rows/3);
           src /= 255.0;
           // [get_ccm_Matrix]:对于每个ColorChecker,都可以计算一个ccm矩阵以进行颜色校正。Model1是ColorCorrectionModel类的对象,可以根据需要来修改参数以获得最佳色彩校正效果。
           ColorCorrectionModel model1(src, COLORCHECKER_Vinyl);
           model1.run();
           Mat ccm = model1.getCCM();
           std::cout<<"ccm "<<ccm<<std::endl;
           double loss = model1.getLoss();
           std::cout<<"loss "<<loss<<std::endl;

           // [make_color_correction]:成员函数infer_image用于使用ccm矩阵进行校正校正。
           Mat img_;
           cvtColor(image, img_, COLOR_BGR2RGB);
           img_.convertTo(img_, CV_64F);
           const int inp_size = 255;
           const int out_size = 255;
           img_ = img_ / inp_size;
           Mat calibratedImage= model1.infer(img_);
           Mat out_ = calibratedImage * out_size;
           // [Save_calibrated_image]:保存已校准的图像。
           out_.convertTo(out_, CV_8UC3);
           Mat img_out = min(max(out_, 0), out_size);
           Mat out_img;
           cvtColor(img_out, out_img, COLOR_RGB2BGR);
           imwrite("output.png",out_img);
       }

       return 0;
    }

    运行上述代码所在文件,即可完成对于 input.png 图片的色彩校正,校正后的图片为 output.png。

    下面展示一组通过本文介绍的色彩校正模块校正前后示例图。通过示例可以看出,原图拍摄色彩较暗,色卡颜色未显示其本身颜色,地板颜色偏暗,毛巾颜色偏蓝;校正后的图片则很好地还原了色卡和物体本身的颜色。

    图片

    参考文献

    1. https://en.wikipedia.org/wiki/Color_correction

    2. Bianco, S., Bruna, A.R., Naccari, F., Schettini, R.: Color correction pipeline optimization for digital cameras. J. Electron. Imaging 22(2), 023014:1–023014:10 (2013)

  • 相关阅读:
    POJ 1984
    剑指offer 7. 斐波那契数列 & leetcode 剑指 Offer 10- I. 斐波那契数列
    剑指offer 60. 把二叉树打印成多行
    数据库的范式(建表的原则)
    剑指offer 59. 按之字形顺序打印二叉树
    力扣142.环形链表II & 剑指offer 55. 链表中环的入口结点
    GET 和 POST 的区别
    理解Cookie和Session的区别及使用
    基本排序算法代码实现,以及使用场景推荐
    The Castle OpenJ_Bailian
  • 原文地址:https://www.cnblogs.com/shuimuqingyang/p/14118617.html
Copyright © 2011-2022 走看看