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++的实现代码,已上传至:
有详细的Readme文件
python的opencv输出窗口左下角有专门的像素坐标提取信息,可以直接使用!