Оптимизация производительности GrabCut в opencv-java

Недавно мне был предоставлен проект, в котором мне нужно извлечь лицо (лицо + волосы) из заданного изображения.

Я решаю эту проблему следующими способами.

  • Я извлекаю места для лица из заданного изображения. [Я получаю прямоугольник]
  • Я извлекаю этот прямоугольник и помещаю его в другое изображение того же размера, что и входное изображение. [face_image]
  • Я применяю алгоритм grabCut на face_image шага 2.

Когда 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, чтобы он обнаруживал только лицо и волосы с данного изображения?

Ответы

Ответ 1

Вы должны быть в состоянии сделать это, помогая grabCut немного узнать о переднем плане и фоне. Существует учебник python, который показывает, как это делается вручную, выбирая передний план и фон.

Чтобы сделать это автоматически, вам нужно будет найти программные способы обнаружения переднего плана и фона. Передний план состоит в основном из волос и кожи, поэтому вам нужно их обнаружить.

Кожа - есть несколько статей и блоги о том, как это сделать, Некоторые из них довольно простые и этот учебник OpenCV также может помочь. Я нашел чистый оттенок/насыщенность, чтобы доставить меня довольно далеко.

Волосы - это сложнее, но определенно все еще выполнимо. Вы можете быть в состоянии волос и просто использовать кожу и фон, если это окажется слишком много работы.

Фон. Вы можете использовать range(), чтобы найти на изображении фиолетовые, зеленые и синие объекты. Вы точно знаете, что эти вещи не являются кожей или волосами и поэтому являются частью фона.

Используйте пороговое значение, чтобы создать маску областей, наиболее вероятных для кожи, волос и фона. Затем вы можете использовать их как bgdModel и fgdModel (или маски для кожи и волос) вместо Mat().

Извините, это настолько высокий уровень. Надеюсь, это поможет!

Ответ 2

Другой подход, поскольку вы уже обнаружили лицо, состоит в том, чтобы просто выбрать лучшую начальную маску для инициализации GrabCut - например, используя овал вместо прямоугольника.

  • Обнаружение прямоугольника лица (как вы уже делаете)
  • Создайте маску:

    a) Создайте новое черное изображение того же размера, что и ваше входное изображение

    b) Нарисуйте эллипс с белым заполнением с одинаковыми по высоте, ширине, верхнему и левому положениям в качестве прямоугольника лица

  • Вызовите GrabCut с помощью GC_INIT_WITH_MASK вместо GC_INIT_WITH_RECT:

    Imgproc.grabCut(image, mask, rectangle, bgdModel, fgdModel, 8, Imgproc.GC_INIT_WITH_MASK);
    

Это инициализирует передний план лучшей моделью, потому что грани более овальной формы, чем прямоугольные, поэтому для начала нужно включить меньше фона.

Ответ 3

Я предлагаю "играть" с координатами прямоугольника (int xOne, int xTwo, int yOne, int yTwo). Используя ваш код и эти координаты 1, 400, 30, 400, я смог избежать фона. (Я попытался опубликовать изображения, которые я успешно обрезал, но для этого мне нужна репутация не менее 10)

Ответ 4

Лучшая оптимизация, которая может быть выполнена для любой Java-процедуры, - это преобразование на родной язык.