Возникли трудности при сшивании изображений с использованием OpenCV
В настоящее время я работаю над сшивкой изображений с использованием OpenCV 2.3.1 в Visual Studio 2010, но у меня возникли некоторые проблемы.
Описание проблемы Я пытаюсь написать код для сшивания нескольких изображений, полученных с нескольких камер (примерно 3-4), т. Е. Код должен продолжать выполнять сшивание изображений до тех пор, пока я не прошу его остановить.
Вот что я сделал до сих пор: (Для упрощения я заменю некоторую часть кода всего несколькими словами)
1.Reading frames(images) from 2 cameras (Currently I'm just working on 2 cameras.)
2.Feature detection, descriptor calculation (SURF)
3.Feature matching using FlannBasedMatcher
4.Removing outliers and calculate the Homography with inliers using RANSAC.
5.Warp one of both images.
Для шага 5. Я следовал за ответом в следующей теме и просто изменил некоторые параметры: Сшивание 2 изображений в opencv
Тем не менее, результат ужасен, хотя. Я только что загрузил результат на YouTube, и, конечно, только те, у кого есть ссылка, смогут увидеть его.
Мой код показан ниже: (показаны только важные части)
VideoCapture cam1, cam2;
cam1.open(0);
cam2.open(1);
while(1)
{
Mat frm1, frm2;
cam1 >> frm1;
cam2 >> frm2;
//(SURF detection, descriptor calculation
//and matching using FlannBasedMatcher)
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{
double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
(Draw only "good" matches
(i.e. whose distance is less than 3*min_dist ))
vector<Point2f> frame1;
vector<Point2f> frame2;
for( int i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
frame1.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );
frame2.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( Mat(frame1), Mat(frame2), CV_RANSAC );
cout << "Homography: " << H << endl;
/* warp the image */
Mat warpImage2;
warpPerspective(frm2, warpImage2,
H, Size(frm2.cols, frm2.rows), INTER_CUBIC);
Mat final(Size(frm2.cols*3 + frm1.cols, frm2.rows),CV_8UC3);
Mat roi1(final, Rect(frm1.cols, 0, frm1.cols, frm1.rows));
Mat roi2(final, Rect(2*frm1.cols, 0, frm2.cols, frm2.rows));
warpImage2.copyTo(roi2);
frm1.copyTo(roi1);
imshow("final", final);
Что еще я должен сделать, чтобы сделать шов лучше?
Кроме того, разумно ли фиксировать матрицу гомографии вместо того, чтобы продолжать ее вычислять? Я имею в виду, что сам определяю угол и смещение между двумя камерами, чтобы получить матрицу гомографии, которая удовлетворяет тому, что я хочу.
Благодарю.:)
2 ответа
Звучит так, будто вы делаете это разумно, но если у вас есть доступ к обеим камерам, и они останутся неподвижными по отношению друг к другу, то калибровка в автономном режиме и простое применение преобразования онлайн сделают ваше приложение более эффективным.
Следует отметить, что вы говорите, что используете функцию findHomography из OpenCV. Из документации эта функция:
Finds a perspective transformation between two planes.
Однако ваши точки не ограничены конкретной плоскостью, поскольку они отображают трехмерную сцену. Если вы хотите выполнить калибровку в автономном режиме, вы можете отобразить шахматную доску с помощью обеих камер, и обнаруженные углы можно использовать в этой функции.
Кроме того, вы можете исследовать фундаментальную матрицу, которая может быть рассчитана с помощью аналогичной функции. Эта матрица описывает относительное положение камер, но для их извлечения потребуется некоторая работа (и хороший учебник).
Если вы можете найти его, я бы настоятельно рекомендовал взглянуть на часть II: "Геометрия двух видов" в книге Ричарда Хартли и Эндрю Циссермана "Равномерная геометрия в компьютерном зрении", в которой подробно рассматривается этот процесс.
В последнее время я работаю над регистрацией изображений. Мой алгоритм берет два изображения, вычисляет характеристики SURF, находит соответствия, находит матрицу гомографии и затем сшивает оба изображения вместе, я сделал это с помощью следующего кода:
void stich(Mat base, Mat target,Mat homography, Mat& panorama){
Mat corners1(1, 4,CV_32F);
Mat corners2(1,4,CV_32F);
Mat corners(1,4,CV_32F);
vector<Mat> planes;
/* compute corners
of warped image
*/
corners1.at<float>(0,0)=0;
corners2.at<float>(0,0)=0;
corners1.at<float>(0,1)=0;
corners2.at<float>(0,1)=target.rows;
corners1.at<float>(0,2)=target.cols;
corners2.at<float>(0,2)=0;
corners1.at<float>(0,3)=target.cols;
corners2.at<float>(0,3)=target.rows;
planes.push_back(corners1);
planes.push_back(corners2);
merge(planes,corners);
perspectiveTransform(corners, corners, homography);
/* compute size of resulting
image and allocate memory
*/
double x_start = min( min( (double)corners.at<Vec2f>(0,0)[0], (double)corners.at<Vec2f> (0,1)[0]),0.0);
double x_end = max( max( (double)corners.at<Vec2f>(0,2)[0], (double)corners.at<Vec2f>(0,3)[0]), (double)base.cols);
double y_start = min( min( (double)corners.at<Vec2f>(0,0)[1], (double)corners.at<Vec2f>(0,2)[1]), 0.0);
double y_end = max( max( (double)corners.at<Vec2f>(0,1)[1], (double)corners.at<Vec2f>(0,3)[1]), (double)base.rows);
/*Creating image
with same channels, depth
as target
and proper size
*/
panorama.create(Size(x_end - x_start + 1, y_end - y_start + 1), target.depth());
planes.clear();
/*Planes should
have same n.channels
as target
*/
for (int i=0;i<target.channels();i++){
planes.push_back(panorama);
}
merge(planes,panorama);
// create translation matrix in order to copy both images to correct places
Mat T;
T=Mat::zeros(3,3,CV_64F);
T.at<double>(0,0)=1;
T.at<double>(1,1)=1;
T.at<double>(2,2)=1;
T.at<double>(0,2)=-x_start;
T.at<double>(1,2)=-y_start;
// copy base image to correct position within output image
warpPerspective(base, panorama, T,panorama.size(),INTER_LINEAR| CV_WARP_FILL_OUTLIERS);
// change homography to take necessary translation into account
gemm(T, homography,1,T,0,T);
// warp second image and copy it to output image
warpPerspective(target,panorama, T, panorama.size(),INTER_LINEAR);
//tidy
corners.release();
T.release();
}
Любой вопрос попробую