点云基础知识储备(复习)

点云基础知识储备(复习)

齐次坐标

一个点的齐次坐标可以表示为(x,y,1),这种表示方法具备以下特征

具有标量乘法不变性:点(x,y,z)与(kx, ky, kz)实际上表示的是同一个点

矩阵表示的便利性:在齐次坐标中,变换一个点可以通过乘以一个变换矩阵来完成

表示直线:直线ax+by+c = 0可以表示为齐次坐标中的点(a,b,0),这种表示方式允许我们将点和直线统一在一个框架内,并且可以轻松地转换为其他坐标系统。

齐次坐标表示欧式变换

齐次坐标可以非常方便的表示旋转和平移 ,如果使用齐次坐标来表达 a’ = R*a + t 的话可以写为:
[ R t 0 1 ] [ a 1 ] = T [ a 1 ] \begin{bmatrix} R&t \\ 0 & 1 \end{bmatrix}\begin{bmatrix} a\\ 1 \end{bmatrix}=T\begin{bmatrix} a\\ 1 \end{bmatrix} [R0t1][a1]=T[a1]
那么进行多次欧氏变换只需要连乘变换矩阵就行了。

旋转矩阵、旋转向量、四元组、欧拉角

旋转矩阵

将二维平面向量绕x轴逆时针旋转θ角,旋转矩阵表示为:

x` = rcos(α+θ) = rcosαcosθ - rsinαsinθ = xcosθ - ysinθ

y` = rsin(α+θ) = rsinαcosθ + rcosαsinθ = xsinθ + ycosθ

[ x ′ y ′ ] = [ c o s θ − s i n θ s i n θ c o s θ ] [ x y ] \begin{bmatrix} x'\\ y' \end{bmatrix} = \begin{bmatrix} cosθ&-sinθ \\ sinθ & cosθ \end{bmatrix}\begin{bmatrix} x\\ y \end{bmatrix} [xy]=[cosθsinθsinθcosθ][xy]

欧拉角

偏航角:绕z轴旋转, 得到偏航角
俯仰角:绕y轴旋转, 得到俯仰角
翻滚角:绕x轴旋转, 得到翻滚角

名字取得很生动,可以自行现象一架飞机在z轴上

欧拉角和旋转矩阵可以相互转换:

在这里插入图片描述

使用Eigen库将旋转矩阵、四元素、旋转向量相互转化

在Eigen库中,旋转向量、旋转矩阵和四元数的相互转换关系如下:

在这里插入图片描述

// 初始化旋转向量
double angle = M_PI/4; // 45°转换为弧度
Vector3d axis = Vector3d::UnitZ(); // Z轴

// 初始化旋转向量 (1)
Vector3d rotation_vector = angle * axis;
// 初始化旋转向量(2)
Eigen::AngleAxisd(const Scalar& angle, const Axis& axis);
// 初始化旋转矩阵
Matrix3d rotation_matrix;
// 初始化四元数
Quaterniond quaternion(rotation_matrix);
// 初始化欧拉角
Vector3d euler_angles = rotation_matrix.eulerAngles(2, 1, 0); // ZYX顺序

相机成像

在这里插入图片描述

相机坐标系下的点P(X, Y, Z)在相机成像平面上成的像为P’(X’, Y’, Z’) 。根据三角形相似原理:
z f = X X ′ = Y Y ′ → X ′ = f X Z , Y ′ = f Y Z ( 1 ) \frac{z}{f} = \frac{X}{X'}= \frac{Y}{Y'} \to X'=f\frac{X}{Z}, Y'=f\frac{Y}{Z} (1) fz=XX=YYX=fZX,Y=fZY1
成像过程一般是以图像中心点为坐标系原点的,如下图所示。而我们做图像处理的时候习惯于从左上角为图像坐标系原点。

在这里插入图片描述

所以需要平移:

U = X’ + Cx (2)

V = Y’ + Cy

{ u = f x X Z + c x v = f y Y Z + c y \left\{\begin{matrix} u={f}_{x}\frac{X}{Z}+{c}_{x}\\ v={f}_{y}\frac{Y}{Z}+{c}_{y} \end{matrix}\right. {u=fxZX+cxv=fyZY+cy

使用齐次坐标表达为:

在这里插入图片描述

极几何与极约束

极几何与极约束在双目立体视觉测量,三位重建,运动估计,机器人导航与地图生成中都有一定作用,通过极线几何约束,可以将对应点匹配从整幅图像寻找压缩到在一条直线上寻找对应点,从而提高匹配效率。

在这里插入图片描述

上图表示的是一个运动的相机在两个不同位置的成像,C0, C1分别是两个位置中相机的光心,P是空间中的一个三维点,p0, p1分别是P点在不同成像平面上对应的像素点。

其中 两个相机光心的连线称为基线(C0C1),COC1与成像平面的交点称为极点,极平面与两像平面的交线,也就是极点与成像点的连线称为极线

由平面关系得:

在这里插入图片描述

叉乘得出平面法向量,它与平面上的向量c0p0的点乘结果为0。

将上述式子中的向量全部转到c0坐标系,得p0·(t×Rp1)= 0,简化得
p 0 T E p 1 = 0 p0 ^T E p1 = 0 p0TEp1=0

E = [ t ] R E = [t]R E=[t]R

E是t的反对称矩阵乘旋转矩阵R,记为本质矩阵(Essential Matrix)

所有的向量可以通过构造得到一个对应的反对称矩阵。在三维空间中,向量的反对称矩阵能够将向量的叉乘转换为矩阵运算。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由于:点p在直线l上的充分必要条件是:

l T ∗ P ′ = 0 l^T*P' = 0 lTP=0
我们把Ep1看成是直线方程 ,那么由

p 0 T E p 1 = 0 p0 ^T E p1 = 0 p0TEp1=0

得:点p0在Ep1上,Ep1既是以C0为原点坐标系的极线。

单应矩阵

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;
// 定义用户数据结构体,结构体包含原始图像im和用户点击的四个点(points)的位置
struct userdata {
    Mat im
    vector<Point2f> points;
};
// 当用户在广告牌图片上单击鼠标左键时,程序会在图像上画一个小圆圈,并将该点的坐标保存到points中。当点击四个点后,程序会停止记录点击。
void mouseHandler(int event, int x, int y, int flags, void* data_ptr) {
    // 检测鼠标左键按下事件
    if (event == EVENT_LBUTTONDOWN) {  
        // 定义了一个 userdata 类型的指针data,指向传入的 userdata 结构体实例
        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函数将鼠标事件和mouseHandler回调函数绑定在一起。
    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
    // 根据标志图像的四个角坐标pts_logo和广告牌四角的坐标pts_ad计算透视变换(单应性)矩阵H。
    Mat H = findHomography(pts_logo, pts_ad);

    // Warp the logo image to fit the billboard area in the destination image
    Mat im_warped;
    // 将标志图像根据透视变换矩阵H进行变换,使其匹配广告牌区域。
    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);
    // 这行代码的作用是将 pts_ad 中的 Point2f 类型的数据转换为 Point 类型,并存储到新的 mask_points 向量中。
    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;
    // copyTo 函数在 ~mask 为非零值的区域复制 im_ad 到 im_ad_masked。因此,广告牌区域会被排除在外,只复制非广告牌区域的背景内容。
    im_ad.copyTo(im_ad_masked, ~mask);  // Copy the background
    // 将 im_warped(即经过透视变换后的标志图像)复制到 im_ad_masked 的广告牌区域。
    im_warped.copyTo(im_ad_masked, mask);  // Overlay the warped logo

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

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值