在opencv-java中优化GrabCut的性能

时间:2015-06-16 15:47:26

标签: java algorithm opencv

最近我得到了一个项目,我必须从给定的图像中提取脸部(脸部+头发)。

我正在通过以下方式解决这个问题。

  1. 我从给定的图像中提取面部位置。 [我正在变成一个矩形]
  2. 我正在提取该矩形并将其放置在与输入图像相同尺寸的另一个图像中。[face_image]
  3. 我在第2步的face_image上应用 grabCut 算法。
  4. 当face_image包含平滑背景时,算法 grabCut 它运行良好但是当face_image的背景很复杂时,算法 grabCut 也会提取背景的某些部分。处理过的图像。

    以下是我得到的结果的快照。

    results of each step

    以下是 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算法的性能,使其只检测给定图像中的脸部和头发?

4 个答案:

答案 0 :(得分:8)

你应该能够通过“帮助”grabCut了解前景和背景来做到这一点。有python tutorial显示如何通过选择前景和背景手动完成此操作。

要自动执行此操作,您需要找到以编程方式检测前景和背景。前景主要由头发和皮肤组成,因此您需要检测它们。

皮肤 - 有关于如何执行此操作的several篇论文和blogs。其中一些pretty simplethis OpenCV tutorial也可能有所帮助。我发现平淡的色调/饱和度让我走得很远。

头发 - 此is trickierdefinitely仍为doable。如果事实证明工作太多,你或许可以使用皮肤和背景。

背景 - 您应该能够使用range()查找图像中紫色,绿色和蓝色的内容。你肯定知道这些东西不是皮肤或头发,因此是背景的一部分。

使用阈值创建最可能是皮肤,头发和背景的区域的蒙版。然后,您可以将其用作bgdModelfgdModel(或皮肤和头发蒙版),而不是Mat()

对不起,这是如此高级别。我希望它有所帮助!

答案 1 :(得分:2)

另一种方法,因为你已经检测到面部,只需选择一个更好的初始掩模来初始化GrabCut - 例如通过使用椭圆而不是矩形。

  1. 检测面部矩形(正如您已经在做的那样)
  2. 创建一个面具:

    a)创建与输入图像大小相同的新黑色图像

    b)绘制一个白色填充的椭圆,其高度,宽度,顶部和左侧位置与面部矩形相同

  3. 使用GC_INIT_WITH_MASK而不是GC_INIT_WITH_RECT调用GrabCut:

    Imgproc.grabCut(image, mask, rectangle, bgdModel, fgdModel, 8, Imgproc.GC_INIT_WITH_MASK);
    
  4. 这会使用更好的模型初始化前景,因为面部比椭圆形更像椭圆形,所以它应该包含较少的背景。

答案 2 :(得分:1)

我建议"玩"使用矩形坐标(int xOne, int xTwo, int yOne, int yTwo)。使用您的代码和这些坐标1,400,30,400我能够避开背景。 (我试图发布我成功裁剪的图片但我需要至少10个声望才能这样做)

答案 3 :(得分:-6)

可以对任何Java例程进行的最佳优化是转换为本机语言。