#B6
# 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

# 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

# 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: {y_pred[i]}")
    axes[i].axis('off')

plt.show()
