最近我得到了一个项目,我必须从给定的图像中提取脸部(脸部+头发)。
我正在通过以下方式解决这个问题。
当face_image包含平滑背景时,算法 grabCut 它运行良好但是当face_image的背景很复杂时,算法 grabCut 也会提取背景的某些部分。处理过的图像。
以下是我得到的结果的快照。
以下是 grabCut 的代码:
public void extractFace(Mat image, String fileNameWithCompletePath,
int xOne, int xTwo, int yOne, int yTwo) throws CvException {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Rect rectangle = new Rect(xOne, yOne, xTwo, yTwo);
Mat result = new Mat();
Mat bgdModel = new Mat();
Mat fgdModel = new Mat();
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(3));
Imgproc.grabCut(image, result, rectangle, bgdModel, fgdModel, 8, Imgproc.GC_INIT_WITH_RECT);
Core.compare(result, source, result, Core.CMP_EQ);
Mat foreground = new Mat(image.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
image.copyTo(foreground, result);
Imgcodecs.imwrite(fileNameWithCompletePath, foreground);
}
如何提高grabCut算法的性能,使其只检测给定图像中的脸部和头发?
答案 0 :(得分:8)
你应该能够通过“帮助”grabCut
了解前景和背景来做到这一点。有python tutorial显示如何通过选择前景和背景手动完成此操作。
要自动执行此操作,您需要找到以编程方式检测前景和背景。前景主要由头发和皮肤组成,因此您需要检测它们。
皮肤 - 有关于如何执行此操作的several篇论文和blogs。其中一些pretty simple和this OpenCV tutorial也可能有所帮助。我发现平淡的色调/饱和度让我走得很远。
头发 - 此is trickier但definitely仍为doable。如果事实证明工作太多,你或许可以使用皮肤和背景。
背景 - 您应该能够使用range()
查找图像中紫色,绿色和蓝色的内容。你肯定知道这些东西不是皮肤或头发,因此是背景的一部分。
使用阈值创建最可能是皮肤,头发和背景的区域的蒙版。然后,您可以将其用作bgdModel
和fgdModel
(或皮肤和头发蒙版),而不是Mat()
。
对不起,这是如此高级别。我希望它有所帮助!
答案 1 :(得分:2)
另一种方法,因为你已经检测到面部,只需选择一个更好的初始掩模来初始化GrabCut - 例如通过使用椭圆而不是矩形。
创建一个面具:
a)创建与输入图像大小相同的新黑色图像
b)绘制一个白色填充的椭圆,其高度,宽度,顶部和左侧位置与面部矩形相同
使用GC_INIT_WITH_MASK
而不是GC_INIT_WITH_RECT
调用GrabCut:
Imgproc.grabCut(image, mask, rectangle, bgdModel, fgdModel, 8, Imgproc.GC_INIT_WITH_MASK);
这会使用更好的模型初始化前景,因为面部比椭圆形更像椭圆形,所以它应该包含较少的背景。
答案 2 :(得分:1)
我建议"玩"使用矩形坐标(int xOne, int xTwo, int yOne, int yTwo)
。使用您的代码和这些坐标1,400,30,400我能够避开背景。 (我试图发布我成功裁剪的图片但我需要至少10个声望才能这样做)
答案 3 :(得分:-6)
可以对任何Java例程进行的最佳优化是转换为本机语言。