Фон
Постановка задачи
Цели
Объем
Загрузка и подготовка изображений
Форматирование и преобразование изображений
Извлечение и выбор функций
Логистическая регрессия
Линейный дискриминантный анализ
K Ближайшие соседи
Деревья решений
Случайный лес
Наивный Байес
Машина опорных векторов
Показатели точности и производительности
Сравнение моделей машинного обучения
Ограничения и проблемы
Краткое изложение достижений
Вклад и значение
Будущая работа и улучшения
Болезни растений представляют собой серьезную угрозу продуктивности сельского хозяйства, приводя к потерям урожая и экономическим трудностям для фермеров. Своевременное и точное выявление болезней растений имеет решающее значение для реализации эффективных стратегий борьбы с болезнями и минимизации ущерба урожаю. Традиционные ручные методы диагностики заболеваний могут быть трудоемкими, субъективными и подверженными ошибкам. Таким образом, интеграция таких технологий, как машинное обучение и обработка изображений, стала многообещающим подходом к автоматизации и улучшению обнаружения болезней растений.
Основная цель этого проекта — разработка системы обнаружения болезней растений с использованием алгоритмов машинного обучения и методов обработки изображений. Цель системы — точно классифицировать листья растений как здоровые или больные путем анализа цифровых изображений листьев. Автоматизируя процесс обнаружения, фермеры и специалисты по сельскому хозяйству могут оперативно выявлять и лечить болезни растений, обеспечивая своевременное вмешательство и оптимизируя методы управления сельскохозяйственными культурами.
Основные цели этого проекта заключаются в следующем
Разработайте надежную и точную систему обнаружения болезней растений.
Внедрить алгоритмы машинного обучения для автоматической классификации листьев растений.
Используйте методы обработки изображений для извлечения соответствующих функций из изображений листьев.
Оцените производительность и точность различных моделей машинного обучения.
Обеспечить удобный интерфейс для простого и интуитивно понятного взаимодействия с системой.
Этот проект направлен на обнаружение болезней растений, особенно в листьях яблони. Набор данных, используемый для обучения и тестирования моделей, получен из набора данных Plant-Village, который содержит изображения здоровых листьев яблони и листьев, пораженных такими болезнями, как парша яблони, черная гниль и ржавчина кедровой яблони. классификацию болезней и предоставить фермерам и специалистам сельского хозяйства практический инструмент для эффективного выявления болезней растений и борьбы с ними. Проект не охватывает обнаружение заболеваний в реальном времени в полевых условиях или интеграцию аппаратных устройств для получения изображений.
Набор данных, используемый для этой системы обнаружения болезней растений, включает изображения листьев яблони, полученные из набора данных Plant-Village. Набор данных организован в четыре основные категории, представляющие различные классы состояния листьев яблони Apple___Apple_scab, Apple___Black_rot, Apple___Cedar_apple_rust и Apple___healthy
Apple___Apple_scab: эта категория содержит 630 изображений, из них 598 изображений предназначены для обучения и 32 изображения для тестирования.
Apple___Black_rot: набор данных включает 621 изображение в этой категории, из них 589 изображений выделены для обучения и 32 изображения для тестирования.
Apple___Cedar_apple_rust: набор данных состоит из 275 изображений листьев, пораженных ржавчиной кедровой яблони, из них 261 изображение используется для обучения и 14 изображений для тестирования.
Apple___healthy: эта категория содержит 1645 изображений здоровых листьев яблони. Из них 1562 изображения предназначены для обучения, а 83 изображения зарезервированы для тестирования.
Обучающие изображения используются для обучения моделей машинного обучения распознаванию закономерностей и различению здоровых и больных листьев. Тестовые изображения используются для оценки производительности и точности обученных моделей на невидимых данных. Используя этот разнообразный набор данных, система обнаружения болезней растений стремится точно классифицировать листья яблони как здоровые или пораженные такими болезнями, как парша яблони, черная гниль или ржавчина кедровой яблони. Состав набора данных позволяет системе учиться на широком спектре состояний листьев и улучшать свою способность обобщать и точно идентифицировать болезни растений.
Загрузка и подготовка изображений
В контексте проекта по обнаружению болезней листьев яблони первым шагом является получение набора данных, состоящего из изображений листьев яблони, пораженных различными заболеваниями. Эти изображения затем загружаются в систему, чтобы сделать их доступными для дальнейшей обработки. Кроме того, изображения подготавливаются путем выполнения необходимых корректировок, таких как изменение их размера до согласованного разрешения, обрезка ненужных частей или нормализация распределения цветов. Форматирование и преобразование изображений. После загрузки изображений листьев яблони их необходимо отформатировать и преобразовать, чтобы обеспечить совместимость с последующими этапами проекта. Это предполагает стандартизацию формата изображений путем преобразования их в файлы определенного типа, например JPEG или PNG. Кроме того, можно внести изменения в разрешение цветового пространства или другие атрибуты изображения, чтобы обеспечить согласованность и облегчить точный анализ.
Извлечение и выбор функций
Извлечение признаков — решающий шаг в обнаружении болезней листьев яблони. Для извлечения соответствующих функций из изображений листьев используются различные методы. Эти методы включают анализ текстуры для выявления структурных закономерностей, связанных с болезнями, изучение цвета для выявления изменений, связанных с конкретными заболеваниями, и изучение формы для выявления нарушений в морфологии листьев. Извлекая эти отличительные особенности, последующие алгоритмы машинного обучения смогут эффективно различать здоровые и больные листья яблони.
Выбор функции
Этот шаг включает в себя выбор подмножества извлеченных признаков на основе их релевантности и дискриминационной силы. Выбор признаков помогает уменьшить размерность набора данных за счет устранения шума и избыточной информации. За счет выбора наиболее информативных признаков можно повысить эффективность и точность модели выявления заболеваний.
Проект по обнаружению болезней листьев яблони использует ряд алгоритмов машинного обучения для разработки эффективной модели классификации болезней. Используются следующие алгоритмы
Логистическая регрессия: Логистическая регрессия используется для прогнозирования вероятности того, что яблоневый лист будет здоровым или больным, на основе извлеченных признаков.
Линейный дискриминантный анализ: Линейный дискриминантный анализ помогает классифицировать листья яблони, находя линейную комбинацию признаков, которая лучше всего разделяет здоровые и больные образцы.
K Nearest Neighbours (KNN): K Nearest Neighbours классифицирует листья яблони, сравнивая их характеристики с характеристиками ближайших соседей в пространстве признаков.
Деревья решений. Деревья решений используют ряд условий if-else для классификации образцов на основе их характеристик и иерархических отношений.
Случайный лес: Случайный лес — это метод ансамблевого обучения, который объединяет несколько деревьев решений для повышения точности классификации.
Наивный Байес: Наивный Байес — это вероятностный алгоритм, который вычисляет вероятность принадлежности яблоневого листа к определенному классу болезней.
Машина опорных векторов (SVM): машина опорных векторов строит гиперплоскости в многомерном пространстве признаков для классификации яблоневых листьев.
После выбора алгоритмов машинного обучения модели обучаются с использованием размеченного набора данных, состоящего из изображений листьев яблони с соответствующими метками заболеваний. На этом этапе обучения модели учатся распознавать закономерности и взаимосвязи между признаками и классами заболеваний. Чтобы обеспечить надежность и обобщение моделей, проводится процесс проверки. Обученные модели оцениваются с использованием отдельного набора проверочных данных, который не использовался во время обучения. Это помогает оценить способность моделей точно классифицировать невидимые образцы яблоневых листьев.
После обучения и проверки моделей они тестируются на отдельном наборе тестовых данных, который содержит новые, ранее не встречавшиеся изображения яблоневых листьев. Модели прогнозируют класс заболевания для каждого образца, а показатели оценки эффективности, такие как точность, точность, отзыв и показатель F1, рассчитываются для измерения эффективности моделей в обнаружении заболеваний.
В [1]:
# -----------------------------------# ИЗВЛЕЧЕНИЕ ГЛОБАЛЬНЫХ ФУНКЦИЙ# --------- --------------------------из sklearn.preprocessing import LabelEncoderиз sklearn.preprocessing import MinMaxScalerimport numpy as npimport mahotasimport cvimport osimport h5py# ----- ---------------#tunable-parameters# --------------------images_per_class = 800fixed_size = кортеж(( 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##### BGR To RGB ConversionIn [2]:# Преобразование каждого изображение в формат RGB из формата BGRdef rgb_bgr(image):rgb_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)return rgb_img##### RGB в HSV (значение насыщенности оттенка) ConversionIn [3]:# Преобразование в формат изображения HSV из RGBdef bgr_hsv(rgb_img):hsv_img = cv2.cvtColor(rgb_img, cv2.COLOR_RGB2HSV)return hsv_img##### Image SegmentationIn [4]:# для извлечения зеленого и коричневого цветаdef img_segmentation(rgb_img, hsv_img):lower_green = np.array([ 25 , 0 , 20 ])upper_green = np.array([ 100 , 255 , 255 ])healthy_mask = cv2.inRange(hsv_img, Lower_green, Upper_green)result = cv2.bitwise_and(rgb_img, rgb_img, маска=healthy_mask)lower_brown = np.array([ 10 , 0 , 10 ])upper_brown = np.array([ 30 , 255 , 255 ])disease_mask = cv2.inRange(hsv_img, low_brown, Upper_brown)disease_result = cv2.bitwise_and(rgb_img, rgb_img, маска=disease_mask)final_mask = здоровая_маска + болезнь_маскафинал_результат = cv2.bitwise_and(rgb_img, rgb_img, маска=final_mask)return Final_result##### Определение дескрипторов функций###### 1. Hu MomentsIn [5]:# Feature-Descriptor-1: Hu Momentsdef fd_hu_moments (изображение): изображение = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)feature = cv2.HuMoments(cv2.moments(image)). Flatten()return Feature###### 2. Haralick TexturesIn [6]:# Feature-Descriptor-2: HaralickTexturedef fd_haralick(изображение):серый = cv2.cvtColor(изображение, cv2.COLOR_BGR2GRAY)haralick = mahotas.features.haralick(gray).mean(axis= 0 )return haralick###### 3. Color HIstogramIn [7]:# Feature-Descriptor-3: Color Histogramdef fd_histogram(image, маска = Нет): изображение = cv2.cvtColor (изображение, cv2.COLOR_BGR2HSV)hist = cv2.calcHist( [изображение], [0, 1, 2], Нет, [ячейки, ячейки, ячейки], [0, 256, 0, 256, 0,256] )cv2.normalize(hist, hist)return hist.flatten()##### Загрузка набора обучающих данныхВ [8]:# получаем обучающую меткуtrain_labels = os.listdir(train_path)# сортируем обучающую меткуstrain_labels.sort() print(train_labels)# пустые списки для хранения векторов объектов и метокglobal_features = []labels = [] ['Apple___Apple_scab', 'Apple___Black_rot', 'Apple___Cedar_apple_rust','Apple___healthy']##### Генерация функций и встраивания меток из набора данныхВ [9]:# цикл по подпапкам обучающих данных для Training_name в train_labels:# join путь к обучающим данным и папка обучения каждого видаimg_dir_path = os.path.join(train_path, Training_name)# получить текущую метку обучения current_label = Training_name# перебрать изображения в каждой подпапке для img в os.listdir(img_dir_path):# получить имя файла изображенияfile = os.path.join( img_dir_path, img)# прочитать изображение и изменить его размер до фиксированного размераimage = cv2.imread(file)image = cv2.resize(image, fix_size)# Выполнение функции побитноRGB_BGR = rgb_bgr(image)BGR_HSV = bgr_hsv(RGB_BGR)IMG_SEGMENT = img_segmentation(RGB_BGR, BGR_HSV)# Вызов дескрипторов глобальных функцийfv_hu_moments = fd_hu_moments(IMG_SEGMENT)fv_haralick = fd_haralick(IMG_SEGMENT)fv_histogram = fd_histogram(IMG_SEGMENT)# Объединить глобальные функцииglobal_feature = np.hstack([fv_histogram, fv_haralick,fv_hu_moments])# обновить список меток и объектов Vectorslabels.append(current_label)global_features.append(global_feature)print("[STATUS] обработанная папка: {}".format(current_label))print("[STATUS] завершено извлечение глобальных объектов...") [СТАТУС] обработанная папка: Apple___Apple_scab[СТАТУС] обработанная папка: Apple___Black_rot[СТАТУС] обработанная папка: Apple___Cedar_apple_rust[СТАТУС] обработанная папка: Apple___healthy[СТАТУС] завершено глобальное извлечение функций... В [10]:# print(global_features)В [ 41]:# получить общий вектор признаков sizeprint("[STATUS] вектор признаков размер {}".format(np.array(global_features).shape)) Размер вектора признаков [STATUS] (3010, 532) В [12]:# получите общий размер обучающей метки# print(labels)print("[STATUS] обучающие метки {}".format(np.array(labels).shape )) [СТАТУС] обучающие этикетки (3010,)
Этикетка Закодированное значениеApple___Apple_scab 0Apple___Black_rot 1Apple___Cedar_apple_rust 2Apple___healthy 3
В [13]:
targetNames = np.unique(labels) le = LabelEncoder() target = le.fit_transform(labels) print(targetNames) print("[STATUS] обучающие метки закодированы...") ['Apple___Apple_scab' 'Apple___Black_rot' 'Apple___Cedar_apple_rust' ' Apple___healthy'] [СТАТУС] этикетки тренировок закодированы...
В [14]:
из sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler(feature_range=( 0 , 1 ))rescaled_features = Scaler.fit_transform(global_features)print("[STATUS] вектор признаков нормализован...") rescaled_features[STATUS] вектор признаков нормализован... Out [14]:array([[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("[STATUS] целевые метки: {}".format(target))print("[STATUS] форма целевых меток: {}".format(target.shape)) [СТАТУС] метки целей: [0 0 0 ... 3 3 3] [СТАТУС] Форма целевых меток: (3010,)
а. Функции
h5f_data = h5py.File(h5_train_features, "w") h5f_data.create_dataset("dataset_1", data=np.array(rescaled_features))Out[16]:<набор данных HDF5 "dataset_1": shape (3010, 532), введите " <f8">
h5f_label = h5py.File(h5_train_labels, "w") h5f_label.create_dataset("dataset_1", data=np.array(target))Out[17]:<набор данных HDF5 "dataset_1": shape (3010,), введите "< i8">В [43]:h5f_data.close()h5f_label.close()
# -----------------------------------# ОБУЧЕНИЕ НАШЕЙ МОДЕЛИ# --------- --------------------------import h5pyimport numpy as npimport osimport cvimport alertsfrom matplotlib import pyplotfrom sklearn.model_selection import train_test_split, cross_val_scorefrom sklearn.model_selection import KFold, StratifiedKFoldиз sklearn.metrics импортирует путаницу_матрицу, Точность_оценка, отчет_классификации из sklearn.linear_model импорт Логистическая регрессия из sklearn.tree импорт DecisionTreeClassifier из sklearn.ensemble импорт RandomForestClassifier из sklearn.neighbours импорт KNeighboursClassifier из sklearn.discriminant_anaанализ импорт LinearDiscriminantAnaанализ из sklearn.naive_bayes импорт GaussianNBfrom sklearn.svm import SVCimport joblibwarnings.filterwarnings("ignore")# --------------------# Tunable-parameters# ---------- ----------num_trees = 100test_size = 0.seed = 9scoring = "accuracy"# получить обучение labelstrain_labels = os.listdir(train_path)# отсортировать обучение labelstrain_labels.sort()if not os.path.exists(test_path):os.makedirs(test_path)# создать все модели машинного обучения .append(("LDA", LinearDiscriminantAnaанализ()))models.append(("KNN", KNeighboursClassifier()))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)))# переменные для хранения результаты и именаresults = []names = []# импортируют вектор признаков и обученную меткуsh5f_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()# проверьте форму вектора признаков и labelsprint("[STATUS] Feature shape: {}".format(global_features.shape))print("[STATUS] labels shape: {}".format(global_labels.shape))print("[STATUS] обучение началось...")print(global_labels, len( global_labels), len(global_features)) [СТАТУС] особенности формы: (3010, 532) Форма меток [СТАТУС]: (3010,) [СТАТУС] обучение началось... [0 0 0 ... 3 3 3] 3010 3010
В [38]:
(trainDataGlobal,testDataGlobal,trainLabelsGlobal,testLabelsGlobal, ) = train_test_split(np.array(global_features), np.array(global_labels),test_size=test_size, random_state=seed)print("[STATUS] разделенные данные поезда и тестовые данные...")print("Данные поезда: {} ".format(trainDataGlobal.shape))print("Тестовые данные: {}".format(testDataGlobal.shape)) [СТАТУС] разделенные данные поезда и тестовые данные... Данные поезда: (2408, 532)Тестовые данные: (602, 532) В [40]:trainDataGlobalOut[40]:array([[9.47066972e-01, 1.97577832e-02) , 5.34481987е-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]])
В [22]:
для имени, модели в моделях: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)" % (имя, 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)
В [23]:
fig = pyplot.figure()fig.suptitle("Сравнение алгоритмов машинного обучения")ax = fig.add_subplot( 111 )pyplot.boxplot(results)ax.set_xticklabels(names)pyplot.show()
Из приведенного выше результата мы видим, что модель случайного лесного классификатора имеет самую высокую точность - 96,7%, а модель Gaussian NB имеет самую низкую точность - 83,9%.
<div class="highlight Highlight-source-python notranslate Position-Relative Overflow-Auto" dir="auto" data-snippet-clipboard-copy-content=" В [24]: clf = RandomForestClassifier(n_estimators=num_trees, random_state= семя) В [25]: clf.fit(trainDataGlobal, trainLabelsGlobal) len(trainDataGlobal), len(trainLabelsGlobal) Out[25]: (2408, 2408) В [34]: y_predict = clf.predict(testDataGlobal) testLabelsGlobal Out[34]: array([3, 3, 1, 3, 0, 3, 1, 1, 2, 1, 1, 0, 1, 3, 3, 3, 3, 2, 0, 2, 0, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 1, 3, 3, 1, 3, 3, 3, 2, 3, 1, 3, 3, 3, 1, 0, 0, 3, 1, 3, 3, 0, 3, 3, 2, 3, 0, 3, 1, 0, 3, 0, 3, 3, 1, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 2, 1, 1, 2, 0, 2, 1, 1, 0, 0, 3, 2, 0, 3, 2, 3, 3, 2, 3, 3, 1, 1, 3, 2, 0, 2, 1, 1, 2, 3, 3, 3, 1, 1, 0, 3, 0, 3, 3, 0, 3, 3, 3, 1, 2, 3, 2, 3, 0, 3, 0, 3, 1, 3, 3, 3, 3, 3, 2, 1, 0, 1, 3, 3, 3, 1, 3, 3, 0, 0, 3, 3, 3, 0, 2, 3, 3, 0, 1, 1, 3, 0, 0, 3, 1, 3, 3, 1, 3, 2, 1, 0, 0, 3, 0, 1, 0, 1, 0, 1, 2, 3, 3, 3, 3, 3, 2, 1, 1, 3, 3, 1, 3, 1, 3, 2, 1, 3, 3, 0, 3, 0, 3, 3, 3, 1, 1, 3, 2, 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 1, 1, 0, 3, 0, 3, 1, 3, 3, 3, 1, 3, 3, 0, 3, 0, 2, 3, 3, 0, 3, 3, 3, 3, 0, 2, 3, 1, 3, 3, 3, 0, 3, 1, 3, 3, 3, 1, 3, 0, 2, 0, 3, 3, 3, 2, 3, 3, 3, 0, 0, 1, 1, 3, 3, 0, 3, 2, 0, 1, 1, 3, 0, 3, 1, 1, 3, 2, 2, 2, 3, 3, 3, 1, 1, 3, 0, 3, 0, 1, 3, 3, 0, 3, 1, 0, 3, 0, 3, 3, 2, 3, 3, 3, 3, 0, 3, 3, 3, 1, 0, 3, 2, 1, 3, 0, 1, 1, 0, 1, 3, 2, 0, 3, 0, 3, 1, 0, 3, 2, 0, 3, 0, 0, 2, 1, 3, 0, 3, 3, 0, 0, 3, 3, 1, 3, 0, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 0, 3, 3, 3, 1, 0, 1, 3, 0, 1, 3, 0, 3, 3, 3, 0, 3, 3, 0, 1, 3, 3, 1, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 1, 0, 3, 3, 0, 3, 3, 1, 0, 3, 1, 1, 3, 3, 3, 2, 3, 0, 0, 3, 3, 3, 3, 3, 3, 2, 1, 3, 3, 0, 3, 0, 1, 3, 1, 3, 3, 1, 1, 1, 1, 3, 3, 3, 1, 3, 0, 3, 3, 3, 2, 3, 1, 3, 3, 1, 1, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 3, 1, 1, 0, 3, 3, 3, 3, 0, 3, 1