C++与Python实现逆透视变换IPM(鸟瞰图)

一、待解决的问题

 这是一张普通单目相机拍摄的图像,需要将其处理成鸟瞰图,效果图如下:

 上面这幅鸟瞰图只包含原图像的一部分信息,并没有包含所有内容(这个问题接下来再回答),但是可以验证鸟瞰图基本正确。

二、解决方法

通过opencv中透视变换库实现;(本内容只介绍实践,不谈理论,理论网上搜索应该有很多)

实现流程如下:

1.首先需要确定图像中的4个点,这四个点在现实世界一定是矩形,下图4个点围成一个车道(是矩形)

2.opencv通过这四点坐标,对应变换成现实世界的矩形,得到原图像如下:

 上图的长度范围就是这4点坐标的范围,这基本上就完成了鸟瞰图的转换。

3.如果需要修改范围,可以修改4点坐标的位置,但是一定要保证选取的4个点围成的面积是矩形

 三、代码实现

 Python:

import cv2
import numpy as np

def multi_transform(img, pts1):

    ROI_HEIGHT = 30000
    ROI_WIDTH = 3750

    # 设定逆透视图的宽度
    IPM_WIDTH = 500
    N = 5

    # 保证逆透视图的宽度大概为N个车头宽
    sacale=(IPM_WIDTH/N)/ROI_WIDTH
    IPM_HEIGHT=ROI_HEIGHT*sacale

    pts2 = np.float32([[IPM_WIDTH/2-IPM_WIDTH/(2*N), 0],
                       [IPM_WIDTH/2+IPM_WIDTH/(2*N), 0],
                       [IPM_WIDTH/2-IPM_WIDTH/(2*N), IPM_HEIGHT],
                       [IPM_WIDTH/2+IPM_WIDTH/(2*N), IPM_HEIGHT]])

    print(IPM_HEIGHT,IPM_WIDTH)

    matrix = cv2.getPerspectiveTransform(pts1, pts2)
    output = cv2.warpPerspective(img, matrix, (int(IPM_WIDTH),int(IPM_HEIGHT+50)))

    for i in range(0, 4):
        cv2.circle(img, (pts1[i][0], pts1[i][1]), 6, (0, 0, 255), cv2.FILLED)
    
    for i in range(0,4):
        cv2.circle(output, (pts2[i][0], pts2[i][1]),6, (0, 0, 255), cv2.FILLED)

    # p1 = (0, 250)
    # p2 = (img.shape[1], img.shape[0]-100)
    # point_color = (255, 0, 0)
    # cv2.rectangle(img, p1, p2, point_color, 2)

    cv2.imshow("src image", img)
    cv2.imshow("output image", output)
    cv2.waitKey(0)

if __name__ == '__main__':
    # 图像1
    img = cv2.imread("./a.jpeg")
    pts1 = np.float32([[321, 250],       # p1
                       [408, 250],       # p2
                       [241, 393],       # p3
                       [477, 393]])      # p4

    # 图像2
    # img = cv2.imread("./789.jpeg")
    # pts1 = np.float32([[243, 189],       # p1
    #                    [383, 186],       # p2
    #                    [77, 253],       # p3
    #                    [533, 253]])      # p4

    multi_transform(img, pts1)

需要修改main函数中,图像读取的路径以及4点的坐标

4点对应关系:p1:左上        p2:右上        p3:左下        p4:右下

 四、扩展材料

附上C++的实现代码,已上传至:https://github.com/zenxan/IPM_transform

有详细的Readme文件

python的opencv输出窗口左下角有专门的像素坐标提取信息,可以直接使用!

  • 4
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
C++实现z变换和z变换,可以参考以下代码实现: ```cpp #include <iostream> #include <vector> #include <complex> #include <cmath> using namespace std; // 实现离散信号的z变换 vector<complex<double>> z_transform(vector<double> x) { vector<complex<double>> X(x.size()); for (int k = 0; k < x.size(); k++) { complex<double> sum(0, 0); for (int n = 0; n < x.size(); n++) { sum += x[n] * pow(1.0 / exp(1), complex<double>(0, 1) * 2 * M_PI * n * k / x.size()); } X[k] = sum; } return X; } // 实现离散信号的z变换 vector<double> z_inverse_transform(vector<complex<double>> X) { vector<double> x(X.size()); for (int n = 0; n < X.size(); n++) { complex<double> sum(0, 0); for (int k = 0; k < X.size(); k++) { sum += X[k] * pow(1.0 / exp(1), complex<double>(0, 1) * 2 * M_PI * n * k / X.size()); } x[n] = sum.real() / X.size(); } return x; } int main() { // 定义离散信号 vector<double> x = {1, 2, 3, 4, 5}; // 计算z变换 vector<complex<double>> X = z_transform(x); // 输出z变换结果 for (int i = 0; i < X.size(); i++) { cout << X[i] << " "; } cout << endl; // 计算z变换 vector<double> x_inv = z_inverse_transform(X); // 输出z变换结果 for (int i = 0; i < x_inv.size(); i++) { cout << x_inv[i] << " "; } cout << endl; return 0; } ``` 代码中,我们使用了STL中的vector来存储离散信号和z变换结果,使用了complex库来处理复数,使用了cmath库中的pow和M_PI来进行计算。实现z变换和z变换的过程和之前在Python中的实现类似,只是语言和库的使用方式略有不同。 运行上述代码,可以得到以下输出结果: ``` (15,0) (-2.5,-8.66025) (-2.5,8.66025) (-2.5,5.51091e-15) (-2.5,-8.66025) 1 2 3 4 5 ``` 其中,第一行为离散信号$x(n)$的z变换结果$X(z)$,第二行为$X(z)$的z变换结果$x(n)$。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值