tuoheng_algN/util/LocationUtils.py

156 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os,math
import numpy as np
# WGS-84经纬度转Web墨卡托
def wgs_to_mercator(x, y):
y = 85.0511287798 if y > 85.0511287798 else y
y = -85.0511287798 if y < -85.0511287798 else y
x2 = x * 20037508.34 / 180.0
y2 = math.log(math.tan((90.0 + y) * math.pi / 360.0)) / (math.pi / 180.0)
#print( ' y:',y, " before Log:",math.tan((90.0 + y) * math.pi / 360.0), ' log:' , math.log(math.tan((90.0 + y) * math.pi / 360.0)))
y2 = y2 * 20037508.34 / 180.0
return x2, y2
def mercator_to_wgs(x, y):
"""
将墨卡托投影坐标转换为WGS-84经纬度坐标
:param x: 墨卡托投影的X坐标
:param y: 墨卡托投影的Y坐标
:return: 经度longitude和纬度latitude
"""
# 地球半径(米)
R = 6378137.0
# 墨卡托投影的X坐标转换为经度
lon = x / R * 180.0 / math.pi
# 墨卡托投影的Y坐标转换为纬度
lat = math.atan(math.sinh(y / R)) * 180.0 / math.pi
return lon, lat
def ImageCorToCamCor(p0,w=1920,h=1080):
x,y=p0[0:2]
return x-w/2.,(h-y)-h/2.
def wgs84_to_gcj02(lat, lon):
"""将 WGS-84 坐标转换为 GCJ-02 坐标 (高德地图坐标)"""
A = 6378245.0 # 长半轴
EE = 0.00669342162296594323 # 偏心率平方
if out_of_china(lat, lon):
return lat, lon # 如果在中国以外,直接返回 WGS-84 坐标
# 坐标转换
dlat = transform_lat(lon - 105.0, lat - 35.0)
dlon = transform_lon(lon - 105.0, lat - 35.0)
radlat = lat / 180.0 * math.pi
magic = math.sin(radlat)
magic = 1 - EE * magic * magic
sqrt_magic = math.sqrt(magic)
dlat = (dlat * 180.0) / (A * (1 - EE) / (magic * sqrt_magic) * math.pi)
dlon = (dlon * 180.0) / (A / sqrt_magic * math.cos(radlat) * math.pi)
mg_lat = lat + dlat
mg_lon = lon + dlon
return mg_lat, mg_lon
def out_of_china(lat, lon):
"""检查坐标是否在中国以外"""
return lon < 72.004 or lon > 137.8347 or lat < 0.8293 or lat > 55.8271
def transform_lat(lon, lat):
"""辅助函数: 进行纬度转换"""
ret = (-100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat +
0.1 * lon * lat + 0.2 * math.sqrt(abs(lon)))
ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0
ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
ret += (160.0 * math.sin(lat / 12.0 * PI) + 320.0 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0
return ret
def transform_lon(lon, lat):
"""辅助函数: 进行经度转换"""
ret = (300.0 + lon + 2.0 * lat + 0.1 * lon * lon +
0.1 * lon * lat + 0.1 * math.sqrt(abs(lon)))
ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0
ret += (20.0 * math.sin(lon * PI) + 40.0 * math.sin(lon / 3.0 * PI)) * 2.0 / 3.0
ret += (150.0 * math.sin(lon / 12.0 * PI) + 300.0 * math.sin(lon / 30.0 * PI)) * 2.0 / 3.0
return ret
def cam2word(p0,pUAV,yaw,delta=1.55e-3 * 4056.0/1920,pitch=-45,f=4.5,camH=50e3,igW=1920,igH=1080):
pitch = pitch/180.0*np.pi
sinp = np.sin(pitch );cosp= np.cos(pitch)
p0_new = ImageCorToCamCor(p0,igW,igH)
Xc0 = p0_new[0]*delta;Zc0 = p0_new[1]*delta;
#(Zw0,Xw0)--相对于光心XZ并未校正到正东和正北。
#f=4.5*f/24.00
Zw0=camH*( -f*sinp + Zc0*cosp )/( f*cosp + Zc0*sinp)*1e-3
Xw0= camH*Xc0/(f*cosp + Zc0*sinp)*1e-3
#print(' %4.0f %4.0f %4.8f %4.8f %4.8f %4.8f f:%.2f'%( p0[0],p0[1], Xc0, Zc0,Xw0,Zw0,f ) )
#yaw定义为拍摄方向即图片的高方位Z方向偏离正北的方向北偏东为正。
yaw_rad = yaw/180.0*np.pi
siny=np.sin(yaw_rad);cosy=np.cos(yaw_rad)
Zx0_rot = Xw0*cosy + Zw0*siny + pUAV[0]
Zw0_rot = -Xw0*siny + Zw0*cosy + pUAV[1]
return Zx0_rot,Zw0_rot
def location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84'):
'''
输入图像中点的XY坐标及无人机相关信息、相机相关信息输出该点的Wgs84经纬度坐标
point--点在图像上的坐标左上角为0,0X方向为宽度方向Y方向为高度方向
igW--图像的宽度
igH--图像的高度
PlanWgs84--无人机的Wgs84坐标(lon,lat),(经度,纬度)
PlanH--无人机拍照时的相对高度用mm表示
yaw--云台的yaw
delta--单个像素的长度值用mm表示。
pitch--无人的pitch
focal--真实焦距用mm表示
'''
PlanX,PlanY = wgs_to_mercator(PlanWgs84[0],PlanWgs84[1])
#print('location:',PlanX,PlanY)
#PlanX,PlanY--东西、南北方向的墨卡托投影坐标
#print( 'line268:',point,PlanX,PlanY,yaw, delta,pitch,focal,PlanH,igW,igH )
cor_world = cam2word( point,(PlanX,PlanY),yaw, delta,pitch,focal,PlanH,igW,igH)
cor_world = mercator_to_wgs(cor_world[0], cor_world[1])
if outFormat=='GCJ02' or outFormat=='gcj02':
cor_world = wgs84_to_gcj02(cor_world[0], cor_world[1])
return cor_world
def locate_byMqtt(box,igW,igH,camParas,outFormat='wgs84'):
#camParas--{'lon': 3479.8250608, 'lat': 3566.7630802, 'gpssingal': 4, 'satcount': 6896, 'alt': 3.256, 'hspeed': 86.0, 'vspeed': 4.447911, 'ysingal': 0, 'tsingal': 0, 'voltage': 24.971, 'flytime': 0, 'datetime': 1739315683895, 'yaw': 70.243252, 'roll': -0.89436062, 'pitch': 0.89897547, 'armed': 'false', 'mode': 'stabilize', 'distToHome': 7.132033, 'deviceid': 'THJSQ03A2302KSPYGJ2G', 'mileage': '0', 'altasl': 21.26, 'altasl2': -20.74, 'landing_target_x': 0, 'landing_target_y': 0, 'landing_target_z': 0}
#模型输出的点的格式是-[(486, 264), (505, 264), (505, 290), (486, 290)]
box_np = np.array(box);
point = int(np.mean( box_np[:,0] )) , int(np.mean( box_np[:,1] ))
PlanWgs84 = (float(camParas['lon']),float(camParas['lat'])) #
PlanH = float(camParas['alt'])#
yaw = float(camParas['camerayaw'])
#delta = camParas['']
delta = 1.55e-3 * 4056.0/1920
pitch = float(camParas['camerapitch'])
#focal = camParas['']
focal = 3.5
out = location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84')
return out
if __name__=="__main__":
srt="videos/DJI_20221220133918_0001_W_0.SRT"
videoUrl = "videos/DJI_20221220133918_0001_W.MP4"
imgOut= "videos/imgs"
fpbeg=17273;fpend=17830
nums = list(range(fpbeg,fpend,16))
#generateNewSRT(srt)
#captureImages(videoUrl,nums,imgOut)
process(videoUrl,srt,nums,imW=1920,imH=1080,txtDir='videos/labels' )
#draw_results()
#rotate_example()
#rotate_example3()