opencv(50) 使用二维特征点(Features2D)和单映射(Homography)寻找已知物体

1 基本概念

Homegraphy概念

考虑 同一个平面(比如书皮)的两张图片,红点表示同一个物理坐标点在两张图片上的各自位置。在 CV 术语中,我们称之为对应点。

Homography 就是将一张图像上的点映射到另一张图像上对应点的3x3变换矩阵。

 对于图中的一对儿对应点,位于图一的  和 位于图二的 H  把二者映射关系建立起来:

对于所有的对应点,只要它们都位于同一个物理平面上,上述 Homography 就是成立的。换句话说,就是可以把图一中书皮上的所有点都映射到图二的书皮上,也就是看起来,图一中的书皮和图二中的书皮对齐了!

那么对于不在此平面上的点呢?这时再应用 Homography 就无法再对齐到对应点了。比如 上图中的 桌面,地面,橱柜面。对于这种图像中有多个平面的情况,我们就需要针对每一个平面使用其对应的Homography了。

如何计算 Homography?

对于 H  矩阵,一般设 , 所以 H 有 8 个未知参数。至少需要8 个等式才能求解。而一组对应点可以提供 2 个等式,所以,至少需要 4 组对应点(任意三点不共线)来求得 H 。 如果有更多组对应点,效果更佳。

OpenCV 可以鲁棒地计算出一个最好地拟合所有对应点的 Homography。通常,图像间的这些对应点通过 SIFT 或者 SURF 这样算法进行自动特征提取和匹配。当然,对于简单的demo,手动选取对应点就足够了。

2 cv2.findHomegraphy()寻找匹配上的关键点的变换

作用:寻找单应性矩阵

原型:

retv,mask=cv2.findHomography(srcPoints,dstPoints[,method[,ransacReprojThreshold]])

参数:

  1. retv为返回的转换矩阵。
  2. mask为返回的查询图像在训练图像中的最佳匹配结果掩模。
  3. srcPoints, dstPoints为查询图像匹配结果的坐标。
  4. method为用于计算透视转换矩阵的方法。
  5. ransacReprojThreshold为可允许的最大重投影误差。

3 cv2.perspectiveTransform() 映射点

作用:

原型:dst=cv2.perspectiveTransform(src,m)

参数:

  1. src为输入的2通道或3通道浮点类型的数组。
  2. m是大小为3X3或4X4的浮点类型的转换矩阵,如使用cv2.findHomography()函数返回的转换矩阵。

dst为输出结果数组,大小和类型与src相同。

4 示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 【1、读入图像】
img1 = cv2.imread('C:/Users/xxx/Downloads/lena.jpg')
# 【1.1 从原图中扣出图像作为匹配图像】
img2 = np.zeros(img1.shape, dtype="uint8")  # 生成image大小的全黑图
img2[250:300,400:600,:]=img1[250:300,400:600,:]


# 【2、灰度处理】
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)


# 【3、检测关键点】
orb=cv2.ORB_create()#创建ORB检测器
kp1, des1 = orb.detectAndCompute(gray1,None)   #des1是描述子
kp2, des2 = orb.detectAndCompute(gray2,None)   #des2是描述子


# 【4、匹配】
bf=cv2.BFMatcher_create(cv2.NORM_HAMMING,crossCheck=True)#创建匹配器
ms=bf.match(des1,des2)#执行特征匹配
ms=sorted(ms,key=lambda x:x.distance)#按距离排序
matchesMask=None
if len(ms)>10:#在有足够数量的匹配结果后,才计算查询在训练图像中的位置
    #计算查询图像匹配结果的坐标
    querypts=np.float32([kp1[m.queryIdx].pt for m in ms]).reshape(-1,1,2)
    #计算训练图像匹配结果的坐标
    trainpts = np.float32([kp1[m.queryIdx].pt for m in ms]).reshape(-1, 1, 2)
    #执行查询图像和训练图像的透视变换
    retv,mask=cv2.findHomography(querypts,trainpts,cv2.RANSAC)
    #计算最佳匹配结果的掩模,用于绘制匹配结果
    matchesMask=mask.ravel().tolist()
    h,w,c=img1.shape
    pts=np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
    #执行向量的透视矩阵变换,获得查询图像在图像中的位置
    dst=cv2.perspectiveTransform(pts,retv)
    #用白色矩形在训练图像中绘制出查询图像的范围
    img2=cv2.polylines(img2,[np.int32(dst)],True,(255,255,255),5)
img3=cv2.cv2.drawMatches(img1,kp1,img2,kp2,ms,None,
                         matchColor=(0,255,0),
                         singlePointColor=None,
                         matchesMask=matchesMask,
                         flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
plt.figure(figsize=(19.2,14.4))
plt.imshow(img3)
plt.axis('off')
plt.show()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV中,可以使用SURF或SIFT算法来检测图像中的特征点,并计算特征描述子。以下是使用SURF算法检测并绘制特征点的示例代码: ```c++ #include <opencv2/opencv.hpp> using namespace cv; int main() { // 读取图像 Mat img = imread("image.jpg"); // 定义SURF特征检测器 Ptr<Feature2D> detector = SURF::create(); // 检测特征点 std::vector<KeyPoint> keypoints; detector->detect(img, keypoints); // 绘制特征点 drawKeypoints(img, keypoints, img, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); // 显示结果 imshow("image", img); waitKey(); return 0; } ``` 在这个示例代码中,我们首先读取图像,然后定义SURF特征检测器,并使用它检测特征点。最后,我们使用OpenCV提供的`drawKeypoints()`函数绘制特征点,并显示结果。 如果你想给特定的物体添加特征点,你可以使用手动标注的方式对物体进行标记,并将标记的位置作为输入传递给特征检测器。以下是一个手动标注特征点的示例代码: ```c++ #include <opencv2/opencv.hpp> using namespace cv; int main() { // 读取图像 Mat img = imread("image.jpg"); // 标注特征点 std::vector<Point2f> points; points.push_back(Point2f(100, 100)); points.push_back(Point2f(200, 100)); points.push_back(Point2f(200, 200)); points.push_back(Point2f(100, 200)); // 定义SIFT特征检测器 Ptr<Feature2D> detector = SIFT::create(); // 检测特征点 std::vector<KeyPoint> keypoints; detector->detect(img, keypoints); // 将标注的特征点添加到检测到的特征点中 for (int i = 0; i < points.size(); i++) { keypoints.push_back(KeyPoint(points[i], 1.f)); } // 绘制特征点 drawKeypoints(img, keypoints, img, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); // 显示结果 imshow("image", img); waitKey(); return 0; } ``` 在这个示例代码中,我们手动标注了四个特征点,并将它们添加到检测到的特征点中。然后,我们使用OpenCV提供的`drawKeypoints()`函数绘制特征点,并显示结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值