Подтвердить что ты не робот

Computer Vision - фильтрация выпуклых оболочек и дефектов выпуклости с помощью OpenCV

У меня проблема с обработкой цифровых сигналов. Я пытаюсь обнаружить кончики пальцев, похожие на решение, которое представлено здесь: Обнаружение рук и пальцев с использованием JavaCV.

Однако я не использую JavaCV, а OpenCV для Android, который немного отличается. Мне удалось сделать все шаги, представленные в учебнике, но фильтрацию выпуклых оболочек и дефектов выпуклости. Вот как выглядит мой образ:

Resolution 640x480

Вот изображение в другом разрешении:

Resolution 320x240

Как вы можете ясно видеть, существует множество желтых точек (выпуклых оболочек), а также многих красных точек (выпуклости). Иногда между двумя желтыми точками нет красной точки, что довольно странно (как вычисляются выпуклые оболочки?)

Мне нужно создать функцию фильтрации simillar, как в предыдущей ссылке, но используя структуры данных OpenCV.

Выпуклая оболочка - это тип MatOfInt... Дефекты выпуклости - это тип MatOfInt4...

Я создал также некоторые дополнительные структуры данных, потому что глупый OpenCV использует разные типы данных, содержащих одни и те же данные, разными способами...

convexHullMatOfInt = new MatOfInt();
convexHullPointArrayList = new ArrayList<Point>();
convexHullMatOfPoint = new MatOfPoint();
convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

Вот что я сделал до сих пор, но он не работает хорошо. Вероятно, проблема заключается в неверном преобразовании данных:

Создание выпуклых оболочек и дефектов выпуклости:

public void calculateConvexHulls()
{
    convexHullMatOfInt = new MatOfInt();
    convexHullPointArrayList = new ArrayList<Point>();
    convexHullMatOfPoint = new MatOfPoint();
    convexHullMatOfPointArrayList = new ArrayList<MatOfPoint>();

    try {
        //Calculate convex hulls
        if(aproximatedContours.size() > 0)
        {
            Imgproc.convexHull( aproximatedContours.get(0), convexHullMatOfInt, false);

            for(int j=0; j < convexHullMatOfInt.toList().size(); j++)
                convexHullPointArrayList.add(aproximatedContours.get(0).toList().get(convexHullMatOfInt.toList().get(j)));
            convexHullMatOfPoint.fromList(convexHullPointArrayList);
            convexHullMatOfPointArrayList.add(convexHullMatOfPoint);    
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

public void calculateConvexityDefects()
{
    mConvexityDefectsMatOfInt4 = new MatOfInt4();

    try {
        Imgproc.convexityDefects(aproximatedContours.get(0), convexHullMatOfInt, mConvexityDefectsMatOfInt4);

        if(!mConvexityDefectsMatOfInt4.empty())
        {
            mConvexityDefectsIntArrayList = new int[mConvexityDefectsMatOfInt4.toArray().length];
            mConvexityDefectsIntArrayList = mConvexityDefectsMatOfInt4.toArray();
        }
    } catch (Exception e) {
        Log.e("Calculate convex hulls failed.", "Details below");
        e.printStackTrace();
    }
}

Фильтрация:

public void filterCalculatedPoints()
    {
        ArrayList<Point> tipPts = new ArrayList<Point>();
        ArrayList<Point> foldPts = new ArrayList<Point>();
        ArrayList<Integer> depths = new ArrayList<Integer>();

        fingerTips = new ArrayList<Point>();

        for (int i = 0; i < mConvexityDefectsIntArrayList.length/4; i++)
        {
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i]));
            tipPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+1]));
            foldPts.add(contours.get(0).toList().get(mConvexityDefectsIntArrayList[4*i+2]));
            depths.add(mConvexityDefectsIntArrayList[4*i+3]);
        }

        int numPoints = foldPts.size();
        for (int i=0; i < numPoints; i++) {
            if ((depths.get(i).intValue()) < MIN_FINGER_DEPTH)
                continue;

            // look at fold points on either side of a tip
            int pdx = (i == 0) ? (numPoints-1) : (i - 1);
            int sdx = (i == numPoints-1) ? 0 : (i + 1);

            int angle = angleBetween(tipPts.get(i), foldPts.get(pdx), foldPts.get(sdx));
            if (angle >= MAX_FINGER_ANGLE)   // angle between finger and folds too wide
                continue; 

            // this point is probably a fingertip, so add to list
            fingerTips.add(tipPts.get(i));
        }
    }

Результаты (белые точки - кончики пальцев после фильтрации):

enter image description here

Не могли бы вы помочь мне написать правильную функцию фильтрации?

ОБНОВЛЕНИЕ 14.08.2013

Я использую стандартную функцию openCV для приближения контуров. Я должен изменить значение аппроксимации с разрешением смены разрешения и расстояние от руки к камере, что довольно сложно сделать. Если разрешение меньше, то палец состоит из меньшего пикселя, поэтому значение аппроксимации должно быть любовником. То же самое с расстоянием. Сохранение этого максимума приведет к полной потере пальцем. Поэтому я считаю, что приближение не является хорошим подходом к решению проблемы, однако небольшая ценность может быть полезна для ускорения вычислений:

Imgproc.approxPolyDP(frame, frame, 2 , true); 

Если я использую высокие значения, результат будет похож на изображение ниже, которое было бы хорошим только в том случае, если расстояние и разрешение не изменились. Кроме того, я совершенно удивлен тем, что методы по умолчанию для точек и точек дефектов корпуса не имеют полезных аргументов для прохождения (минимальный угол, расстояние и т.д.)...

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

Чтобы подвести итог, я хотел бы знать:

  • как фильтровать точки
  • Как я могу сделать разрешение и независимое от расстояния приближение, которое всегда будет работать.
  • Если кто-то знает или имеет некоторые материалы (графическое представление, объяснение) об этих структурах данных, используемых в OpenCV, я был бы рад прочитать его. (Mat, MatOfInt, MatOfPoint, MatOfPoint2, MatOfPoint4 и т.д.).

enter image description here

4b9b3361

Ответ 1

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

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

Пример вашего кода - это один проход вычисления дефектов выпуклости, а затем их удаление.. это логическая ошибка.. вам нужно удалить точки, когда вы идете. (a) быстрее и проще делать все в одном -pass (b) он избегает удаления точек с первого прохода и должен добавить их позже, потому что любое удаление изменяет предыдущие вычисления.

Эта базовая техника очень проста и поэтому работает для основной открытой ладони. Однако он не понимает сущность руки или жестов, поэтому настройка параметров масштаба, угла и длины только когда-либо заставит вас "до сих пор".

Ссылки на методы: длина фильтра и угол "дефект выпуклости" Simen Andresen blog http://simena86.github.io/blog/2013/08/12/hand-tracking-and-recognition-with-opencv/

Библиотека С# на основе Kinect SDK с добавлением пальцев http://candescentnui.codeplex.com/ http://blog.candescent.ch/2011/11/improving-finger-detection.html

"Саморастворимый и организованный нейронный газ" (SGONG) Проф. Никос Папамаркос http://www.papamarkos.gr/uploaded-files/Hand%20gesture%20recognition%20using%20a%20neural%20network%20shape%20fitting%20technique.pdf

Коммерческий продукт Дэвид Хольц и Майкл Баквальд основатели "Leap Motion" http://www.engadget.com/2013/03/11/leap-motion-michael-buckwald-interview/

Ответ 2

Я думаю, вы пропустили этот момент:

Создание корпуса и анализ дефектов ускоряются за счет использования низкополигональной аппроксимации контура, а не оригинала.