【发布时间】:2017-03-02 12:48:22
【问题描述】:
我正在努力寻找礼服的主要颜色。
1) 第一步是去除背景。我使用提到的解决方案 here 做到了这一点。它完美地工作并使背景变黑。
2) 现在,根据第一步的结果,我正在尝试使用提到的解决方案here 找到主色。但我将black(背景)作为主要颜色之一。
如何忽略第 2 步中的背景像素?
【问题讨论】:
-
如果您认为他们有帮助,请考虑接受最佳答案。
我正在努力寻找礼服的主要颜色。
1) 第一步是去除背景。我使用提到的解决方案 here 做到了这一点。它完美地工作并使背景变黑。
2) 现在,根据第一步的结果,我正在尝试使用提到的解决方案here 找到主色。但我将black(背景)作为主要颜色之一。
如何忽略第 2 步中的背景像素?
【问题讨论】:
根据具体情况,您可以找到感兴趣区域的边界矩形。如果颜色像素的数量远高于边界矩形内的黑色像素数量,则不应检测到黑色作为主色。
在面具的二进制图像上调用findContours(binaryMask)。确保你找到了你正在寻找的轮廓。如果没有,请过滤它们以获得最适合应用程序的一个。然后在轮廓上调用boundingRect(cnt)。然后使用该矩形裁剪图像并运行您的函数。如果这还不够,请尝试minAreaRect(cnt),但裁剪有点棘手:see this answer。
如果这不起作用,我可能会选择“愚蠢”的解决方案,将遮罩的颜色更改为 99% 不会出现在连衣裙上的颜色,然后 - 知道它的确切 RGB 值- 从结果中过滤掉。
下次请记得提供您的案例图片,这样答案可能会更准确。
【讨论】:
一种简单的方法是简单地将黑色作为主要颜色丢弃。比你真正想要的多抓一个集群,忽略黑色。如果黑色可能真的是主要颜色,请使用不同的背景颜色重复操作并丢弃它;比较结果。这会很慢,但做起来很简单。
或者,您只能从前景中的像素中采样。从您的前景提取方法中,您应该有一个二进制的黑白前景/背景蒙版。如果您仅从蒙版的白色区域采样,则应仅考虑这些颜色。
我有一个粗略的 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);
您的主色将存储在中心行中,您可以在其中随心所欲地使用它们。
【讨论】:
删除背景。这为您提供了二值图像 - 前景和背景像素。现在进行形态关闭以关闭前景图像中的小孔并通常清理轮廓。最后再次替换像素以获得彩色前景图像。
【讨论】: