Skip to content

Instantly share code, notes, and snippets.

@paul121
Created May 3, 2020 20:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paul121/408dacd4f87a6967257d2bc303148d6e to your computer and use it in GitHub Desktop.
Save paul121/408dacd4f87a6967257d2bc303148d6e to your computer and use it in GitHub Desktop.
Create a farmOS Observation log with Timestamp and Geometry from a JPEG image.
import base64
from datetime import datetime
from farmOS import farmOS
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
hostname = "http://localhost"
username = "username"
password = "password"
image_filepath = "test_img.jpg"
# GPSInfo code derived from:
# https://www.sylvaindurand.org/gps-data-from-photos-with-python/
def get_exif(filename):
exif = Image.open(filename).getexif()
if exif is not None:
for key, value in exif.items():
name = TAGS.get(key, key)
data = exif.pop(key)
exif[name] = data
if 'GPSInfo' in exif:
for key in exif['GPSInfo'].keys():
name = GPSTAGS.get(key,key)
exif['GPSInfo'][name] = exif['GPSInfo'].pop(key)
return exif
def get_decimal_coordinates(info):
for key in ['Latitude', 'Longitude']:
if 'GPS'+key in info and 'GPS'+key+'Ref' in info:
e = info['GPS'+key]
ref = info['GPS'+key+'Ref']
info[key] = ( e[0][0]/e[0][1] +
e[1][0]/e[1][1] / 60 +
e[2][0]/e[2][1] / 3600
) * (-1 if ref in ['S','W'] else 1)
if 'Latitude' in info and 'Longitude' in info:
return [info['Longitude'], info['Latitude']]
exif = get_exif(image_filepath)
log = {
"name": "My Photo Observation",
"type": "farm_observation",
"done": 1,
}
# Read GPSInfo from image data.
if exif is not None and 'GPSInfo' in exif:
latlong = get_decimal_coordinates(exif['GPSInfo'])
if latlong is not None:
log['geofield'] = [
{
"geom": f"POINT ({latlong[0]} {latlong[1]})",
},
]
# Read timestamp from image.
if exif is not None and 'DateTime' in exif:
image_date = datetime.strptime(exif['DateTime'], '%Y:%m:%d %H:%M:%S')
log['timestamp'] = image_date.timestamp()
# Image binary.
with open(image_filepath, "rb") as imageFile:
image_binary = base64.b64encode(imageFile.read())
log['images'] = [
f"data:image/jpeg;base64,{image_binary.decode('utf-8')}"
]
farm = farmOS(hostname=hostname, username=username, password=password)
farm.authenticate()
res = farm.log.send(payload=log)
print(res)
@bonushenricus
Copy link

bonushenricus commented May 7, 2020

Hello @paul121
Thank you
I have a problem with the 16 and 45

AttributeError: 'JpegImageFile' object has no attribute 'getexif'

It doesn't seem a problem of my jpeg.
But the image filepath in my localhost how I have to write?

@paul121
Copy link
Author

paul121 commented May 7, 2020

@bonushenricus hmm interesting. I'm assuming you have the pillow library installed in your Python environment?

Maybe the image file isn't being loaded? The image_filepath variable needs to be a path relative to where you run the script. If you put your image.jpeg in the same directory as farmos_image_gps_obvservation.py then the path should work as image.jpeg

@bonushenricus
Copy link

Oh sorry mmh: pip install pillow !
Ok.
Now the script end without error (what do the "f" in lines 59 and 73 mean?)
but with "None"
also if I try "python farmos_image_gps_observation.py" in the script directory with the file image inside.

@paul121
Copy link
Author

paul121 commented May 8, 2020

Oh sorry mmh: pip install pillow !

Ah yes. Sorry, I didn't really take any time to document this. Glad that worked!

(what do the "f" in lines 59 and 73 mean?)

In Python you can use f"my string {my_variable} the rest of my string" to easily format variables inside. The alternative would be "my string " + my_variable + " the rest of my string."

Now the script end without error....but with "None"
also if I try "python farmos_image_gps_observation.py" in the script directory with the file image inside.

Hmm I'm not sure what you mean. The last line of my script is print(res) - that should print the response from the POST to the farmOS server. Perhaps that is failing? That might explain "None".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment