代码原理

无人机正射拍摄,已知像素物理尺寸,使用大疆飞机拍摄的信息,进行像素坐标估算,理论精度应该在米级,但是航偏角以及定位误差导致与实际有所不同

部分参数查看无人机相机参数
在这里插入图片描述

关键代码 1. 提取图像参数

def Get_Image_Yaw_angle(file_path):
    """
    :param file_path: 输入图片路径
    :return: 图片的偏航角
    """
    # 获取图片偏航角
    #print("----------------------------------大疆exifread信息---------------------------------")
    # 定义字节模式 b 和 a,用于查找大疆EXIF数据的起始和结束标记
    b = b"\x3c\x2f\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x3e"
    a = b"\x3c\x72\x64\x66\x3a\x44\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20"
    # 打开图片文件,以二进制模式读取
    img = open(file_path, 'rb')
    # 初始化一个字节数组用于存储EXIF数据
    data = bytearray()
    # 初始化一个标志,用于判断是否已经找到EXIF数据的起始标记
    flag = False
    # 逐行读取图片文件内容
    for line in img.readlines():
        # 如果当前行包含EXIF数据的起始标记,则设置标志为True
        if a in line:
            flag = True
            # 如果标志为True,则将当前行添加到EXIF数据中
        if flag:
            data += line
            # 如果当前行包含EXIF数据的结束标记,则跳出循环
        if b in line:
            break
            # 如果提取到的EXIF数据不为空
    dj_data_dict = {}
    # 遍历过滤后的行,并提取键值对存入字典中
    if len(data) > 0:
        # 将字节数据解码为ASCII字符串
        data = str(data.decode('ascii'))
        # 过滤出包含drone-dji的行,并分割每行为键值对
        lines = list(filter(lambda x: 'drone-dji:' in x, data.split("\n")))
        #lines = list(filter(lambda x: x, data.split("\n")))
        # 初始化一个空字典用于存储提取到的数据
        for d in lines:
            if "640" in d:
                print(d)
            d = d.strip()[10:]  # 去除每行的前后空格和'\n'字符,并从第10个字符开始处理(因为drone-dji:占据了前9个字符)
            res = d.split("=")
            k, v = res[0],res[1] # 将当前行分割为键和值两部分
            dj_data_dict[k] = v  # 将键值对存入字典中
    return dj_data_dict  # 返回偏航角的值。如果未找到偏航角,则返回None。
def get_value(dj_data_dict, key):
    valu = dj_data_dict[key]
    valu = valu.replace('"', '').replace('+', '')
    return valu

关键代码 2.旋转位姿

# 定义经纬度与平面坐标系的转换
wgs84 = Proj(init="epsg:4326")  # WGS 84 经纬度坐标系
mercator = Proj(init="epsg:3857")  # 墨卡托投影坐标系
def rotate_point(x, y, x_center, y_center, pic_row):

    # 将点平移至旋转中心
    x_prime = x - x_center
    y_prime = y - y_center
    
    # 将角度转换为弧度
    theta = radians(pic_row)
    
    # 应用旋转矩阵
    x_rot = x_prime * cos(theta) - y_prime * sin(theta)
    y_rot = x_prime * sin(theta) + y_prime * cos(theta)
    
    # 将旋转后的坐标平移回去
    x_rot += x_center
    y_rot += y_center
    
    return x_rot, y_rot

关键代码 3.计算坐标


def calculate_pos(center_pix: tuple, center_pos: tuple, height: float, board_corners: tuple, pic_row: float) -> Tuple[float, float]:
    focal_length, dist_per_pix = (91*53/40)*1e-4, 6e-6  # unit: m, m/pix   / 2
    #维度
    ratio = height / focal_length  # unit: None
    board_center = board_corners  # unit: pix
    dx_pix, dy_pix = board_center[0] - center_pix[0], center_pix[1] - board_center[1]  # unit: pix, pix
    dx_ccd, dy_ccd = dx_pix * dist_per_pix, dy_pix * dist_per_pix  # unit: m, m
    dx_real, dy_real = dx_ccd * ratio, dy_ccd * ratio  # unit: m, m
    #dlon, dlat = dx_real / dist_per_lon, dy_real / dist_per_lat  # unit: deg, deg
    result = (center_pos[0] + dx_real, center_pos[1] + dy_real)
    #这个为假设图像为正北方向,如果图像不是正北方向,需要根据实际情况
    # 点result绕点center_pos中心点旋转pic_row度的坐标
    result = rotate_point(result[0], result[1], center_pos[0], center_pos[1], pic_row)
    result = (result[0], result[1])

    return result

详细完整代码放在我的资源下载,可以免费下载

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐