File size: 10,376 Bytes
28bd053
7b46d95
3884aa8
7b46d95
3884aa8
7b46d95
3884aa8
7b46d95
 
 
 
 
 
 
 
 
28bd053
3884aa8
 
e97a4c5
3884aa8
7b46d95
3884aa8
 
28bd053
3884aa8
 
 
a3fa85f
3884aa8
7b46d95
 
 
 
 
 
 
 
3884aa8
7b46d95
 
 
 
 
 
a3fa85f
 
 
7b46d95
3884aa8
 
1dc1ab5
7b46d95
 
 
16787a7
1dc1ab5
3884aa8
7b46d95
3884aa8
7b46d95
 
3884aa8
7b46d95
 
 
 
a3fa85f
 
 
 
 
 
 
 
 
 
28bd053
3884aa8
 
a3fa85f
 
 
 
 
b02da62
 
 
 
a3fa85f
28bd053
a3fa85f
3884aa8
7b46d95
 
3884aa8
7b46d95
a3fa85f
7b46d95
a3fa85f
7b46d95
 
a3fa85f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3884aa8
a3fa85f
 
 
 
 
7b46d95
a3fa85f
 
7b46d95
a3fa85f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b46d95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a3fa85f
7b46d95
 
a3fa85f
7b46d95
 
52a6248
7b46d95
 
28bd053
7b46d95
 
a3fa85f
 
 
7b46d95
3884aa8
7b46d95
 
3884aa8
7b46d95
3884aa8
a3fa85f
7b46d95
3884aa8
7b46d95
3884aa8
7b46d95
65903c8
28bd053
7b46d95
28bd053
7b46d95
3884aa8
 
7b46d95
3884aa8
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
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()