| Summary: | feature request: improved reverse geolocation | ||
|---|---|---|---|
| Product: | [Applications] digikam | Reporter: | lig <georg.lipps> |
| Component: | Geolocation-ReverseGeoCoding | Assignee: | Digikam Developers <digikam-bugs-null> |
| Status: | RESOLVED FIXED | ||
| Severity: | wishlist | CC: | jens-bugs.kde.org, metzpinguin |
| Priority: | NOR | ||
| Version First Reported In: | 7.8.0 | ||
| Target Milestone: | --- | ||
| Platform: | Ubuntu | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | 8.0.0 | |
| Sentry Crash Report: | |||
|
Description
lig
2016-07-30 20:50:00 UTC
See also #351987. This is a super-old feature request from myself. I meanwhile coded a python script to reverse geocode outside of digikam. I include the code here for further use. Unfortunately I am not able to code in C++ and thus to contribute directly. The reverse geocoding is not super-perfect but gives reasonable results for sightseeing and hiking.
It uses gmaps to set or correct the gps determined elevation. Nominatim and Geonames services are used to collect relevant information for tagging. The two most abundant entries are then selected for tagging into the IPTC fields.
def reverse(path_file, force=False): # Force will overwrite existing definitions
APIKEY = "please order by yourself"
gmaps = googlemaps.Client(key=APIKEY)
lang = "de" # language used for Nominatin Service
tolerance_elevation = 100
slowdown = 1 # interval to slowdown request
metadata = GExiv2.Metadata(path_file)
if 'Xmp.photoshop.CaptionWriter' in metadata and force == False:
if 'Nominatim & GeoNames' in metadata['Xmp.photoshop.CaptionWriter']:
logging.info('Skipping already processed file %s' % path_file)
return
lat = metadata.try_get_gps_latitude()
lon = metadata.try_get_gps_longitude()
if lat == 0 and lon == 0:
logging.warning("Nothing to do since no valid GPS coordinates in file %s" % path_file)
return
logging.info('Processing file %s' % path_file)
elevation = round(gmaps.elevation((lat, lon))[0]["elevation"], 0)
gps_elevation = metadata.try_get_gps_altitude()
true_elevation = gps_elevation # assume first picture data
logging.info('gps elevation: %s \tgmaps elevation: %s' % (gps_elevation, elevation))
if gps_elevation <= 0.0: # no valid elevation
true_elevation = elevation
logging.info("No valid elevation data in file, elevation set to gmaps value %s", elevation)
metadata.try_set_gps_info(lon, lat, true_elevation)
elif abs(gps_elevation - elevation) > tolerance_elevation: # too strong deviation
true_elevation = int(elevation)
logging.info("Too strong deviation, elevation corrected to gmaps value %s", elevation)
metadata.set_gps_info(lon, lat, true_elevation)
query = "%15.12f,%15.12f" % (lat, lon)
# Nominatim service
nominatim_dict = {}
geolocator = Nominatim(timeout=60, user_agent="reverse")
location = geolocator.reverse(query, language=lang) # work-around
for attribute in ['country', 'village', 'city', 'town', 'historic', 'tourism', 'neighbourhood', 'amenity',
'locality']:
try:
location.raw["address"][attribute]
except:
nominatim_dict[attribute] = ''
else:
nominatim_dict[attribute] = location.raw["address"][attribute]
logging.info('Nomatim %s %s' % (location.raw["address"], nominatim_dict))
# Geonames service
geonames_dict = {}
geolocator = GeoNames(username="biokomiker")
try:
location = geolocator.reverse(query, find_nearby_type="findNearby", exactly_one=False)
except GeocoderTimedOut as e:
logging.debug("Error: geocode failed on input %s with message %s" % (query, e.message))
return
for attribute in ['toponymName', 'name']:
try:
location[0].raw[attribute]
except:
geonames_dict[attribute] = ''
else:
geonames_dict[attribute] = location[0].raw[attribute]
logging.info('Geonames %s %s' % (location[0].raw, geonames_dict))
city_village = nominatim_dict['village'] + nominatim_dict['city'] + nominatim_dict['town']
ort = Counter(
[nominatim_dict[k] for k in ['historic', 'tourism', 'neighbourhood', 'amenity', 'locality']] + [geonames_dict[k]
for k in
['toponymName',
'name']])
ort.pop('')
try:
final_ort = ort.most_common(2)[0][0] + ' / ' + ort.most_common(2)[1][0]
except:
final_ort = ort.most_common(1)[0][0]
IPTC = 'Iptc.Application2.'
metadata[IPTC + 'City'] = city_village
metadata['Xmp.photoshop.City'] = city_village
metadata[IPTC + 'CountryName'] = nominatim_dict['country']
metadata['Xmp.photoshop.Country'] = nominatim_dict['country']
metadata.try_clear_tag(IPTC + 'LocationName')
metadata.try_clear_tag('Xmp.iptc.Location')
metadata.set_tag_string(IPTC + 'LocationName', final_ort)
metadata.set_tag_string('Xmp.iptc.Location', final_ort)
now = datetime.datetime.now()
metadata['Xmp.photoshop.CaptionWriter'] = 'Nominatim & GeoNames @ %s-%s-%s' % (now.year, now.month, now.day)
metadata.save_file()
logging.info("\nFinal annotation:\nOrt: %s \nCity/Village: %s \nCountry: %s \nElevation: %s " % (
metadata[IPTC + 'LocationName'], metadata[IPTC + 'City'], metadata[IPTC + 'CountryName'], true_elevation))
print("\nFinal annotation\nOrt: %s \nCity/Village: %s \nCountry: %s \nElevation: %s " % (
metadata[IPTC + 'LocationName'], metadata[IPTC + 'City'], metadata[IPTC + 'CountryName'], true_elevation))
sleep(slowdown)
return
Git commit 8c6b332ee8c9dc0465d2fa9532b29f5996c094c5 by Maik Qualmann. Committed on 04/12/2022 at 08:34. Pushed by mqualmann into branch 'master'. add support for country codes Related: bug 410425, bug 351987 M +6 -1 core/utilities/geolocation/geoiface/items/gpsitemcontainer.cpp M +309 -52 core/utilities/geolocation/geoiface/reversegeocoding/rgwidget.cpp M +4 -0 core/utilities/geolocation/geoiface/reversegeocoding/rgwidget.h https://invent.kde.org/graphics/digikam/commit/8c6b332ee8c9dc0465d2fa9532b29f5996c094c5 |