Fondo
Declaración del problema
Objetivos
Alcance
Cargando y preparando imágenes
Formato y conversión de imágenes
Extracción y selección de características
Regresión logística
Análisis discriminante lineal
K vecinos más cercanos
Árboles de decisión
Bosque aleatorio
Bayes ingenuo
Máquina de vectores de soporte
Métricas de precisión y rendimiento
Comparación de modelos de aprendizaje automático
Limitaciones y desafíos
Resumen de logros
Contribuciones y significado
Trabajo futuro y mejoras
Las enfermedades de las plantas plantean amenazas importantes para la productividad agrícola, provocando pérdidas de rendimiento y dificultades económicas para los agricultores. La detección oportuna y precisa de enfermedades de las plantas es crucial para implementar estrategias efectivas de manejo de enfermedades y minimizar el daño a los cultivos. Los métodos manuales tradicionales de diagnóstico de enfermedades pueden llevar mucho tiempo, ser subjetivos y propensos a errores. Por lo tanto, la integración de tecnología, como el aprendizaje automático y el procesamiento de imágenes, ha surgido como un enfoque prometedor para automatizar y mejorar la detección de enfermedades de las plantas.
El principal objetivo de este proyecto es desarrollar un sistema de detección de enfermedades de las plantas utilizando algoritmos de aprendizaje automático y técnicas de procesamiento de imágenes. El sistema tiene como objetivo clasificar con precisión las hojas de las plantas como sanas o enfermas mediante el análisis de imágenes digitales de las hojas. Al automatizar el proceso de detección, los agricultores y expertos agrícolas pueden identificar y abordar rápidamente las enfermedades de las plantas, lo que permite intervenciones oportunas y optimizar las prácticas de manejo de cultivos.
Los objetivos principales de este proyecto son los siguientes
Desarrollar un sistema de detección de enfermedades vegetales robusto y preciso
Implementar algoritmos de aprendizaje automático para la clasificación automatizada de hojas de plantas.
Utilice técnicas de procesamiento de imágenes para extraer características relevantes de imágenes de hojas.
Evaluar el rendimiento y la precisión de diferentes modelos de aprendizaje automático.
Proporcionar una interfaz fácil de usar para una interacción fácil e intuitiva con el sistema.
Este proyecto se centra en la detección de enfermedades vegetales específicamente en hojas de manzano. El conjunto de datos utilizado para entrenar y probar los modelos se obtiene del conjunto de datos Plant-Village, que contiene imágenes de hojas de manzano sanas y hojas afectadas por enfermedades como Apple Scab, Black Rot y Cedar Apple Rust. El sistema tiene como objetivo lograr una alta precisión en clasificación de enfermedades y proporcionar una herramienta práctica para que los agricultores y profesionales agrícolas identifiquen y gestionen enfermedades de las plantas de forma eficaz. El proyecto no cubre la detección de enfermedades en tiempo real en campo ni la integración de dispositivos hardware para la adquisición de imágenes.
El conjunto de datos utilizado para este sistema de detección de enfermedades vegetales comprende imágenes de hojas de manzano obtenidas del conjunto de datos Plant-Village. El conjunto de datos está organizado en cuatro categorías principales que representan diferentes clases de condiciones de las hojas del manzano Apple___Apple_scab, Apple___Black_rot, Apple___Cedar_apple_rust y Apple___healthy.
Apple___Apple_scab: esta categoría contiene 630 imágenes, con 598 imágenes asignadas para entrenamiento y 32 imágenes para prueba.
Apple___Black_rot: el conjunto de datos incluye 621 imágenes en esta categoría, con 589 imágenes asignadas para entrenamiento y 32 imágenes para prueba.
Apple___Cedar_apple_rust: el conjunto de datos consta de 275 imágenes de hojas afectadas por la roya del cedro, con 261 imágenes utilizadas para entrenamiento y 14 imágenes para pruebas.
Manzana___saludable: esta categoría contiene 1645 imágenes de hojas de manzana saludables. De ellas, 1562 imágenes están designadas para entrenamiento y 83 imágenes están reservadas para prueba.
Las imágenes de entrenamiento se utilizan para enseñar a los modelos de aprendizaje automático a reconocer patrones y distinguir entre hojas sanas y enfermas. Las imágenes de prueba se utilizan para evaluar el rendimiento y la precisión de los modelos entrenados en datos invisibles. Al aprovechar este conjunto de datos diverso, el Sistema de Detección de Enfermedades de las Plantas tiene como objetivo clasificar con precisión las hojas de manzano como sanas o afectadas por enfermedades como la sarna del manzano, la podredumbre negra o la podredumbre negra. roya del cedro. La composición del conjunto de datos permite al sistema aprender de una amplia gama de condiciones de las hojas y mejorar su capacidad para generalizar e identificar enfermedades de las plantas con precisión.
Cargando y preparando imágenes
En el contexto del proyecto de detección de enfermedades de la hoja del manzano, el primer paso es adquirir un conjunto de datos que consta de imágenes de hojas de manzano afectadas por diferentes enfermedades. Luego, estas imágenes se cargan en el sistema para que sean accesibles para su posterior procesamiento. Además, las imágenes se preparan realizando los ajustes necesarios, como cambiar su tamaño a una resolución consistente, recortar partes innecesarias o normalizar la distribución del color. Formato y conversión de imágenes Una vez cargadas las imágenes de hojas de manzana, es necesario formatearlas y convertirlas para garantizar compatibilidad con las siguientes etapas del proyecto. Esto implica estandarizar el formato de imagen convirtiéndolas a un tipo de archivo específico como JPEG o PNG. Además, se pueden realizar ajustes en la resolución del espacio de color u otros atributos de la imagen para garantizar la coherencia y facilitar un análisis preciso.
Extracción y selección de características
La extracción de características es un paso crucial en la detección de enfermedades en las hojas de manzano. Se utilizan varias técnicas para extraer características relevantes de las imágenes de las hojas. Estas técnicas incluyen analizar la textura para capturar patrones de textura asociados con enfermedades, examinar el color para identificar variaciones relacionadas con enfermedades específicas y estudiar la forma para detectar irregularidades en la morfología de las hojas. Al extraer estas características distintivas, los algoritmos de aprendizaje automático posteriores pueden diferenciar eficazmente entre hojas de manzano sanas y enfermas.
Selección de funciones
Este paso implica elegir un subconjunto de las características extraídas en función de su relevancia y poder discriminatorio. La selección de funciones ayuda a reducir la dimensionalidad del conjunto de datos al eliminar el ruido o la información redundante. Al seleccionar las funciones más informativas, se puede mejorar la eficiencia y precisión del modelo de detección de enfermedades.
El proyecto de detección de enfermedades de la hoja del manzano utiliza una variedad de algoritmos de aprendizaje automático para desarrollar un modelo de clasificación de enfermedades eficaz. Se emplean los siguientes algoritmos
Regresión logística: la regresión logística se utiliza para predecir la probabilidad de que una hoja de manzana esté sana o enferma en función de las características extraídas.
Análisis discriminante lineal: el análisis discriminante lineal ayuda a clasificar las hojas de manzano al encontrar una combinación lineal de características que separa mejor las muestras sanas y enfermas.
K Vecinos más cercanos (KNN): K Vecinos más cercanos clasifica las hojas de manzano comparando sus características con las de los vecinos más cercanos en el espacio de características.
Árboles de decisión: los árboles de decisión utilizan una serie de condiciones if-else para clasificar muestras en función de sus características y sus relaciones jerárquicas.
Random Forest: Random Forest es un método de aprendizaje conjunto que combina múltiples árboles de decisión para mejorar la precisión de la clasificación.
Naïve Bayes: Naïve Bayes es un algoritmo probabilístico que calcula la probabilidad de que una hoja de manzana pertenezca a una clase de enfermedad particular.
Máquina de vectores de soporte (SVM): la máquina de vectores de soporte construye hiperplanos en un espacio de características de alta dimensión para clasificar hojas de manzana
Después de seleccionar los algoritmos de aprendizaje automático, los modelos se entrenan utilizando un conjunto de datos etiquetados que consta de imágenes de hojas de manzano con las correspondientes etiquetas de enfermedades. Los modelos aprenden a reconocer patrones y relaciones entre características y clases de enfermedades durante esta fase de entrenamiento. Para garantizar la confiabilidad y generalización de los modelos, se lleva a cabo un proceso de validación. Los modelos entrenados se evalúan utilizando un conjunto de datos de validación separado que no se utilizó durante el entrenamiento. Esto ayuda a evaluar la capacidad de los modelos para clasificar con precisión muestras de hojas de manzano invisibles.
Una vez que los modelos están entrenados y validados, se prueban en un conjunto de datos de prueba separado que contiene imágenes de hojas de manzano nuevas e invisibles. Los modelos predicen la clase de enfermedad para cada muestra y se calculan métricas de evaluación del desempeño como exactitud, precisión, recuperación y puntuación F1 para medir la efectividad de los modelos en la detección de enfermedades.
En [1]:
# -----------------------------------# EXTRACCIÓN DE CARACTERÍSTICAS GLOBALES# --------- --------------------------desde sklearn.preprocessing import LabelEncoderdesde sklearn.preprocessing import MinMaxScalerimport numpy as npimport mahotasimport cvimport osimport h5py# ----- ---------------# parámetros-ajustables# --------------------images_per_class = 800fixed_size = tupla(( 500, 500))train_path = "../dataset/train"test_path = "../dataset/test"h5_train_features = "../embeddings/features/features.h5"h5_train_labels = "../embeddings/labels/labels .h5"bins = 8##### Conversión de BGR a RGB en [2]:# Conversión de cada imagen a RGB desde el formato BGRdef rgb_bgr(imagen):rgb_img = cv2.cvtColor(imagen, cv2.COLOR_BGR2RGB)return rgb_img##### Conversión de RGB a HSV (valor de saturación de tono) en [3]:# Conversión a imagen HSV formato de RGBdef bgr_hsv(rgb_img):hsv_img = cv2.cvtColor(rgb_img, cv2.COLOR_RGB2HSV)return hsv_img##### Segmentación de imagen en [4]:# para extracción de color verde y marróndef img_segmentation(rgb_img, hsv_img):lower_green = np.array([ 25, 0, 20 ])superior_verde = np.array([ 100 , 255 , 255 ])healthy_mask = cv2.inRange(hsv_img, lower_green, Upper_green)resultado = cv2.bitwise_and(rgb_img, rgb_img, mask=healthy_mask)lower_brown = np.array([ 10 , 0 , 10 + Disease_maskfinal_result = cv2.bitwise_and(rgb_img, rgb_img, mask=final_mask)return final_result##### Determinando los descriptores de características###### 1. Hu MomentsIn [5]:# feature-descriptor-1: Hu Momentsdef fd_hu_moments( imagen):imagen = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY) característica = cv2.HuMoments (cv2.moments (imagen)). :gris = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY)haralick = mahotas.features.haralick(gray).mean(axis= 0 )return haralick###### 3. HIstograma de color en [7]:# feature-descriptor-3: Histograma de colordef fd_histogram(imagen, máscara=Ninguno):imagen = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV)hist = cv2.calcHist( [imagen], [0, 1, 2], Ninguno, [contenedores, contenedores, contenedores], [0, 256, 0, 256, 0,256] )cv2.normalize(hist, hist)return hist.flatten()##### Cargando el conjunto de datos de entrenamientoEn [8]:# obtener las etiquetas de entrenamientotrain_labels = os.listdir(train_path)# ordenar las etiquetas de entrenamientotrain_labels.sort() print(train_labels)# listas vacías para contener vectores de características y etiquetasglobal_features = []labels = [] ['Apple___Apple_scab', 'Apple___Black_rot', 'Apple___Cedar_apple_rust','Apple___healthy']##### Generando las características y las incrustaciones de etiquetas a partir del conjunto de datos En [9]:# recorre las subcarpetas de datos de entrenamiento para Training_name en train_labels:# join la ruta de datos de entrenamiento y la carpeta de entrenamiento de cada especieimg_dir_path = os.path.join(train_path, Training_name)# obtener la etiqueta de entrenamiento actualcurrent_label = Training_name# recorrer las imágenes en cada subcarpeta para img en os.listdir(img_dir_path):# obtener el archivo de imagen nombrefile = os.path.join( img_dir_path, img)# lee la imagen y cambia su tamaño a una imagen de tamaño fijo = cv2.imread(file)image = cv2.resize(image, fix_size)# Función en ejecución bit por bitRGB_BGR = rgb_bgr(image)BGR_HSV = bgr_hsv(RGB_BGR)IMG_SEGMENT = img_segmentation(RGB_BGR, BGR_HSV)# Convocatoria de descriptores de funciones globalesfv_hu_moments = fd_hu_moments(IMG_SEGMENT)fv_haralick = fd_haralick(IMG_SEGMENT)fv_histogram = fd_histogram(IMG_SEGMENT)# Concatenar características globalesglobal_feature = np.hstack([fv_histogram, fv_haralick,fv_hu_moments])# actualizar la lista de etiquetas y características vectoreslabels.append(current_label)global_features.append(global_feature)print("[ESTADO] carpeta procesada: {}".format(current_label))print("[ESTADO] Extracción de funciones globales completada...") [ESTADO] carpeta procesada: Apple___Apple_scab[ESTADO] carpeta procesada: Apple___Black_rot[ESTADO] carpeta procesada: Apple___Cedar_apple_rust[ESTADO] carpeta procesada: Apple___healthy[ESTADO] Extracción de funciones globales completada... En [10]:# print(global_features)En [ 41]:# obtener el tamaño del vector de características generalprint("[ESTADO] vector de características tamaño{}".formato(np.array(global_features).forma)) [ESTADO] tamaño del vector de características (3010, 532)En [12]:# obtener el tamaño general de la etiqueta de entrenamiento# print(labels)print("[ESTADO] Etiquetas de entrenamiento {}".format(np.array(labels).shape )) [ESTADO] Etiquetas de entrenamiento (3010,)
Etiqueta Valor codificadoApple___Apple_scab 0Apple___Black_rot 1Apple___Cedar_apple_rust 2Apple___healthy 3
En [13]:
targetNames = np.unique(labels) le = LabelEncoder() target = le.fit_transform(labels) print(targetNames) print("[ESTADO] etiquetas de entrenamiento codificadas...") ['Apple___Apple_scab' 'Apple___Black_rot' 'Apple___Cedar_apple_rust' ' Apple___healthy'] [ESTADO] etiquetas de entrenamiento codificadas...
En [14]:
de sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler(feature_range=( 0 , 1 ))rescaled_features = scaler.fit_transform(global_features)print("[ESTADO] vector de características normalizado...")rescaled_features[ESTADO] vector de características normalizado...Fuera [14]:matriz([[0.8974175, 0,03450962, 0,01845123, ..., 0,02027887, 0,12693291, 0,96573218], [0,89815922, 0,13025558, 0,02774864, ..., 0,02027767, 0,12692423, 0,96573354], [0.56777027, 0. , 0.01540143, ..., 0.02027886, 0.12693269,0.96573218], ..., [0,95697685, 0,01228793, 0,00548476, ..., 0,02027886, 0,12693346, 0,96573218], [0,97704002, 0,10614054, 0,03136325, ..., 0,02027885, 0,12692424, 0,96573217], [0.95214074, 0.03819411, 0.03671892, ..., 0.02027886, 0.12692996,0.96573217]])print("[ESTADO] etiquetas de destino: {}".format(destino))print("[ESTADO] forma de etiquetas de destino: {}".formato(objetivo.forma)) [ESTADO] etiquetas de destino: [0 0 0 ... 3 3 3] [ESTADO] forma de etiquetas de destino: (3010,)
a. Características
h5f_data = h5py.File(h5_train_features, "w")h5f_data.create_dataset("dataset_1", data=np.array(rescaled_features))Out[16]:
h5f_label = h5py.File(h5_train_labels, "w")h5f_label.create_dataset("dataset_1", data=np.array(target))Out[17]:En [43]:h5f_data.close()h5f_label.close()
# -----------------------------------# ENTRENANDO NUESTRO MODELO# --------- --------------------------importar h5pyimportar numpy como npimport osimportar cvimport advertencias de matplotlib importar pyplot de sklearn.model_selection importar train_test_split, cross_val_scorede sklearn.model_selection importar KFold, StratifiedKFoldde sklearn.metrics importa confusion_matrix, precision_score,classification_report de sklearn.linear_model importar LogisticRegression de sklearn.tree importar DecisionTreeClassifier de sklearn.ensemble importar RandomForestClassifier de sklearn.neighbors importar KNeighborsClassifier de sklearn.discriminant_analysis importar LinearDiscriminantAnalysis de sklearn.naive_bayes importar GaussianNBdesde sklearn.svm import SVCimport joblibwarnings.filterwarnings("ignore")# --------------------# parámetros-ajustables# ----------- ---------num_trees = 100test_size = 0.seed = 9scoring = "accuracy"# obtener las etiquetas de entrenamientotrain_labels = os.listdir(train_path)# ordenar las etiquetas de entrenamientotrain_labels.sort()si no os.path.exists(test_path):os.makedirs(test_path)# crea todos los modelos de aprendizaje automáticomodels = []models.append(("LR", LogisticRegression(random_state=seed)))models.append(("LDA" , Análisis discriminante lineal()))models.append(("KNN", KNeighborsClassifier()))models.append(("DTC", DecisionTreeClassifier(random_state=seed)))models.append(("RF", RandomForestClassifier(n_estimators=num_trees,random_state=seed)))models.append(("NB", GaussianNB()))models.append(("SVM ", SVC(random_state=seed)))# variables para contener los resultados y nombresresultados = []nombres = []# importar la característica etiquetas vectoriales y entrenadash5f_data = h5py.File(h5_train_features, "r")h5f_label = h5py.File(h5_train_labels, "r")global_features_string = h5f_data["dataset_1"]global_labels_string = h5f_label["dataset_1"]global_features = np.array(global_features_string)global_labels = np.array(global_labels_string)h5f_data.close()h5f_label.close()# verificar la forma del vector de características y las etiquetasprint("[ESTADO] forma de características: {}".format(global_features. forma))print("[ESTADO] forma de etiquetas: {}".format(global_labels.shape))print("[ESTADO] entrenamiento iniciado...")print(global_labels, len(global_labels), len(global_features)) [ESTADO] presenta forma: (3010, 532) [ESTADO] forma de etiquetas: (3010,) [ESTADO] el entrenamiento comenzó... [0 0 0 ... 3 3 3] 3010 3010
En [38]:
(trainDataGlobal,testDataGlobal,trainLabelsGlobal,testLabelsGlobal, ) = train_test_split(np.array(global_features), np.array(global_labels),test_size=test_size, random_state=seed)print("[ESTADO] datos de prueba y tren divididos...")print("Datos del tren: {} ".format(trainDataGlobal.shape))print("Datos de prueba: {}".format(testDataGlobal.shape)) [ESTADO] datos de prueba y tren divididos... Datos del tren: (2408, 532)Datos de prueba: (602, 532)En [40]:trainDataGlobalOut[40]:array([[9.47066972e-01, 1.97577832e-02 , 5.34481987e-04, ...,2.02788613e-02, 1.26936845e-01, 9.65732178e-01], [9.67673181e-01, 4.20456024e-02, 5.76285634e-02, ...,2.02788294e-02, 1.26933581e-01, 9.65732217e-01], [9.84705756e-01, 2.97800312e-02, 1.34500344e-02, ...,2.02788553e-02, 1.26941878e-01, 9.65732187e-01], ..., [8.64347882e-01, 5.89053245e-02, 4.27430333e-02, ...,2.02791643e-02, 1.26961451e-01, 9.65733689e-01], [9.85818416e-01, 1.47428536e-03, 3.35008392e-03, ...,2.02767694e-02, 1.26792776e-01, 9.65732951e-01], [9.93152188e-01, 1.31020292e-03, 8.50637768e-04, ...,2.02910354e-02, 1.27475382e-01, 9.65721108e-01]])
En [22]:
para nombre, modelo en modelos:kfold = KFold(n_splits= 10 )cv_results = cross_val_score(model, trainDataGlobal, trainLabelsGlobal, cv=kfold,scoring=scoring)results.append(cv_results)names.append(name)msg = "%s : %f (%f)" % (nombre, cv_results.mean(), cv_results.std())print(msg)LR: 0.900346 (0.020452)LDA: 0.892038 (0.017931)KNN: 0.884978 (0.019588)CART: 0.886210 (0.014771)RF: 0,967191 (0,012676)NB: 0,839293 (0,014065)SVM: 0,885813 (0,021190)
En [23]:
fig = pyplot.figure()fig.suptitle("Comparación de algoritmos de aprendizaje automático")ax = fig.add_subplot( 111 )pyplot.boxplot(resultados)ax.set_xticklabels(nombres)pyplot.show()
Del resultado anterior podemos ver que el modelo Random Forest Classifier tiene la precisión más alta del 96,7% y el modelo Gaussiano NB tiene la precisión más baja del 83,9%.