HighwayEnv icon indicating copy to clipboard operation
HighwayEnv copied to clipboard

How the coordinate conversion mechanism work in this work?

Open Joe12138 opened this issue 2 years ago • 12 comments

Hi, thank for your excellent work! I have a question about the coordinate conversion mechanism in this work. For example, what does the s0 mean in road/graphics.py. The corresponding code is as below: `@classmethod def display(cls, lane: AbstractLane, surface: WorldSurface) -> None: """ Display a lane on a surface.

    :param lane: the lane to be displayed
    :param surface: the pygame surface
    """
    print(surface.get_height()) # surface.get_height() = screen.height
    print(surface.get_width()) # surface.get_width() = screen.width
    print(surface.origin)
    stripes_count = int(2 * (surface.get_height() + surface.get_width()) / (cls.STRIPE_SPACING * surface.scaling))
    s_origin, _ = lane.local_coordinates(surface.origin)
    s0 = (int(s_origin) // cls.STRIPE_SPACING - stripes_count // 2) * cls.STRIPE_SPACING
    print("s0 = {}".format(s0))
    for side in range(2):
        if lane.line_types[side] == LineType.STRIPED:
            cls.striped_line(lane, surface, stripes_count, s0, side)
        elif lane.line_types[side] == LineType.CONTINUOUS:
            cls.continuous_curve(lane, surface, stripes_count, s0, side)
        elif lane.line_types[side] == LineType.CONTINUOUS_LINE:
            cls.continuous_line(lane, surface, stripes_count, s0, side)`

Could you give a detail document to introduce this.

Joe12138 avatar Nov 11 '21 11:11 Joe12138

Hi @Joe12138 , thanks!

Basically, a lane is described by a curve representing its centerline, and this curve is parameterized by its longitudinal abscissa. And any point which is not on the centerline also has a lateral coordinate, which is its (signed) distance to the centerline.

In your example, s_0 is the longitudinal coordinate (along the lane centerline) of the first stripe to be drawn.

For more references, see Frenet coordinate system, e.g. https://github.com/fjp/frenet#frenet-features

eleurent avatar Nov 11 '21 20:11 eleurent

Thanks for your reply! But I still cannot under the meaning of the source code.
For example,

  1. in the class LaneGraphics which is in road/graphics.py file, Does the parameter STRIPE_SPACING mean the distance between two stripes?
  2. in method display, in the class LaneGraphics which is in road/graphics.py file, what does the parameter stripe_count mean? (stripes_count = int(2 * (surface.get_height() + surface.get_width()) / (cls.STRIPE_SPACING * surface.scaling))) Why do you use the perimeter of the screen to divide the pixel of STRIPE_SPACING? Why does it mean stripe_count?
  3. in method 'continuous_line', in the class LaneGraphics which is in road/graphics.py file, is the calculation method of the parameter "ends" right? (ends = [longitudinal + stripes_count * cls.STRIPE_SPACING + cls.STRIPE_LENGTH]) Does it need to be relative to the parameter of the lane.length?

I am very sorry to bother you with these small question. But it is very important to help to construct an environment with .osm file automatically.

Joe12138 avatar Nov 12 '21 08:11 Joe12138

Before answering your question, I want to stress that this code is used to render the lane graphics, so I don't think you need to understand this, it is not required for defining a road network and geometry. You simply need to be able to define lane segments in the world coordinates, and not worry about how this translates to pixel space for instance.

Here are my answers, however:

in the class LaneGraphics which is in road/graphics.py file, Does the parameter STRIPE_SPACING mean the distance between two stripes?

STRIPE SPACING is the distance between two starts of stripes, so the distance between two stripes + the stripe length

in method display, in the class LaneGraphics which is in road/graphics.py file, what does the parameter stripe_count mean? (stripes_count = int(2 * (surface.get_height() + surface.get_width()) / (cls.STRIPE_SPACING * surface.scaling))) Why do you use the perimeter of the screen to divide the pixel of STRIPE_SPACING? Why does it mean stripe_count? in method 'contin

This is just a simple heuristic, and there is probably a much better way of implementing this. Basically, the approach I had is to write a method that writes N stripes from a starting longitudinal position along the lane (defined in the lane's coordinate system), each stripe with a certain length and distance to the next stripe.

But to compute the longitudinal position of the first stripe, we need to be able to compute the intersections between the lane and the screen boundaries, which is not easy. As an approximate heuristic, I compute the longitudinal coordinate of the middle of the screen. Then, the distance from the center to the starting/ending longidutinal positions rendered on screen is upper-bounded by the screen diagonal, itself upper-bounded by the screen height+width. And since the road may not be straight, I add a *2 factor to make it more conservative. The number of stripes rendered in this road segment is thus the total distance (2 * (height + width)) divided by the stripe spacing. And since height+width is given in the pixel space (px) rather than world space (m), I need to scale if by the surface.scaling ratio.

in method 'continuous_line', in the class LaneGraphics which is in road/graphics.py file, is the calculation method of the parameter "ends" right? (ends = [longitudinal + stripes_count * cls.STRIPE_SPACING + cls.STRIPE_LENGTH]) Does it need to be relative to the parameter of the lane.length?

Yes, the longidutinal coordinate of the end of any stripe can be obtained by

  1. starting with the longitudinal position of the first stripe
  2. adding the spacing (distance + length, remember) of every stripe before
  3. adding the current stripe length

It is not related directly to the lane.length, since here we are looking at line segments rendered on screen, and the lane could be much longer and continue offscreen for an indefinite distance. So their is no direct relation between the two.

I hope that makes sense to you, I realize this is not the most intuitive, especially without a drawing. However, I do not think you have to bother with these. You should be able to simply define linear road segments by specifying their start and end world positions, and that should be enough.

eleurent avatar Nov 14 '21 16:11 eleurent

Thanks for your patience reply! I understood what you mean. Thank you very much again! Now, I have finished the work which I mentioned in #238. But it cannot fill the road correctly. Can you help me to address this problem? The problem is as below: This is the road network shown in the INTERACTION dataset (You don't need to care the number.): CHN_Merge_map This is the road network constructed by this package. Screenshot from 2021-11-29 16-30-26 Sorry! I don't know how to show the complete road network. Therefore, I only can show a part of the road network. As you can see, the road are not filled by the gray color. Can you help me to address this problem?

Joe12138 avatar Nov 29 '21 08:11 Joe12138

This is pretty weird, would you mind sharing the code that you used to generate this, so that I can have a look?

eleurent avatar Nov 30 '21 23:11 eleurent

Sorry! I just saw your reply. Thank for your nice reply! I have fixed this bug. The reason is that the width of lanes in .osm path is not always equal. So I have to change the road-drawing mechanism based on your code. This the results after fixing this bug:

The original Merge scene in .osm file

CHN_Merge

The Merge scene in highway environment (just the initial result):

CHN_MERGE However, the .osm parser written by me cannot handle the .osm file with different scenes. For example,

The original Roundabout scene in .osm file

R_CHN_Roundabout_LN

The Roundabout scene in highway environment (just the initial result):

Screenshot from 2021-12-07 17-18-57

For me, I really want to embed this function into highway-env. I am glad that I can complete this function with you. If you have free time and would like to do this with me, please let me know.

Anyway, thanks for your nice and patience reply!!!

Joe12138 avatar Dec 10 '21 08:12 Joe12138

Hi @Joe12138, this is very nice work! I also think this function would be very useful, and would be glad to help whenever I have some free time. Please feel free to share the source code of your current osm parser, and example scene that is not being correctly parsed or rendered, and I will have a look.

eleurent avatar Dec 12 '21 11:12 eleurent

Thank you for your help! The code of the osm parser can be available at https://github.com/Joe12138/EnvBasedHDMap.git. I am sorry that these code are with less comments. The code of osm parser are in osm_paerser folder. The HD map files of the scenes are in the map folder. Please let me know if your have any question about the code. Thank you very much again!

Joe12138 avatar Dec 13 '21 07:12 Joe12138

Hi @Joe12138 I wanted to have a look today, but it seems that you are relying on the lanelet2 library, which requires quite heavy dependencies like ROS. I am a bit reluctant to install them, especially since I don't have any machine running on Linux at the moment, only Windows. Any change you may consider moving to lanelet2-parser instead, which is conveniently packaged with PyPi?

eleurent avatar Dec 18 '21 14:12 eleurent

Also, I could not find any example script to run your project (e.g. which dataset_file_path, osm_file_path, vehicle_id etc. should I use?)

eleurent avatar Dec 18 '21 14:12 eleurent

Hi @eleurent , Thanks for your nice feedback! I am sorry that I cannot do this (moving to lanelet2-parser) right now. Since I am writing my report and I will do it as soon as possible. But I can convert the information in .osm file to .json format just for your test. Additionally, I have added an example script in my project. All these have been done and more information about how to use can be found in the READEME.md in the project. Thank you for your nice help! Again, please let me know if you have any question!

Joe12138 avatar Dec 23 '21 08:12 Joe12138

Hi @Joe12138 Many thanks for the json export, I managed to load the scenes you attached! (I noticed that you also use the Interaction Dataset to get the vehicle positions, but since I don't have this dataset and you need to fill a form to download it I simply commented out the vehicle loading part and put a dummy vehicle in the middle of the scene instead)

Here is what I got after loading the DR_USA_Roundabout_SR scene: original

I first noticed that a few lane segments seem to have the points in their borders defined in the wrong order, which gives these 'diabolo' shapes: original_circ

To better see what's going on, I chose random colors for each Lane segment, and also drew red circles at each point of their border colors

By switching the order in which the right border of each lane is traversed, we can see that it fixes the three diabolo patches at the bottom, but not the one at the top:

color_switch_right - Copie

So I guess there is something wrong in the order in which the point list of the two lane borders are generated from the osm.

Note that overlapping both conventions (left + reversed(right) as expected, and left + right in addition for faulty patches) would not work since it would draw inside regions outside of the polygon for non-convex lanes.

Another issue is that some points should be shared between the borders of two Lanes, but instead belong to only one of them. See e.g. the circled point at the bottom, which only belongs to the yellow patch while it should also belong to the purple patch below so that the dashed region is filled.

Finally, only looking at the lane borders and hiding the patches, it seems quite clear that the curved part of the roundabout has been traversed in the wrong order: see my annotation below (could be the reversed order) borders_1

where it should instead be something like this: borders_2

So all these issues seem to stem from how you read lanes in an OSM file, and convert them to Lane objects, and not to the rendering code itself. I'm not sure what else I could do to help, but I advise you to go back to your conversion code with these kind of visualization and try to ensure that everything is handled in the correct order.

Good luck! :)

eleurent avatar Jan 05 '22 19:01 eleurent