Android: использование calcOpticalFlowPyrLK с MatOfPoint2f
Мне не удалось использовать calcOpticalFlowPyrLK с MatOfPoint2f. Я объявил свои типы следующим образом:
private Mat mPreviousGray; // previous gray-level image
private List<MatOfPoint2f> points; // tracked features
private MatOfPoint initial; // initial position of tracked points
И используйте следующее для поиска и отслеживания функций (Мой код основан на примере приложения оптического потока на C++ Роберта Лаганьера.)
// Called whenever a new frame m is captured
private void OpticalFlow(Mat m, int maxDetectionCount, double qualityLevel,
double minDistance) {
if (points.get(0).total() < maxDetectionCount/2) // Check if new points need to be added
{
// maxDetectionCount = 500
// qualityLevel = 0.01
// minDistance = 10
Imgproc.goodFeaturesToTrack(m, initial, maxDetectionCount, qualityLevel, minDistance);
// add the detected features to the currently tracked features
points.get(0).push_back(initial);
// Have checked length of points.get(0), is not zero.
}
// for first image of the sequence
if(mPreviousGray.empty())
m.copyTo(mPreviousGray);
if( points.get(0).total() > 0 ) // EMG - 09/22/11 - fix optical flow crashing bug
{
// 2. track features
Video.calcOpticalFlowPyrLK(mPreviousGray, m, // 2 consecutive images
points.get(0), // input point position in first image
points.get(1), // output point postion in the second image
status, // tracking success
error); // tracking error
}
...
m.copyTo(mPreviousGray);
...
}
Ранее переменная points
был типа List<List<Point>>
и я бы конвертировать между типами, создавая MatOfPoint2f с fromList
и передать его в calcOpticalFlowPyrLK.
Однако я больше не хотел этого делать, потому что это преобразование из списков и в них теряет соответствие между точками в initial
а также points
, Я хочу сохранить это соответствие, чтобы рисовать оптические линии потока, перебирая элементы в обеих матрицах одновременно.
К сожалению, теперь у меня есть следующая ошибка утверждения:
09-24 10:04:30.400: E/cv::error()(8216): OpenCV Error: Assertion failed ((npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0) in void cv::calcOpticalFlowPyrLK(const cv::_InputArray&, const cv::_InputArray&, const cv::_InputArray&, const cv::_OutputArray&, const cv::_OutputArray&, const cv::_OutputArray&, cv::Size, int, cv::TermCriteria, int, double), file X:\Dev\git\opencv-2.4\modules\video\src\lkpyramid.cpp, line 593
09-24 10:04:30.400: E/AndroidRuntime(8216): FATAL EXCEPTION: Thread-321
09-24 10:04:30.400: E/AndroidRuntime(8216): CvException [org.opencv.core.CvException: X:\Dev\git\opencv-2.4\modules\video\src\lkpyramid.cpp:593: error: (-215) (npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0 in function void cv::calcOpticalFlowPyrLK(const cv::_InputArray&, const cv::_InputArray&, const cv::_InputArray&, const cv::_OutputArray&, const cv::_OutputArray&, const cv::_OutputArray&, cv::Size, int, cv::TermCriteria, int, double)
09-24 10:04:30.400: E/AndroidRuntime(8216): ]
09-24 10:04:30.400: E/AndroidRuntime(8216): at org.opencv.video.Video.calcOpticalFlowPyrLK_2(Native Method)
09-24 10:04:30.400: E/AndroidRuntime(8216): at org.opencv.video.Video.calcOpticalFlowPyrLK(Video.java:445)
Как ни странно, если я сам добавлю это утверждение перед вызовом calcOpticalFlowPyrLK, оно не завершится неудачей.
Я надеюсь, что кто-то может помочь мне понять, в чем заключается настоящая проблема, и как я могу сохранить эту связь между отслеживаемыми точками между кадрами.
Изменить: я обнаружил, что нужно сделать, чтобы избежать этой ошибки утверждения, и приложение тогда ведет себя правильно, но:
- Я не знаю почему.
- У меня похожая проблема сейчас для Calib3d.solvePnP, но применение convertTo к imagePoints и objectPoints не решает проблему здесь, ни с
CvType.CV_32FC2
ниCvType.CV_32F
или жеCvType.CV_64F
Чтобы исправить ошибку подтверждения в случае calcOpticalFlowPyrLK
, Я изменился points.get(0).push_back(initial);
к следующему:
Imgproc.goodFeaturesToTrack(m, initial, maxDetectionCount, qualityLevel, minDistance);
MatOfPoint2f initial2f = new MatOfPoint2f();
initial.convertTo(initial2f, CvType.CV_32FC2);
// add the detected features to the currently tracked features
trackedpoints.get(0).push_back(initial2f);
Поэтому мой вопрос изменился на: Может ли кто-нибудь объяснить общий случай для меня, чтобы я знал, как решить и мою проблему с Calib3d.solvePnP?
2 ответа
Параметры точки calcOpticalFlowPyrLK имеют тип MatOfPoint2f, который внутренне является CV_32FC2.
Первый параметр solvePnP - это MatOfPoint3f, который внутренне является CV_32FC3. Попытайтесь преобразовать это, чтобы видеть, исправляет ли это.
Некоторые функции opencv ожидают определенных типов Mat, я думаю, из соображений эффективности вы должны вручную выбрать правильные, а не угадывать / конвертировать opencv автоматически.
Кто -то в другой теме имел эту проблему раньше. У меня недавно была эта проблема (утверждение) в функции оптического потока OpenCV4Android. Это решение работает только тогда, когда вы не можете обработать матрицу предыдущих точек:
вместо использования метода convertTo() вы должны поместить каждый элемент массива Keypoint[], который вы получили из matOfKeyPoints.ToArray(), в массив matOfPoints2f.
причина объяснена на этой странице:
KeyPoint[] arrayOfkp = keypoints.toArray();
org.opencv.core.Point[] arrayOfp = new org.opencv.core.Point[arrayOfkp.length];
for(int j =0;j<arrayOfkp.length;j++)
{
arrayOfp[j] = new org.opencv.core.Point(0, 0);
arrayOfp[j].x = (int) arrayOfkp[j].pt.x;
arrayOfp[j].y = (int) arrayOfkp[j].pt.y;
}
prevPts.fromArray(arrayOfp);