Panoramax JuraMap trail views


JuraMap ¦ JuraMap mapping


Panoramax notes

A simplified version of the deprecated proof-of-concept TrekView Explorer has been used for the panoramic viewing of JuraMap trails. This Rails-based server is being replaced by the backend and web API of a Panoramax instance for storing and viewing field photos. The trails are displayed on the "Trails" layer of the detailed raster JuraMap.

The background map tiles for the Panoramax trails layer is the vector JuraMap which is rendered using TileKiln, as explained in an Implementation Note.

The menu system for the raster JuraMap allows a Panoramax web viewer to be displayed using a modal (the Panoramax web viewer derived from the Geovisio web viewer is demonstrated here). The same approach can be used for the vector JuraMap.

1. Dynamic alignment

A major issue arose. It is unclear how the Geovisio/Panoramax viewer's map can be centred dynamically so as to align with the base map. As discussed below, one way to achieve alignment is to set an intial centre for the Geovisio web viewer and then to calculate the map centre when the base map is moved.

2. Distance between photos

The JuraMap trails are historic trails (i.e., probably existed at the end of the 19th century). As shown on the vector JuraMap , the trails involve hiking (OpenStreetMap sac_scale = hiking) or mountain hiking (sac_scale = mountain_hiking) with visibility ranging from "excellent" through "intermediate" to "bad".

The speed of walking is generally fairly slow and the distance between photos need only be about 100 to 200 metres in most cases (we do not plan to use the shorter distances needed for feature detection models).

Using a Google Pixel 4a smartphone, it is proving fairly difficult to establish Panoramax settings that avoid having duplicate photos which break the line representing the sequence of photos that is shown on the Panoramax map.

The problem may be the smartphone's relatively inacurate GPS. This is demonstrated in the Panoramax viewer where photos appear to correspond to points that are a few metres from trails. Moreover, the EXIF coordinate data for some photos are transferred to the next photo. Repositioning the photos is needed (using, for example, the JSOM OpenStreetMap editor with the photoadjust and photo_geotagging plugins).

3. Photo sequence mapping

To make sure that a sequence of photos that are separated by a fairly long distance (typically 100 to 200 metres), the variable ST_Length has changed from 50 to 300 in the Postgresql database function "compute_sequence_geometry" (thus making a multiline geometry for the sequence, spliting each picture separated by more than 300 meters). This changed can be made using pgAdmin or by executing a Python migration.after editing the file in "geovisio/migrations" with the name starting with "20240813". In the API repository, a change from 50 metres to 75 metres was made recently.

4. Playback speed

The other significant change was to force the time duration of the web-viewer's playback of each photo in a sequence to be the maximum. This was done by adding "&speed=3000" to the urlHash variable described below or by setting a viewer option ("transition:3000") according to the web viewer API documentation.

This change is for the variable "TransitionDuration Changes" which is the duration of stay on a picture during a sequence play. It is not immediately clear how the duration can be set more elegantly to the maximum value (speed = 3000). It may also be necesssary to set the Flask environment variable PIC_MAX_STAY_DURATION=3000.

Setting a constant playback speed of 3000 (or a smaller value for a shorter duration) was needed because the drop-down in the Geovisio web viewer to adjust the sequence playback speed sometimes was not displayed for an unknown reason.


A. Panoramax installation

A1. Geovisio API

Installing a Postgresql database followed the normal procedure for OpenStreetMap editing and rendering applications. Installing the Panoramax API is straightforward (see gitlab repository).

Regarding API settings, for initial testing it is useful to use Flask and simply execute in a terminal:

  • flask run

with an .env file of the form:


FLASK_APP=geovisio

DB_URL=postgres://user:user@localhost:5432/geovisio

FS_URL=/home/user/geovisio/data

INFRA_NB_PROXIES=1

FLASK_RUN_HOST=0.0.0.0

PICTURE_PROCESS_DERIVATES_STRATEGY=PREPROCESS

API_ACCEPT_DUPLICATE

PIC_MAX_STAY_DURATION=3000


It is noted that the Geovisio API is set up to run behind an Apache2 proxy (hence the environment setting "INFRA_NB_PROXIES=1", see documentation).

A2. Geovisio (Panoramax) web viewer

To integrate the Geovisio web viewer into the JuraMap raster app, following the documentation the most straightforward approach was to clone the repository, rename its directory from "web-viewer" to "geovisio-viewer" for clearer identification, and execute in terminal:

  • cd geovisio-viewer
  • npm install
  • npm build

The files "geovisio-viewer/build/index.js" and "geovisio-viewer/build/index.css" were then copied to the JuraMap raster map web directory called "history" (i.e., to "/var/www/html/history" for a Ubuntu 18.04 system). With the renaming of Geovisio to Panoramax in the Gitlab repository, the index files are best called geovisio-index.js or more correctly index-panoramax.js, and similarly for index.css

To integrate in the JuraMap raster app, a Leaflet Bootstrap modal (see repository) was set up that had as its body statement:

  • <div id="viewer" class="fullpage">

which is the same as the statement used for the Geovisio web viewer (see the file "geovisio-viewer/build/viewer.html").

The JuraMap raster app uses Leaflet.ActiveLayers so a Leaflet layerGroup is needed for the "Trails" layer of Panoramax photos that are displayed using the Bootstrap modal:

  • var viewerLayer1 = new L.layerGroup(viewer)
  • this.trails = {name:"Trails", layer:viewerLayer1}

The key statement in the JuraMap raster Javascript is:

  • viewer = new Geovisio.Viewer("viewer,"https://geovisio.juramap.org/api",{transition:3000,style:"https://www.juramap.org/tiles/pnorman.json",map:{center: mapCenterCoords, startWide:true, minZoom:19, maxZoom:19}});

where:

  • "https://geovisio.juramap.org/api" is the Geovision (Panoramax) API address;
  • "https://www.juramap.org/tiles/pnorman.json" is the address of the JuraMap vector map TileKiln renderer.

The web viewer's API Reference is crucial. Aside from the options for "map" (i.e., "options.map") "startWide", "minZoom" and "maxZoom" also listed are "raster", "center", "zoom", "bounds", and "geocoder". According to the API Reference "raster" must be a MapLibre raster source definition, so all the options may not work for a web viewer that uses a vector map as a background source.

However, alignment of the base map and the viewer map seems to work if:

  • the centre is initially set as center:[6.61,46.48] for an initial map centre at latitude 46.48 and longitude 6.61;

Once the base map is moved, the viewer map is aligned by calculating mapCentre according to the maplibre-gl LngLatLike object definition and an URL hash:

  • var latCentre = map.getCenter().lat.toFixed(6);
  • var lngCentre = map.getCenter().lng.toFixed(6);
  • var jsonDataAry = [{"coordinates":[lngCenter, latCenter]}];
  • mapCenter = jsonDataAry[0].coordinates;
  • var urlHash = mapZoom+"/"+latCenter+"/"+lngCenter+"&focus=map&map="+mapZoom+"/"+latCenter+"/"+lngCenter
  • window.location.hash = urlHash;

B. Photography

Streetview ("Panoramax") photography seems to be poorly established for use in remote locations in less-developed countries. Although apps such as SW Maps with GPS correction data from a NTIRP caster (streamed directly to SW Maps or by having the provider of the Android mock connection app - a developer option - set as the GNSS Master app) work well, one would hope to be able to acquire and automatically geo-tag high-resolution panoramic or photosphere images.

Accurate positioning using Global Navigation Satellite System (GNSS) correction services can be implemented to give the position of each photo uploaded to the Panoramax server. The aim is to take photos at a rover's position, where the rover's position is determined using two approaches:

  • RT-PPP - using real-time Precise Point Positioning (the rover is essentially a single moving base station).
  • RTK-PPP - in conjunction with the base station (a precisely positioned static base station sends corrections to a moving rover to obtain high real-time precision for the rover's position using Real-Time Kinetic positioning);

Implementating both alternatives is discussed in a separate positioning Implementation Note.

Single-station RTK-PPP is the most straightforward. It involves connecting a NTRIP caster to a NTRIP client that transmits corrections to a GPS receiver (corrections are calculated by the receiver). GNSS positioning models errors using data generated by a network of global reference stations to deliver corrections to a GPS receiver via satellite or over the Internet to improve position accuracy. In our case, for field work power must come from a portable power bank. With the receiver as a base station, the aim is for a geolocated photo taken at the receiver's position and uploaded to the Panoramax server to have its position coordinates stored in the photograph file as EXIF tags.

The simplest way to obtain geo-tagged high-resolution panoramas is to use a mock Android location with Mapillary for Android, SW Maps, Baba or OpenCamera with the geo-tagging data supplied by a GNSS receiver (a u-blox ZED-F9P in our case) connected to a microcomputer (a Raspberry Pi 3B+ in our case).

The mock location is established using a RT-PPP commercial service such as the real-time PointPerfect SPARTN GNSS correction service (requires setting up a Thingstream account) with a client such as the Lefebure or GNSS Master Android apps to transfer positioning data as image geo-tags. Unfortunately, commercial real-time correction services are expensive, require an Internet connection and are not available in remote areas. Aternatives, notably the freely available and global Galileo High Accuracy Service - HAS) are described in the positioning Implementation Note.

In using RT-PPP, a major issue is the connection between the smartphone and the Raspberry Pi. In principle, the connection can be either a Bluetooth connection or a TCP/IP Internet connection but generally speaking a TCP/IP appears to be the only option.

C. Location geo-tag accuracy

A second issue is the accuracy of the mock location information that is stored as EXIF tags in images.

For a modern, low-cost precision GNSS receiver such as the u-blox ZED-F9P, the receiver's UBX ⇒ CFG ⇒ NMEA ⇒ CFG-NMEA-DATA2 ⇒ "High precision mode" configuration setting in principle allows for EXIF tages with 7 digits after the decimal point, which is non-standard.

Mapillary. For the Mapillary app, as a guest as opposed to being logged in to Mapillary, the app allows a single, wide-angle photo to be taken that can be saved to the Pictures -> Mapillary folder. The saved .jpg 72 dpi 4032 x 3024 pixels standard 0.6 magnified Pixel 4a 4 x 3 "full image" retains the images' EXIF geo-tags that include the mock location information. Panoramas made by rotating the smartphone comprise a series of stiched photos. Each photo can also be saved, but not the stiched panorama. The Mapillary app retains significantly high precision EXIF geo-tags for its .jpg images. Using an EXIF editor or reader that parses EXIF meta-data correctly or Windows Explorer to view properties shows that the Mapillary app saves high-precision position geo-tag location data as Degrees; Minutes; Seconds (DMS, e.g., 46; 26; 57.901908) with seconds to 6 decimal places. It is therefore unfortunate that Mapillary's guest-mode only allows a single wide-angle photo to be taken instead of a stitched panorama.

SW Maps. For the SW Maps app, which does not have a panorama mode, for the high-precision geo-tag message configuration the app displays Decimal Minutes (DMM) with 6 decimal places before saving an image as a .jpg file. A SW Maps .jpg image has DMS tags with seconds to only 4 decimal places..

Baba. Baba uses the smartphone camera and stores the mock location as DMS with seconds to 6 decimal places. The app can be built in Android Studio for a Remote Device (a Pixel 4a with Android 14.0 as the operating system in our case) but we have had no luck so far in building a compatable .apk file that can be installed (a .apk is available for the latest - 1.5.1 - release). The advantage here is that the app can be fairly easily adjusted for use with self-hosted maps and a Panoramax server. Further development is envisaged. As for the Mapillary app, Baba image EXIF geo-tags are stored as DMS with seconds to 6 decimal places.

OpenCamera. Open Camera has a panorama mode and panoramas are geo-tagged to DMS with seconds to 5 decimal places when parsed using Windows Explorer. This is one decimal place less than for the Mapillary and Baba camera apps. For some unknown reason, we are having difficulty taking 360-degree panoramas (we manage at most about 180 degrees). Assuming nonetheless that a full 360-degree panorama can be taken, it is unfortunate that the OpenCamera's geo-tag precision is less than for some of the other camera apps.

D. Base station summary

The discussion has summarised how the accurate geo-tagging of photos taken at a specific position (called a base station position) can be carried out using a simple kit comprising:

  • a smartphone (Pixel 4a) having available a mobile data Internet connection and access to an Internet-distributed GPS correction service (PointPerfect);
  • a low-cost GPS receiver (Drotex DP0601 connected to a Drotek DA09011 survey antenna or a patch antenna);
  • a small computer (RaspberryPi 3B+) with on-board wireless networking (WiFi);
  • a low-cost smartphone power bank (SBS) to power the RaspberryPi and the receiver.

The focus has been on a simple approach that uses a commercial real-time Precise Point Positioning (RT-PPP) service (PointPerfect) and setup to geo-tag images. The implementation in hardware of RT-PPP and its alternative (RTK-PPP involving a base station and a rover) is discussed separately.

Notable will be the implementation of RT-PPP and RTK-PPP using the Galileo HAS (High Accuracy Service) Internet Data Distribution NTRIP service. HAS is in principle available in regions not presently covered by GNSS correction services including PointPerfect (a HAS request for access has been approved). Moreover, Internet is not needed if the receiver is able to process directly HAS satellite messages.

The 20-cm base-station accuracy provided by HAS correction is in principle adequate for Panoramax streetview photography. The main issue is whether or not this level of accuracy can be maintained when photographs are taken in conjunction with a base station (RT-PPP) or a fixed base station with a moving rover (RTK-PPP).


23 January 2025

APK

PeterBoswell.com