问题及需求

获取当前carla世界三维坐标的二维俯视坐标系表达,即将三维坐标投射到二维坐标系上。

可将carla世界的三维坐标转换为俯视地图上的二维坐标。

可以将汽车在carla世界的连续坐标,投射到俯视地图中,获得汽车轨迹的直观表述。

当前环境

  1. Ubuntu 20.04.6 LTS

  2. carla0.9.14

程序位置

https://github.com/DarkerSun6/carla_bev_map_coordinate.giticon-default.png?t=O83Ahttps://github.com/DarkerSun6/carla_bev_map_coordinate.git

实现效果 

问题解决1-获取carla三维三维点坐标

加载carla地图,设置俯视观察视角,可选是否卸载地图除路网外的其他元素,在carla世界中生成原点和随机点,在carla世界中将其绘制出来,并将carla世界三维点坐标保存到carla_points2.txt

此时还需截图当前carla俯视图,应包含carla整个世界,其中一个包含绘制点,一个不包含,注意两个截图大小位置应完全相同,保存为carla_town03_allmap_points.png,carla_town03_allmap.png两个文件

关键程序1-设置俯视观察视角

def set_spectator_transform():
    # world = client.get_world()#获取世界
    spectator = world.get_spectator()
    spectator_transform = carla.Transform(
        carla.Location(x=0.0, y=0.0, z=200.0),
        carla.Rotation(pitch=-90,yaw=-90)  # 设置俯视角度
    )
    spectator.set_transform(spectator_transform)

关键程序2-生成并绘制世界原点和随机点

def get_spawn_points(num_points):
    map = world.get_map()                     
    # 获取所有可能的车辆生成点
    spawn_points = map.get_spawn_points() 
    # 随机选择生成点
    random.shuffle(spawn_points)
    vehicle_spawn_points = spawn_points[:num_points]
    #将第一个点的location设置为0,0,0
    vehicle_spawn_points[0].location = carla.Location(0,0,0)
    # 在地图上标记这10个点,并显示编号
    for index, spawn_point in enumerate(vehicle_spawn_points):
        # 在地面上绘制一个3D文本显示数字
        text = str(index)
        world.debug.draw_string(spawn_point.location, text, draw_shadow=False,
                                color=carla.Color(r=255, g=0, b=0), life_time=600.0,
                                persistent_lines=True)
    return vehicle_spawn_points

问题解决2-获取图片二维像素点坐标

读取carla_town03_allmap_points.png文件,依照上面carla世界点的位置,左键标记所有绘制点,此时得到carla世界点坐标对应的像素坐标,保存到Img_lable2.txt

关键程序-读取照片并可以标记储存像素点

import os
import cv2 as cv
import numpy as np

img_name = "Coordinate_system/carla_town03_allmap_points.png"
# name = "Town03.jpg" 
file_name = 'Coordinate_system/img_label_2.txt'
data = []
def readImage(img_name):
    img1 = cv.imread(img_name)  
    return img1
def draw_(event, x, y,flag, param):
    global  data, img1 
    if event == cv.EVENT_LBUTTONDOWN:
        """左键单击打标签"""
        xy = "%d,%d" % (x, y)
        cv.circle(img1, (x, y),2, (255, 0, 0), thickness=-1)
        data.append([x,y])
def save_points(file_name):
    with open(file_name, 'w') as f:
        for i in range(len(data)):
            f.write(f"{data[i][0]}, {data[i][1]}\n")
        f.close()
    ab_filename = os.path.abspath(file_name)
    print(ab_filename)

try:
    cv.namedWindow('image',cv.WINDOW_NORMAL)
    cv.setMouseCallback('image', draw_)
    img1 = readImage(img_name)
    while 1:
        cv.imshow('image', img1)
        c = cv.waitKey(10) & 0xFF
        if c == ord('c'): #按c退出
            break
        f = cv.waitKey(10) & 0xFF    # 按f保存
        if f == ord('f'):
            save_points(file_name)
finally:
    cv.destroyAllWindows()

问题解决3-计算转换矩阵

读取carla_points2.txt和Img_lable2.txt,计算出carla世界点坐标和像素点坐标之间的转换矩阵

将旋转、缩放、平移矩阵和总的变换矩阵保存到translation_matrix.txt中

计算carla世界原点坐标对应像素原点坐标,并计算carla世界坐标点距离差和像素点坐标距离差的对应比例

关键程序1-计算转换矩阵

def compute_transform_parameters(points_a, points_b):
    """
    计算缩放因子、旋转角度和平移量。
    """
    # 目标函数,最小化残差
    def residuals(params, points_a, points_b):
        sx, sy, theta, tx, ty = params
        c, s = np.cos(theta), np.sin(theta)
        rotation_matrix = np.array([[c, -s], [s, c]])
        scale_matrix = np.array([[sx, 0], [0, sy]])
        transformation_matrix = rotation_matrix  @ scale_matrix
        transformed_points = np.dot(points_a, transformation_matrix.T) + [tx, ty]
        return (transformed_points - points_b).flatten()  # 展平为一维数组
    initial_guess = [1.0, 1.0, 0.0, 0.0, 0.0]  # 初始猜测值  缩放因子sx, sy,旋转角,平移x,平移y
    result = least_squares(residuals, initial_guess, args=(points_a, points_b))  #使用最小二乘法优化
    return result.x[0], result.x[1], result.x[2], result.x[3], result.x[4]

关键程序2- 构建变换矩阵

def build_transformation_matrix(sx, sy, angle, translation):
    """
    根据给定的参数构建变换矩阵。
    """
    c, s = np.cos(angle), np.sin(angle)
    rotation_matrix = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
    print("Rotation angle (radians):")
    print(rotation_matrix)

    scale_matrix = np.array([[sx, 0, 0], [0, sy, 0], [0, 0, 1]])
    print("Scale factor:")
    print( scale_matrix)

    translation_matrix = np.array([[1, 0, translation[0]], [0, 1, translation[1]], [0, 0, 1]])
    print("Translation vector:" )
    print(translation_matrix)

    # 计算最终的变换矩阵
    transform_matrix = translation_matrix @  scale_matrix @  rotation_matrix
    print("\nFinal Transformation Matrix:")
    print(transform_matrix)
    print("----------------------------------------")
    return rotation_matrix,scale_matrix,translation_matrix,transform_matrix

关键程序3-计算原点坐标和两个坐标系的比例转换

def test_carla2img(points,transform_matrix,width,height):
    all_carla2img_points = []
    for point in points:
        print(f"carla point : {point}")
        carla2img_point = np.dot(point, transform_matrix[:2, :2].T) 
        carla2img_point += transform_matrix[:2, 2]
        carla2img_point[0] += width/2
        carla2img_point[1] += height/2
        # 将carla2img_point四舍五入为整数
        carla2img_point = np.round(carla2img_point)
        # 化为整数
        carla2img_point = carla2img_point.astype(int)
        print(f"test_carla2img point: {carla2img_point}")
        print("----------------------------------------")
        all_carla2img_points.append(carla2img_point)
    gloal_interval_x,gloal_interval_y = 0,0
    num_x,num_y = 0,0
    for i in range(len(all_carla2img_points)-1):
        if all_carla2img_points[i][0] != all_carla2img_points[i+1][0]:
            gloal_interval_x += abs(all_carla2img_points[i][0]-all_carla2img_points[i+1][0])
            num_x += 1
        if all_carla2img_points[i][1] !=  all_carla2img_points[i+1][1]:
            gloal_interval_y += abs(all_carla2img_points[i][1]-all_carla2img_points[i+1][1])
            num_y += 1
    grid_interval_x =gloal_interval_x/num_x
    grid_interval_y = gloal_interval_y/num_y

问题解决4-绘制carla世界俯视二维坐标系

将第一步得到的carla_town03_allmap.png

第三步得到的像素原点坐标,carla世界坐标点距离差和像素点坐标距离差的对应比例

提供给create_grid_on_image绘制方法,并给定输出位置

绘制一张carla世界俯视二维坐标系

关键程序-绘制坐标系

def create_grid_on_image(image_path, origin,grid_interval_x,grid_interval_y,add_x,add_y, output_path):
    try:
        # 加载图像
        img = Image.open(image_path)
    except IOError as e:
        print(f"Error opening image file: {e}")
        return
    draw = ImageDraw.Draw(img)
    # 获取图像尺寸
    width, height = img.size
    # 设置坐标轴的颜色
    axis_color = 'green'
    grid_color = 'gray'
    label_color = 'red'
    # 尝试加载字体
    try:
        # font = ImageFont.truetype("STKaiti", 20)
        fontsize = 15
        font = ImageFont.truetype(fm.findfont(fm.FontProperties(family='DejaVu Sans')),fontsize)
    except IOError:
        # 如果找不到字体文件,则使用默认字体
        print("Error loading font. Using default font.")
        font = ImageFont.load_default()
    # 计算中心位置作为原点 (0,0)
    center_x = origin[0]
    center_y = origin[1]
    # 绘制网格线
    for x in range(center_x, width, grid_interval_x):
        draw.line([(x, 0), (x, height)], fill=grid_color)
    for x in range(center_x, 0, -grid_interval_x):
        draw.line([(x, 0), (x, height)], fill=grid_color)
    for y in range(center_y, height, grid_interval_y):
        draw.line([(0, y), (width, y)], fill=grid_color)
    for y in range(center_y, 0, -grid_interval_y):
        draw.line([(0, y), (width, y)], fill=grid_color)
    # 绘制坐标轴
    draw.line([(0, center_y), (width, center_y)], fill=axis_color)
    draw.line([(center_x, 0), (center_x, height)], fill=axis_color)
    # 在坐标轴上放置坐标值标签
    x_label_ps,x_label_ng = 0,0
    for x in range(center_x , width, grid_interval_x):
        draw.text((x-10, center_y ), str(x_label_ps), fill=label_color, font=font)
        x_label_ps += add_x
    for x in range(center_x , 0, -grid_interval_x):
        draw.text((x-10, center_y ), str(x_label_ng), fill=label_color, font=font)
        x_label_ng -= add_x
    y_label_ps,y_label_ng = 0,0
    for y in range(center_y+grid_interval_y, height, grid_interval_y):
        y_label_ps += add_y
        draw.text((center_x , y-10), str(y_label_ps), fill=label_color, font=font)
    for y in range(center_y-grid_interval_y, 0, -grid_interval_y):
        y_label_ng -= add_y
        draw.text((center_x , y-10), str(y_label_ng), fill=label_color, font=font)
    # 保存带有网格的图像
    img.save(output_path)
    img.show()

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐