OpenCV:实验室颜色量化为预定义颜色

时间:2017-10-26 14:18:16

标签: c++ opencv

我尝试使用以下功能将图像颜色缩小为某些预定义颜色:

void quantize_img(cv::Mat &lab_img, std::vector<cv::Scalar> &lab_colors) {
    float min_dist, dist;
    int min_idx;
    for (int i = 0; i < lab_img.rows*lab_img.cols * 3; i += lab_img.cols * 3) {
        for (int j = 0; j < lab_img.cols * 3; j += 3) {
            min_dist = FLT_MAX;
            uchar &l = *(lab_img.data + i + j + 0);
            uchar &a = *(lab_img.data + i + j + 1);
            uchar &b = *(lab_img.data + i + j + 2);
            for (int k = 0; k < lab_colors.size(); k++) {
                double &lc = lab_colors[k](0);
                double &ac = lab_colors[k](1);
                double &bc = lab_colors[k](2);
                dist = (l - lc)*(l - lc)+(a - ac)*(a - ac)+(b - bc)*(b - bc);
                if (min_dist > dist) {
                    min_dist = dist;
                    min_idx = k;
                }
            }
            l = lab_colors[min_idx](0);
            a = lab_colors[min_idx](1);
            b = lab_colors[min_idx](2);
        }
    }
}

然而它似乎无法正常工作!例如,以下输入的输出看起来很棒!

if (!(src = imread("im0.png")).data)
    return -1;
cvtColor(src, lab, COLOR_BGR2Lab);
std::vector<cv::Scalar> lab_color_plate_({
    Scalar(100,  0 ,   0),  //white
    Scalar(50 ,  0 ,   0),  //gray
    Scalar(0  ,  0 ,   0),  //black
    Scalar(50 , 127, 127),  //red
    Scalar(50 ,-128, 127),  //green
    Scalar(50 , 127,-128),  //violet
    Scalar(50 ,-128,-128),  //blue
    Scalar(68 , 46 ,  75),  //orange
    Scalar(100,-16 ,  93)   //yellow
});
//convert from conventional Lab to OpenCV Lab
for (int k = 0; k < lab_color_plate_.size(); k++) {
    lab_color_plate_[k](0) *= 255.0 / 100.0;
    lab_color_plate_[k](1) += 128;
    lab_color_plate_[k](2) += 128;
}
quantize_img(lab, lab_color_plate_);
cvtColor(lab, lab, CV_Lab2BGR);
imwrite("im0_lab.png", lab);

输入图片: Input image

输出图像 enter image description here

任何人都可以解释问题所在吗?

1 个答案:

答案 0 :(得分:1)

检查算法后,我注意到算法是正确的100%,问题是你的色彩空间....让我们采取一种“错误地”改变的颜色,就像树上的绿色一样。

在GIMP中使用颜色选择器工具,它告诉您至少有一个使用的绿色是RGB(111,139,80)。当它转换为LAB时,你得到(54.4,-20.7,28.3)。到绿色的距离是(通过你的公式)21274.34,灰色的距离是1248.74 ...因此它将选择灰色而不是绿色,即使它是绿色。

LAB中的许多值都可以生成绿色值。您可以在this webpage中测试颜色范围。我建议你使用HSV或HSL并仅比较H值的H值。其他值仅改变绿色调,但Hue中的小范围确定它是绿色。这可能会给您更准确的结果。

作为改进代码的一些建议,请使用Vec3b和cv :: Mat这样的函数:

for (int i = 0; i < lab_img.rows; ++i) {
    for (int j = 0; j < lab_img.cols; ++j) {
        Vec3b pixel = lab_img.at<Vec3b>(i,j);
    }
}

这样代码更具可读性,一些检查在调试模式下完成。

另一种方法是做一个循环,因为你不关心索引

 auto currentData = reinterpret_cast<Vec3b*>(lab_img.data); 
 for (size_t i = 0; i < lab_img.rows*lab_img.cols; i++)
 {
     auto& pixel = currentData[i];
 }

这种方式也更好。最后一部分只是一个建议,你当前的代码没有任何问题,只是更难理解外界的观众。