Análisis de la precisión obtenida con la app Plantnet para la identificación de especies de plantas

Creado por: José Francisco Núñez Obando y María Laura Pizarro

El siguiente documento corresponde con una evaluación del porcentaje de precisión en la identificación de especies de plantas mediante el uso de la aplicación Plantnet.

Para cumplir con este objetivo se descargan una serie de fotografías desde los sitios GBIF y EOL usando sus api's respectivas, las cuales posteriormente se utilizan como objetos de prueba para la identificación de especies en la aplicación de PlantNet que se encuentra en linea, siendo esta la misma que se encuentra en formato de app para android e ios. Al respecto de la puesta a prueba de dicho servicio de identificación, se planteo el uso de la técnica de webscrapping utilizando para ello el webdriver de 'chrome' y la librería de Python llamada Selenium, además de otras librerías que complementan el análisis.

En los siguientes apartados se describen los procedimientos y se anotan las partes de código utilizadas para llavar a cabo cada proceso.

A continuación, algunas de las librerías python utilizadas inicialmente para completar con los primeros procedimientos:

In [8]:
import requests
import urllib.request
from lxml import html, etree
import json
from pandas.io.json import json_normalize
#import squarify
import warnings
warnings.filterwarnings('ignore')
import time
import pandas as pd
import numpy as np
import glob
import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from bs4 import BeautifulSoup
from fuzzywuzzy import fuzz

Descarga de datos usando la API de GBIF

En esta sección se procede a realizar la consulta a la API de GBIF en la que únicamente se establecen como parámetros el país y el reino.

In [9]:
parameters = {"country": "CR",
              "limit":300,
              "scientificname" : "Plantae"
              }
url = "https://api.gbif.org/v1/occurrence/search?"

q_gbif = requests.request(method="get", url=url, params=parameters)
j_gbif = json.loads(q_gbif.text)
L = json_normalize(j_gbif['results'])
L = L[['kingdom', 'phylum','order', 'family', 'genus', 'species', 'scientificName']]

Una vez se obtienen los resultados de la consulta, se procedio a realizar una selección de 20 muestras aleatorias del total.

In [10]:
L2 = L.sample(n=20, random_state=1)
L2
Out[10]:
kingdom phylum order family genus species scientificName
189 Plantae Tracheophyta Fabales Fabaceae Senna Senna alata Senna alata (L.) Roxb.
123 Plantae Tracheophyta Cucurbitales Cucurbitaceae Momordica Momordica charantia Momordica charantia L.
185 Plantae Tracheophyta Arecales Arecaceae Cocos Cocos nucifera Cocos nucifera L.
213 Plantae Tracheophyta Asterales Asteraceae Sphagneticola Sphagneticola trilobata Sphagneticola trilobata (L.) Pruski
106 Plantae Tracheophyta Zingiberales Heliconiaceae Heliconia Heliconia latispatha Heliconia latispatha Benth.
127 Plantae Tracheophyta Lamiales Acanthaceae Aphelandra Aphelandra scabra Aphelandra scabra (Vahl) Sm.
176 Plantae Tracheophyta Piperales Piperaceae Peperomia Peperomia pittieri Peperomia pittieri C.DC. ex T.Durand & Pittier
73 Plantae Tracheophyta Malpighiales Hypericaceae Vismia Vismia macrophylla Vismia macrophylla Kunth
275 Plantae Tracheophyta Ericales Primulaceae Clavija Clavija biborrana Clavija biborrana Oerst.
242 Plantae Tracheophyta Gentianales Rubiaceae Hamelia Hamelia patens Hamelia patens Jacq.
266 Plantae Tracheophyta Solanales Convolvulaceae Ipomoea Ipomoea cairica Ipomoea cairica (L.) Sweet
147 Plantae Tracheophyta Zingiberales Heliconiaceae Heliconia Heliconia psittacorum Heliconia psittacorum L.f.
299 Plantae Tracheophyta Fabales Fabaceae Caesalpinia Caesalpinia pulcherrima Caesalpinia pulcherrima (L.) Sw.
58 Plantae Tracheophyta Lamiales Acanthaceae Asystasia Asystasia gangetica Asystasia gangetica subsp. gangetica
122 Plantae Tracheophyta Commelinales Haemodoraceae Xiphidium Xiphidium caeruleum Xiphidium caeruleum Aubl.
78 Plantae Tracheophyta Zingiberales Musaceae Musa Musa paradisiaca Musa paradisiaca L.
11 Plantae Tracheophyta Asparagales Orchidaceae Maxillaria Maxillaria umbratilis Maxillaria umbratilis L.O.Williams
167 Plantae Tracheophyta Asterales Asteraceae Sphagneticola Sphagneticola trilobata Sphagneticola trilobata (L.) Pruski
220 Plantae Tracheophyta Alismatales Araceae Caladium Caladium bicolor Caladium bicolor (Aiton) Vent.
29 Plantae Tracheophyta Lamiales Gesneriaceae Drymonia Drymonia coriacea Drymonia coriacea (Oerst.) Wiehler

Consulta a la API de Encyclopedia of Life (EOL)

Con el fin de obtener una cantidad de 3 fotos de cada una especie de la muestra, se realiza una consulta a la API de EOL desde la que se obtiene una referencia a una subpagina de la especie correspondiente. En dicha subpágina se consulta de forma automatizada la sección de media en la que se encuentran las imágenes por especie, por lo que para una descarga de las misma se emplea una técnica de web scrapping. Al final se obtiene un dataframe que contiene el nombre de especie y una URL de las fotografías asociadas a esta.

In [11]:
def eol (data):
  L3=data.groupby(['species'])['species'].head(1).reset_index(drop=True)
  url_eol = "http://eol.org/api/search/1.0.json?"
  df = pd.DataFrame(columns=('specie', 'url'))

  species_count=0
  rows_list = []
  for i in L3:
      #EOL DATA
      parameters = {"q": i}
      q_eol = requests.request(method="get", url=url_eol, params=parameters)
      j_eol = json.loads(q_eol.text)
      
      #Se filtran los datos que tengan mas de 3 resultados 
      jd_eol = json_normalize(j_eol['results'])
      rows_temp = []  
      #Se recorren los links de los resultados y se evalua si el link devuelve informacion
      for link in j_eol['results']:
          r = requests.get(link['link']+'/media')
          html = r.text
          soup = BeautifulSoup(html, 'lxml')
          links = soup.find_all('div', {'class': 'js-grid-modal-toggle uk-card-media-top uk-inline-clip uk-transition-toggle'})
          
          for y in links:
              dict1 = {}
              dict1.update({'Specie':i, 'Url':y.find('img')['src']})
              
              rows_temp.append(dict1) 
              if(len(rows_temp) == 3):
                  species_count+=1
                  rows_list += rows_temp
                  break
          if(len(rows_temp) == 3):
              break
      #Se detiene el ciclo cuando ya se hayan obtenido 3 imagenes de 20 especies
      if (species_count == 21):
          break

  df_eol = pd.DataFrame(rows_list)
  return df_eol

La anterior función se aplica la lista de especies obtenida de GBIF y se imprime para conocer los resultados.

In [12]:
df_eol0 = eol(L2)
In [13]:
df_eol0.head()
Out[13]:
Specie Url
0 Senna alata https://content.eol.org/data/media/7e/e2/22/54...
1 Senna alata https://content.eol.org/data/media/7e/e2/27/54...
2 Senna alata https://content.eol.org/data/media/7e/e3/ec/54...
3 Momordica charantia https://content.eol.org/data/media/80/d1/b1/54...
4 Momordica charantia https://content.eol.org/data/media/80/d1/b4/54...

Con el fin de conocer cuantas de las especies no fue posible obtener datos desde EOL se realiza la siguiente operación.

In [14]:
print('La cantidad de especies sin foto son: ',20-((df_eol0.Specie.value_counts().sum())/3))
La cantidad de especies sin foto son:  3.0

Con el dato de la cantidad faltantes, se aplica la extracción de 3 especies del total del dataframe obtenido de GBIF.

In [15]:
L2_1 = L.sample(3, replace=True)
L2_1
Out[15]:
kingdom phylum order family genus species scientificName
239 Plantae Tracheophyta Gentianales Apocynaceae Aspidosperma Aspidosperma spruceanum Aspidosperma spruceanum Benth. ex Müll.Arg.
250 Plantae Tracheophyta Fabales Fabaceae Andira Andira inermis Andira inermis (W.Wright) DC.
233 Plantae Tracheophyta Gentianales Rubiaceae Alibertia Alibertia edulis Alibertia edulis (Rich.) A.Rich. ex DC.

Y con ello, se realiza el checkeo de especies entre listas para ver que las últimas no esten incluidas en la primera lista a la que se le aplico la función EOL.

In [16]:
spec1 = list(df_eol0['Specie'].unique())
spec2 = list(L2_1.species.unique())

check =  any(item in spec2 for item in spec1)
 
if check is True:
    print("La lista si contiene algunas especies de la primera lista")   
else :
    print("Las listas no contiene especies iguales.")
Las listas no contiene especies iguales.

El resultado anterior nos da una luz verde para realizar la busqueda de fotografías en EOL para la segunda lista.

In [17]:
df_eol1 = eol(L2_1)
In [21]:
df_eol1
Out[21]:
Specie Url
0 Bromelia pinguin https://content.eol.org/data/media/61/7e/d6/50...
1 Bromelia pinguin https://content.eol.org/data/media/61/7e/d6/50...
2 Bromelia pinguin https://content.eol.org/data/media/61/7e/d6/50...
3 Tridax procumbens https://content.eol.org/data/media/7f/82/65/54...
4 Tridax procumbens https://content.eol.org/data/media/7f/82/65/54...
5 Tridax procumbens https://content.eol.org/data/media/7f/82/65/54...
6 Tithonia diversifolia https://content.eol.org/data/media/80/5e/ff/54...
7 Tithonia diversifolia https://content.eol.org/data/media/80/5e/ff/54...
8 Tithonia diversifolia https://content.eol.org/data/media/80/5e/ff/54...

Con el resultado anterior se procede a la unión entre el dataframe 1 y 2 de la obtención desde EOL.

In [18]:
df_eol_f = df_eol0.append(df_eol1)
print('La cantidad de fotos total por especies es: ', df_eol_f['Url'].value_counts().sum())
La cantidad de fotos total por especies es:  60

El resultado mostrado nos indica que se han conseguido la cantidad de 60 fotografías en total para las 20 especies.

De modo tal que se procede a la descarga de estas para poderlas analizar en la plataforma de identificación de especies de PlantNet.

In [19]:
count = 0
for name, url in zip(df_eol_f['Specie'], df_eol_f['Url']):
    n = os.path.exists("./imagenes/"+name+'.jpg')
    if n:
        count +=1
        if (count < 3):
            urllib.request.urlretrieve(str(url), "./imagenes/"+name+'_'+str(count)+".jpg")
    else:
        count = 0
        urllib.request.urlretrieve(str(url), "./imagenes/"+name+".jpg")

file_list = glob.glob(os.path.join(os.getcwd(), "./imagenes/", "*.jpg"))
print("La cantidad de imagenes descargadas son: ",len(file_list))
La cantidad de imagenes descargadas son:  60

A través del siguiente Link se pueden visualizar las fotografias: fotos de especies

Prueba del identificador de especies de Plantnet

En las siguientes líneas de código se realizan una serie de procesos automatizados que corresponden con la técnica de webscrapping los cuales corresponden con ejecución del webdriver en cuyo caso abre el GoogleChrome, posteriormente se busca el sitio web de plantnet que corresponde con la app de identificación y, en este sitio se utiliza el boton de subida de imagenes para su respectiva identificación, con esto se obtiene un resultado del cual únicamente se copia la información de la primera fila, siendo este el resultado top de la lista, y con el que se crea un dataframe que incluye como columnas el nombre del archivo evaluado, la nombre científico, la familia, el nombre común y el porcentaje de precisión que se obtuvo con la identificación que realiza la app.

A continuación, una lista de las librerías utilizadas en esta seccion:

In [22]:
#URL de descarga del webdriver: https://chromedriver.chromium.org/

#Se cargan las librerias respectivas
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
wd = webdriver.Chrome(options=options)
In [55]:
#Se ejecuta el webdriver para chrome
wd = webdriver.Chrome(executable_path="chromedriver.exe")
wd.implicitly_wait(0.5)
wd.maximize_window()

#Se especifica la pagina web
wd.get("https://identify.plantnet.org/")

#Identificar el elemento donde cargar la foto
s = wd.find_element_by_xpath("//input[@type='file']")

#Se crea un dataset con los datos obtenidos
fname = list()
nsc = list()
fam = list()
ncom = list()
prec = list()

# Procedimiento para enviar las fotografias a la app y del resultado arrojado se agrega a listas los diversos datos
for i in range(0, len(file_list)):
    s.send_keys(str(file_list[i]))
    fname.append(os.path.basename(file_list[i]))
    try:
      text_plant = WebDriverWait(wd, 30)\
        .until(EC.visibility_of_element_located((By.XPATH, '/html/body/div[2]/div[1]/div/div/div/div[1]/div[1]/div')))
    except TimeoutException:
        nsc.append("ND")
        fam.append("ND")
        ncom.append("ND")
        prec.append("0%")
        continue
    text_plant = text_plant.text
    text_plant = text_plant.split('\n')
    nsc.append(text_plant[0])
    fam.append(text_plant[1])
    if(len(text_plant) == 4):
        ncom.append(text_plant[2])
    else:
        ncom.append("ND")
    prec.append(text_plant[-1])
print("Termino la identificacion de fotos en la app de PlantNet")
wd.quit()
Termino la identificacion de fotos en la app de PlantNet

A partir del procedimiento anterior se construye una tabla en la que se agregan los nombres de las fotografías evaluadas, las cuales poseen como nombre aquel extraido de la consulta a GBIF y EOL, además de algunos de los resultados obtenidos con la evaluación realizada en PlantNet, dentro de los que figuran: el nombre científico, Familia, Nombre común y Precisión top obtenida con la identificación de la especie. A esta tabla se agregan otras columnas que corresponden con Ratio y Similitud, las cuales respectivamente corresponden con un cálculo de comparación entre el nombre de la fotografía y el nombre científico dado por PlantNet y, a partir de este, una columna que asigna un 1 a la mayor similitud obtenida en la comparación y a la de menor un 0 y para ello se establecio como 70 el límite Ratio entre la comparación, esto después de evaluar en promedio los diferentes rangos del ratio así como la comparación.

In [65]:
df = pd.DataFrame({'Foto': fname,'Nombre_cientifico': nsc, 'Familia': fam, 'Nombre_comun': ncom, 'Precision':prec})
df['Precision'] = [float(v.replace('%','').strip()) for v in df.Precision]
df['Ratio'] = df.apply(lambda x: fuzz.partial_ratio(x['Foto'], x['Nombre_cientifico']), axis=1)
df['Similitud'] = np.where(df['Ratio'] >= 70, 1, 0)

La tabla resultante es la siguiente:

In [66]:
df
Out[66]:
Foto Nombre_cientifico Familia Nombre_comun Precision Ratio Similitud
0 Alibertia edulis.jpg Psidium friedrichsthalianum (O.Berg) Nied. Myrtaceae Costa Rican guava 4.30 39 0
1 Alibertia edulis_1.jpg Tabernaemontana pandacaqui Lam. Apocynaceae Dogbane 4.22 33 0
2 Alibertia edulis_2.jpg Epimedium brevicornu Maxim. Berberidaceae ND 1.93 27 0
3 Andira inermis.jpg Machaerium biovulatum Micheli Leguminosae ND 4.35 33 0
4 Andira inermis_1.jpg Meliosma pinnata (Roxb.) Maxim. Sabiaceae ND 5.42 30 0
5 Andira inermis_2.jpg Lomariopsis japurensis (Mart.) J. Sm. Lomariopsidaceae ND 13.02 25 0
6 Aphelandra scabra.jpg Rhagodia parabolica R. Br. Amaranthaceae ND 4.67 42 0
7 Aphelandra scabra_1.jpg Aphelandra scabra (Vahl) Sm. Acanthaceae ND 17.18 74 1
8 Aphelandra scabra_2.jpg Aphelandra scabra (Vahl) Sm. Acanthaceae ND 4.07 74 1
9 Aspidosperma spruceanum.jpg Acacia mangium Willd. Leguminosae Black wattle 1.13 38 0
10 Aspidosperma spruceanum_1.jpg Pouteria sapota (Jacq.) H.E.Moore & Stearn Sapotaceae Mamey sapote 20.03 31 0
11 Aspidosperma spruceanum_2.jpg Pouteria sapota (Jacq.) H.E.Moore & Stearn Sapotaceae Mamey sapote 9.16 31 0
12 Asystasia gangetica.jpg Asystasia gangetica (L.) T.Anderson Acanthaceae Chinese violet 94.63 87 1
13 Asystasia gangetica_1.jpg Asystasia gangetica (L.) T.Anderson Acanthaceae Chinese violet 16.93 80 1
14 Asystasia gangetica_2.jpg Brunfelsia americana L. Solanaceae Lady-of-the-night 26.47 43 0
15 Caesalpinia pulcherrima.jpg Caesalpinia pulcherrima (L.) Sw. Leguminosae Dwarf poinciana 24.89 89 1
16 Caesalpinia pulcherrima_1.jpg Habenaria rhodocheila Hance Orchidaceae Little Dragon 27.09 41 0
17 Caesalpinia pulcherrima_2.jpg Caesalpinia pulcherrima (L.) Sw. Leguminosae Dwarf poinciana 26.32 83 1
18 Caladium bicolor.jpg Caladium bicolor (Aiton) Vent. Araceae Heart-of-Jesus 40.57 80 1
19 Caladium bicolor_1.jpg Smilax pumila Walter Smilacaceae Sarsaparilla-vine 6.15 35 0
20 Caladium bicolor_2.jpg Caladium lindenii (André) Madison Araceae Indian-kale 10.82 45 0
21 Clavija biborrana.jpg Clavija biborrana Oerst. Primulaceae ND 56.39 81 1
22 Clavija biborrana_1.jpg Vantanea parviflora Lam. Humiriaceae ND 13.63 37 0
23 Clavija biborrana_2.jpg Garcinia madruno (Kunth) Hammel Clusiaceae Lemon Drop Mangosteen 32.59 26 0
24 Cocos nucifera.jpg Cocos nucifera L. Arecaceae Coconut 41.83 88 1
25 Cocos nucifera_1.jpg Cocos nucifera L. Arecaceae Coconut 10.78 88 1
26 Cocos nucifera_2.jpg ND ND ND 0.00 0 0
27 Drymonia coriacea.jpg Drymonia coriacea (Oerst. ex Hanst.) Wiehler Gesneriaceae ND 18.32 81 1
28 Drymonia coriacea_1.jpg Streblus asper Lour. Moraceae Siamese rough-bush 3.44 24 0
29 Drymonia coriacea_2.jpg Drymonia alloplectoides Hanst. Gesneriaceae ND 22.66 57 0
30 Hamelia patens.jpg Hamelia patens Jacq. Rubiaceae Redhead 98.14 78 1
31 Hamelia patens_1.jpg Hamelia patens Jacq. Rubiaceae Redhead 41.15 75 1
32 Hamelia patens_2.jpg Hamelia patens Jacq. Rubiaceae Redhead 34.06 75 1
33 Heliconia latispatha.jpg Heliconia latispatha Benth. Heliconiaceae Expanded lobsterclaw 38.72 83 1
34 Heliconia latispatha_1.jpg Heliconia latispatha Benth. Heliconiaceae Expanded lobsterclaw 26.75 77 1
35 Heliconia latispatha_2.jpg Heliconia latispatha Benth. Heliconiaceae Expanded lobsterclaw 62.47 77 1
36 Heliconia psittacorum.jpg Canna tuerckheimii Kraenzl. Cannaceae Maraca roja 6.42 24 0
37 Heliconia psittacorum_1.jpg Heliconia densiflora Verl. Heliconiaceae ND 18.38 58 0
38 Heliconia psittacorum_2.jpg Heliconia hirsuta L.f. Heliconiaceae ND 59.34 59 0
39 Ipomoea cairica.jpg Ipomoea cairica (L.) Sweet Convolvulaceae Railroad-creeper 24.04 84 1
40 Ipomoea cairica_1.jpg Ipomoea cairica (L.) Sweet Convolvulaceae Railroad-creeper 19.69 76 1
41 Ipomoea cairica_2.jpg Ipomoea sagittata Poir. Convolvulaceae Saltmarsh morning-glory 11.76 52 0
42 Momordica charantia.jpg Momordica balsamina L. Cucurbitaceae Balsam-apple 67.84 68 0
43 Momordica charantia_1.jpg Momordica balsamina L. Cucurbitaceae Balsam-apple 51.48 68 0
44 Momordica charantia_2.jpg Anthyllis alpestris (Schult.) Kit. Leguminosae ND 1.76 36 0
45 Musa paradisiaca.jpg Tecophilaea violiflora Bertero ex Colla Tecophilaeaceae ND 2.96 20 0
46 Musa paradisiaca_1.jpg Arthropodium cirrhatum (G.Forst.) R.Br. Asparagaceae ND 4.42 23 0
47 Musa paradisiaca_2.jpg Musa ornata Roxb. Musaceae Flowering banana 18.40 47 0
48 Senna alata.jpg Parkinsonia praecox (Ruiz & Pav.) Hawkins Leguminosae ND 33.70 33 0
49 Senna alata_1.jpg Phyllanthus niruri L. Phyllanthaceae Niruri 41.17 24 0
50 Senna alata_2.jpg Senna alata (L.) Roxb. Leguminosae Christmas-candle 52.07 71 1
51 Sphagneticola trilobata.jpg Sphagneticola trilobata (L.) Pruski Compositae Creeping oxeye 42.45 89 1
52 Sphagneticola trilobata_1.jpg Sphagneticola trilobata (L.) Pruski Compositae Creeping oxeye 97.07 83 1
53 Sphagneticola trilobata_2.jpg Sphagneticola trilobata (L.) Pruski Compositae Creeping oxeye 31.75 83 1
54 Vismia macrophylla.jpg Rhopalostylis baueri (Hook.f.) H.Wendl. & Drude Arecaceae Norfolk palm 3.19 27 0
55 Vismia macrophylla_1.jpg Juglans mandshurica Maxim. Juglandaceae Manchurian walnut 8.50 31 0
56 Vismia macrophylla_2.jpg Vismia macrophylla Kunth Hypericaceae ND 7.38 75 1
57 Xiphidium caeruleum.jpg ND ND ND 0.00 0 0
58 Xiphidium caeruleum_1.jpg Xiphidium caeruleum Aubl. Haemodoraceae ND 88.31 80 1
59 Xiphidium caeruleum_2.jpg Xiphidium caeruleum Aubl. Haemodoraceae ND 47.13 80 1

Por último, con el fin de evaluar en términos globales la precisión que se obtuvo con la puesta a prueba de esta app, se aplican estadísticas descriptivas a las columnas 'Precision','Ratio' y 'Similitud', las cuales se presentan a continuación:

In [67]:
df['Precision'].describe()
Out[67]:
count    60.000000
mean     26.724833
std      25.487973
min       0.000000
25%       5.967500
50%      19.045000
75%      40.715000
max      98.140000
Name: Precision, dtype: float64
In [68]:
df['Ratio'].describe()
Out[68]:
count    60.000000
mean     54.966667
std      25.522982
min       0.000000
25%      32.500000
50%      57.500000
75%      80.000000
max      89.000000
Name: Ratio, dtype: float64
In [70]:
df['Similitud'].value_counts()
Out[70]:
0    34
1    26
Name: Similitud, dtype: int64

De estas estadísticas se puede observar que se evaluaron 60 fotografías de 20 especies diferentes en las cuales se obtuvo una precision promedio de 26%, siendo 0% la precision mínima y 98% la máxima, tal y como es es posible apreciar en la tabla de resultados. Respecto al ratio en el que se comparan los nombres científicos de la fuente y el resultado de la identificación se tiene un promedio de 54%, siendo el mínimo logrado en 0% y 89% el máximo. Por último, respecto de lo que se podría llamar peso de similitud entre fuente y resultados se logró una cantidad de 26 fotografías con identificación precisa o casi precisa y 34 fotografías en las que no se logró la optima identificación, de modo tal que la evaluación obtenida muestra cantidades similares entre los aciertos y desaciertos, siendo este último el que obtuvo una mayor cantidad desafortunadamente.

Por tanto, se puede concluir que, aunque la herramienta de PlantNet posee un gran potencial en la identificación de especies, aun falta por mejorar en cuanto a su grado de certeza, aunque es importante reconocer que también la calidad de las fotografías para la evaluación no siempre es la más adecuada y por ende pueden desfavorecer la funcionalidad de la app aquí evaluada, por lo que sería importante destacar esto al inicio del uso de la app.