У меня проблема с обработкой цифровых сигналов. Я пытаюсь обнаружить кончики пальцев, похожие на решение, которое представлено здесь: Обнаружение рук и пальцев с использованием JavaCV.
Однако я не использую JavaCV, а OpenCV для Android, который немного отличается. Мне удалось сделать все шаги, представленные в учебнике, но фильтрацию выпуклых оболочек и дефектов выпуклости. Вот как выглядит мой образ:
Вот изображение в другом разрешении:
Как вы можете ясно видеть, существует множество желтых точек (выпуклых оболочек), а также многих красных точек (выпуклости). Иногда между двумя желтыми точками нет красной точки, что довольно странно (как вычисляются выпуклые оболочки?)
Мне нужно создать функцию фильтрации 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));
}
}
Результаты (белые точки - кончики пальцев после фильтрации):
Не могли бы вы помочь мне написать правильную функцию фильтрации?
ОБНОВЛЕНИЕ 14.08.2013
Я использую стандартную функцию openCV для приближения контуров. Я должен изменить значение аппроксимации с разрешением смены разрешения и расстояние от руки к камере, что довольно сложно сделать. Если разрешение меньше, то палец состоит из меньшего пикселя, поэтому значение аппроксимации должно быть любовником. То же самое с расстоянием. Сохранение этого максимума приведет к полной потере пальцем. Поэтому я считаю, что приближение не является хорошим подходом к решению проблемы, однако небольшая ценность может быть полезна для ускорения вычислений:
Imgproc.approxPolyDP(frame, frame, 2 , true);
Если я использую высокие значения, результат будет похож на изображение ниже, которое было бы хорошим только в том случае, если расстояние и разрешение не изменились. Кроме того, я совершенно удивлен тем, что методы по умолчанию для точек и точек дефектов корпуса не имеют полезных аргументов для прохождения (минимальный угол, расстояние и т.д.)...
Ниже представлен эффект, который я хотел бы достичь всегда независимо от разрешения или расстояния от руки к камере. Также я не хочу видеть желтые точки, когда я закрываю ладонь...
Чтобы подвести итог, я хотел бы знать:
- как фильтровать точки
- Как я могу сделать разрешение и независимое от расстояния приближение, которое всегда будет работать.
- Если кто-то знает или имеет некоторые материалы (графическое представление, объяснение) об этих структурах данных, используемых в OpenCV, я был бы рад прочитать его. (Mat, MatOfInt, MatOfPoint, MatOfPoint2, MatOfPoint4 и т.д.).