Я работаю над проектом вычитания фона Android, с движущейся камерой. Я пытаюсь использовать сопоставление функций, findHomography и warpPerspective, чтобы найти перекрывающиеся пиксели между двумя кадрами. Однако вывод, который я получаю, немного некорректен. Я совершенно новичок в обработке изображений, поэтому я не знаком со всей терминологией. У меня есть 2 основных вопроса:
1) Результат warpPerspective чрезмерно искажен - например, изображение искажено, объекты на изображении перевернуты, скручены и т.д. Как это решить?
2) Иногда я получаю сообщение об ошибке "Ошибка с ошибкой OpenCV: ошибка присвоения", что приводит к сбою моего приложения. Эта ошибка отображается в warpPerspective. Примечания: размеры в image1 (предыдущий кадр) и image2 (текущий кадр) одинаковы. Я преобразую изображения в серый цвет до обнаружения функций (в настоящее время от RGB). Я иногда получал аналогичную ошибку с подтверждением OpenCV с помощью findHomography, но я узнал, что ей нужно как минимум 4 балла, поэтому добавление оператора if решило его, но не удалось решить проблему с помощью warpPerspective.
Ошибка, которую я получаю:
02-24 15:30:49.554: E/cv::error()(4589): OpenCV Error: Assertion failed (type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U))
in void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool),
file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/core/src/stat.cpp, line 2473
Мой код:
void stitchFrames(){
//convert frames to grayscale
image1 = prevFrame.clone();
image2 = currFrame.clone();
if(colourSpace==1){ //convert from RGB to gray
cv::cvtColor(image1, image1Gray,CV_RGB2GRAY);
cv::cvtColor(image2, image2Gray,CV_RGB2GRAY);
}
else if(colourSpace==2){ //convert from HSV to gray
cv::cvtColor(image1, image1Gray,CV_HSV2RGB);
cv::cvtColor(image1Gray,image1Gray,CV_RGB2GRAY);
cv::cvtColor(image2, image1Gray,CV_HSV2RGB);
cv::cvtColor(image2Gray,image1Gray,CV_RGB2GRAY);
}
else if(colourSpace==3){ //no need for conversion
image1Gray = image1;
image2Gray = image2;
}
//----FEATURE DETECTION----
//key points
std::vector<KeyPoint> keypoints1, keypoints2;
int minHessian;
cv::FastFeatureDetector detector;
detector.detect(image1Gray,keypoints1); //prevFrame
detector.detect(image2Gray,keypoints2); //currFrame
KeyPoint kp = keypoints2[4];
Point2f p = kp.pt;
float i = p.y;
//---FEATURE EXTRACTION----
//extracted descriptors
cv::Mat descriptors1,descriptors2;
OrbDescriptorExtractor extractor;
extractor.compute(image1,keypoints1,descriptors1); //prevFrame
extractor.compute(image2,keypoints2,descriptors2); //currFrame
//----FEATURE MATCHING----
//BruteForceMacher
BFMatcher matcher;
std::vector< cv::DMatch > matches; //result of matching descriptors
std::vector< cv::DMatch > goodMatches; //result of sifting matches to get only 'good' matches
matcher.match(descriptors1,descriptors2,matches);
//----HOMOGRAPY - WARP-PERSPECTIVE - PERSPECTIVE-TRANSFORM----
double maxDist = 0.0; //keep track of max distance from the matches
double minDist = 80.0; //keep track of min distance from the matches
//calculate max & min distances between keypoints
for(int i=0; i<descriptors1.rows;i++){
DMatch match = matches[i];
float dist = match.distance;
if (dist<minDist) minDist = dist;
if(dist>maxDist) maxDist=dist;
}
//get only the good matches
for( int i = 0; i < descriptors1.rows; i++ ){
DMatch match = matches[i];
if(match.distance< 500){
goodMatches.push_back(match);
}
}
std::vector< Point2f > obj;
std::vector< Point2f > scene;
//get the keypoints from the good matches
for( int i = 0; i < goodMatches.size(); i++ ){
//--keypoints from image1
DMatch match1 = goodMatches[i];
int qI1 = match1.trainIdx;
KeyPoint kp1 = keypoints2[qI1];
Point2f point1 = kp1.pt;
obj.push_back(point1);
//--keypoints from image2
DMatch match2 = goodMatches[i];
int qI2 = match2.queryIdx;
KeyPoint kp2 = keypoints1[qI2];
Point2f point2 = kp2.pt;
scene.push_back(point2);
}
//calculate the homography matrix
if(goodMatches.size() >=4){
Mat H = findHomography(obj,scene, CV_RANSAC);
warpPerspective(image2,warpResult,H,Size(image1.cols,image1.rows));
}
}
Что касается (1), то я предполагаю, что гомография, которую вы оцениваете, основана на плохих матчах.
Сначала я начну с использования ORB-детектора вместо FAST, а затем измените параметр findHomography
ransacReprojThreshold
. Значение по умолчанию - 3, подробности:
ransacReprojThreshold:
Максимально допустимая ошибка перепрограммирования для обработки пары точек как более интенсивной (используется только в методе RANSAC). То есть, если:
| dstPoints_i - convertPointsHomogeneous (H * srcPoints_i) | > ransacReprojThreshold
то точка я считается выбросом. Если srcPoints и dstPoints измеряются в пикселях, обычно имеет смысл установить этот параметр где-то в диапазоне от 1 до 10.
Другими словами, если предположить, что по умолчанию 3 пикселя, если после применения гомографии к srcPoint его расстояние до dstPoint составляет более 3 пикселей, эта пара считается более медленной (то есть: хорошей).
Это только начало, это также поможет вам найти лучший фильтр для хороших матчей и хорошую гомографию, вы найдете несколько ответов на эти вопросы:
OpenCV Orb не находит совпадений.
Как вы можете определить, приемлема ли матрица гомографии или нет?
Что касается вашего первого вопроса, я думаю, что искажение, о котором вы говорите, связано с тем, что:
вы оцениваете гомографию H
отображающую координаты в image1, для координат на изображении 2. Когда вы делаете Mat H = findHomography(obj,scene, CV_RANSAC);
, obj
- координаты точки на изображении 1, а scene
- координаты точки на изображении 2.
вы затем использовать H
в функции warpPerspective
, как если бы это было отображение координат в образе 2 координатам в изображении 1, так как вы ожидаете, чтобы превратить image2
в warpResult
, который я предполагаю, должен быть пришита к image1
.
Следовательно, вы должны оценить гомографию H
следующим образом: Mat H = findHomography(scene, obj, CV_RANSAC);
,
Что касается вашего второго вопроса, я думаю, что это вызвано этой инструкцией:
matcher.match(descriptors1,descriptors2,matches);
Ошибка говорит, что выражение
(type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U))
было признано ложным, тогда как функция должна работать. Аналогичная проблема была решена здесь: перед вызовом match
функции, необходимо вручную проверить, верно следующее:
(descriptors1.type()==descriptors2.type() && descriptors1.cols==descriptors2.cols)
Mat H = findHomography(scene, obj, CV_RANSAC);