I recently published a quick and dirty photo viewer onto GitHub, you just need to have Python installed. It will create a simple web map that uses the Google Maps API and a plugin to handle overlapping markers.
To use, simple double-click the PhotoMapperUI.pyw
file which starts up this GUI:
You can choose to create a portable web app (where it will copy all the photos with the web app to be put in a new folder somewhere) or an embedded app where it just creates the HTML page in the same directory as your photos. You do not need a web server to view it, it will just launch and is read locally by your browser.
This utility will provide a JSON file that stores all the coordinate info you need and you could even glean out the popup which is already formatted as HTML, so it would pretty easily to translate that to KML if you really needed Google Earth viewing capabilities.
This script will take as an input a folder of images, and a shapefile. The shapefile needs to be attributed with the image name, and the lat and long of the point.
The script will write to the EXIF tag of the image the lat and long from the attribute table. After execution the image location will be the same as the point location. The script requires the pyexiv2 library and therefore, only works with Python 2.7 and ArcGIS 10.x. I will port it to Python 3 if anyone asks.
Make a backup of your data before you run this code!
import pyexiv2, traceback, sys, arcpy
#the folder of images...
inFolder = "C:/gTemp/WriteEXIFtest/sfnooksack_lo"
#The points that show the correct image locations...
inFC = 'C:/gTemp/WriteEXIFtest/sfnooksack_lo.shp'
#the shapefile needs to have attributes with the image name, lat and long (as DD)
fields = ['IMAGE', 'lat', 'long']
try:
def ddlongtodms(dd):
#converts decimal degrees to degrees minutes and seconds.
if dd < 0:
dd = abs(dd)
GPSLongitudeRef = 'W'
else:
GPSLongitudeRef = 'E'
minutes,seconds = divmod(dd*3600,60)
degrees,minutes = divmod(minutes,60)
return (GPSLongitudeRef,int(degrees),int(minutes),seconds)
def ddlattodms(dd):
#converts decimal degrees to degrees minutes and seconds.
if dd < 0:
dd = abs(dd)
GPSLatitudeRef = 'S'
else:
GPSLatitudeRef = 'N'
minutes,seconds = divmod(dd*3600,60)
degrees,minutes = divmod(minutes,60)
return (GPSLatitudeRef,int(degrees),int(minutes),seconds)
with arcpy.da.SearchCursor(inFC, fields) as cursor:
for row in cursor:
#in this case the image name does not have a .jpg suffix so I add it here...
imagePath = inFolder +'/'+row[0]+'.jpg'
print imagePath
pointLong = ddlongtodms(row[2])
pointLat = ddlattodms(row[1])
print pointLong
print pointLat
try:
metadata = pyexiv2.ImageMetadata(imagePath)
metadata.read()
latitude = [pyexiv2.Rational(pointLat[1],1),pyexiv2.Rational(pointLat[2], 1),pyexiv2.Rational(int(pointLat[3]*100000), 100000)]
longitude = [pyexiv2.Rational(pointLong[1],1),pyexiv2.Rational(pointLong[2], 1),pyexiv2.Rational(int(pointLong[3]*100000), 100000)]
metadata['Exif.GPSInfo.GPSLatitude'] = latitude
metadata.write()
metadata['Exif.GPSInfo.GPSLongitude'] = longitude
metadata.write()
metadata['Exif.GPSInfo.GPSLatitudeRef'] = pointLat[0]
metadata.write()
metadata['Exif.GPSInfo.GPSLongitudeRef'] = pointLong[0]
metadata.write()
except:
print "something bad happened with this file..."
print "Done"
except:
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1])
print pymsg + "\n"
And this should work for Python 3 but the Python interpreter is locked in a walled garden in ArcGIS Pro. ESRI may have blocked the ability to add the pyexiv2 library. In that case you may need to make a clone.
import pyexiv2, traceback, sys, arcpy
#the folder of images...
inFolder = "C:/gTemp/WriteEXIFtest/sfnooksack_lo"
#The points that show the correct image locations...
inFC = 'C:/gTemp/WriteEXIFtest/sfnooksack_lo.shp'
#the shapefile needs to have attributes with the image name, lat and long (as DD)
fields = ['IMAGE', 'lat', 'long']
try:
def ddlongtodms(dd):
#converts decimal degrees to degrees minutes and seconds.
if dd < 0:
dd = abs(dd)
GPSLongitudeRef = 'W'
else:
GPSLongitudeRef = 'E'
minutes,seconds = divmod(dd*3600,60)
degrees,minutes = divmod(minutes,60)
return (GPSLongitudeRef,int(degrees),int(minutes),seconds)
def ddlattodms(dd):
#converts decimal degrees to degrees minutes and seconds.
if dd < 0:
dd = abs(dd)
GPSLatitudeRef = 'S'
else:
GPSLatitudeRef = 'N'
minutes,seconds = divmod(dd*3600,60)
degrees,minutes = divmod(minutes,60)
return (GPSLatitudeRef,int(degrees),int(minutes),seconds)
with arcpy.da.SearchCursor(inFC, fields) as cursor:
for row in cursor:
#in this case the image name does not have a .jpg suffix so I add it here...
imagePath = inFolder +'/'+row[0]+'.jpg'
pointLong = ddlongtodms(row[2])
pointLat = ddlattodms(row[1])
try:
metadata = pyexiv2.ImageMetadata(imagePath)
metadata.read()
latitude = [pyexiv2.Rational(pointLat[1],1),pyexiv2.Rational(pointLat[2], 1),pyexiv2.Rational(int(pointLat[3]*100000), 100000)]
longitude = [pyexiv2.Rational(pointLong[1],1),pyexiv2.Rational(pointLong[2], 1),pyexiv2.Rational(int(pointLong[3]*100000), 100000)]
metadata['Exif.GPSInfo.GPSLatitude'] = latitude
metadata.write()
metadata['Exif.GPSInfo.GPSLongitude'] = longitude
metadata.write()
metadata['Exif.GPSInfo.GPSLatitudeRef'] = pointLat[0]
metadata.write()
metadata['Exif.GPSInfo.GPSLongitudeRef'] = pointLong[0]
metadata.write()
except:
print ("something bad happened with this file...")
print ("Done")
except:
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1])
print (pymsg + "\n")
Best Answer
I'm using Open Camera (http://opencamera.sourceforge.net) for exactly this feature on my Motorola Moto G 3. Just install (also available via F-Droid) and enable "Store compass direction" under "Location settings...". You can also enable "Show compass direction" and "Show compass direction lines" in the "On screen GUI..." menu to check the direction before taking a picture.
I then use the current beta version of GeoSetter (http://www.geosetter.de/download/) to visualise the pictures and their position / camera angle.