当前位置: 首页 > article >正文

从零开始学习SLAM六(单应矩阵)

本文参考:计算机视觉life

概念

单应性(homography)是指两个平面之间的一种保直线性的对应关系。如果一个平面上的点集经过某种变换后,在另一个平面上形成的新点集仍然保持原来的线性特性(如共线的点仍然共线),那么这种变换就称为单应性变换。在数学上,单应性变换可以用一个3x3的矩阵来表示,这个矩阵就是所谓的单应矩阵。

回顾相机成像

世界坐标系到相机坐标系的变换为:
在这里插入图片描述
我们简化表达式为, 其中M是3 x 3的矩阵:

( u v 1 ) = M ( x y z 1 ) \begin{pmatrix} u\\ v\\ 1 \end{pmatrix} = M\begin{pmatrix} x\\ y\\ z\\ 1 \end{pmatrix} uv1 =M xyz1

对于两个不同的相机,像素坐标和空间点坐标可以写成如下的表示
在这里插入图片描述
我们把上面两个式子合并一下就得到了下面这个式子,其中的H就是单应矩阵啦!H矩阵的两边是两张图像对应的匹配点对。也就是说单应矩阵H把三维空间中同一平面的点在两个相机的成像图片坐标进行了映射。
在这里插入图片描述
有时1会被平面方程替代,是因为
1.约束条件:在推导单应矩阵的过程中,通常会涉及到多个未知数。为了求解单应矩阵 H,我们需要建立足够的约束条件。平面方程在这里被用来增加额外的约束条件,以便降低问题的自由度。
2. 降维: 由于单应矩阵 H 是一个3x3的矩阵,理论上包含9个参数。但由于它是齐次坐标下的矩阵,所以可以任意缩放,这意味着有一个自由度是冗余的。因此,单应矩阵实际上有8个自由度。为了求解这8个自由度,我们需要至少4对匹配点来建立8个线性方程。
3. 平面方程: 在某些推导过程中,可能会引入平面方程作为约束条件。例如,假设我们有一个平面nTx+d=0,其中 n是平面的法向量,x 是平面上的点,d 是常数。在某些情况下,可以将这个平面方程中的 d 替换为1,从而简化计算或引入额外的约束。

平面方程:在讨论单应矩阵时提到的平面方程,通常指的是图像中的某个平面在三维空间中的方程。具体来说,当我们在处理单应矩阵时,我们关注的是两个图像之间对应点的关系,这些点通常位于同一个平面上。这个平面可以是场景中的任何一个平面,例如墙面、地面或者任何具有平面结构的物体表面。平面方程nTx+d=0中的x = (X,Y, Z)指的是三维世界坐标系中的点,世界坐标系是一个固定的参考坐标系,用于描述三维空间中的物体位置和方向。在这个坐标系中,每个点的位置可以用三个坐标(X,Y, Z)来表示。如下图:
在这里插入图片描述

下面给出代码:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

struct userdata {
    Mat im;
    vector<Point2f> points;
};

void mouseHandler(int event, int x, int y, int flags, void* data_ptr) {
    if (event == EVENT_LBUTTONDOWN) {
        userdata* data = (userdata*)data_ptr;
        circle(data->im, Point(x, y), 3, Scalar(0, 255, 255), 5, LINE_AA);
        imshow("Image", data->im);
        if (data->points.size() < 4) {
            data->points.push_back(Point2f(x, y));
        }
    }
}

int main(int argc, char** argv) {
    // Read in the logo and the image with the billboard
    Mat im_logo = imread("cy.png");
    Mat im_ad = imread("tm.jpg");

    if (im_logo.empty() || im_ad.empty()) {
        cout << "Could not open or find the images!" << endl;
        return -1;
    }

    // Define the four corners of the logo in the logo image (source points)
    Size logo_size = im_logo.size();
    vector<Point2f> pts_logo = {
        Point2f(0, 0),
        Point2f(logo_size.width - 1, 0),
        Point2f(logo_size.width - 1, logo_size.height - 1),
        Point2f(0, logo_size.height - 1)
    };

    // Destination image
    Mat im_temp = im_ad.clone();
    userdata data;
    data.im = im_temp;

    // Show the image and set mouse callback
    imshow("Image", im_temp);
    cout << "Click on four corners of the billboard and then press ENTER" << endl;
    setMouseCallback("Image", mouseHandler, &data);
    waitKey(0);

    // Check if we have exactly four points
    if (data.points.size() != 4) {
        cout << "You need to click exactly four points!" << endl;
        return -1;
    }

    // Define the four corners of the billboard in the destination image (destination points)
    vector<Point2f> pts_ad = data.points;

    // Compute the perspective transform matrix
    Mat H = findHomography(pts_logo, pts_ad);

    // Warp the logo image to fit the billboard area in the destination image
    Mat im_warped;
    warpPerspective(im_logo, im_warped, H, im_ad.size());

    // Create a mask for the warped logo
    Mat mask = Mat::zeros(im_ad.size(), CV_8UC1);
    vector<Point> mask_points(pts_ad.begin(), pts_ad.end());
    fillConvexPoly(mask, mask_points, Scalar(255));

    // Blend the warped logo with the destination image
    Mat im_ad_masked;
    im_ad.copyTo(im_ad_masked, ~mask);  // Copy the background
    im_warped.copyTo(im_ad_masked, mask);  // Overlay the warped logo

    // Display the final result
    imshow("Result", im_ad_masked);
    waitKey(0);

    return 0;
}

最后出图是一位绝顶大帅哥(不是秃头):
在这里插入图片描述


http://www.kler.cn/news/285012.html

相关文章:

  • 探索视觉的边界:PyTorch与TorchVision的深度融合
  • zabbix4.0 实现钉钉告警
  • [ABC001A] 積雪深差
  • [服务器_1]rpc框架收集
  • 如何五分钟使用 Cocos Creator 快速部署 TON 游戏(第一部分)
  • Docker容器技术(下)超多好上手的实验,保姆级教程
  • 【时间盒子】-【1.序言】高效人士都在用的时间管理方法。我是如何通过鸿蒙元服务APP实现?
  • 深度学习第一周周报
  • Sobel算子,Scharr算子和Laplacian算子
  • 如何利用 Go 语言开发高性能服务
  • Fetch API 的基本使用
  • 探索JSON Schema的世界
  • 小程序使用iconfont字体图标
  • 【Unity-UGUI组件拓展】| ContentSizeFitter 组件拓展,支持设置最大宽高值
  • 网页html版——在线查字典的一个web服务器
  • Android 移除最近任务列表展示
  • CSND文章质量分批量查询
  • 类图的关联关系
  • Python基础 3 - 函数及数据容器
  • JAVA毕业设计167—基于Java+Springboot+vue3+小程序的物业管理系统小程序(源代码+数据库+万字论文+文献综述)
  • Llamaindex RAG实践
  • 并发服务器
  • 代码随想录算法训练营第六十天 | 图论part10
  • SkyWalking部署(监控系统)
  • jquery下载的例子如何应用到vue中
  • 【秋招笔试】8.30饿了么秋招(算法岗)-三语言题解
  • MongoDB 中国用户大会8月31日 (MongoDB 8.0 发布)
  • 医院建筑的电气设计——保障医疗质量与安全的坚固基石
  • 深度学习100问20:什么是RNN
  • GPT带我学-设计模式-责任链模式