gexu13's picture
Upload app.py
738077c verified
import numpy as np
import cv2
import os
import gradio as gr
from skimage.feature import graycomatrix, graycoprops, local_binary_pattern
from skimage.io import imread
from skimage.color import rgb2gray
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.preprocessing import StandardScaler
# Paths to dataset
DATASET_PATH = ""
CATEGORIES = ["stone", "brick", "wood"]
def preprocess_image(image):
"""Ensure the image is 2D grayscale and integer type."""
if image is None:
print("❌ Warning: Received an empty image.")
return None
# Remove extra batch dimensions if they exist
if len(image.shape) == 4:
print(f"⚠️ Removing extra dimension: {image.shape}")
image = np.squeeze(image, axis=0)
# Convert RGBA to RGB if necessary
if len(image.shape) == 3 and image.shape[2] == 4:
print(f"⚠️ Converting RGBA to RGB: {image.shape}")
image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
# Convert to grayscale if needed
if len(image.shape) == 3 and image.shape[2] == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Convert to uint8
return image.astype(np.uint8)
def extract_glcm_features(image):
"""Extract GLCM texture features from a grayscale image."""
gray = preprocess_image(image)
if gray is None:
return None
glcm = graycomatrix(gray, distances=[1, 3, 5], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
levels=256, symmetric=True, normed=True)
contrast = graycoprops(glcm, 'contrast').flatten()
correlation = graycoprops(glcm, 'correlation').flatten()
energy = graycoprops(glcm, 'energy').flatten()
homogeneity = graycoprops(glcm, 'homogeneity').flatten()
return np.hstack([contrast, correlation, energy, homogeneity])
def extract_lbp_features(image):
"""Extract LBP texture features from a grayscale image."""
gray = preprocess_image(image)
if gray is None:
return None
radius = 1
points = 8 * radius
lbp = local_binary_pattern(gray, P=points, R=radius, method="uniform")
# Compute histogram
n_bins = int(lbp.max() + 1)
hist, _ = np.histogram(lbp.ravel(), bins=n_bins, range=(0, n_bins), density=True)
return hist
def augment_image(image):
"""Perform multiple augmentation techniques on an image."""
augmented = []
# Flip horizontally
augmented.append(cv2.flip(image, 1))
# Flip vertically
augmented.append(cv2.flip(image, 0))
# Rotate 90 degrees clockwise
augmented.append(cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE))
# Rotate 90 degrees counterclockwise
augmented.append(cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE))
# Add Gaussian noise
noise = np.random.normal(0, 10, image.shape).astype(np.uint8)
noisy_image = cv2.add(image, noise)
augmented.append(noisy_image)
return augmented
def load_dataset():
"""Load images and extract features while handling different image formats."""
features_glcm, labels_glcm = [], []
features_lbp, labels_lbp = [], []
original_images = [] # Store original images for augmentation
for label, category in enumerate(CATEGORIES):
category_path = os.path.join(DATASET_PATH, category)
def is_image_file(file):
return file.lower().endswith((".png", ".jpg", ".jpeg", ".bmp", ".tiff"))
image_files = [f for f in os.listdir(category_path) if is_image_file(f)]
for img_file in image_files:
img_path = os.path.join(category_path, img_file)
image = imread(img_path)
if image is None:
print(f"❌ Skipping: {img_path} (Failed to load)")
continue
image = preprocess_image(image)
original_images.append(image) # Store for augmentation
glcm_features = extract_glcm_features(image)
lbp_features = extract_lbp_features(image)
if glcm_features is not None and lbp_features is not None:
features_glcm.append(glcm_features)
labels_glcm.append(label)
features_lbp.append(lbp_features)
labels_lbp.append(label)
max_len_glcm = max(len(x) for x in features_glcm)
features_glcm = np.array([np.pad(x, (0, max_len_glcm - len(x)), mode='constant') for x in features_glcm])
max_len_lbp = max(len(x) for x in features_lbp)
features_lbp = np.array([np.pad(x, (0, max_len_lbp - len(x)), mode='constant') for x in features_lbp])
return np.array(features_glcm), np.array(labels_glcm), np.array(features_lbp), np.array(labels_lbp), original_images
# Load dataset
X_glcm, y_glcm, X_lbp, y_lbp, original_images = load_dataset()
scaler_lbp = StandardScaler()
X_lbp = scaler_lbp.fit_transform(X_lbp)
# Create train-test split while keeping track of original indices
X_train_glcm, X_test_glcm, y_train_glcm, y_test_glcm, train_indices, test_indices = train_test_split(
X_glcm, y_glcm, np.arange(len(y_glcm)), test_size=0.3, random_state=42
)
X_train_lbp, X_test_lbp, y_train_lbp, y_test_lbp = train_test_split(
X_lbp, y_lbp, test_size=0.3, random_state=42
)
# Apply augmentation only to training images
X_train_glcm_aug, y_train_glcm_aug = list(X_train_glcm), list(y_train_glcm)
X_train_lbp_aug, y_train_lbp_aug = list(X_train_lbp), list(y_train_lbp)
# 🔹 Corrected: Use indices from the original dataset correctly
for idx, original_idx in enumerate(train_indices):
image = original_images[original_idx] # Retrieve correct original image
augmented_images = augment_image(image)
for aug_img in augmented_images:
glcm_features = extract_glcm_features(aug_img)
lbp_features = extract_lbp_features(aug_img)
if glcm_features is not None and lbp_features is not None:
X_train_glcm_aug.append(glcm_features)
y_train_glcm_aug.append(y_train_glcm[idx]) # ✅ Use correct training label
X_train_lbp_aug.append(lbp_features)
y_train_lbp_aug.append(y_train_lbp[idx]) # ✅ Use correct training label
# Convert augmented dataset back to numpy arrays
X_train_glcm = np.array(X_train_glcm_aug)
y_train_glcm = np.array(y_train_glcm_aug)
X_train_lbp = np.array(X_train_lbp_aug)
y_train_lbp = np.array(y_train_lbp_aug)
# Train classifiers
svm_glcm = SVC(kernel='linear')
svm_glcm.fit(X_train_glcm, y_train_glcm)
knn_glcm = KNeighborsClassifier(n_neighbors=3)
knn_glcm.fit(X_train_glcm, y_train_glcm)
svm_lbp = SVC(kernel='linear')
svm_lbp.fit(X_train_lbp, y_train_lbp)
knn_lbp = KNeighborsClassifier(n_neighbors=5, metric='manhattan')
knn_lbp.fit(X_train_lbp, y_train_lbp)
# Evaluate models
print("SVM GLCM Performance:\n", classification_report(y_test_glcm, svm_glcm.predict(X_test_glcm)))
print("KNN GLCM Performance:\n", classification_report(y_test_glcm, knn_glcm.predict(X_test_glcm)))
print("SVM LBP Performance:\n", classification_report(y_test_lbp, svm_lbp.predict(X_test_lbp)))
print("KNN LBP Performance:\n", classification_report(y_test_lbp, knn_lbp.predict(X_test_lbp)))
def classify_texture(image, algorithm):
image = preprocess_image(image)
if algorithm == "SVM (GLCM)":
features = extract_glcm_features(image).reshape(1, -1)
prediction = svm_glcm.predict(features)
elif algorithm == "KNN (GLCM)":
features = extract_glcm_features(image).reshape(1, -1)
prediction = knn_glcm.predict(features)
elif algorithm == "SVM (LBP)":
features = extract_lbp_features(image).reshape(1, -1)
features = scaler_lbp.transform(features)
prediction = svm_lbp.predict(features)
elif algorithm == "KNN (LBP)":
features = extract_lbp_features(image).reshape(1, -1)
features = scaler_lbp.transform(features)
prediction = knn_lbp.predict(features)
return CATEGORIES[prediction[0]]
interface = gr.Interface(
fn=classify_texture,
inputs=[
gr.Image(type="numpy"),
gr.Radio(["SVM (GLCM)", "KNN (GLCM)", "SVM (LBP)", "KNN (LBP)"], label="Select Algorithm")
],
outputs=gr.Label(label="Predicted Texture"),
title="Texture Classification",
description="Upload an image of a texture and choose an algorithm to classify it as stone, brick, or wood."
)
interface.launch()