Classifying plants & creating an excursion diary
About 3 years ago, I became interested in learning more about plant taxonomy.
In Switzerland, there is a certification, starting with the most common 200 plants, which you have to know by their latin name (family and species). I haven't attempted it yet, but I've been learning at least parts of the list by random plant encounters on the way.
For classifying plants out in the field, the Pl@ntNet project turned out to be immensely useful, as it allows to give a classification, including certainty.
I like going on a hike, but trying to classify more than a handful of plants on the way turned out to be pretty tedious work, and I don't like to stumble too much of the way with my smartphone out.
When coming back from a hike I got the idea of automatically creating a plant diary afterwards - with my photos, all the information was there!
It looks like this:
Using the Pl@ntNet API
Besides an App, Pl@ntNet also provides an API, with some generous limitation (last time I checked 500 calls per day were okay). If you register on identify.plantnet.org, you can get a free API key to make classification requests.
I decided to use Python to make multiple requests for a list of images provided:
def get_species(filename: str) -> List[str]:
files = {'images': open(filename, 'rb')}
response = requests.post(base_url, files=files, data={'organs': ['flower']}) # or 'leaf'
json_result = json.loads(response.text)
names = []
for result in json_result['results']:
score = result['score']
# Ignore results with certainty below 5%
if score < 0.05:
break
lat_name = result['species']['scientificNameWithoutAuthor']
common_name = '-'
if len(result['species']['commonNames']) > 0:
common_name = result['species']['commonNames'][0]
names.append([lat_name + ' (' + str(score * 100)[:4] + '%)', common_name])
return names
Using this script, the latin name and common names will be collected and returned, and added to the image as information.
Reading GPS info
I decided to include a small map with Leaflet, and set a pin on the first GPS coordinates found in any image.
With PIL it is pretty easy to read out the EXIF metadata from images:
from PIL import Image
def get_exif(filename):
exif = Image.open(filename)._getexif()
if exif is not None:
# 34853 corresponds to 'GPSInfo'
entry = list(filter(lambda x: x[0] == 34853, exif.items()))
gps_info = entry[0][1]
print('gps_info:', gps_info)
exif = get_exif('img.jpg')
This would return something like this:
gps_info: {1: 'N', 2: (46.0, 26.0, 49.63992), 3: 'E', 4: (7.0, 53.0, 20.6736), 5: 0, 6: 2076.0}
(This can be converted to the more common decimal number format, see script below.)
Python script
Combining the above with a simple HTML template, a single Python script is enough to generate a plant diary for an excursion, as seen above.
I added some image transformations to downscale the images and put them into an img_scaled
folder, suitable for serving them for web. You can visit the diary page from above here: http://kleemans.ch/static/plant-diary/.
You can find the Python script here: Github Gist
Happy classifying!