1. What We Are Making
We are making a Python program that can classify a picture as mango, dog, or cat.
Input image → CNN model → Predicted class
Possible outputs:
mango
dog
cat
2. Zero Level: What Is a Picture?
A picture is a grid of pixels. Each pixel has color values. A normal color image has three color channels:
So an image is stored as:
height × width × 3
In our lesson every image becomes:
64 × 64 × 3
| Part | Meaning |
|---|---|
64 |
Image height |
64 |
Image width |
3 |
Red, Green, and Blue color channels |
3. Required Folder Structure
Keep the training images inside class folders. The folder names are the class names.
classification/
picture/
cnnclassifier.py
test.png
pictures/
mango/
mango1.png
mango2.png
dog/
dog1.png
dog2.png
cat/
cat1.png
cat2.png
| Folder | Class | Label Number |
|---|---|---|
mango |
Mango | 0 |
dog |
Dog | 1 |
cat |
Cat | 2 |
4. Install Required Libraries
Run this command in the terminal:
pip install pillow numpy matplotlib tensorflow
| Library | Use |
|---|---|
pillow |
To open and resize images |
numpy |
To handle image arrays and numbers |
matplotlib |
To show images and graphs |
tensorflow |
To create and train the CNN model |
5. Import Libraries
from PIL import Image
import numpy as np
import os
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.utils import to_categorical
6. Basic Settings
base_folder = "classification/picture/pictures"
classes = ["mango", "dog", "cat"]
image_width = 64
image_height = 64
number_of_classes = len(classes)
The model will learn three classes. Every image is resized to
64 × 64 so all inputs have the same size.
7. Convert Image into CNN Input
def image_to_array(image_path):
img = Image.open(image_path).convert("RGB")
img = img.resize((image_width, image_height))
arr = np.array(img)
arr = arr / 255.0
return arr
What this function does
Why divide by 255?
Pixel values normally go from 0 to 255.
CNN training works better when values are small, so we convert them to
the range 0 to 1.
0 / 255 = 0.0
128 / 255 = 0.501
255 / 255 = 1.0
8. X, y, and One-Hot Labels
In Machine Learning, X usually stores input data and y
stores correct answers.
X = []
y = []
| Name | Meaning |
|---|---|
X |
Stores image arrays |
y |
Stores correct labels |
Normal labels
mango → 0
dog → 1
cat → 2
One-hot labels
mango → [1, 0, 0]
dog → [0, 1, 0]
cat → [0, 0, 1]
In code:
y_categorical = to_categorical(y, number_of_classes)
9. Create the CNN Model
model = Sequential()
model.add(
Conv2D(
filters=16,
kernel_size=(3, 3),
activation="relu",
input_shape=(image_height, image_width, 3)
)
)
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(
Conv2D(
filters=32,
kernel_size=(3, 3),
activation="relu"
)
)
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64, activation="relu"))
model.add(Dense(number_of_classes, activation="softmax"))
Layer-by-layer meaning
| Layer | Meaning |
|---|---|
Conv2D |
Finds patterns like edges, textures, shapes, and small visual features. |
MaxPooling2D |
Reduces size and keeps important information. |
Flatten |
Converts 2D feature maps into a 1D list. |
Dense |
Combines learned features and makes decisions. |
softmax |
Gives probability for each class. |
10. Compile and Train the CNN
Compile
model.compile(
optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"]
)
| Term | Meaning |
|---|---|
adam |
Optimizer that improves the model during training. |
categorical_crossentropy |
Loss function for multi-class classification. |
accuracy |
Shows how many predictions are correct. |
Train
history = model.fit(
X,
y_categorical,
epochs=50,
batch_size=2,
verbose=1
)
11. Predict a New Image
test_image_path = "classification/picture/test.png"
test_arr = image_to_array(test_image_path)
test_arr = np.array(test_arr).reshape(1, image_height, image_width, 3)
prediction = model.predict(test_arr)
predicted_number = np.argmax(prediction[0])
predicted_class = classes[predicted_number]
Why reshape?
One image has shape:
(64, 64, 3)
But CNN expects a batch:
(1, 64, 64, 3)
Meaning:
1 image
64 height
64 width
3 color channels
Prediction probabilities
[[0.12, 0.18, 0.70]]
| Class | Probability |
|---|---|
| mango | 12% |
| dog | 18% |
| cat | 70% |
np.argmax() finds the position of the highest probability.
In this example the highest probability is for cat.
12. Complete CNN Code
from PIL import Image
import numpy as np
import os
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.utils import to_categorical
# --------------------------------------------------
# 1. Basic settings
# --------------------------------------------------
base_folder = "classification/picture/pictures"
# Mango 0, Dog 1, Cat 2
classes = ["mango", "dog", "cat"]
image_width = 64
image_height = 64
number_of_classes = len(classes)
# --------------------------------------------------
# 2. Function to convert image into CNN input
# --------------------------------------------------
def image_to_array(image_path):
"""
This function:
1. Opens the image
2. Converts it to RGB
3. Resizes it to 64 x 64
4. Converts it to NumPy array
5. Divides pixel values by 255
"""
img = Image.open(image_path).convert("RGB")
img = img.resize((image_width, image_height))
arr = np.array(img)
# Normalize pixel values from 0-255 to 0-1
arr = arr / 255.0
return arr
# --------------------------------------------------
# 3. Read training images manually
# --------------------------------------------------
X = []
y = []
# Mango images
folder_path = os.path.join(base_folder, "mango")
image_path = os.path.join(folder_path, "mango1.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(0)
image_path = os.path.join(folder_path, "mango2.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(0)
# Dog images
folder_path = os.path.join(base_folder, "dog")
image_path = os.path.join(folder_path, "dog1.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(1)
image_path = os.path.join(folder_path, "dog2.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(1)
# Cat images
folder_path = os.path.join(base_folder, "cat")
image_path = os.path.join(folder_path, "cat1.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(2)
image_path = os.path.join(folder_path, "cat2.png")
print(image_path)
arr = image_to_array(image_path)
X.append(arr)
y.append(2)
# --------------------------------------------------
# 4. Convert lists to NumPy arrays
# --------------------------------------------------
X = np.array(X)
y = np.array(y)
print("X shape:", X.shape)
print("y:", y)
# Convert labels into one-hot format
y_categorical = to_categorical(y, number_of_classes)
print("One-hot labels:")
print(y_categorical)
# --------------------------------------------------
# 5. Create CNN model
# --------------------------------------------------
model = Sequential()
# First convolution layer
model.add(
Conv2D(
filters=16,
kernel_size=(3, 3),
activation="relu",
input_shape=(image_height, image_width, 3)
)
)
model.add(MaxPooling2D(pool_size=(2, 2)))
# Second convolution layer
model.add(
Conv2D(
filters=32,
kernel_size=(3, 3),
activation="relu"
)
)
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64, activation="relu"))
model.add(Dense(number_of_classes, activation="softmax"))
# --------------------------------------------------
# 6. Compile CNN model
# --------------------------------------------------
model.compile(
optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"]
)
print()
print("CNN Model Summary:")
model.summary()
# --------------------------------------------------
# 7. Train CNN model
# --------------------------------------------------
history = model.fit(
X,
y_categorical,
epochs=50,
batch_size=2,
verbose=1
)
print()
print("CNN training completed successfully.")
# --------------------------------------------------
# 8. Predict a new image
# --------------------------------------------------
test_image_path = "classification/picture/test.png"
test_arr = image_to_array(test_image_path)
# Convert one image into a batch of one image
test_arr = np.array(test_arr).reshape(1, image_height, image_width, 3)
prediction = model.predict(test_arr)
print()
print("Prediction probabilities:")
print(prediction)
predicted_number = np.argmax(prediction[0])
predicted_class = classes[predicted_number]
print("Predicted class number:", predicted_number)
print("Predicted class:", predicted_class)
# --------------------------------------------------
# 9. Show test image with prediction
# --------------------------------------------------
img = Image.open(test_image_path)
plt.imshow(img)
plt.axis("off")
plt.title("Predicted class: " + predicted_class)
plt.show()
# --------------------------------------------------
# 10. Show training accuracy graph
# --------------------------------------------------
plt.figure(figsize=(8, 5))
plt.plot(history.history["accuracy"], marker="o")
plt.title("CNN Training Accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.grid(True)
plt.show()
# --------------------------------------------------
# 11. Show training loss graph
# --------------------------------------------------
plt.figure(figsize=(8, 5))
plt.plot(history.history["loss"], marker="o")
plt.title("CNN Training Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.grid(True)
plt.show()
13. Improved Version: Read All Images Automatically
The previous code manually reads mango1.png, mango2.png,
dog1.png, and so on. This improved version reads all images from folders.
X = []
y = []
for label_number, class_name in enumerate(classes):
folder_path = os.path.join(base_folder, class_name)
if not os.path.exists(folder_path):
print("Folder not found:", folder_path)
continue
for file_name in os.listdir(folder_path):
file_name_lower = file_name.lower()
if (
file_name_lower.endswith(".png")
or file_name_lower.endswith(".jpg")
or file_name_lower.endswith(".jpeg")
):
image_path = os.path.join(folder_path, file_name)
try:
arr = image_to_array(image_path)
X.append(arr)
y.append(label_number)
print("Loaded:", image_path, "Label:", class_name)
except Exception as e:
print("Could not load:", image_path)
print("Error:", e)
14. Very Important Warning
This lesson uses only 2 mango images, 2 dog images, and 2 cat images. That is enough for understanding the program, but it is not enough for a real CNN.
| Level | Images Needed |
|---|---|
| Demo only | 2 images per class |
| Beginner practice | 20 images per class |
| Better learning | 50 images per class |
| Good project | 100+ images per class |
15. Final Mental Model
Image
↓
Resize to 64 × 64
↓
Convert to NumPy array
↓
Normalize pixels from 0-255 to 0-1
↓
CNN layer learns edges and patterns
↓
Pooling reduces size
↓
More CNN layers learn better patterns
↓
Flatten converts features to list
↓
Dense layer decides
↓
Softmax gives probabilities
↓
Highest probability becomes final class
16. Practice Questions
Question 1
What is the shape of one image after resizing?
64 × 64 × 3
Question 2
Why do we divide pixel values by 255?
To normalize pixel values from 0-255 to 0-1.
Question 3
What does Conv2D do?
It scans the image and learns visual patterns.
Question 4
What does MaxPooling2D do?
It reduces size while keeping important features.
Question 5
What does softmax do?
It gives probability for each class.
17. Next Step: From Demo to Real Project
After this lesson, improve the project by adding:
model.save().