nutonomy / nuscenes-devkit

The devkit of the nuScenes dataset.
https://www.nuScenes.org
Other
2.25k stars 624 forks source link

scale-factor of x-/y-axis of translation data #960

Closed meissnerda71974 closed 11 months ago

meissnerda71974 commented 1 year ago

Hello, started working with the nuscenes data and i want to transform the translation of the ego_pose into lat/long, just the same as discribed in #144. I am using pyproj to first transform the given origin_latlon to utm-coordinates. trans = Proj(proj='utm', zone=utm_sector, datum='WGS84', preserve_units=False) origin_lat = 42.336849169438615 origin_long = -71.05785369873047 x_origin, y_origin = trans(longitude=origin_long, latitude=origin_lat) Then I am adding the x/y-translation and I transform the new utm-coordinattes into lat/lon: x = x_origin + x_translation y = y_origin + y_translation longitude, latitude = trans(x, y, inverse=True) The results are lat/lon's that are very close to the positions identified by the frames of the cam_cannels (CAM_BACK, CAM_BACK_LEFT etc.), but there is at least a drift of 30-40 meters. Am I missing here something? Is the x-/y-axis of the translation scaled? It seems to me that an scale-factor of around x_factor = 1.059 and y_factor_0.98 brings me close to positions estimated by the frames of the cam_channels.

I am currently working with the boston-seaport map.

Thanks in advance. Best regards, Daniel.

whyekit-motional commented 1 year ago

@meissnerda71974 if you could provide a working code snippet, we could look deeper into this

meissnerda71974 commented 1 year ago

Hello @whyekit-motional, thank you for the fast response. Sure, this is my code:

from nuscenes.nuscenes import NuScenes from pyproj import Proj

data_root = '$HOME/nuscenes-devkit/data/sets/nuscenes' version = 'v1.0-mini' nusc = NuScenes(dataroot=data_root, version=version)

bostion-seaport

scene_idx = 1 sample_idx = 0

scene = nusc.scene[scene_idx] sample_tokens = nusc.field2token('sample', 'scene_token', scene['token']) sample_token = sample_tokens[sample_idx] sample = nusc.get('sample', sample_token)

ego_pose_token = sample['data']['LIDAR_TOP'] translation = nusc.get('ego_pose', ego_pose_token)['translation']

x_translation = translation[0] y_translation = translation[1]

origin_lat/lon map boston-seaport

origin_lat = 42.336849169438615 origin_long = -71.05785369873047 utm_sector = 19

trans = Proj(proj='utm', zone=utm_sector, datum='WGS84', preserve_units=False)

transform origin lat/long in UTM-cooinates

x_origin, y_origin = trans(longitude=origin_long, latitude=origin_lat)

add the x/y translation provided by nuscenes to the origin-UTM-coordinate

x = x_origin + x_translation y = y_origin + y_translation

transform x/y back to lat/long

longitude, latitude = trans(x, y, inverse=True)


The output for latitude, longitude is: 42.35180763288225, -71.05105567530991. If i compare this to the camera_frames of this sample, the location is around 50 meters away.

I couldn't attach a screenshot from googlemaps, but let me try it in another comment.

Thank you for your help. Daniel.

whyekit-motional commented 1 year ago

@meissnerda71974 I don't quite fully understand this part of your code:

x_origin, y_origin = trans(longitude=origin_long, latitude=origin_lat)

Both x_origin and y_origin should be 0 since the global coordinate frame is wrt the map

meissnerda71974 commented 1 year ago

@whyekit-motional This part transforms the origin lat/lon into utm x/y-coordinates (units=meter). Further i add the translation of the nuscenes-data to the utm x/y-coordinates and then i calculate the utm-coordinates in a last step back into lat/lon.

x_origin and y_origin are the into utm transformed origin coordinates given here: https://github.com/nutonomy/nuscenes-devkit/issues/144#issuecomment-505377023

whyekit-motional commented 1 year ago

@meissnerda71974 got it :ok_hand:

Can you also show the code where you retrieve the lat/lon from the cameras in order to make the comparison with the lat/lon you derived from your code snippet in https://github.com/nutonomy/nuscenes-devkit/issues/960#issuecomment-1678786430?

meissnerda71974 commented 1 year ago

@whyekit-motional sorry, i estimate this by looking at the provided camera-frames by myself. I have no code for this. But as we have a 360 degree view, i think you can estimate a good position by comparing the features of the pictures with a map like googlemaps. If i do this, i am at a position at least 40 to 50 meters away from the calculated lat/lon.

whyekit-motional commented 1 year ago

In that case, if you could include some screenshots to illustrate what you mean, that would be great

meissnerda71974 commented 1 year ago

Hi @whyekit-motional, sure i hope the following illustrations helps to understand my matter.

If I am running the code above (https://github.com/nutonomy/nuscenes-devkit/issues/960#issuecomment-1678786430) it returns me the following lat/lon: 42.35180763288225, -71.05105567530991, which you can see in the screenshot of googlemaps is in the middle of the bridge (red marker).

Screenshot googlemaps (location: boston-seaport): Screenshot from 2023-08-15 13-27-31

However, if i am taking a look at camera-frames and the rendering of the scene 1/sample 1 i think especially the frame from "CAM_FRONT_LEFT" shows good, that the car starts at the very end of the bridge (green-marker). The "Hood Milk Bottle" is also a good reference point. So there is an error of arround 40-50 meters. Those are the frames "CAMERA_FRONT" and "CAMERA_FRONT_LEFT" and the rendering of sample1/scene1 in boston-seaport:

CAMERA_FRONT: n008-2018-08-01-15-16-36-0400__CAM_FRONT__1533151603512404

CAMERA_FRONT_LEFT: n008-2018-08-01-15-16-36-0400__CAM_FRONT_LEFT__1533151603504799

RENDERING LIDAR_TOP: Screenshot from 2023-08-21 09-07-45

Every coordinate seems to have a delay, what moves them all in the same wrong direction. I have tried to move them manually in the right direction in the mean time, to see if i can estimate a scaling factor by myself, but it doesn't work at all. Still every sample of one scene seems to have kind of the same drift (in any scene). In the following screenshot shows for example a scene of singapur-onenorth, where you also can see the blue coordinate-markers away from the road.

Screenshot projected coordinates singapur-onenorth: Screenshot 2023-08-21 094226

If I am just transforming a utm-coordinate (x/y) from a provided lat/lon and then transforming that utm-coordinate (x/y) back into lat/lon, I am receiving back the originally provided value. I also compared the projection to an web-application (https://www.latlong.net/lat-long-utm.html) from which i am also getting the same results. This is why i think the projection works properly.

So my conclusion was that there has to be something with the data, what i am currently not understanding. Maybe the nuscenes-map does not align perfect to the utm-coordinate system, but i think a error of 40-50 meters, what i am currently seeing, would be too much as drift.

I really hope the information helpful and we can solve the issue. Thanks a lot!

Best regards, Daniel.

whyekit-motional commented 1 year ago

@meissnerda71974 could you try with EPSG:4326 (instead of EPSG:3857)?

myc634 commented 1 year ago

@meissnerda71974 could you try with EPSG:4326 (instead of EPSG:3857)?

Hi, I think here in his code, he had already used EPSG:4326. I had met the same problem.

whyekit-motional commented 1 year ago

To get the latlon from a given ego pose in nuScenes, try this instead:

from nuscenes.nuscenes import NuScenes
from nuscenes.scripts.export_poses import derive_latlon

nusc = NuScenes(version='v1.0-mini', dataroot='/data/sets/nuscenes', verbose=False)

scene_idx = 1
sample_idx = 0

scene = nusc.scene[scene_idx]
sample_tokens = nusc.field2token('sample', 'scene_token', scene['token'])
sample_token = sample_tokens[sample_idx]
sample = nusc.get('sample', sample_token)
ego_pose_token = sample['data']['LIDAR_TOP']

latlons = derive_latlon(
    location=nusc.get('log', scene['log_token'])['location'], 
    poses=[nusc.get('ego_pose', ego_pose_token)]
)

for latlon in latlons:
    print(f"At timestamp {latlon['timestamp']}, the ego is at latlon ({latlon['latitude']}, {latlon['longitude']}).")

That should give:

At timestamp 1533151603547590, the ego is at latlon (42.351648599736414, -71.05055898203881).

This latlon looks more correct (closer to the green marker of @meissnerda71974's image in https://github.com/nutonomy/nuscenes-devkit/issues/960#issuecomment-1685842676)