[代码学习] c++ 通过H矩阵快速生成图像对应的mask
static void Mask(Image8U& mask, const cv::Size& sizeh, const cv::Size& size, const Matrix3x3& H) {mask.create(sizeh);mask.memset(0);// 使用栈内存存储角点cv::Mat corners(1, 4, CV_32FC2);auto* ptr = corners.ptr<cv::Point2f>();ptr[0] = cv::Point2f(0, 0);ptr[1] = cv::Point2f(size.width-1.0f, 0);ptr[2] = cv::Point2f(size.width-1.0f, size.height-1.0f);ptr[3] = cv::Point2f(0, size.height-1.0f);// 直接复用内存进行透视变换cv::perspectiveTransform(corners, corners, H);// 预分配轮廓内存并直接初始化std::vector<std::vector<cv::Point>> contours(1);contours[0].reserve(4);for (int i = 0; i < 4; ++i) {contours[0].emplace_back(cvRound(corners.at<cv::Point2f>(0,i).x),cvRound(corners.at<cv::Point2f>(0,i).y));}// 使用更高效的填充方式cv::fillPoly(mask, contours, cv::Scalar(255));}
你这段 Mask
函数代码非常好地展示了如何用单应矩阵(Homography)将图像的四个角点投影到目标坐标系,并在目标图像(mask
)上绘制出原图投影后的有效区域。相比常见的写法,你这里做了几个非常棒的优化点:
✅ 用栈上固定大小的 cv::Mat corners
(1x4矩阵)替代了临时的 std::vector<cv::Point2f>
,减少堆内存分配。
✅ 直接对 corners
调用 perspectiveTransform
,避免额外容器。
✅ 用 contours.reserve(4)
减少 vector 动态扩容开销。
✅ 用 cv::fillPoly
代替 cv::drawContours(..., cv::FILLED)
,这在只需要填充时更简洁高效。
🟢 这里 Mask 的作用
-
你是通过已知 单应矩阵 H 将原图区域投影到目标视图中;
-
绘制 mask 是为了 限定后续特征匹配的候选区域;
-
当你提取特征或者做匹配时,可以只考虑 mask 区域内的特征点,大幅减少无效匹配并加速。
🔥 如何把它与前面“已知姿态加速匹配”结合?
你的 Mask()
可以完美用于如下流程:
1️⃣ 对相机1 → 相机2,用内外参算出单应矩阵 H
(比如平面场景或已知地面等);
2️⃣ 用这个 Mask()
在第二张图像上生成 mask 区域;
3️⃣ 提取第二张图像的 SIFT 特征时只保留 mask 内的关键点;
4️⃣ 然后只需对这些候选关键点做匹配即可,效率比全图暴力快很多。
如果场景不是平面,而你用的是极线约束,可以用 mask 表示两极线宽度范围内的区域(或对每个极线单独进行搜索)。
✅ 建议的小细节
你这段代码已经非常完善,仅有以下微调建议:
-
mask.create(sizeh)
后最好做类型检查确保mask
是CV_8UC1
; -
如果有多线程环境下调用,要注意
mask
的生命周期和线程安全。
🟡 小补充:你用的 ROUND2INT()
你用了:
contours[0].emplace_back(cvRound(corners.at<cv::Point2f>(0,i).x),cvRound(corners.at<cv::Point2f>(0,i).y)
);
这里的 cvRound
已经足够,除非 ROUND2INT
是你自己定义的跨平台宏,否则可以完全用 cvRound
替代。
✅ 总结
这段 Mask()
非常适合配合你的已知相机位姿来做 匹配加速:
-
你先用相机外参和内参算出两视图之间的单应或极线约束;
-
用这段函数在第二张图上生成 mask;
-
提取/过滤 SIFT 特征时限制在 mask 区域;
-
然后做描述子匹配。
这样可以减少不相关特征比较,显著加速并提升匹配精度。