图像全景拼接--Using Homographies

本文介绍了如何使用单应性矩阵实现图像拼接。首先通过SIFT特征点检测找到两幅图像间的对应点,然后计算单应性矩阵,最后进行图像拼接。文章详细展示了使用OpenCV实现这一过程的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章简单介绍过什么是Homographies,点击链接

这里总结一下Homographies:

      假设我们有两个相同平面对象的图像,它们之间有一些重叠(存在对应点)。让P1成为第一图像中的点的像素坐标[P1x,P1y,1 ],P2是第二图像中的点的像素坐标[P2X,P2Y,1 ]。我们将第一图像称为目的图像,第二图像称为源图像。单应性1H2是将第二图像中的每个像素坐标与第一图像中的像素坐标映射关系。

P1 = 1H2 * P2

获取对应点

可以使用特征点检测,如 SIFT,SURF,ORB等,这里,我们使用sift,虽然慢,但是相比于其他,这个是最准确的。

1,两张有重叠部分的图

2 如果我们想把源图像的像素粘贴在一个大的画布上,我们需要考虑在更大的画布上的目标图像。

int offsetx = 800;
int offsety = 1000;
Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, offsetx, 0, 1, offsety);
warpAffine(im1, im1, trans_mat, Size(3 * im1.cols, 3 * im1.rows));

结果

SIFT特征检测

cv::Ptr<Feature2D> f2d = xfeatures2d::SIFT::create();

// Step 1: Detect the keypoints:
std::vector<KeyPoint> keypoints_1, keypoints_2;
f2d->detect( im_1, keypoints_1 );
f2d->detect( im_2, keypoints_2 );

// Step 2: Calculate descriptors (feature vectors)
Mat descriptors_1, descriptors_2;
f2d->compute( im_1, keypoints_1, descriptors_1 );
f2d->compute( im_2, keypoints_2, descriptors_2 );

// Step 3: Matching descriptor vectors using BFMatcher :
BFMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );

// Keep 200 best matches only.
// We sort distance between descriptor matches
Mat index;
int nbMatch = int(matches.size());
Mat tab(nbMatch, 1, CV_32F);
for (int i = 0; i < nbMatch; i++)
	tab.at<float>(i, 0) = matches[i].distance;
sortIdx(tab, index, SORT_EVERY_COLUMN + SORT_ASCENDING);
vector<DMatch> bestMatches;

for (int i = 0; i < 200; i++)
	bestMatches.push_back(matches[index.at < int > (i, 0)]);

匹配对应点

计算单应性矩阵

// 1st image is the destination image and the 2nd image is the src image
std::vector<Point2f> dst_pts;                   //1st
std::vector<Point2f> source_pts;                //2nd

for (vector<DMatch>::iterator it = bestMatches.begin(); it != bestMatches.end(); ++it) {
	//-- Get the keypoints from the good matches
	dst_pts.push_back( keypoints_1[ it->queryIdx ].pt );
	source_pts.push_back( keypoints_2[ it->trainIdx ].pt );
}

Mat H = findHomography( source_pts, dst_pts, CV_RANSAC );
cout << H << endl;

输出H为

[0.119035947337248, -0.04651626756941147, 1700.852494625838;
 -0.5652916039380339, 0.9340629651977271, 1045.011078408947;
 -0.0004251711674909509, 1.783961055570689e-05, 1]

现在我们有单应性。我们只需要将ima2上的透视扭曲应用于IMA1大小的空白黑色画布上。

Mat wim_2;
warpPerspective(im_2, wim_2, H, im_1.size());

im_2经过H 变换,变为wim_2,

效果图如下:

      大部分事情现在都完成了。我们只需要把这两个图像合并在一起。这一粗暴和简单的方法是:复制所有这些像素的wim_2到im_1是黑色的im_1。

// We can do this since im_1 and wim_2 have the same size.
for (int i = 0; i < im_1.cols; i++)
	for (int j = 0; j < im_1.rows; j++) {
		Vec3b color_im1 = im_1.at<Vec3b>(Point(i, j));
		Vec3b color_im2 = wim_2.at<Vec3b>(Point(i, j));
		if (norm(color_im1) == 0)
			im_1.at<Vec3b>(Point(i, j)) = color_im2;
	}

展示im_1:

 

更多详情请关注个人工作号:

 

### 实现旋转场景下图像拼接的方法 对于旋转场景下的图像拼接,自动全景图缝合算法提供了一种有效的方式处理多个无序图像拼接问题[^1]。该方法主要涉及特征检测、描述符创建以及基于这些特征匹配来估计变换矩阵。 #### 特征点提取与描述子构建 为了使图像能够抵抗尺度变化、旋转和平移的影响,在每个关键点处建立描述符至关重要,这一步骤确保了即使存在一定程度仿射变换的情况下也能保持不变性[^3]。SIFT(Scale-Invariant Feature Transform)是一种常用的特征描述算子,它通过多尺度空间极值检测找到稳定的兴趣点,并计算局部梯度直方图作为描述向量。 ```python import cv2 import numpy as np def extract_features(image): sift = cv2.SIFT_create() keypoints, descriptors = sift.detectAndCompute(image, None) return keypoints, descriptors ``` #### 图像配准与几何校正 一旦获得了两幅或多幅图片之间的对应关系,则可以利用RANSAC随机抽样一致性算法筛选出最佳单应性矩阵H用于表示两张照片间的投影映射关系。此过程有助于消除错误匹配并提高最终结果的质量。 ```python def match_images(descriptors1, descriptors2): bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True) matches = bf.match(descriptors1, descriptors2) sorted_matches = sorted(matches, key=lambda x: x.distance) src_pts = np.float32([kp.pt for kp in keypoints1]).reshape(-1, 1, 2) dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in sorted_matches[:10]]).reshape(-1, 1, 2) H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) return H ``` #### 多视图融合 当面对更多数量的输入视角时,可以通过增量方式逐步增加新加入的照片到现有全景图中去;也可以采用全局优化策略一次性求解所有相机姿态参数从而获得更精确的结果。在此基础上应用加权平均滤波器平滑过渡区域边界线,使得整个合成后的画面看起来更加自然连贯。 ```python def stitch_images(images, homographies): result = images[0] for i in range(1, len(images)): h_inv = np.linalg.inv(homographies[i]) warped_image = cv2.warpPerspective(images[i], h_inv, (result.shape[1]+images[i].shape[1], result.shape[0])) # Create a mask where the first image exists. mask = np.zeros_like(warped_image) mask[:result.shape[0], :result.shape[1]] = result # Blend two images together using weighted average filter. blended_result = cv2.addWeighted(mask.astype(np.uint8), 0.5, warped_image.astype(np.uint8), 0.5, 0) result = blended_result return result ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值