File size: 8,452 Bytes
738077c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | 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()
|