无人机像素经纬度识别

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

问题描述

  无人机像素经纬度识别。根据代码,我的需求就是鼠标点击照片中某一点的坐标,能迅速识别出这一点的经纬度信息,但是两张照片,拍摄的同一位置显示的结果并不相同,我的无人机是垂直于地面飞行,不考虑地球曲率、图像畸变,我的思路是先提取出图像的经纬度信息,这个经纬度信息是飞行器拍摄位置也是图像中心点的经纬度坐标,知道了图像的GSD,调用鼠标,计算鼠标点击区域的经纬度信息。

代码如下:

import exifread
import cv2
import numpy as np
import math
 
# 从图像文件中提取GPS信息
def extract_gps_info(file_path):
    with open(file_path, 'rb') as f:
        tags = exifread.process_file(f)
        if 'GPS GPSLatitude' in tags and 'GPS GPSLongitude' in tags:
            latitude = tags['GPS GPSLatitude'].values
            longitude = tags['GPS GPSLongitude'].values
            latitude_ref = tags['GPS GPSLatitudeRef'].values
            longitude_ref = tags['GPS GPSLongitudeRef'].values
 
            lat_degrees = float(latitude[0].num) / float(latitude[0].den)
            lat_minutes = float(latitude[1].num) / float(latitude[1].den)
            lat_seconds = float(latitude[2].num) / float(latitude[2].den)
 
            lon_degrees = float(longitude[0].num) / float(longitude[0].den)
            lon_minutes = float(longitude[1].num) / float(longitude[1].den)
            lon_seconds = float(longitude[2].num) / float(longitude[2].den)
 
            if latitude_ref == 'S':
                lat_degrees = -lat_degrees
            if longitude_ref == 'W':
                lon_degrees = -lon_degrees
 
            latitude_decimal = lat_degrees + lat_minutes/60 + lat_seconds/3600
            longitude_decimal = lon_degrees + lon_minutes/60 + lon_seconds/3600
 
            return latitude_decimal, longitude_decimal
        else:
            return None
 
# 主函数
if __name__ == '__main__':
    # 图像文件路径
    file_path = 'DJI_20231225165215_0426_T.JPG'
 
    # 提取GPS信息
    gps_info = extract_gps_info(file_path)
    if gps_info is not None:
        latitude_decimal, longitude_decimal = gps_info
        print(f"Latitude: {latitude_decimal:.6f}")
        print(f"Longitude: {longitude_decimal:.6f}")
    else:
        print("No GPS information found in the image.")
 
    # 加载热红外图像
    infrared_image = cv2.imread(file_path, cv2.IMREAD_UNCHANGED)
 
    # 无人机位置和姿态数据
    uav_latitude = latitude_decimal  # 无人机纬度
    uav_longitude = longitude_decimal  # 无人机经度
    uav_altitude = 20  # 无人机高度(米)
    uav_roll_angle = 0  # 无人机横滚角(度)
    uav_pitch_angle = -90  # 无人机俯仰角(度)
    uav_yaw_angle = 64.60
        #74.40  # 无人机偏航角(度)
 
    # 相机内参数
    focal_length = 758.33# 焦距(像素)
    sensor_size_width = 7.68  # 传感器宽度(毫米)
    sensor_size_height = 6.144  # 传感器高度(毫米)
    image_width = 640  # 图像宽度(像素)
    image_height = 512  # 图像高度(像素)
    gsd = 0.05275  # 单位:米 (meters),地面采样距离
 
    # 计算相机的内外参数矩阵
    camera_matrix = np.array([[focal_length, 0, image_width / 2],
                              [0, focal_length, image_height / 2],
                              [0, 0, 1]], dtype=np.float32)
 
    dist_coefs = np.zeros((4, 1), dtype=np.float32)  # 假设无畸变
 
 
    # 鼠标单击事件回调函数
    def get_pixel_coord(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            # 计算点击位置在图像中的坐标
            pixel_x = x
            pixel_y = y
 
            # 计算点击点相对于中心的偏移量
            cx = image_width / 2 # 单位:像素 (pixels)
            cy = image_height / 2  # 单位:像素 (pixels)
            delta_x = pixel_x - cx  # 单位:像素 (pixels)
            delta_y = pixel_y - cy  # 单位:像素 (pixels)
 
            # 考虑偏航角
            theta = math.radians(uav_yaw_angle)  # 单位:弧度 (radians)
 
            # 旋转偏移量以考虑偏航角
 
            delta_x_prime = delta_x * math.cos(theta) - delta_y * math.sin(theta)  # 单位:像素 (pixels)
            delta_y_prime = delta_x * math.sin(theta) + delta_y * math.cos(theta)  # 单位:像素 (pixels)
 
            # 根据GSD计算实际距离
            delta_x_meters = delta_x_prime * gsd  # 单位:米 (meters)
            delta_y_meters = delta_y_prime * gsd  # 单位:米 (meters)
 
            # 计算点击点的经纬度
            click_lat = uav_latitude + delta_y_meters / (111000)  # 111000米大约是1度纬度的距离,单位:度 (degrees)
            click_lon = uav_longitude + delta_x_meters / (111000 * math.cos(math.radians(uav_latitude)))  # 单位:度 (degrees)
 
 
            print(f"Pixel coordinates: ({x}, {y})")
            print(f"Latitude: {click_lat:.8f}")
            print(f"Longitude: { click_lon:.8f}")
 
    cv2.imshow('Infrared Image', infrared_image)
    cv2.setMouseCallback('Infrared Image', get_pixel_coord)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

友情提示:
  如上问题有的来自我自身项目开发,有的收集网站,有的来自读者…如有侵权,立马删除。再者,针对此专栏中部分问题及其问题的解答思路或步骤等,存在少部分搜集于全网社区及人工智能问答等渠道,若最后实在是没能帮助到你,还望见谅!并非所有的解答都能解决每个人的问题,在此希望屏幕前的你能够给予宝贵的理解,而不是立刻指责或者抱怨!如果你有更优解,那建议你出教程写方案,一同学习!共同进步。

解决方案

  如下是上述问题的解决方案,仅供参考:

  您的代码目的是通过鼠标点击图像来获取该点的经纬度信息。您已经实现了从图像中提取GPS信息,以及通过鼠标点击事件计算点击点的经纬度。但是,您提到两张照片拍摄同一位置时显示的结果不同,这可能是由几个因素造成的:

  1. GPS信息的准确性:确保提取的GPS信息是准确的。有时,GPS信息可能因为多种原因(如遮挡、干扰等)而不准确。

  2. 图像缩放或旋转:如果图像在拍摄或处理过程中被缩放或旋转,可能会影响到计算结果。

  3. GSD(地面采样距离)的一致性:确保两张照片的GSD是一致的,如果GSD不同,即使同一位置,点击相同像素点也会得到不同的经纬度。

  4. 相机参数的一致性:包括焦距、传感器大小等,这些参数的不同可能导致计算结果的差异。

  5. 地球曲率和图像畸变:虽然您提到不考虑地球曲率和图像畸变,但在实际应用中,这些因素可能对精确计算有影响。

  6. 鼠标点击的精度:用户点击的精度也会影响最终结果。

为了解决这个问题,您可以尝试以下步骤:

  • 验证提取的GPS信息是否准确无误。
  • 确保两张照片的相机参数和GSD是一致的。
  • 如果可能,检查图像是否在拍摄或处理过程中被修改过。
  • 考虑实现一个更精确的地理坐标转换算法,如使用地理坐标系转换库。

此外,您的代码中有几个潜在的问题需要修正:

  • 在计算点击点的经纬度时,您使用了111000作为每度纬度的平均米数,但这个值在不同纬度下会有所变化。更准确的计算应该考虑当前纬度的地球半径。
  • 您的代码中uav_yaw_angle有两个赋值,应该只保留一个。

修正后的代码段如下:

# 计算点击点的经纬度
# 使用WGS-84模型下的地球半径
earth_radius = 6378137  # 单位:米
click_lat = uav_latitude + (delta_y_meters / earth_radius) * (math.pi / 180)
click_lon = uav_longitude + (delta_x_meters * math.cos(math.radians(click_lat)) / earth_radius) * (math.pi / 180)

请注意,这些修正只是基于您提供的代码和描述。实际问题可能需要更详细的分析和调整。如果问题依然存在,建议检查所有可能影响计算的因素,并考虑使用更专业的地理信息系统(GIS)工具或库来处理经纬度转换。

  希望如上措施及解决方案能够帮到有需要的你。

  PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。

  若有对当前Bug有与如下提供的方法不一致,有个不情之请,希望你能把你的新思路或新方法分享到评论区,一起学习,目的就是帮助更多所需要的同学,正所谓「赠人玫瑰,手留余香」。

☀️写在最后

  ok,以上就是我这期的Bug修复内容啦,如果还想查找更多解决方案,你可以看看我专门收集Bug及提供解决方案的专栏《CSDN问答解惑-专业版》,都是实战中碰到的Bug,希望对你有所帮助。到此,咱们下期拜拜。

码字不易,如果这篇文章对你有所帮助,帮忙给 bug菌 来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。

同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿哇。


  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以使用python的Pillow库来读取图片,然后使用EXIF数据来获取图片的经纬度信息。以下是示例代码: ``` from PIL import Image from PIL.ExifTags import GPSTAGS, TAGS def get_exif_data(image): """ 获取图片的元数据 """ exif_data = {} with Image.open(image) as img: info = img._getexif() if info: for tag, value in info.items(): decoded = TAGS.get(tag, tag) exif_data[decoded] = value return exif_data def get_geotagging(exif_data): """ 获取图片的经纬度信息 """ lat = None lng = None gps_info = {} if "GPSInfo" in exif_data: # 获取GPS信息 gps_info = exif_data["GPSInfo"] gps_latitude = get_gps_coords(gps_info, "GPSLatitude") gps_latitude_ref = gps_info.get("GPSLatitudeRef") gps_longitude = get_gps_coords(gps_info, "GPSLongitude") gps_longitude_ref = gps_info.get("GPSLongitudeRef") lat = convert_to_degrees(gps_latitude) if gps_latitude_ref != "N": lat = 0 - lat lng = convert_to_degrees(gps_longitude) if gps_longitude_ref != "E": lng = 0 - lng return lat, lng def get_gps_coords(gps_info, gps_tag): """ 获取GPS信息中的经纬度坐标值 """ coords = gps_info.get(gps_tag) if coords is None: return None num, den = coords[0], coords[1] val = float(num) / float(den) for i in range(2, len(coords)): num, den = coords[i], coords[i + 1] if i + 1 < len(coords) else 1 val += (float(num) / float(den)) / 60.0 return val def convert_to_degrees(value): """ 将经纬度转换为以度为单位的值 """ deg, minutes = int(value[0]), value[1:] val = deg + (float(minutes[0]) / float(minutes[1])) / 60.0 return val # 调用上述函数来获取图片的经纬度信息 exif_data = get_exif_data("image.jpg") lat, lng = get_geotagging(exif_data) print("经度:", lng) print("纬度:", lat) ``` 需要注意的是,无人机拍摄的图片可能不包含GPS信息,或是GPS信息不完整甚至不正确,此时获取到的经纬度信息就可能是不准确的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug菌¹

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值