Увы! Время пришло!
Пришло время применить наши знания по обработке изображений к реальной проблеме машинного обучения. В этом блоге давайте решим простую задачу классификации, включающую листья. В качестве группового задания нашей команде был предоставлен каталог, содержащий изображения листьев различных растений. Эти изображения представлены следующим образом:
Как видно, в каталоге найдено 5 классов листьев. Следовательно, мы остаемся с этой проблемой машинного обучения:
Можно ли различать разные классы листьев с помощью традиционных методов машинного обучения с учителем?
Прочтите эту статью до конца, чтобы узнать.
Извлечение функций
Первый вопрос, который вы можете задать: какие функции мы собираемся использовать в анализе? Чтобы машинное обучение работало, нам необходимо изучить особенности, которые являются общими для каждой категории листьев, чтобы алгоритм затем мог решить, что отличает лист от другого. Достижения в области глубокого обучения, в частности сверточных нейронных сетей (CNN), позволяют нам уже извлекать множество функций и в большинстве случаев получать высокие оценки точности. Однако, поскольку это блог об использовании методов обработки изображений, мы отложим использование CNN в анализе.
Итак, если нам не разрешено использовать CNN для извлечения признаков из листьев, то как мы вообще собираемся их получить? И это основная тема этого блога - использование обработки изображений для извлечения листовых функций для машинного обучения в Python.
Как всегда, для начала обсуждения необходимо импортировать следующие библиотеки:
from skimage.io import imshow, imread from skimage.color import rgb2gray from skimage.filters import threshold_otsu from skimage.morphology import closing from skimage.measure import label, regionprops, regionprops_table from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from matplotlib import pyplot as plt import pandas as pd import numpy as np from tqdm import tqdm import os
Чтобы следить за реализацией кода, вы можете скачать изображения по этой ссылке: Leaves
Примечание. Прежде чем продолжить, реализация кода для этого блога предполагает, что каталог листьев находится в том же каталоге, что и блокнот jupyter. Для вашей информации и справки.
Давайте посмотрим на одно из наших изображений в оттенках серого. Запустите приведенный ниже код:
# get the filenames of the leaves under the directory “Leaves” image_path_list = os.listdir("Leaves") # looking at the first image i = 0 image_path = image_path_list[i] image = rgb2gray(imread("Leaves/"+image_path)) imshow(image)
Теперь давайте приступим к извлечению объектов с помощью "свойств региона" скимэджа. Но перед этим нам нужно предварительно обработать наше изображение, мы предварительно обрабатываем изображение, преобразуя его в двоичную форму, используя метод Оцу, и очищаем его, используя морфологическую операцию закрытия. Реализация показана ниже:
binary = image < threshold_otsu(image) binary = closing(binary) imshow(binary)
Затем мы можем пометить предварительно обработанное изображение для подготовки к извлечению признаков.
label_img = label(binary) imshow(label_img)
Наконец, давайте извлечем элементы из изображения, используя свойства региона. В целях иллюстрации давайте сначала рассмотрим это изображение. Позже мы будем извлекать черты из каждого листа. Реализация кода представлена следующим образом:
table = pd.DataFrame(regionprops_table(label_img, image, ['convex_area', 'area', 'eccentricity', 'extent', 'inertia_tensor', 'major_axis_length', 'minor_axis_length'])) table['convex_ratio'] = table['area']/table['convex_area'] table['label'] = image_path[5] table
Это даст нам фрейм данных с функциями, которые мы вызвали из функции regionprops_table.
Блестяще! Действительно возможно получить функции. Однако это только для одного изображения. Получим характеристики для остальных. Как это сделать? Не беспокойтесь, этот блог поможет вам. Реализация кода о том, как это сделать, представлена ниже:
image_path_list = os.listdir("Leaves") df = pd.DataFrame() for i in range(len(image_path_list)): image_path = image_path_list[i] image = rgb2gray(imread("Leaves/"+image_path)) binary = image < threshold_otsu(image) binary = closing(binary) label_img = label(binary) table = pd.DataFrame(regionprops_table(label_img, image ['convex_area', 'area', 'eccentricity', 'extent', 'inertia_tensor', 'major_axis_length', 'minor_axis_length', 'perimeter', 'solidity', 'image', 'orientation', 'moments_central', 'moments_hu', 'euler_number', 'equivalent_diameter', 'mean_intensity', 'bbox'])) table['perimeter_area_ratio'] = table['perimeter']/table['area'] real_images = [] std = [] mean = [] percent25 = [] percent75 = [] for prop in regionprops(label_img): min_row, min_col, max_row, max_col = prop.bbox img = image[min_row:max_row,min_col:max_col] real_images += [img] mean += [np.mean(img)] std += [np.std(img)] percent25 += [np.percentile(img, 25)] percent75 += [np.percentile(img, 75)] table['real_images'] = real_images table['mean_intensity'] = mean table['std_intensity'] = std table['25th Percentile'] = mean table['75th Percentile'] = std table['iqr'] = table['75th Percentile'] - table['25th Percentile'] table['label'] = image_path[5] df = pd.concat([df, table], axis=0) df.head()
Реализуя код, он сгенерировал в общей сложности 51 функцию для всех листьев на наших изображениях. Теперь мы готовы к внедрению машинного обучения. Но перед этим давайте объясним некоторые функции, которые были извлечены для обеспечения контекста.
Мы рассчитали 4 характеристики на основе свойств региона.
1 . inertia_tensor - это кортеж, представляющий тензор инерции. Это относится к вращению сегмента вокруг своей массы.
2. minor_axis_length - длина вспомогательной оси или более короткой оси сегмента.
3. Плотность - это просто соотношение площади выпуклой оболочки и площади двоичного изображения.
4. эксцентриситет - эксцентриситет - это отношение фокусного расстояния (расстояния между фокусными точками) к длине главной оси.
Мы также извлекли эти свойства из сегмента необработанного изображения в градациях серого. Все приведенные ниже функции - это просто статистика значений оттенков серого. IQR - это просто разница 25-го и 75-го процентилей.
- 25-й процентиль
- 75-й процентиль
- mean_intensity
- std_intensity
- IQR
Реализация машинного обучения
Круто Приступим к реализации машинного обучения.
X = df.drop(columns=['label', 'image', 'real_images']) #features X = X[['iqr','75th Percentile','inertia_tensor-1-1', 'std_intensity','mean_intensity','25th Percentile', 'minor_axis_length', 'solidity', 'eccentricity']] #target y = df['label'] columns = X.columns #train-test-split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.25, random_state=123, stratify=y)
Выберите алгоритм классификатора. Для нашей команды наиболее эффективным оказался классификатор повышения градиента. Реализация следующая:
clf = GradientBoostingClassifier(n_estimators=50, max_depth=3, random_state=123) clf.fit(X_train, y_train) #print confusion matrix of test set print(classification_report(clf.predict(X_test), y_test)) #print accuracy score of the test set print(f"Test Accuracy: {np.mean(clf.predict(X_test) == y_test)*100:.2f}%")
Выполнение описанного выше алгоритма дает следующие результаты:
Выводы
Самым эффективным алгоритмом был GBM, так как он имеет лучшую точность тестирования, чем все классификаторы, с точностью тестирования около 87% по сравнению со вторым лучшим из 82% от Random Forest. Мы достигли довольно высокой точности, учитывая, что PCC всего 20%. Кроме того, ограниченное количество выборок позволяет легко переобучать обучающий набор с помощью классификаторов. Эту проблему можно решить, увеличив набор данных для большей обобщаемости.
И вот он, подход к проблеме машинного обучения, основанный на обработке изображений. Отличная работа для достижения этой точки! Увидимся в следующий раз в моей следующей статье.