Bildverarbeitung mit Python – Implementierung maschinellen Lernens | von Francis Camarao | Juni 2023

0
27


Die Essenz des maschinellen Lernens in der Bildverarbeitung:

Maschinelles Lernen hat den Bereich der Bildverarbeitung revolutioniert, indem es Computern ermöglicht, Muster zu lernen und anhand visueller Daten Vorhersagen zu treffen. Im Zusammenhang mit der Blattklassifizierung können maschinelle Lernalgorithmen anhand eines Datensatzes beschrifteter Blattbilder trainiert werden, um verschiedene Arten anhand ihrer einzigartigen Merkmale zu erkennen und zu kategorisieren. Indem wir die Leistungsfähigkeit des maschinellen Lernens nutzen, können wir den Prozess der Blattidentifizierung automatisieren und zu botanischen Forschungs- und Naturschutzbemühungen beitragen.

Lassen Sie uns zunächst alle erforderlichen Bibliotheken importieren.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from math import isclose
from fractions import Fraction
from skimage import information, io, filters, util, colour
from skimage.morphology import (disk, sq., rectangle, skeletonize,
erosion, dilation, opening, closing,
binary_erosion, binary_dilation,
binary_opening, binary_closing)
from skimage.measure import label, regionprops
from skimage.io import imread, imshow
from skimage.colour import rgb2gray
from tqdm.pocket book import tqdm, trange

from imblearn.over_sampling import SMOTE

from sklearn.preprocessing import (StandardScaler, MinMaxScaler,
OneHotEncoder, OrdinalEncoder)
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split, GridSearchCV, KFold
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import LinearSVC
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier

import cv2
import torch
from tqdm.pocket book import tqdm, trange
from PIL import Picture
from transformers import YolosFeatureExtractor, YolosForObjectDetection
from yoloface import face_analysis
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as T
from torch.utils.information import DataLoader
from torchvision import fashions, transforms, datasets
import matplotlib.pyplot as plt
from PIL import Picture, ImageDraw, ImageFont
import time
import math
import shutil
import copy
from pathlib import Path
from torchsummary import abstract
import warnings

warnings.filterwarnings("ignore", class=DeprecationWarning)
warnings.filterwarnings("ignore", class=UserWarning)

# Empty the GPU reminiscence cache
torch.cuda.empty_cache()

Sehen wir uns nun ein Beispielbild an!

image_raw = io.imread('leaves/plantA_1.jpg')
fig, ax = plt.subplots()
ax.imshow(image_raw,cmap='grey');
gray_leaves = rgb2gray(image_raw[:,:,:3])
binary_leaves = util.invert(gray_leaves > 0.5)
plt.determine()
plt.imshow(binary_leaves, cmap='grey')
plt.present()

Segmentierung

label_leaves = label(binary_leaves)
plt.determine()
plt.imshow(label_leaves);
raw_props = regionprops(label_leaves)[1:] # take away the background class
clean_props = [prop for prop in raw_props if prop.area > 10]

Ich werde diese verwenden regionprops Eigenschaften zur Unterscheidung der Blätter für das ML-Modell.

  1. Bereich
  2. Umfang
  3. Exzentrizität
  4. Solidität
  5. Ausmaß

Extraktion von Objektmerkmalen

def get_class(fpath):
'''
Extracts the category of the leaves from the filepath.
'''
return fpath.cut up('/')[1].cut up('.')[0].cut up('_')[0]

leaves_data = []

folder_path = 'leaves'

for filename in tqdm(os.listdir(folder_path)):
file_path = os.path.be a part of(folder_path, filename)

if os.path.isfile(file_path):

image_raw = io.imread(file_path)
gray_leaves = rgb2gray(image_raw[:,:,:3])
binary_leaves = util.invert(gray_leaves > 0.5)

label_leaves = label(binary_leaves)

raw_props = regionprops(label_leaves)[1:]
clean_props = [prop for prop in raw_props if prop.area > 10]
for prop in clean_props:

leaves_data.append({'space': prop.space,
'perim': prop.perimeter,
'ecc': prop.eccentricity,
'strong': prop.solidity,
'extent': prop.extent,
'label': get_class(file_path)
})

df_leaves = pd.DataFrame(information=leaves_data)
show(df_leaves)

KNN

pipeline = Pipeline(steps=[('scl', StandardScaler()),
('model', KNeighborsClassifier())])

param_grid = {'model__n_neighbors': checklist(vary(5, 31, 5)),
}

scoring = 'accuracy'
cv = 3

grid_search = GridSearchCV(estimator=pipeline,
param_grid=param_grid,
scoring=scoring,
cv=cv,
n_jobs=-1,
verbose=1,
return_train_score=True)

grid_search.match(X_trainval, y_trainval)
# grid_search.match(X_trainval_res, y_trainval_res)

val_acc = grid_search.best_score_
train_acc = grid_search.cv_results_[
'mean_train_score'][grid_search.best_index_]
hold_acc = grid_search.rating(X_hold, y_hold)

print(f'nKNN ClassifiernnTrain rating: {train_acc:.3f}nVal rating: {val_acc:.3f}nnTest rating: {hold_acc:.3f}')

Becoming 3 folds for every of 6 candidates, totalling 18 matches

KNN Classifier

Practice rating: 0.825
Val rating: 0.803

Take a look at rating: 0.714

Logistische Regression

pipeline = Pipeline(steps=[('scl', StandardScaler()),
('model', LogisticRegression())])

param_grid = {'model__C': [0.1, 1, 5, 10, 100, 1000],
'model__penalty': ['l2'],
'model__solver': ['liblinear'],
'model__random_state': [69]
}

scoring = 'accuracy'
cv = 3

grid_search = GridSearchCV(estimator=pipeline,
param_grid=param_grid,
scoring=scoring,
cv=cv,
n_jobs=-1,
verbose=1,
return_train_score=True)

grid_search.match(X_trainval, y_trainval)
# grid_search.match(X_trainval_res, y_trainval_res)

val_acc = grid_search.best_score_
train_acc = grid_search.cv_results_[
'mean_train_score'][grid_search.best_index_]
hold_acc = grid_search.rating(X_hold, y_hold)

print(f'nLogistic RegressionnnTrain rating: '
f'{train_acc:.3f}nVal rating: {val_acc:.3f}'
f'nnTest rating: {hold_acc:.3f}')

Becoming 3 folds for every of 6 candidates, totalling 18 matches

Logistic Regression

Practice rating: 0.865
Val rating: 0.831

Take a look at rating: 0.714

GBM

pipeline = Pipeline(steps=[('scl', StandardScaler()),
('model', GradientBoostingClassifier())])

param_grid = {'model__learning_rate': [0.001],
'model__max_features': [3, 4, 5],
'model__max_depth': [10, 20],
'model__random_state': [69]
}

scoring = 'accuracy'
cv = 3

grid_search = GridSearchCV(estimator=pipeline,
param_grid=param_grid,
scoring=scoring,
cv=cv,
n_jobs=-1,
verbose=1,
return_train_score=True)

grid_search.match(X_trainval, y_trainval)
# grid_search.match(X_trainval_res, y_trainval_res)

val_acc = grid_search.best_score_
train_acc = grid_search.cv_results_[
'mean_train_score'][grid_search.best_index_]
hold_acc = grid_search.rating(X_hold, y_hold)

print(f'GBMnnTrain rating: '
f'{train_acc:.3f}nVal rating: {val_acc:.3f}'
f'nnTest rating: {hold_acc:.3f}')

Becoming 3 folds for every of 6 candidates, totalling 18 matches
GBM

Practice rating: 0.998
Val rating: 0.798

Take a look at rating: 0.821

Tiefes Lernen

Ich werde auch versuchen, Deep Studying zu implementieren, um die Blätter zu klassifizieren

output_folder = 'cropped_leaves'

# Delete the 'cropped_leaves' folder if it exists
if os.path.exists(output_folder):
shutil.rmtree(output_folder)

if not os.path.exists(output_folder):
os.makedirs(output_folder)

class_count = {}
leaf_count = 0
courses = []

for filename in tqdm(os.listdir(folder_path)):
file_path = os.path.be a part of(folder_path, filename)

if os.path.isfile(file_path):
leaf_class = get_class(file_path)
if leaf_class not in courses:
courses.append(leaf_class)
if leaf_class not in class_count:
class_count[leaf_class] = 0

image_raw = io.imread(file_path)
gray_leaves = rgb2gray(image_raw[:,:,:3])
binary_leaves = util.invert(gray_leaves > 0.5)

label_leaves = label(binary_leaves)

raw_props = regionprops(label_leaves)[1:] # take away the background class
clean_props = [prop for prop in raw_props if prop.area > 10] # simply the leaves, take away specks

picture = Picture.open(file_path)

for prop in clean_props:
class_count[leaf_class] += 1
leaf_count += 1

cropped_image = picture.crop((prop.bbox[1], # left
prop.bbox[0], # prime
prop.bbox[3], # proper
prop.bbox[2]) # backside
)
class_folder = os.path.be a part of(output_folder, leaf_class)

if not os.path.exists(class_folder):
os.makedirs(class_folder)

new_filename = f"leaf_{leaf_count}.jpg"
new_file_path = os.path.be a part of(class_folder, new_filename)
cropped_image.save(new_file_path)

# Rename information to make sure monotonically labeled filenames

for leaf_class, depend in class_count.objects():
class_folder = os.path.be a part of(output_folder, leaf_class)
for i, filename in enumerate(os.listdir(class_folder), begin=1):
file_path = os.path.be a part of(class_folder, filename)
new_filename = f"leaf_{i}.jpg"
new_file_path = os.path.be a part of(class_folder, new_filename)
os.rename(file_path, new_file_path)

def create_dataset(src, dst, range_, class_):
"""Copy photographs of sophistication class_ inside range_ from src to dst.

Parameters
----------
src : str
supply listing
dst : str
vacation spot listing
range_ : tuple
tuple of min and max picture index to repeat
class_ : str
picture class ('plantA', 'plantB', ...)
"""
if os.path.exists(dst):
shutil.rmtree(dst)
os.makedirs(dst)
fnames = [f'leaf_{i}.jpg' for i in range(*range_)]
for fname in fnames:
src_file = os.path.be a part of(src, fname)
dst_file = os.path.be a part of(dst, fname)
shutil.copyfile(src_file, dst_file)
# looping by create_dataset for every class
class_counts = [len(os.listdir(os.path.join(output_folder, class_))) for class_ in classes] # Variety of photos for every class

for class_, depend in zip(courses, class_counts):
src = output_folder

# Outline the customized ranges for every cut up based mostly on the accessible depend
train_range = (1, int(0.7 * depend)) # 70% for coaching
validation_range = (int(0.7 * depend) + 1, int(0.9 * depend)) # 20% for validation
test_range = (int(0.9 * depend) + 1, depend) # 10% for testing

dst = f'cropped_leaves/prepare/{class_}'
create_dataset(src+'/'+class_, dst, range_=train_range, class_=class_)

dst = f'cropped_leaves/validation/{class_}'
create_dataset(src+'/'+class_, dst, range_=validation_range, class_=class_)

dst = f'cropped_leaves/take a look at/{class_}'
create_dataset(src+'/'+class_, dst, range_=test_range, class_=class_)
data_path = Path(output_folder)

data_path_list = checklist(data_path.glob("*/*.jpg"))

train_dir = data_path / "prepare"
val_dir = data_path / "validation"
test_dir = data_path / "take a look at"
train_data = datasets.ImageFolder(root=train_dir,
rework=transforms.Compose(
[transforms.Resize((224, 224)),
transforms.ToTensor()]))

all_images = torch.stack([img_t for img_t, _ in train_data], dim=3)
means = all_images.view(3, -1).imply(dim=1).numpy()
stds = all_images.view(3, -1).std(dim=1).numpy()
data_transforms = {
'prepare': transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=means, std=stds)
]),
'validation': transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=means, std=stds)
]),
'take a look at': transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=means, std=stds)
])
}

data_dir = data_path

image_datasets = {x: datasets.ImageFolder(os.path.be a part of(data_dir, x),
data_transforms[x])
for x in ['train', 'validation', 'test']}

dataloaders = {x: DataLoader(image_datasets[x], batch_size=1,
shuffle=True)
for x in ['train', 'validation', 'test']}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation', 'test']}

class_names = image_datasets['train'].courses
class_names

['plantA', 'plantB', 'plantC', 'plantD', 'plantE']

Fein abgestimmtes VGG-19

# Set gadget
gadget = torch.gadget("cuda" if torch.cuda.is_available() else "cpu")

# Load prepare, validation, and take a look at datasets
train_data = image_datasets['train']
val_data = image_datasets['validation']
test_data = image_datasets['test']

# Outline information loaders
train_loader = dataloaders['train']
valid_loader = dataloaders['validation']
test_loader = dataloaders['test']

# Load the pretrained VGG19 mannequin
mannequin = fashions.vgg19(pretrained=True)

# Freeze the parameters of the pretrained layers
for param in mannequin.parameters():
param.requires_grad = False

# Modify the final absolutely linked layer to match the variety of courses
num_classes = len(class_names)
mannequin.classifier[6] = nn.Linear(4096, num_classes)

# Transfer the mannequin to the suitable gadget
mannequin = mannequin.to(gadget)

# Outline loss perform and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(mannequin.parameters(), lr=0.001)

# Practice the mannequin
num_epochs = 30
best_valid_loss = float('inf')

for epoch in vary(num_epochs):
train_loss = 0.0
valid_loss = 0.0

# Coaching
mannequin.prepare()
for photographs, labels in train_loader:
photographs, labels = photographs.to(gadget), labels.to(gadget)

optimizer.zero_grad()

outputs = mannequin(photographs)
loss = criterion(outputs, labels)

loss.backward()
optimizer.step()

train_loss += loss.merchandise() * photographs.dimension(0)

# Validation
mannequin.eval()
with torch.no_grad():
for photographs, labels in valid_loader:
photographs, labels = photographs.to(gadget), labels.to(gadget)

outputs = mannequin(photographs)
loss = criterion(outputs, labels)

valid_loss += loss.merchandise() * photographs.dimension(0)

train_loss = train_loss / len(train_loader.dataset)
valid_loss = valid_loss / len(valid_loader.dataset)

print(f"Epoch: {epoch+1}/{num_epochs}, Practice Loss: {train_loss:.4f}, "
f"Legitimate Loss: {valid_loss:.4f}")

# Save one of the best mannequin based mostly on validation loss
if valid_loss < best_valid_loss:
best_valid_loss = valid_loss
torch.save(mannequin.state_dict(), 'best_leaves_model.pt')

# Take a look at the mannequin
mannequin.load_state_dict(torch.load('best_leaves_model.pt'))
mannequin.eval()
right = 0
whole = 0

with torch.no_grad():
for photographs, labels in test_loader:
photographs, labels = photographs.to(gadget), labels.to(gadget)

outputs = mannequin(photographs)
_, predicted = torch.max(outputs.information, 1)

whole += labels.dimension(0)
right += (predicted == labels).sum().merchandise()

accuracy = 100 * right / whole
print(f"Take a look at Accuracy: {accuracy:.2f}%")

Epoch: 1/30, Practice Loss: 0.4749, Legitimate Loss: 0.1140
Epoch: 2/30, Practice Loss: 0.1253, Legitimate Loss: 0.1190
Epoch: 3/30, Practice Loss: 0.1363, Legitimate Loss: 0.1185
Epoch: 4/30, Practice Loss: 0.0705, Legitimate Loss: 0.0598
Epoch: 5/30, Practice Loss: 0.0796, Legitimate Loss: 0.0407
Epoch: 6/30, Practice Loss: 0.0894, Legitimate Loss: 0.0853
Epoch: 7/30, Practice Loss: 0.0718, Legitimate Loss: 0.0495
Epoch: 8/30, Practice Loss: 0.0468, Legitimate Loss: 0.0574
Epoch: 9/30, Practice Loss: 0.0561, Legitimate Loss: 0.0269
Epoch: 10/30, Practice Loss: 0.0543, Legitimate Loss: 0.0370
Epoch: 11/30, Practice Loss: 0.0639, Legitimate Loss: 0.1421
Epoch: 12/30, Practice Loss: 0.0657, Legitimate Loss: 0.0481
Epoch: 13/30, Practice Loss: 0.0876, Legitimate Loss: 0.0563
Epoch: 14/30, Practice Loss: 0.0704, Legitimate Loss: 0.0673
Epoch: 15/30, Practice Loss: 0.0948, Legitimate Loss: 0.0335
Epoch: 16/30, Practice Loss: 0.0389, Legitimate Loss: 0.0402
Epoch: 17/30, Practice Loss: 0.0598, Legitimate Loss: 0.0882
Epoch: 18/30, Practice Loss: 0.0962, Legitimate Loss: 0.0865
Epoch: 19/30, Practice Loss: 0.0872, Legitimate Loss: 0.0295
Epoch: 20/30, Practice Loss: 0.0600, Legitimate Loss: 0.0713
Epoch: 21/30, Practice Loss: 0.0445, Legitimate Loss: 0.1138
Epoch: 22/30, Practice Loss: 0.0997, Legitimate Loss: 0.2957
Epoch: 23/30, Practice Loss: 0.0483, Legitimate Loss: 0.0287
Epoch: 24/30, Practice Loss: 0.0539, Legitimate Loss: 0.0495
Epoch: 25/30, Practice Loss: 0.0744, Legitimate Loss: 0.0827
Epoch: 26/30, Practice Loss: 0.1011, Legitimate Loss: 0.1187
Epoch: 27/30, Practice Loss: 0.0960, Legitimate Loss: 0.2000
Epoch: 28/30, Practice Loss: 0.0857, Legitimate Loss: 0.1095
Epoch: 29/30, Practice Loss: 0.0709, Legitimate Loss: 0.0857
Epoch: 30/30, Practice Loss: 0.0584, Legitimate Loss: 0.1196
Take a look at Accuracy: 96.00%
mannequin.load_state_dict(torch.load('best_leaves_model.pt'))
mannequin.eval()

label_map = {ok: v for ok, v in enumerate(image_datasets['train'].courses)}

fig, ax = plt.subplots(5, 5, figsize=(25, 25))
ax = ax.flatten()
plt.suptitle('Take a look at set predictions vs floor fact', fontsize=24)
plt.subplots_adjust(wspace=0.1, hspace=0.3)

for idx, (photographs, labels) in enumerate(test_loader):
photographs = photographs.to(gadget)
labels = labels.to(gadget)

outputs = mannequin(photographs)
_, predicted = torch.max(outputs.information, 1)

# Map the expected class index to the corresponding label
predicted_labels = [label_map[p.item()] for p in predicted]

# Convert the labels to an inventory of strings
actual_labels = [label_map[l.item()] for l in labels]

# Iterate over the pictures, precise labels, and predicted labels
for picture, actual_label, predicted_label in zip(photographs,
actual_labels, predicted_labels):
# Transfer the picture to the CPU and convert it to a NumPy array
picture = picture.cpu().numpy()
picture = np.transpose(picture, (1, 2, 0))

# Clip the picture information to the legitimate vary [0, 1]
picture = np.clip(picture, 0, 1)

# Show the picture
ax[idx].imshow(picture)
ax[idx].axis('off')

# Add the precise and predicted labels as title
if actual_label == predicted_label:
ax[idx].set_title(f"Precise: {actual_label}nPredicted: "
f"{predicted_label}nCORRECT", fontsize=16)
else:
ax[idx].set_title(f"Precise: {actual_label}nPredicted: "
f"{predicted_label}nWRONG", fontsize=16)
fig.present()

Bedeutung und Anwendungen des maschinellen Lernens bei der Blattklassifizierung

Die Anwendung maschinellen Lernens bei der Blattklassifizierung hat erhebliche Auswirkungen auf verschiedene Bereiche. Von botanischer Forschung und Artenidentifizierung bis hin zu ökologischen Studien und der Erkennung von Pflanzenkrankheiten bieten auf maschinellem Lernen basierende Blattklassifizierungstechniken unschätzbare Erkenntnisse und Automatisierungsmöglichkeiten. Durch die Nutzung umfangreicher Datensätze und leistungsstarker Algorithmen können wir unser Verständnis der Pflanzenbiodiversität verbessern und zu nachhaltigen Umweltpraktiken beitragen.

Schlussgedanken

Durch die Implementierung maschineller Lerntechniken in der Blattbildverarbeitung haben wir die transformativen Möglichkeiten dieses Ansatzes erlebt. Indem wir Modelle trainieren, um Blattbilder genau zu klassifizieren, können wir den Prozess der Blattidentifizierung automatisieren und rationalisieren und so Möglichkeiten für botanische Forschung und Naturschutzbemühungen eröffnen. Die Stärke des maschinellen Lernens liegt in seiner Fähigkeit, aus riesigen Mengen visueller Daten zu lernen, was es zu einem unschätzbar wertvollen Werkzeug im Bereich der Blattklassifizierung und darüber hinaus macht. Nutzen wir additionally das Potenzial des maschinellen Lernens in der Bildverarbeitung und begeben wir uns auf eine Reise, um die Wunder unserer botanischen Welt durch automatisierte Blattklassifizierung zu entdecken.

Verweise

Benjur Emmanuel L. Borja. 2023. Bildverarbeitung (MSDS2023). Asiatisches Institut für Administration.



Source link

HINTERLASSEN SIE EINE ANTWORT

Please enter your comment!
Please enter your name here