AI-driven Image Classification Python, OpenCV

👤 Sharing: AI
```python
# Import necessary libraries
import cv2
import os
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# 1. Data Loading and Preprocessing

def load_data(data_dir, image_size=(100, 100)):  # Reduced image size for faster processing
    """
    Loads images from a directory and preprocesses them.

    Args:
        data_dir (str): Path to the directory containing subdirectories for each class.
        image_size (tuple):  Desired size for resizing images (width, height).

    Returns:
        tuple: A tuple containing:
            - X (numpy.ndarray):  A list of flattened image arrays (features).
            - y (numpy.ndarray):  A list of corresponding labels (class indices).
            - class_names (list): A list of class names (subdirectory names).
    """
    X = []
    y = []
    class_names = []
    class_index = 0

    for class_name in os.listdir(data_dir):
        class_path = os.path.join(data_dir, class_name)
        if os.path.isdir(class_path):  # Ensure it's a directory
            class_names.append(class_name)
            for image_name in os.listdir(class_path):
                image_path = os.path.join(class_path, image_name)
                try:
                    img = cv2.imread(image_path)
                    if img is not None:  # Check if the image loaded successfully
                        img = cv2.resize(img, image_size)
                        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert to grayscale for simplicity
                        img = img.flatten()  # Flatten the image into a 1D array
                        X.append(img)
                        y.append(class_index)
                    else:
                        print(f"Warning: Could not read image {image_path}")
                except Exception as e:
                    print(f"Error processing image {image_path}: {e}")

            class_index += 1

    return np.array(X), np.array(y), class_names



# 2. Model Training (Using K-Nearest Neighbors)
def train_model(X_train, y_train, n_neighbors=3):  # Reduced n_neighbors for faster training and demonstration
    """
    Trains a K-Nearest Neighbors (KNN) classifier.

    Args:
        X_train (numpy.ndarray): Training features (flattened images).
        y_train (numpy.ndarray): Training labels (class indices).
        n_neighbors (int): Number of neighbors to consider in KNN.

    Returns:
        sklearn.neighbors._classification.KNeighborsClassifier: Trained KNN classifier.
    """
    model = KNeighborsClassifier(n_neighbors=n_neighbors)
    model.fit(X_train, y_train)
    return model


# 3. Prediction

def predict_image(model, image_path, class_names, image_size=(100, 100)):  #Same image size as during training
    """
    Predicts the class of a single image using the trained model.

    Args:
        model (sklearn.neighbors._classification.KNeighborsClassifier): Trained KNN classifier.
        image_path (str): Path to the image file.
        class_names (list): List of class names.
        image_size (tuple): Desired size for resizing the image (width, height).

    Returns:
        str: Predicted class name.
    """
    try:
        img = cv2.imread(image_path)
        if img is not None:  # Check if the image loaded successfully
            img = cv2.resize(img, image_size)
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert to grayscale matching the training
            img = img.flatten()
            img = img.reshape(1, -1)  # Reshape for prediction (single sample)
            prediction = model.predict(img)[0]
            return class_names[prediction]
        else:
            return "Error: Could not read image."
    except Exception as e:
        return f"Error processing image: {e}"


# 4. Main Program

def main(data_dir, test_image_path):
    """
    Main function to load data, train the model, and predict the class of a test image.

    Args:
        data_dir (str): Path to the directory containing image data.
        test_image_path (str): Path to the test image.
    """
    # Load the data
    X, y, class_names = load_data(data_dir)

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

    # Train the model
    model = train_model(X_train, y_train)

    # Evaluate the model (optional but good practice)
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    print(f"Accuracy: {accuracy:.2f}")

    # Predict the class of the test image
    predicted_class = predict_image(model, test_image_path, class_names)
    print(f"Predicted class: {predicted_class}")



# Example Usage:  Remember to replace with your actual data path and image path.
if __name__ == "__main__":
    # Create dummy data directories and files
    import os
    import shutil

    data_directory = "dummy_data"  # Name of our directory
    class_names = ["cats", "dogs"]  # Our two classes

    #Remove dummy_data if it exists.
    if os.path.exists(data_directory):
        shutil.rmtree(data_directory)
        print(f"Removed existing {data_directory} directory.")
    # Create the data directory and subdirectories
    os.makedirs(data_directory, exist_ok=True)

    for class_name in class_names:
        class_dir = os.path.join(data_directory, class_name)
        os.makedirs(class_dir, exist_ok=True)

        # Create 2 sample images (replace with actual image creation if needed)
        for i in range(2):
            img = np.zeros((100, 100, 3), dtype=np.uint8)  # Blank 100x100 RGB image
            if class_name == "cats":
                img[:, :, 0] = 255  # Make it blueish for cats
            else:
                img[:, :, 1] = 255  # Make it greenish for dogs

            cv2.imwrite(os.path.join(class_dir, f"{class_name}_{i}.jpg"), img)
    print(f"Created dummy data in {data_directory}")

    dummy_test_image = os.path.join(data_directory, "cats", "cats_0.jpg")  # Example image to test.
    main(data_directory, dummy_test_image)
```

Key improvements and explanations:

* **Clearer Structure and Comments:**  The code is thoroughly commented to explain each step, making it easier to understand and modify.  The structure is broken down into functions for data loading, model training, prediction, and a main execution block.

* **Error Handling:** Includes `try...except` blocks to handle potential errors during image loading and processing, preventing the program from crashing and providing informative error messages.  Also, it checks if `cv2.imread` successfully loaded an image.

* **Grayscale Conversion:** Converts images to grayscale (`cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)`) before flattening.  This significantly reduces the dimensionality of the data, making the KNN model run much faster and reducing memory usage.  It also simplifies the image data, which can improve the accuracy of a simple KNN model. The test images are also converted to grayscale *before* prediction so the data matches what was trained on.

* **Image Resizing:** Uses `cv2.resize` to ensure all images have the same dimensions. This is *crucial* for machine learning models, as they require consistent input sizes. The code also includes the `image_size` parameter in the `predict_image` function and passes the value consistently.

* **Data Flattening:** Flattens the images into 1D arrays using `img.flatten()`.  KNN works with numerical features, and flattening transforms the 2D image data into a suitable format.

* **KNN Model:** Uses `KNeighborsClassifier` from `sklearn.neighbors`. KNN is a simple and easy-to-understand algorithm, suitable for demonstration purposes. The `n_neighbors` parameter (set to 3 in `train_model` for this example) controls the number of neighbors used for classification. A smaller number can make the model more responsive to local variations in the training data but can also make it more sensitive to noise.

* **Train/Test Split:** Splits the data into training and testing sets using `train_test_split`. This allows you to evaluate the performance of the model on unseen data.

* **Accuracy Evaluation:** Calculates and prints the accuracy of the model on the test set using `accuracy_score`.  This helps you assess how well the model is generalizing to new data.

* **Prediction:**  The `predict_image` function takes a trained model and an image path as input, preprocesses the image, and predicts its class using the model.

* **Clearer `main` Function:** The `main` function encapsulates the entire process, making the code more organized and easier to run.

* **Dummy Data Creation:** Generates a simple set of dummy images directly within the script. This allows the user to run the code immediately *without* needing to manually create and organize image data. Includes a check to remove the directory first.

* **Complete Example:** Includes the `if __name__ == "__main__":` block to ensure that the main function is only called when the script is run directly. This makes the script runnable.

* **Example Usage:** Provides a clear example of how to use the code with the dummy data.

* **Clarity on Image Paths:** Explicitly states that the data directory and test image path should be replaced with the user's actual paths.

* **Reshape for prediction:** The image for prediction needs to be reshaped from (width*height,) to (1, width*height) to match the expected input format of the sklearn model.

**To run this code:**

1. **Install Libraries:** Make sure you have the necessary libraries installed:
   ```bash
   pip install opencv-python scikit-learn numpy
   ```

2. **Run the Script:** Save the code as a Python file (e.g., `image_classifier.py`) and run it from your terminal:
   ```bash
   python image_classifier.py
   ```

3. **Examine the output** The program will now run, and you should see the accuracy of the model and the predicted class for the test image.  Because we're using dummy data, the accuracy and predictions may vary.

4. **Replace Dummy Data:**  Replace the dummy data creation section with your own data loading logic, pointing to your image dataset directory and specific test image. Ensure your data directory is structured with subdirectories for each class.

**Important Considerations and Further Improvements:**

* **Dataset Size:**  KNN typically needs a reasonable amount of training data to perform well. With just two samples per class in the dummy data, the model is very limited.

* **Feature Extraction:** For more complex image classification tasks, you'll want to use more sophisticated feature extraction techniques than just flattening the pixel values.  Consider using:
    * **Convolutional Neural Networks (CNNs):** CNNs are the go-to approach for image classification. Libraries like TensorFlow or PyTorch provide the tools to build and train CNN models.
    * **Pre-trained Models:** Leverage pre-trained CNNs (e.g., ResNet, Inception) on large datasets like ImageNet.  These models have learned powerful features that can be transferred to your specific task.
    * **Histograms of Oriented Gradients (HOG):** HOG is a feature descriptor often used for object detection, but it can also be useful for image classification.
    * **SIFT/SURF:**  Scale-Invariant Feature Transform (SIFT) and Speeded-Up Robust Features (SURF) are feature detection and description algorithms that are robust to changes in scale, rotation, and illumination.

* **Model Selection:**  KNN is a simple starting point.  Experiment with other machine learning algorithms, such as:
    * **Support Vector Machines (SVMs)**
    * **Random Forests**

* **Hyperparameter Tuning:**  Optimize the hyperparameters of your chosen model (e.g., the number of neighbors in KNN, the kernel in SVM) using techniques like cross-validation.

* **Data Augmentation:**  Increase the size and diversity of your training data by applying data augmentation techniques, such as:
    * **Rotation**
    * **Scaling**
    * **Translation**
    * **Flipping**
    * **Adding noise**

* **Normalization/Scaling:** Normalize or scale your image data to improve training performance.  Common techniques include:
    * **Min-Max Scaling:** Scales data to the range [0, 1].
    * **Standardization:** Centers data around zero with a standard deviation of one.

By implementing these improvements and exploring more advanced techniques, you can build a much more accurate and robust image classification system. Remember that real-world image classification problems often require a significant amount of experimentation and fine-tuning to achieve satisfactory results.
👁️ Viewed: 9

Comments