LAB-2 / app.py
nnibras's picture
Update app.py
e97a4c5 verified
import glob
import cv2
import numpy as np
import gradio as gr
import matplotlib.pyplot as plt
from sklearn.model_selection import KFold, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import (
accuracy_score,
classification_report,
confusion_matrix,
precision_score,
recall_score,
f1_score,
)
from skimage.feature import graycomatrix, graycoprops, local_binary_pattern
# Define directories for grass and wood images
grass_dir = "images/Grass/Train_Grass"
wood_dir = "images/Wood/Train_wood"
# Constants for Local Binary Pattern (LBP) and Gray Level Co-occurrence Matrix (GLCM)
RADIUS = 1
N_POINTS = 12 * RADIUS
TARGET_SIZE = (30, 30)
distances = [1]
angles = [0]
def load_and_convert_images(directory):
"""Load images from a specified directory using glob and convert them to grayscale.
Args:
directory (str): The path to the image directory.
Returns:
list: A list of resized grayscale images.
"""
dataset = []
for img_path in glob.glob(f"{directory}/*.*"):
if img_path.endswith((".jpg", ".png", ".jpeg")):
img = cv2.imread(img_path) # Read the image
if img is not None:
# Convert to grayscale and resize the image
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
resized_image = cv2.resize(
gray_image, TARGET_SIZE, interpolation=cv2.INTER_AREA
)
dataset.append(resized_image)
return dataset
# Load datasets using glob
grass_dataset = load_and_convert_images(grass_dir)
wood_dataset = load_and_convert_images(wood_dir)
def calc_glcm_features(images):
"""Calculate GLCM features for a list of images.
Args:
images (list): A list of grayscale images.
Returns:
list: A list of GLCM features for each image.
"""
features = []
for img in images:
glcm = graycomatrix(img, distances, angles, symmetric=True, normed=True)
# Calculate GLCM properties
contrast = graycoprops(glcm, "contrast")[0, 0]
dissimilarity = graycoprops(glcm, "dissimilarity")[0, 0]
homogeneity = graycoprops(glcm, "homogeneity")[0, 0]
energy = graycoprops(glcm, "energy")[0, 0]
correlation = graycoprops(glcm, "correlation")[0, 0]
features.append([contrast, dissimilarity, homogeneity, energy, correlation])
return features
# Calculate GLCM features for grass and wood datasets
grass_glcm_features = calc_glcm_features(grass_dataset)
wood_glcm_features = calc_glcm_features(wood_dataset)
# Print the sizes of the GLCM feature arrays
print(f"Size of GLCM features for grass dataset: {len(grass_glcm_features)}")
print(f"Size of GLCM features for wood dataset: {len(wood_glcm_features)}")
def extract_lbp_features(images):
"""Extract LBP features from a list of images.
Args:
images (list): A list of grayscale images.
Returns:
list: A list of LBP histograms for each image.
"""
lbp_features = []
for image in images:
lbp = local_binary_pattern(image, N_POINTS, RADIUS, method="uniform")
n_bins = int(lbp.max() + 1)
lbp_hist, _ = np.histogram(lbp, bins=n_bins, range=(0, n_bins), density=True)
lbp_features.append(lbp_hist)
return lbp_features
# Extract LBP features for grass and wood datasets
grass_lbp_features = extract_lbp_features(grass_dataset)
wood_lbp_features = extract_lbp_features(wood_dataset)
# Create labels (0 for grass, 1 for wood)
grass_labels = [0] * len(grass_dataset) # Label all grass images as 0
wood_labels = [1] * len(wood_dataset) # Label all wood images as 1
# Combine features and labels for GLCM classifier
glcm_features = np.array(grass_glcm_features + wood_glcm_features)
glcm_labels = grass_labels + wood_labels
# Prepare labels and features for LBP classifier
lbp_features = np.array(grass_lbp_features + wood_lbp_features)
lbp_labels = grass_labels + wood_labels
# Number of images
num_grass = len(grass_dataset)
num_wood = len(wood_dataset)
# Define labels for classification
y = np.array([0] * num_grass + [1] * num_wood)
# Define KFold cross-validation
k = 5
kf = KFold(n_splits=k, shuffle=True, random_state=42)
# Store results for GLCM and LBP classifiers
glcm_metrics = {"accuracy": [], "precision": [], "recall": [], "f1_score": []}
lbp_metrics = {"accuracy": [], "precision": [], "recall": [], "f1_score": []}
y_true_glcm, y_true_lbp = [], []
y_pred_glcm, y_pred_lbp = [], []
# Parameter tuning using GridSearchCV for KNN classifier
param_grid = {"n_neighbors": [3, 5, 7], "p": [1, 2]}
# GLCM Classifier Training and Evaluation
glcm_knn = KNeighborsClassifier()
glcm_grid_search = GridSearchCV(glcm_knn, param_grid, cv=kf)
glcm_grid_search.fit(glcm_features, y)
# Perform cross-validation and evaluate GLCM classifier
for train_index, test_index in kf.split(glcm_features):
x_train, x_test = glcm_features[train_index], glcm_features[test_index]
y_train, y_test = y[train_index], y[test_index]
glcm_classifier = KNeighborsClassifier(
n_neighbors=glcm_grid_search.best_params_["n_neighbors"]
)
glcm_classifier.fit(x_train, y_train)
y_pred = glcm_classifier.predict(x_test)
# Collect true and predicted labels
y_true_glcm.extend(y_test)
y_pred_glcm.extend(y_pred)
# Calculate and store metrics
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average="macro")
recall = recall_score(y_test, y_pred, average="macro")
f1 = f1_score(y_test, y_pred, average="macro")
glcm_metrics["accuracy"].append(accuracy)
glcm_metrics["precision"].append(precision)
glcm_metrics["recall"].append(recall)
glcm_metrics["f1_score"].append(f1)
# Print metrics for this fold
print(
f"GLCM Fold Metrics: Accuracy={accuracy:.2f}, Precision={precision:.2f}, Recall={recall:.2f}, F1-Score={f1:.2f}"
)
# Print average metrics for GLCM classifier
print("\nAverage GLCM Classifier Metrics:")
for metric in glcm_metrics:
avg_metric = np.mean(glcm_metrics[metric])
print(f"{metric.capitalize()}: {avg_metric:.2f}")
# Confusion Matrix for GLCM
glcm_conf_matrix = confusion_matrix(y_true_glcm, y_pred_glcm)
print("\nConfusion Matrix for GLCM Classifier:")
print(glcm_conf_matrix)
# Classification Report for GLCM
print("\nClassification Report for GLCM Classifier:")
print(classification_report(y_true_glcm, y_pred_glcm))
# LBP Classifier Training and Evaluation
lbp_knn = KNeighborsClassifier()
lbp_grid_search = GridSearchCV(lbp_knn, param_grid, cv=kf)
lbp_grid_search.fit(lbp_features, y)
# Perform cross-validation and evaluate LBP classifier
for train_index, test_index in kf.split(lbp_features):
x_train, x_test = lbp_features[train_index], lbp_features[test_index]
y_train, y_test = y[train_index], y[test_index]
lbp_classifier = KNeighborsClassifier(
n_neighbors=lbp_grid_search.best_params_["n_neighbors"]
)
lbp_classifier.fit(x_train, y_train)
y_pred = lbp_classifier.predict(x_test)
# Collect true and predicted labels
y_true_lbp.extend(y_test)
y_pred_lbp.extend(y_pred)
# Calculate and store metrics
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average="macro")
recall = recall_score(y_test, y_pred, average="macro")
f1 = f1_score(y_test, y_pred, average="macro")
lbp_metrics["accuracy"].append(accuracy)
lbp_metrics["precision"].append(precision)
lbp_metrics["recall"].append(recall)
lbp_metrics["f1_score"].append(f1)
# Print metrics for this fold
print(
f"LBP Fold Metrics: Accuracy={accuracy:.2f}, Precision={precision:.2f}, Recall={recall:.2f}, F1-Score={f1:.2f}"
)
# Print average metrics for LBP classifier
print("\nAverage LBP Classifier Metrics:")
for metric in lbp_metrics:
avg_metric = np.mean(lbp_metrics[metric])
print(f"{metric.capitalize()}: {avg_metric:.2f}")
# Confusion Matrix for LBP
lbp_conf_matrix = confusion_matrix(y_true_lbp, y_pred_lbp)
print("\nConfusion Matrix for LBP Classifier:")
print(lbp_conf_matrix)
# Classification Report for LBP
print("\nClassification Report for LBP Classifier:")
print(classification_report(y_true_lbp, y_pred_lbp))
def classify_texture(image, method):
"""Classify the texture of the uploaded image as grass or wood using the selected method.
Args:
image (numpy.ndarray): The uploaded image to classify.
method (str): The feature extraction method ('GLCM' or 'LBP').
Returns:
Tuple[str, numpy.ndarray]: The classification result ('Grass' or 'Wood') and the highlighted image.
"""
# Pre-process the image
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
resized_image = cv2.resize(gray_image, TARGET_SIZE, interpolation=cv2.INTER_AREA)
# Extract features based on the selected method
if method == "GLCM":
feature = calc_glcm_features([resized_image])
prediction = glcm_classifier.predict(feature)
elif method == "LBP":
feature = extract_lbp_features([resized_image])
prediction = lbp_classifier.predict(feature)
else:
raise ValueError("The method is not recognized")
# Classify the prediction
result = "Grass" if prediction == 0 else "Wood"
# Highlight the image based on the classification
if result == "Grass":
highlighted_image = cv2.cvtColor(
image, cv2.COLOR_BGR2RGB
) # Convert to RGB for displaying
highlighted_image[:] = [0, 255, 0] # Highlight in green
else:
highlighted_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
highlighted_image[:] = [165, 42, 42] # Highlight in brown
return result, highlighted_image
# Gradio interface setup with a dropdown for method selection
iface = gr.Interface(
fn=classify_texture,
inputs=[
gr.Image(type="numpy", label="Upload Image"),
gr.Dropdown(choices=["Choose Here", "GLCM", "LBP"], label="Select Feature Extraction Method"),
],
outputs=["text", gr.Image(type="numpy", label="Highlighted Image")],
title="Texture Classification",
description="Upload an image of grass or wood to classify the texture. Select GLCM or LBP as the method.",
)
# Launch Gradio interface
iface.launch()