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]()
Ответы
Ответ 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
Я думаю, вы пропустили этот момент:
Создание корпуса и анализ дефектов ускоряются за счет использования низкополигональной аппроксимации контура, а не оригинала.