OpenStreetMap

Branko Kokanovic's Diary

Recent diary entries

Introduction

Car in action with Insta360 ONE

In this post, I will try to explain my process how to get best out of Insta360 ONE RS 1-inch camera and successfully upload images to Mapillary. It started out of my frustration of dealing with this camera and Mapillary and I hope you will not have to go through what I have beenšŸ™‚. I will be focusing here more on software side (how to deal with data) rather than on hardware side (how to set up rig for image capture).

Let me first start with disclaimer that this is not easiest camera to work with Mapillary (hence this guide) and that not even Mapillary is recommending it. It definitively captures better images than GoPro 360, but everything with GoPro is more smooth over whole process, so be aware of this. Camera needs to record in video mode and it relies on additional GPS dongle you have to buy.

This guide assumes familiarity with Python and Linux. Most steps are optional, and you can treat everything as pure recommendation, and while you can always ping me to help you, beware that some technical knowledge (and determinationšŸ™‚) is needed if you want to extract highest quality from this camera.

Capturing street view

First, you will need another hardware - ā€œGPS Action Remoteā€ with this. In theory, you donā€™t need it, as you can record with phone (or some other device), but in practice - you just turn on this remote and it works. With phone, you need to have Insta app turned on all the time, worry about display, whether app will get killed by battery optimizations, GPS reception inside carā€¦. I decided to keep my sanity and use this little gadget. It will record GPS (poorly). Connect them and pair them and you can control camera through this remote. Once it show green, it means it is connected to camera and it acquired GPS signal.

GPS Action Remote in action

Mapillary is suggesting to capture images in timelapse mode. If you do this, you will not get any GPS data (that is - you will get first coordinate and that lat/long will be on all images, so unusable). With this camera, you have to record in video mode. This will result in larger files, more drained battery and prolonged post-processing, but hey - at least it will work. You can expect 1h 10 min of recording if you fully top up battery.

If you are using it outside of car, you can strap both GPS remote and additional battery altogether (watch for hot days and direct exposure of battery to the sun!), but I recommend to go out every 10-20 minutes and check if tripod is holding good. If you are like me and you want to be anonymous and donā€™t like to be captured by camera, every time you go out, do stop and start video recording again. If you just have one large video, it will be harder to remove yourself (but not impossible), so consider doing this. If you donā€™t care if your head is in video, then no need for this. This is example how our setup looked like:

Insta 360 in action

If you do not want to do video splitting, you will have to keep your video under 7-8 minutes! If you go over this time, you will have to cut them in post-processing as Mapillary cannot ingest video larger than 8 minutes.

Getting video and track

Once you go home, you will end up with .insv files. Download and open Insta360 Studio application. Import this .insv file. You can adjust quality of image if you want. I usually cut beginning and end of video to only parts where I am driving. If I went outside of car and were checking tripod, I also cut those parts (you cannot cut parts of video, but you can export same video multiple times with different start/end cut times). Once satisfied with cutting, export video. Important thing here is to check ā€œExport GPX trackā€.

If you donā€™t want to deal with Linux and cutting video/gpx later, this is your time to cut video into 5-6 minutes segments. Anything larger than this increases probability that Mapillary processing will fail (anything above 8 minutes is impossible to be processed).

At the end of the process, you should end with one .mp4 video file and one .gpx track file. Letā€™s call them input.mp4 and input.gpx.

Fixing GPX track (optional)

GPX that is recorded with this ā€œAction Remoteā€ dongle is crime against all scientist, engineers, mechanics and everyone who worked hard to give us ability to know where we are using GPS. For this part, you will need to run Python program. If you can live with poor GPS, no need to fix anything, but I just couldnā€™t. Here is how it looks before (turquoise color) and after (blue color) processing:

And, no, it is not error in OSM geometry

What I did is I used Geoapify platform to do map matching of GPX for me. This is process where you snap GPX trace to closest road. It is really hard problem and I found that Geoapify do very good job converting this Insta360 mess of GPX and their free pricing is more than enough (not affiliated with them, just found them good and easy to work with). First go to their website, sign in and obtain API key (click ā€œNew Projectā€, type any name and on next dialog, just remember generated API key). Here is simple Python script that will take your input.gpx, send it to Geoapify for map matching and then update original .gpx to have new points (while keeping all other attributes like time the same):

import xml.etree.ElementTree as ET
import json
import requests

ET.register_namespace('', 'http://www.topografix.com/GPX/1/1')
ns = {'': 'http://www.topografix.com/GPX/1/1'}

def gpx_to_json(input_filename):
    converted_gpx = {'mode': 'drive', 'waypoints': []}
    tree = ET.parse(input_filename)
    root = tree.getroot()
    trksegs = root.findall('.//trkseg', ns)[0]
    for trkseg in trksegs:
        converted_gpx['waypoints'].append({
            'timestamp': trkseg.find('time', ns).text,
            'location': [float(trkseg.attrib['lon']), float(trkseg.attrib['lat'])]
        })
    return converted_gpx

def do_mapmatching(input_json):
    url = "https://api.geoapify.com/v1/mapmatching?apiKey=<YOUR_APIKEY>"
    headers = {"Content-Type": "application/json"}
    resp = requests.post(url, headers=headers, data=json.dumps(input_json))
    if resp.status_code != 200:
        raise resp
    return resp.json()

def adopt_gpx(input_gpx_filename, mapmatched_json, output_gpx_filename):
    # Load original GPX and segments
    tree = ET.parse(input_gpx_filename)
    root = tree.getroot()
    trksegs = root.findall('.//trkseg', ns)[0]

    # Load mapmatched segments
    waypoints = mapmatched_json['features'][0]['properties']['waypoints']

    assert len(waypoints) == len(trksegs)

    # Change location in original gpx and save it
    for waypoint, trkseg, i in zip(waypoints, trksegs, range(len(waypoints))):
        assert i == waypoint['original_index']
        trkseg.attrib['lon'] = str(waypoint['location'][0])
        trkseg.attrib['lat'] = str(waypoint['location'][1])
    tree.write(output_gpx_filename, default_namespace="")

if __name__ == '__main__':
    input_gpx_filename = 'input.gpx'
    input_gpx_as_json = gpx_to_json(input_gpx_filename)
    mapmatched_json = do_mapmatching(input_gpx_as_json)
    adopt_gpx(input_gpx_filename, mapmatched_json, 'output.gpx')

Save this code as ā€œmapmatching.pyā€, change ā€œYOUR_APIKEYā€ to value obtained from Geoapify, run it with python3 mapmatching.py with input.gpx in same directory. At the end of it, you should get output.gpx. Open this file in GPX editor of your choice and manually inspect it. Move any bogus points (it can happen, especially with hairpin roads) and save it - you can now use this .gpx instead of old one. I am using GpsPrune software (available for Linux too) to move points. Here is (rare) example where mapmatching can go wrong:

Splitting videos (optional)

If you ended with videos larges than 8 minutes, this is your time to cut them. I am using ffmpeg and exiftool command from Linux. This is command that will take input.mp4 and split it into out000.mp4, out001.mp4 ā€¦ files, each up to 5 minutes in length. After that, I am using exiftool to bring back metadata from original video (just so it is nicer to play it in 360 mode in VLC, but I think it is not required for Mapillary):

ffmpeg -i input.mp4 -c copy -strict experimental -map 0:0 -segment_time 00:05:00 -f segment -reset_timestamps 1 out%03d.mp4
exiftool -api LargeFileSupport=1 -tagsFromFile input.mp4 -all:all out000.mp4 # repeat for other out*.mp4 files

Unfortunately, you will have to split .gpx manually (I could create Python script for this too if someone wants, but it was easier for me to just split it in text editor). That is - open .gpx in any text editor, observe time of first point, add 5 minutes to that value and remove all points that happened after exactly fifth minute. If you do this correctly and if you had video of 14 minutes and you cut it in 6 minute segments, you should end up with 3 video - 6 minutes, 6 minutes and 2 minutes as well as 3 .gpx traces - 6 minutes, another one with middle 6 minutes and another one with final 2 minutes. Do rename .mp4 and .gpx to have same names!

You are now ready to upload all these video using Mapillary Desktop Uploader. As long as names of .mp4 and .gpx are the same, you can just drag .mp4 file into Desktop Uploader app and it will show you trace and it will let you upload to Mapillary.

Producing images (optional)

In general, you donā€™t need this step. This is step if you want to convert video to bunch of images. Some of the reason you might want images:

  • You donā€™t like how Mapillary is handling videos (street view images too close to each other), or
  • you ended up with large videos that you cannot/donā€™t know how to split, or
  • you have part of video that you donā€™t want in Mapillary at all, and you donā€™t want to split it in Insta Studio app all the time
  • you donā€™t want to backup large videos, you would rather have images
  • you have poor internet connection to upload those giant video files

In these cases, you can try to generate bunch of images from your videos and upload these. For this, mapillary_tools can help you, but it is not easy to get proper arguments. What I found that works for me is this set of options:

mkdir tmp/
mapillary_tools video_process ./out000.mp4 ./tmp/ --geotag_source "gpx" --geotag_source_path ./out000.gpx --video_sample_distance -1 --video_sample_interval 1 --interpolation_use_gpx_start_time --overwrite_all_EXIF_tags --interpolate_directions

Conclusion

I hope this guide could help you with this camera, if you plan to use it for street view. Feel free to ping me if you need help in any of these steps or if you find that something is missing, or that Mapillary made some things easier in the meantime! Big thanks to friends BrackoNe and borovac who borrowed me this camera and who took these pictures (and whose car this isšŸ™‚).

Call for ideas from Microsoft

Posted by Branko Kokanovic on 11 December 2023 in English.

Hi,

My name is Branko from Microsoft. Microsoftā€™s involvement with OSM spans several impactful contributions:

  • Providing Bing imagery since 2010 for free use in OSM for whole world (and all the drama that comes with it)
  • Creating Map builder ā€“ intuitive editor for Bing users that want to edit OSM map (and all the drama that comes with it)
  • Maintaining iD in the interim period before Martin took over (sorry, no drama here, just plain good old maintainership)
  • Released world coverage of AI-mined building footprints and road data as open data

This list is not intended to be PR for Microsoft, and I know this sounds like a corporate clichĆ©, but this list is hopefully showing that Microsoft is really committed to success of OSM. Stuff that we did previously, stuff in that list above, is stuff that we think will benefit the community and improve OSM contributions. And we hope it did! A lot of us recently visited SotM EU 2023 and I hope you saw us all around. That event allowed us to see stuff from a different perspective and to try to think out of the box. So, we thought, what if we pause trying to figure out what is the best way to improve OSM contributions on our own and instead - ask YOU how Microsoft can help!? Yes, YOU, the community, directly here in the diaryšŸ˜Š. I know this may sound unconventional, but hey ā€“ OSM is also not the most conventional project out there, so we thought this might just be the proper way to gather interesting ideas.

Some projects are easy and a single individual can tackle them easily. But some projects might require larger teams of developers, designers and resources. We think we are well positioned to take on ideas that sit nicely in these sweet spots. Ideas to think of should be 6-12 months in scope (but donā€™t be shy to suggest other ideas, we can brainstorm on how to increase scope if project is small, or how to transition it in maintenance mode if it is too big/needs lot of service work). Ideally, ideas should help improve quality and/or quantity of data on OSM map in some direct way (and in a broad coverage). But, honestly, there are no hard constraints, this is brainstorming only, every idea is fair game. Of course, no need to say that we donā€™t promise that these ideas will come to life (maybe none of them will), but what we can promise is that we will look at each of them and discuss them. And even if there is nothing out of it, comments in this diary will stay, someone next might come after us, look at this diary and some new ideas might emerge from reading them.

Maybe you think we should create a new vandalism detection platform, maybe we should implement that Segment Anything model in JOSM (half-way there, but seems not that easy) and host it in Azure for the whole world, maybe we should tackle first item on v0.7 wishlist ā€“ messaging API, or maybe we should just implement something cool inside Map builderā€¦ please tell us what you think in comments below and letā€™s brainstorm together. Again, no promises, but we would like to hear from you.

TL;DR

Watch https://peertube.openstreetmap.fr/w/56SduK2wYnnUesnSroucbd


I have one nice way of finding best routes for bike rides. It is a mix of BRouter and Strava heatmaps. Whenever I show this to someone, they think it is really cool, but I never shared it with a world. Finally I found time to record my process. You only need Strava account and web browser to create these routes. I still think it is the best way to explore routes on desktop, but let me know if you can beat this:)

15 min video with subtitles is here: https://peertube.openstreetmap.fr/w/56SduK2wYnnUesnSroucbd

Thanks for checking it out!

Mapping the city of Mladenovac

Posted by Branko Kokanovic on 11 December 2021 in English.

OSM Serbia community is having its first ā€œofficialā€ tasking manager task. We are mapping small city of Mladenovac:

https://tasks.osm-hr.org/project/21

Tasking manager instance was kindly borrowed by Croatian community. Why Mladenovac? Well, we took Mladenovac as it had worst ratio of population/building at disaster.ninja:) If this is succesful, we thought that people who contributed the most choose next city:)

This is great as this will be good reference of what we can pull together and how many local people we can attract! We already took some nice ā€œbeforeā€ pictures, so it should be nice comparasion once we are done:) Feel free to drop by or ping here if you want to help out! Everyone is welcome:)

More details in Serbian here: https://openstreetmap.rs/mapirajmo-mladenovac/

Location: Banja, ŠœŠ»Š°Š“ŠµŠ½Š¾Š²Š°Ń† (Š²Š°Ń€Š¾Ńˆ), Mladenovac Urban Municipality, City of Belgrade, Central Serbia, 11400, Serbia

TL;DR I wrote new console app that takes GTFS as an input and tells you exact changes you need to do in OSM to make it as close to GTFS as possible. Head to source to start using it.

Try it out on your GTFS and let me know how it went! I am open to suggestions, new ideas and new checks!

Description

Purpose of this tool is to help find errors and differences between GTFS and OSM data. It will also help point to errors in PTv2 routes in OSM. It covers wide range of errors, tag checks, geometry checksā€¦ (when I say ā€œwideā€, I really mean it! - check README.md to keep me honest, I am really proud what you can check today).

Once you import data in OSM (or when new version of GTFS data is released), you can use this tool to check if all data from GTFS is imported in OSM correctly and what are differences.

Tool is heavily relying on PTv2 spec and do not try to deviate from it. One would might say it is ā€œopinionatedā€:)

This tool is not general-purpose PTv2 quality assurance tool, even though it points to a lot of PTv2 errors in OSM. It is handy if you are OK with console output and quick iterations as you can grep it, cron it, sed it as you like. Check this wiki for other great tools.

Why new tool

Belgrade, Serbia released open GTFS data and I wanted to conflate it to OSM (as an authorative dataset). However, none of the tools could scratch my itch. PTNA is awesome tool and Toni was great to onboard Belgrade, and while it shows errors, I didnā€™t have level of control I wanted. Our western neighbors in Croatia also developed a tool named Triglav. I experimented with it, but it was currently not generic enough to accept another city and I didnā€™t know Elixir enough to adopt it to Belgrade:) I tried to fiddle with GO-Sync, but I really didnā€™t have any control and it was that non-intuitive that I didnā€™t know how to even start (and yes, I read documentation:D) So, basically, that was whole ecosystem I can find. So, I started writing it as a way to help GTFS=>OSM syncing with a goal to make it usable for any GTFS in the world. I think I am halfway there:)

Whatā€™s next

I would like to see some better output. Some HTML dump with some fancy <table> that can do filtering, or even show Leaflet map with GTFS and OSM route for visual inspection. This is ideal task for beginner. If you want to start learning Python, or deepen your knowledge of it, I am willing to mentor you!

Additionally, this tool could be used to automate commits (if you are brave enough and you get sign off from import mailing list and local community:).

Location: Dorcol, Old Town, Belgrade, City of Belgrade, Central Serbia, 11000, Serbia

I worked for some time to create Mapnik-based tileserver where names are internationalized. I managed to do it by pulling data from names from Wikidata and Wikipedia. Project is released at: https://gitlab.com/stalker314314/osm-wikinames

You can see showcases at: https://gitlab.com/stalker314314/osm-wikinames/-/blob/master/showcase.md

Idea is to create new columns in PostGIS which get populated from wikidata/wikipedia and then, use those columns in renderer.

Do check it out if you find this useful and submit issues if you see any bugs, or this doesnā€™t completely do the job for your case!