我尝试使用以下功能将图像颜色缩小为某些预定义颜色:
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);
任何人都可以解释问题所在吗?
答案 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];
}
这种方式也更好。最后一部分只是一个建议,你当前的代码没有任何问题,只是更难理解外界的观众。