【OpenCV学习】计算两幅图像的重叠区域

本文介绍了一种方法,通过图像匹配计算两幅图像的重叠区域,并在原图像上标识出来。使用SIFT算法进行关键点检测和匹配,找到单应矩阵以融合图像,进而计算多边形交集来确定重叠部分。

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

【OpenCV学习】计算两幅图像的重叠区域

问题描述:已知两幅图像Image1和Image2,计算出两幅图像的重叠区域,并在Image1和Image2标识出重叠区域。

算法思想:

若两幅图像存在重叠区域,则进行图像匹配后,会得到一张完整的全景图,因而可以转换成图像匹配问题。

图像匹配问题,可以融合两幅图像,得到全景图,但无法标识出在原图像的重叠区域。

将两幅图像都理解为多边形,则其重叠区域的计算,相当于求多边形的交集。

通过多边形求交,获取重叠区域的点集,然后利用单应矩阵还原在原始图像的点集信息,从而标识出重叠区域。

算法步骤:

1.图像匹配计算,获取单应矩阵。

2.根据单应矩阵,计算图像2的顶点转换后的点集。

3.由图像1的顶点集合和图像2的转换点集,计算多边形交集。

4.根据单应矩阵的逆,计算多边形的交集在图像2中的原始点集。

代码实现如下所示:


复制代码
1 bool ImageOverlap(cv::Mat &img1,cv::Mat &img2,std::vector<cv::Point> &vPtsImg1,std::vector<cv::Point> &vPtsImg2)
2 {
3 cv::Mat g1(img1,Rect(0,0,img1.cols,img1.rows));
4 cv::Mat g2(img2,Rect(0,0,img2.cols,img2.rows));
5
6 cv::cvtColor(g1,g1,CV_BGR2GRAY);
7 cv::cvtColor(g2,g2,CV_BGR2GRAY);
8
9 std::vector<cv::KeyPoint> keypoints_roi, keypoints_img; /* keypoints found using SIFT */
10 cv::Mat descriptor_roi, descriptor_img; /* Descriptors for SIFT */
11 cv::FlannBasedMatcher matcher; /* FLANN based matcher to match keypoints */
12 std::vector<cv::DMatch> matches, good_matches;
13 cv::SIFT sift;
14 int i, dist=80;
15
16 sift(g1, Mat(), keypoints_roi, descriptor_roi); /* get keypoints of ROI image */
17 sift(g2, Mat(), keypoints_img, descriptor_img); /* get keypoints of the image */
18 matcher.match(descriptor_roi, descriptor_img, matches);
19
20 double max_dist = 0; double min_dist = 1000;
21
22 //-- Quick calculation of max and min distances between keypoints
23 for( int i = 0; i < descriptor_roi.rows; i++ )
24 {
25 double dist = matches[i].distance;
26 if( dist < min_dist ) min_dist = dist;
27 if( dist > max_dist ) max_dist = dist;
28 }
29
30 for (i=0; i < descriptor_roi.rows; i++)
31 {
32 if (matches[i].distance < 3*min_dist)
33 {
34 good_matches.push_back(matches[i]);
35 }
36 }
37
38 //printf("%ld no. of matched keypoints in right image\n", good_matches.size());
39 /* Draw matched keypoints */
40
41 //Mat img_matches;
42 //drawMatches(img1, keypoints_roi, img2, keypoints_img,
43 // good_matches, img_matches, Scalar::all(-1),
44 // Scalar::all(-1), vector<char>(),
45 // DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
46 //imshow("matches",img_matches);
47
48 vector<Point2f> keypoints1, keypoints2;
49 for (i=0; i<good_matches.size(); i++)
50 {
51 keypoints1.push_back(keypoints_img[good_matches[i].trainIdx].pt);
52 keypoints2.push_back(keypoints_roi[good_matches[i].queryIdx].pt);
53 }
54 //计算单应矩阵
55 Mat H = findHomography( keypoints1, keypoints2, CV_RANSAC );
56
57 //show stitchImage
58 // cv::Mat stitchedImage;
59 // int mRows = img2.rows;
60 // if (img1.rows> img2.rows)
61 // {
62 // mRows = img1.rows;
63 // }
64 // stitchedImage = Mat::zeros(img2.cols+img1.cols, mRows, CV_8UC3);
65 // warpPerspective(img2,stitchedImage,H,Size(img2.cols+img1.cols,mRows));
66 // Mat half(stitchedImage,Rect(0,0,img1.cols,img1.rows));
67 // img1.copyTo(half);
68 // imshow("stitchedImage",stitchedImage);
69
70 std::vector<cv::Point> vSrcPtsImg1;
71 std::vector<cv::Point> vSrcPtsImg2;
72
73 vSrcPtsImg1.push_back(cv::Point(0,0));
74 vSrcPtsImg1.push_back(cv::Point(0,img1.rows));
75 vSrcPtsImg1.push_back(cv::Point(img1.cols,img1.rows));
76 vSrcPtsImg1.push_back(cv::Point(img1.cols,0));
77
78 vSrcPtsImg2.push_back(cv::Point(0,0));
79 vSrcPtsImg2.push_back(cv::Point(0,img2.rows));
80 vSrcPtsImg2.push_back(cv::Point(img2.cols,img2.rows));
81 vSrcPtsImg2.push_back(cv::Point(img2.cols,0));
82
83 //计算图像2在图像1中对应坐标信息
84 std::vector<cv::Point> vWarpPtsImg2;
85 for(int i = 0;i < vSrcPtsImg2.size();i++ )
86 {
87 cv::Mat srcMat = Mat::zeros(3,1,CV_64FC1);
88 srcMat.at<double>(0,0) = vSrcPtsImg2[i].x;
89 srcMat.at<double>(1,0) = vSrcPtsImg2[i].y;
90 srcMat.at<double>(2,0) = 1.0;
91
92 cv::Mat warpMat = H * srcMat;
93 cv::Point warpPt;
94 warpPt.x = cvRound(warpMat.at<double>(0,0)/warpMat.at<double>(2,0));
95 warpPt.y = cvRound(warpMat.at<double>(1,0)/warpMat.at<double>(2,0));
96
97 vWarpPtsImg2.push_back(warpPt);
98 }
99 //计算图像1和转换后的图像2的交点
100 if(!PolygonClip(vSrcPtsImg1,vWarpPtsImg2,vPtsImg1))
101 return false;
102
103 for (int i = 0;i < vPtsImg1.size();i++)
104 {
105 cv::Mat srcMat = Mat::zeros(3,1,CV_64FC1);
106 srcMat.at<double>(0,0) = vPtsImg1[i].x;
107 srcMat.at<double>(1,0) = vPtsImg1[i].y;
108 srcMat.at<double>(2,0) = 1.0;
109
110 cv::Mat warpMat = H.inv() * srcMat;
111 cv::Point warpPt;
112 warpPt.x = cvRound(warpMat.at<double>(0,0)/warpMat.at<double>(2,0));
113 warpPt.y = cvRound(warpMat.at<double>(1,0)/warpMat.at<double>(2,0));
114 vPtsImg2.push_back(warpPt);
115 }
116 return true;
117 }
复制代码
其中,多边形求交集可参考:http://www.cnblogs.com/dwdxdy/p/3232110.html

最终,程序运行的示意图如下:


http://www.cnblogs.com/dwdxdy/archive/2013/08/02/3232331.html


### 使用 Python 和 OpenCV 实现图像叠加 在 Python 中,可以借助 OpenCV 提供的 `cv2.addWeighted` 函数实现加权图像叠加[^1]。此方法适用于两张大小相同、通道数一致的图片。如果需要更灵活的操作(如调整位置),则可以通过 NumPy 数组操作完成。 #### 方法一:使用 `cv2.addWeighted` 以下是基于 `cv2.addWeighted` 的代码示例: ```python import cv2 import numpy as np # 读取两幅图像并确保它们具有相同的尺寸和颜色通道 image1 = cv2.imread('image1.jpg') image2 = cv2.imread('image2.jpg') # 如果图像尺寸不同,则需先调整至同一尺寸 if image1.shape != image2.shape: image2 = cv2.resize(image2, (image1.shape[1], image1.shape[0])) # 设置权重参数 alpha 和 beta (范围为 [0,1]) alpha = 0.7 # 图像1的透明度 beta = 0.3 # 图像2的透明度 gamma = 0 # 偏移量 # 执行加权叠加 result = cv2.addWeighted(image1, alpha, image2, beta, gamma) # 显示结果 cv2.imshow('Blended Image', result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 上述代码中,`alpha` 和 `beta` 控制每张图的贡献比例,而 `gamma` 是偏置项。 --- #### 方法二:通过 NumPy 操作实现自定义叠加 当需要将一张图像放置到另一张图像上的特定区域时,可通过 NumPy 切片操作实现。以下是一个例子: ```python import cv2 import numpy as np # 读取背景图像和前景图像 background = cv2.imread('background.jpg') # 背景图像 foreground = cv2.imread('foreground.png', cv2.IMREAD_UNCHANGED) # 前景带 Alpha 通道 # 获取前景图像的高度和宽度 rows, cols, channels = foreground.shape # 将前景图像中的 RGB 颜色提取出来 fg_rgb = foreground[:, :, :3] # 创建掩码用于控制透明部分 mask = foreground[:, :, 3] / 255.0 # 定义要放置的位置 x_offset = 50 y_offset = 50 # 截取背景对应的部分 roi = background[y_offset:y_offset+rows, x_offset:x_offset+cols] # 计算最终像素值 blended_roi = fg_rgb * mask[..., None] + roi * (1 - mask[..., None]) # 替换回原 ROI 区域 background[y_offset:y_offset+rows, x_offset:x_offset+cols] = blended_roi.astype(np.uint8) # 展示结果 cv2.imshow('Result', background) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在此代码片段中,我们假设前景图像带有 Alpha 通道以表示透明度[^4]。如果没有 Alpha 通道,可以直接跳过掩码计算步骤。 --- #### 总结 两种方式各有优劣: - **`cv2.addWeighted`** 更适合简单的全局混合需求。 - **NumPy 自定义叠加** 提供更高的灵活性,允许指定叠加位置以及复杂的透明度处理。 以上均依赖于输入图像满足基本条件(例如分辨率匹配)。如果不符,应提前预处理数据[^2]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值