【问题标题】:Optimizing performance of GrabCut in opencv-java在 opencv-java 中优化 GrabCut 的性能
【发布时间】:2015-09-01 13:16:48
【问题描述】:

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

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

  1. 我正在从给定图像中提取人脸位置。 [我得到一个矩形]
  2. 我正在提取该矩形并将其放置在与输入图像相同尺寸的另一个图像中。[face_image]
  3. 我正在对第 2 步的 face_image 应用 grabCut 算法。

当 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 算法的性能,使其仅检测给定图像中的面部和头发?

【问题讨论】:

    标签: java algorithm opencv


    【解决方案1】:

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

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

    皮肤 - 有 several 论文和 blogs 关于如何做到这一点。其中一些是pretty simplethis OpenCV tutorial 也可能有帮助。我发现简单的色调/饱和度可以让我走得很远。

    头发 - 这是is trickier,但仍然是definitely doable。如果工作量太大,您也许可以做头发,只使用皮肤和背景。

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

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

    对不起,这太高级了。希望对你有帮助!

    【讨论】:

    • 我已经尝试了很多这样的事情,这些事情并没有达到我的预期.....
    • 如果您可以更详细地了解您尝试了什么以及它如何不起作用并将其添加到您的问题中,也许我可以提供更多帮助。
    • 我有不同类型的图像,对于某些图像,背景与头发非常相似,程序无法区分它们,而且提到的东西在所有情况下都不起作用案例....
    • 虽然 GrabCut 相当不错,但它确实有其局限性。在 GrabCut 运行后,您可能需要执行自己的优化。不幸的是,您所做的仍然是一个开放的研究课题,因此很难找到可以为您完成所有工作的预制库调用。您还可以尝试查找/实现另一种分割算法,例如 TVSeg。祝你好运!
    【解决方案2】:

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

    【讨论】:

    • 这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
    • 嗨,拉姆,如果这不是发帖的正确位置,我很抱歉。问:如何提高grabCut 算法的性能,使其只检测给定图像中的面部和头发?我的回答:矩形越靠近脸部,效果就越好。
    • 我正在查看您的帖子,并选择了要显示的通用系统消息。它基本上说这更像是一个有用的评论,而不是一个答案,因为它不够详细,不能作为一个答案,它要求你将它作为评论发布。我知道您不能将其发布为评论,因为您没有这样做的声誉。请回答一些您知道的问题以收集声誉,然后尝试评论或使用示例和图像作为链接使您的答案更详细,我将通过为您添加链接将链接转换为图像。
    【解决方案3】:

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

    【讨论】:

    • Java 接口访问用 C++ 实现的 OpenCV 库。这是一种“本机”语言,并且该库也进行了高度优化。你在这里的断言是不正确的。
    【解决方案4】:

    由于您已经检测到人脸,另一种方法是简单地选择一个更好的初始掩码来初始化 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);
      

    这会用一个更好的模型初始化前景,因为人脸的椭圆形比矩形的多,所以它应该从一开始就包含更少的背景。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 2017-01-24
      • 1970-01-01
      • 2010-12-17
      • 2013-05-08
      • 1970-01-01
      相关资源
      最近更新 更多