我试图找到礼服中的主色调。
1)第一步是删除背景。我使用提到的here解决方案做到了这一点。它完美地工作并使背景变黑。
2)现在有了第一步的结果,我试图使用提到的here解决方案找到主色。但我得到print_r(array_column($data,X));
(背景)作为主色之一。
如何忽略步骤2中的背景像素?
答案 0 :(得分:2)
根据具体情况,您可以找到您感兴趣的区域的边界矩形。如果颜色像素的数量远远高于该边界矩形内的黑色像素数,则黑色不应该是#39 ; t被检测为主色。
在面具的二进制图像上调用findContours(binaryMask)
。确保您找到了您正在寻找的轮廓。如果没有,请过滤它们以获得应用程序的最佳效果。然后在轮廓上调用boundingRect(cnt)
。然后使用该矩形裁剪图像并运行您的功能。如果这不够,请尝试minAreaRect(cnt)
,但裁剪有点棘手:see this answer。
如果这不起作用,我可能会选择" dumb"解决方案,通过将面具的颜色更改为99%不会出现在衣服上的颜色然后 - 知道它的确切RGB值 - 从结果中过滤掉它。
下次请记得提供案例图片,以便答案更准确。
答案 1 :(得分:1)
一种简单的方法就是简单地将黑色作为主色调。抓住一个比你真正想要的集群,忽略黑色。如果黑色可能真的是主色,请用不同的背景颜色重复操作并丢弃;比较结果。这会很慢,但很容易做到。
或者,您只能从前景中的像素进行采样。从前景提取方法,您应该有一个二进制黑白前景/背景蒙版。如果您只从蒙版的白色区域进行采样,则只应考虑这些颜色。
我有一个粗略的C ++实现,但它几乎肯定不是最有效的。也许这是你可以开始工作的开始?
Mat src; //Your source image
Mat mask; //Your black & white foreground/background image
Mat samples(src.rows * src.cols, 3, CV_32F);
//Set up samples with only foreground pixels
for (int y = 0; y < src.rows; y++) {
for (int x = 0; x < src.cols; x++) {
if (mask.at<uchar>(y, x) == 255) {
for (int z = 0; z < 3; z++) {
samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y, x)[z];
}
}
}
}
int clusterNo = 3;
int attempts = 5;
Mat labels;
Mat centers;
kmeans(samples, clusterNo, labels, TermCriteria(), attempts, KMEANS_RANDOM_CENTERS, centers);
您的主色将存储在中心行中,您可以在其中执行所需的操作。
答案 2 :(得分:0)
删除背景。这给你一个二进制图像 - 前景和背景像素。现在进行形态学关闭以关闭前景图像中的小孔并且通常清理轮廓。最后再次替换像素以获得彩色前景图像。