最近开发基于OpenCV的图像处理,OpenCV的确强大,根据近来的所学心得,来个比较麻烦也比较有代表性的项目,图像拼接,根据图像surf特征拼接.
首先准备两张有关联的图片,或者直接把一张图片分成两半。
大概步骤如下:
1 特征提取
载入图片后,转灰度,计算图片的特征点,经典的surf算法就可以。
直接使用OpenCV方法:cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, params );
2 特征点匹配
特征点的匹配的准确性直接影响投影矩阵,所以匹配要求还是要尽量去准确,采用opencv例程中的匹配算法,
需要计算特征向量的距离,计算欧式距离,采用最近邻(Nearest Neighbor,NN)方法对特征点进行粗匹配来判断是否匹配
int naiveNearestNeighbor( const float* vec, int laplacian,
const CvSeq* model_keypoints,
const CvSeq* model_descriptors )
{
int length = (int)(model_descriptors->elem_size/sizeof(float));
int i, neighbor = -1;
double d, dist1 = 1e6, dist2 = 1e6;
CvSeqReader reader, kreader;
cvStartReadSeq( model_keypoints, &kreader, 0 );
cvStartReadSeq( model_descriptors, &reader, 0 );
for( i = 0; i total; i++ )
{
const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
const float* mvec = (const float*)reader.ptr;
CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
if( laplacian != kp->laplacian )
continue;
d = compareSURFDescriptors( vec, mvec, dist2, length );
if( d 一对特征保存连续的集合中,后面计算在分别取出奇数和偶数对特征,取出特征
findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
n = ptpairs.size()/2;
if( n <4 )
return 0;
pt1.resize(n);
pt2.resize(n);
for( i = 0; i pt;
pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt;
}
3 特征点提纯
4 旋转矩阵
根据取出的特征,求单应性矩阵,
_pt1 = cvMat(1, n, CV_32FC2, &pt1[0] );
_pt2 = cvMat(1, n, CV_32FC2, &pt2[0] );
单应性矩阵 cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 )
此处用CV_RANSAC算法
计算投影图像各点的投影位置
for( i = 0; i <4; i++ )
{
double x = src_corners[i].x, y = src_corners[i].y;
double Z = 1./(h[6]*x + h[7]*y + h[8]);
double X = (h[0]*x + h[1]*y + h[2])*Z;
double Y = (h[3]*x + h[4]*y + h[5])*Z;
dst_corners[i] = cvPoint2D32f(X,Y/*cvRound(X), cvRound(Y)*/);
}
对图像进行投影:cvWarpPerspective(object,m_projImg,&PH);
m_projImg 即是投影后的图片,待拼接
5 图像拼接
根据投影的图像,进行拼接,分别设置roi,
CvRect roiRect = cvRect(xMin+m_iXL,yMin+m_iYT,xMax-xMin,yMax-yMin);
cvSetImageROI(m_pBigImg,roiRect);
roiRect = cvRect(xMin,yMin,xMax-xMin,yMax-yMin);
cvSetImageROI(m_projImg,roiRect);
cvCopy(m_projImg,m_pBigImg);
6.测试结果
大图:
暂时效果是可以,因为还没做图像融合,所以还需进一步处理,
全部代码地址:http://download.csdn.net/detail/inmiracle/8578651
欢迎大家交流学习,Q群:213700322