#6 Use non-parametric K-Nearest Neighbor (KNN) techniques to classify grayscale images of shapes (e.g., circles, squares, and triangles). #Evaluate and compare the classification accuracy of both methods.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
import cv2  # Required for triangle generation

# Function to generate square
def generate_square(image_size=64):
    img = np.zeros((image_size, image_size), dtype=np.uint8)
    img[16:48, 16:48] = 255  # Create a square in the center
    return img

# Function to generate circle
def generate_circle(image_size=64):
    img = np.zeros((image_size, image_size), dtype=np.uint8)
    y, x = np.ogrid[:image_size, :image_size]
    mask = (x - image_size // 2) ** 2 + (y - image_size // 2) ** 2 <= (image_size // 4) ** 2
    img[mask] = 255
    return img

# Function to generate triangle
def generate_triangle(image_size=64):
    img = np.zeros((image_size, image_size), dtype=np.uint8)
    pts = np.array([[32, 16], [16, 48], [48, 48]], np.int32)
    cv2.fillPoly(img, [pts], 255)
    return img

# Function to generate the appropriate shape based on the label
def generate_shape(shape):
    if shape == 'square':
        return generate_square()
    elif shape == 'circle':
        return generate_circle()
    elif shape == 'triangle':
        return generate_triangle()

# Create synthetic dataset
shapes = ['square', 'circle', 'triangle']
X = []  # Features (flattened images)
y = []  # Labels (0: Square, 1: Circle, 2: Triangle)
n_samples = 1000

for shape_idx, shape in enumerate(shapes):
    for _ in range(n_samples // 3):
        img = generate_shape(shape)
        X.append(img.flatten())  # Flatten image to 1D
        y.append(shape_idx)  # Assign corresponding label

X = np.array(X)
y = np.array(y)

# Split dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Train KNN classifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)

# Make predictions and evaluate
y_pred = knn.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

print(f"Accuracy: {accuracy * 100:.2f}%")
print("\nClassification Report:\n", classification_report(y_test, y_pred))

# Visualize test images with predicted labels
fig, axes = plt.subplots(1, 5, figsize=(12, 6))
for i in range(5):
    axes[i].imshow(X_test[i].reshape(64, 64), cmap='gray')
    axes[i].set_title(f"Pred: {shapes[y_pred[i]]}")
    axes[i].axis('off')

plt.show()
