Lecture 02 — Image Formation and Digital Images

Lecture 2

Dr. Muhammad Kazim

Department of Intelligent Systems, University of Lahore

What is an Image and how is it formed?

Blue Marble, NASA / Apollo 17

Image Formation

Scene / object

Light as a signal

Camera / sensor

A camera measures light from the world and turns it into a digital image.

Signal

Signal: A (multi-dimensional) function that contains information about a phenomenon (e.g., light, heat, gravity, sound, pressure, motion).

  • Signals can be continuous, such as light in the physical world.
  • Measurements are often discrete samples of that continuous signal.
  • Sampling reduces a continuous signal to a finite set of values.

Sampling in 1D

  • Sampling a 1D continuous function returns a vector whose elements are values of that function at selected sample points.
  • Instead of the full function, we store values at selected locations.

Sampling in 2D

Sampling a 2D function returns a matrix.

2D Image

Image: A sampling of a function that contains information about a 2D signal.

  • The function stores brightness or intensity.
  • The image samples brightness along the \(x\) and \(y\) dimensions.
  • A video can be viewed as a time-varying 2D image signal: \((x, y, t)\).

Note

Cameras observe a 2D projection of the 3D world.

Examples of 2D Images

2D images appear in many sensing modalities:

  • Natural images
  • Thermal images
  • Satellite/aerial images
  • Microscopy
  • Ultrasound
  • MRI / CT slices
  • Radar images
  • Depth images

Note

The signal may not always be visible light. An image arranges what we have measured over a 2D domain.

Sampling in Practice

World / scene

Continuous signal

Camera

The imaging pipeline converts a continuous physical signal into discrete sensor measurements.

Sampling in Practice: Digital Image

Scene / image plane

Light signal

CMOS / CCD sensor

Digital cameras use sensor arrays to sample light and produce a grid of pixel values.

Sensor Array

Camera / sensor hardware

CMOS sensor array

Continuous light is sampled and quantized by the 2D sensor array (pixels) to produce a digital image.

Elements of a Digital Image

A pixel is a picture element.

For a grayscale image:

\[ I(x, y) = \text{intensity at image location} (x,y) \]

  • \(x\): horizontal coordinate
  • \(y\): vertical coordinate

Example:

I(x1, y1) = 101
I(x2, y2) = 191

Different pixel locations can have different intensity values.

Digital Image is a 2D Signal



A digital image can be interpreted as a 2D function whose value is brightness or intensity.

Light Integration Over a Pixel Region

  • A single pixel does not measure an infinitely thin ray.

  • It measures light integrated over a small region of the sensor and the corresponding cone/frustum of incoming light.


Note

This is one reason why cameras blur, average, and alias details that are smaller than a pixel can represent.

Resolution: Geometric vs. Spatial

Both images can have the same number of pixels, but the amount of scene detail represented can be different.

Low geometric resolution

High geometric resolution

Note

Spatial resolution counts pixels. Geometric resolution is how accurately those pixels represent the positions of objects in the real world.

Quantization

  • Sampling chooses where to measure a signal.
  • Quantization chooses which values can be represented.
  • For example, an 3 bits can represent: \[ 2^3 = 8 \] possible intensity levels in a grayscale image.

Quantization Effects — Radiometric Resolution

  • Radiometric resolution is the number of distinct intensity levels available.
Bit depth Number of levels
1 bit 2 levels
2 bit 4 levels
4 bit 16 levels
8 bit 256 levels
  • Higher bit depth can represent more subtle intensity differences.
  • In photography, this is closely related to dynamic range.

Dimensionality of an Image

  • An image of size \(1000 \times 1000\) with 8-bit quantization per pixel has: \[ 256^{1000 \times 1000} \approx 10^{2,408,239} \] possible intensity configurations.

  • This is an enormous high-dimensional space – the known universe has only about \(10^{80}\) atoms!

  • Computer vision works in this extremely high dimensional space – but real images are not arbitrary arrays and they occupy a small, structured subset of this space.

Checkpoint: What Did Your Phone Already Do Today?

Hands up for each one — which of these did your phone do today or this week?

  1. Unlocked with your face — FaceID / face unlock
  2. Blurred the background of a photo — Portrait mode
  3. Read text off a bill, receipt, or QR code — Text / code recognition
  4. Auto-grouped your photos into a “People” album — Face clustering
  5. Stabilised a shaky video — Frame-to-frame motion estimation

Note

All five. Every one of these is a computer-vision task. By the end of this lecture you should be able to name the task, its input, its output, and roughly what it costs to run.

A Short History of Computer Vision — The Classical Era

1960s–2010  —  the human designs the features

YearMilestoneWhy it matters
1959Hubel & Wiesel map the visual cortexInspires convolution
1963Roberts’ Blocks WorldFirst 3D scene from an image
1966MIT “Summer Vision Project”Vision assumed to be one summer’s work
1980Neocognitron (Fukushima)Direct ancestor of the CNN
1986Canny edge detectorStill used today
1999SIFTScale-invariant keypoints
2001Viola–Jones face detectionReal-time, ships in every camera
2005HOG + SVMPedestrian detection
2009ImageNet released14M labelled images

For fifty years, a person had to look at the problem and decide, by hand, what a “feature” was — an edge, a corner, a keypoint — before writing code to detect it.

A Short History of Computer Vision — The Deep Era

2012–present  —  the network learns the features

YearMilestoneWhy it matters
2012AlexNetReLU + dropout + GPU. Error 26% → 15%
2014VGG16 · InceptionDepth by stacking small convolutions; multi-scale filters
2015ResNetSkip connections, 152 layers, beats human top-5
2014–17R-CNN → Fast → FasterTwo-stage detection
2016YOLO / SSDOne stage — fast enough for video & robotics
2017Mask R-CNNPer-pixel instance segmentation
2019Detectron2Production detection library
2020ViTImage as patch sequence — Transformer absorbs vision
2021CLIPJoint image + text embedding → zero-shot vision
2022Diffusion (Stable Diffusion, DALL·E 2)Generative vision
2023SAMSegment anything, promptable
2023→VLMsVision + language in one model

After AlexNet in 2012, the feature itself became something a network learns from data, rather than something a human designs by hand. That shift is what the rest of this course builds on.

Checkpoint: Did You Actually Read the Timeline?

Fingers up — 1, 2, or 3. Everyone answers every question; wrong answers are the useful ones.

  1. What made 2012 the break point?
    1. A bigger dataset    2. ReLU + dropout + GPUs on a CNN    3. A new camera sensor

  2. Before 2010, who decided what a “feature” was?
    1. The network, by training    2. A human, by hand    3. The dataset, automatically

  3. Which came first?
    1. SIFT keypoints    2. YOLO detection    3. Mask R-CNN

  4. Why is YOLO in every robotics stack?
    1. It is the most accurate    2. One stage — fast enough for live video    3. It needs no training data

Checkpoint: Answers

  1. 2 — ReLU, dropout, and GPUs made training a deep CNN (AlexNet) practical.
  2. 2 — A human, by hand. SIFT, HOG, and Canny were all hand-designed detectors.
  3. 1 — SIFT (1999) came well before YOLO (2016) or Mask R-CNN (2017).
  4. 2 — One stage, fast enough for live video, which is exactly what a robot needs.

If you missed one, that miss is exactly the classical-vs-deep distinction this lecture is sharpening.

Image Processing vs. Computer Vision

Both start from the same input — an image — but they aim at different outputs.

Image Processing

Input: image  →  Output: an image, for human consumption.

  • Image enhancement
  • Image restoration
  • Image compression
  • Image registration

Computer Vision

Input: image  →  Output: image attributes, for computer use.

  • Image segmentation
  • Recognition (feature extraction)
  • Motion analysis & tracking
  • 3D shape reconstruction

This course sits mostly on the computer-vision side: we care about what an image tells us, not only how it looks.

From Pixels to Tasks

Every task in this course starts from the same object: a grid of numbers. The differences are in what we compute from that grid.

  • Classification — what is in this image?
  • Object detection — what is in this image, and where?
  • Semantic segmentation — which pixels belong to which category?
  • Object tracking — where did each object go, frame to frame?
  • Object counting — how many instances are present?
  • Pose estimation — how are the parts of an object arranged?

Note

All six tasks take the same input — a pixel array. They only differ in the shape of the output. Keep this in mind as we move from raw pixels toward algorithms.

Classification, Localization, and Detection

Three panels: plain classification labelled CAT, classification with localization showing a red box around the cat, and object detection on a second image with boxes and labels for CAT, DOG, and DUCK.

  • Classification assigns one label to the whole image.
  • Localization adds a bounding box for the labelled object.
  • Detection finds and labels every object instance in the scene.

Object Detection in Practice

Street scene with bounding boxes and labels for cars, a truck, a traffic light, a person, a bicycle, and a bicyclist.

A real detector outputs a box, a class label, and a confidence score for every object it finds — often dozens of boxes per frame.

Semantic Segmentation

A beach photo of three people flying a kite next to its semantic segmentation mask, where people, sky, sand, and the kite are each flat-coloured regions.

Instead of one label per image or one box per object, segmentation assigns a category to every pixel — the output is itself an image.

Object Tracking and Counting

Overhead view of pedestrians on a plaza, each enclosed by a tracking box with a trailing motion line.

Tracking: identity across frames

Chocolate candies on a conveyor, each boxed and numbered with a confidence score, with running in/out counts.

Counting: instances over time

Tracking keeps a consistent ID for each object across frames; counting turns that into a running tally.

Pose Estimation

A stick-figure skeleton next to a photo of a person with the same skeleton of joints overlaid on their body.

Pose estimation locates a fixed set of keypoints — joints — and connects them into a skeleton, describing the arrangement of an object's parts rather than its outline.

Computer Vision Applications, by Domain

  • Healthcare & Medical — imaging analysis, tumor detection, retinal screening
  • Automotive & Transportation — self-driving cars, driver assistance, traffic monitoring
  • Manufacturing & Industrial — quality control, line automation, factory safety
  • Security & Surveillance — facial recognition, crowd and intrusion monitoring
  • Retail & E-commerce — visual product search, inventory counting, cashier-less stores
  • Agriculture & Food — crop monitoring, pest detection, quality inspection
  • Entertainment & Media — augmented reality, motion capture, sports analytics
  • Finance & Banking — document processing, check verification, fraud detection
  • Real Estate & Construction — property valuation, construction and building inspection
  • Environmental & Geospatial — climate monitoring, wildlife conservation, disaster assessment

Computer Vision You Know Is Just the Tip of the Iceberg

An iceberg photo, annotated: the small visible tip above the waterline is labelled 'common customer-facing applications', while the much larger mass submerged below is labelled 'thousands of applications in the background'.

Note

Underneath sits a much larger set of applications running quietly in the background — quality-control cameras on a factory line, satellite crop monitoring, medical-scan triage, and thousands more you never see running. Every one of them is built from the same six tasks you just learned.

Images in Python: Grayscale Arrays

For an \(N \times M\) grayscale image im:

im[0, 0]        # top-left pixel value
im[y, x]        # y rows down, x columns right
im[N-1, M-1]    # bottom-right pixel value

Important

In NumPy, image indexing is usually row first, column second: im[y, x], not im[x, y].

Grayscale Intensity

A grayscale image is a matrix that stores one intensity value per pixel.

Color Images

  • A color image stores multiple intensity values per pixel.
  • For RGB images, each pixel has three channels:
    • Red intensity
    • Green intensity
    • Blue intensity
image shape: height × width × 3

Note

Different libraries may use different channel order conventions. OpenCV commonly uses BGR; Matplotlib commonly expects RGB.

Images in Python: Color Arrays

For an \(N \times M\) color image im with three channels:

im[0, 0, 0]          # top-left pixel, first channel
im[y, x, 1]          # pixel at row y, column x, second channel
im[N-1, M-1, 2]      # bottom-right pixel, third channel

Typical shape:

im.shape  # (height, width, channels)

For an RGB image:

channel 0 = red
channel 1 = green
channel 2 = blue

For OpenCV-loaded images:

channel 0 = blue
channel 1 = green
channel 2 = red

Predict First: What Does This Print?

A file red_square.png is a 640 × 480 image of a pure red square. Before you run it, predict the output:

img = cv2.imread("red_square.png")
print(img.shape)
print(img[0, 0])
  1. (640, 480, 3) then [255 0 0]
  2. (480, 640, 3) then [255 0 0]
  3. (480, 640, 3) then [0 0 255]
  4. (3, 480, 640) then [255 0 0]

Write your answer down, then turn the page.

Two Traps, Both Famous

The answer is option 3: (480, 640, 3) then [0 0 255].

Important

Rows before columns. NumPy indexes an image as im[y, x] — height first. A 640-wide, 480-tall image has shape (480, 640, 3), not (640, 480, 3). Every “my output is rotated” bug starts here.

OpenCV is BGR, not RGB. Pure red is stored as [0, 0, 255]. Hand a BGR array straight to Matplotlib and your red car turns blue.

Most cohorts split between options 2 and 3 — each gets one trap but not both.

Images in Python: Data Types

Take care of image data types.

# uint8 image: values 0 to 255
im = cv2.imread("file.jpg")

# convert to float32, still values 0 to 255
im_float = im.astype(np.float32)

# normalize to 0 to 1
im_norm = im.astype(np.float32) / 255.0

Important

Many image-processing bugs come from mixing uint8, float32, and different value ranges.

Random Images in Python

from numpy import random as r

I = r.rand(256, 256)

r.rand(256, 256) creates a 256 by 256 array of random floating-point values in the range \([0,1)\).

Questions:

  • What is I?
  • What does it look like?
  • Which values does it contain?
  • How many values are there?

Displaying an Image in Python

from matplotlib import pyplot as plt
from numpy import random as r

I = r.rand(256, 256)

plt.imshow(I, cmap="gray")
plt.axis("off")
plt.show()

Is this an image?

Coding in This Course

We will use:

  • Python for programming
  • Conda for managing the course environment
  • NumPy for numerical arrays
  • OpenCV for image processing and computer vision
  • PyTorch for deep learning topics
  • VS Code for editing, debugging, and notebooks

Important

Do not use GenAI to solve homework for you. If you copy-paste code without understanding it, you will not learn how to code.

Be kind and supportive: students come from different backgrounds and have different levels of Python experience.

Python / Tool Refresher

Course tutorials are available here:

https://kazimbalti.github.io/intelligent-vision-systems/tutorials/

Review as needed:

  • WSL + Ubuntu — recommended Linux environment for Windows users
  • Git & GitHub — cloning, committing, pulling, pushing, and GitHub Classroom
  • Python & Conda — installing Conda and creating the course environment
  • Visual Studio Code — Python interpreter, notebooks, and debugging
  • NumPy — arrays, indexing, vectorization, matrices, and image-related operations

Tip

These tutorials are reference material. Use them when you need help with the tools so class time can focus on computer vision.

Before We Create the Environment

Open a terminal and check the tools you already have.

Git

git --version

Conda

conda --version

Existing Conda environments

conda env list

Windows users working in WSL can also check:

uname -a

Tip

If conda is not installed yet, open the Python & Conda tutorial and follow the Miniforge installation section.

The Course Environment

We use a dedicated Conda environment named:

cv

The environment file is maintained in the course repository:

https://github.com/Kazimbalti/intelligent-vision-systems/blob/main/code/cv-environment.yml

It defines the software stack used by the course, including:

  • Python
  • NumPy / SciPy
  • OpenCV
  • PyTorch / TorchVision
  • Matplotlib
  • scikit-image / scikit-learn
  • Jupyter and VS Code notebook support

Do not manually assemble your own version of the environment.

Get the Environment File

Option 1 — Clone the course repository

cd ~/cv_projects
git clone https://github.com/Kazimbalti/intelligent-vision-systems.git
cd intelligent-vision-systems/code

You should now see:

ls

including:

cv-environment.yml

Option 2 — Download only the environment file

curl -L -o cv-environment.yml \
https://raw.githubusercontent.com/Kazimbalti/intelligent-vision-systems/main/code/cv-environment.yml

Create the cv Environment

From the directory containing cv-environment.yml:

conda env create -f cv-environment.yml

This may take several minutes.

The environment file already specifies the name:

cv

When installation finishes:

conda activate cv

Your terminal prompt should now begin with something similar to:

(cv)

Important

Whenever you run course Python code, make sure the cv environment is active.

Verify the Environment

With cv activated:

python --version

Check which Python is being used:

which python

Then verify the main packages:

python -c "import numpy; print('NumPy:', numpy.__version__)"
python -c "import cv2; print('OpenCV:', cv2.__version__)"
python -c "import torch; print('PyTorch:', torch.__version__)"
python -c "import torchvision; print('TorchVision:', torchvision.__version__)"

If all four commands work, the core environment is ready.

Configure VS Code

Open the project folder from your terminal:

code .

Windows + WSL users should see WSL: Ubuntu in the VS Code status area.

Then:

  1. Open the Command Palette: Ctrl+Shift+P
  2. Search for Python: Select Interpreter
  3. Select the interpreter associated with cv

For notebooks, use Select Kernel and choose the same cv environment.

Verify from Python:

import sys
print(sys.executable)

The path should point into the cv Conda environment.

What Is OpenCV?

The world's most widely used computer-vision library, with roughly 5.8 million downloads per week on PyPI.

  • Image and video I/O — read/write/display images and videos; capture from webcam or file
  • Image processing — resize, rotate, flip, crop, color conversions (BGR, Gray, HSV, LAB), filters (blur, sharpen, edge detection)
  • Drawing and GUI — shapes, text, mouse and keyboard events
  • Feature and object recognition — edges, corners, keypoints (SIFT, ORB), feature matching, face/object detection
  • Tracking, motion, segmentation — built-in trackers, optical flow, GrabCut, watershed
  • 3D vision and ML — camera calibration, stereo/depth, classical ML (SVM, k-NN), and running deep models (YOLO, ONNX)

We will use a small slice of this in the course, starting today.

Our First Computer Vision Program

Create a file named:

first_cv.py

Start by importing the libraries:

from pathlib import Path

import cv2
import matplotlib.pyplot as plt
import numpy as np

Create a folder for output files:

output_dir = Path("outputs")
output_dir.mkdir(exist_ok=True)

Create and Save a Simple Image

For today’s example, we will create a small synthetic image so everyone has the same input.

height = 360
width = 640

image = np.full(
    (height, width, 3),
    235,
    dtype=np.uint8,
)

# OpenCV uses BGR color ordering.
cv2.rectangle(
    image, (70, 80), (260, 280),
    (255, 100, 0), thickness=-1
)

cv2.circle(
    image, (470, 180), 90,
    (0, 180, 255), thickness=-1
)

cv2.putText(
    image, "Computer Vision",
    (150, 335),
    cv2.FONT_HERSHEY_SIMPLEX,
    1.0, (30, 30, 30), 2
)

cv2.imwrite(str(output_dir / "sample_image.png"), image)

We now have a real image file on disk that we can load with OpenCV.

Load and Inspect the Image

Load the image:

image_bgr = cv2.imread(
    str(output_dir / "sample_image.png")
)

Important

If imread is given a bad path, it does not raise an error — it quietly returns None, and the next line crashes somewhere else entirely. Always check the return value before using it.

Inspect it:

print("Shape:", image_bgr.shape)
print("Data type:", image_bgr.dtype)

You should see something similar to:

Shape: (360, 640, 3)
Data type: uint8

An image is fundamentally a NumPy array.

Display the Image

OpenCV loads color images in BGR order.

Matplotlib expects RGB, so convert before displaying:

image_rgb = cv2.cvtColor(
    image_bgr,
    cv2.COLOR_BGR2RGB
)

plt.imshow(image_rgb)
plt.axis("off")
plt.show()

A useful rule:

OpenCV processing → usually BGR
Matplotlib display → RGB

Note

Using Matplotlib is also convenient in notebooks and avoids problems that can occur with cv2.imshow() in some WSL setups.

A First Image-Processing Operation

Convert the image to grayscale:

gray = cv2.cvtColor(
    image_bgr,
    cv2.COLOR_BGR2GRAY
)

Detect edges:

edges = cv2.Canny(
    gray,
    100,
    200
)

Display the result:

plt.imshow(edges, cmap="gray")
plt.axis("off")
plt.show()

What Just Happened?

In only a few lines, we used several ideas that will appear throughout the course:

  • An image is represented as a NumPy array
  • Image dimensions are described by .shape
  • Pixel values have a data type such as uint8
  • OpenCV can load, save, transform, and analyze images
  • Color-channel conventions matter: BGR vs. RGB
  • Computer vision pipelines are often sequences of simple operations
image
  ↓
load
  ↓
represent as an array
  ↓
transform / analyze
  ↓
display or use the result

How Do Filters Work?

cv2.Canny looked like a black box above. Under the hood it — like almost every classical image-processing operation — relies on convolution.

A simple input image split in half, white on the left and black on the right, next to its pixel-value matrix of 1s on the left columns and 0s on the right columns.

  • A filter (or kernel) is a small grid of numbers, usually \(3\times3\).
  • The kernel slides over the image. At every position, multiply each kernel weight by the pixel underneath it, then sum the nine products into a single output pixel.
  • Repeating this at every position produces the entire output image.

Predict First: What Does This Filter Do?

The question 'What if we use this filter?' next to a 3 by 3 kernel: 0, -1, 0 on the top row, -1, 4, -1 in the middle row, 0, -1, 0 on the bottom row.

Slide this kernel over the black-and-white input image above. Where do you expect it to produce a large, non-zero output — and where should it produce exactly 0?

Reveal: The Filtered Output

The expected output image: almost entirely black, except a thin bright vertical line exactly where the input image transitioned from white to black. Its pixel-value matrix is mostly 0s with a column of 1s marking that boundary.

Note

Weights that sum to zero make a filter respond to change (an edge), not to absolute brightness — a flat, uniform patch always produces 0. That is why the whole output is black except a single bright seam exactly at the boundary.

Worksheet: Do One Convolution by Hand

You will never have to do this again by hand — but after this, filter2D will never be a black box.

Input patch (grayscale)

1010109090
1010109090
1010109090
1010109090
1010109090

Kernel (Sobel-x)

−10+1
−20+2
−10+1

Multiply each kernel cell by the pixel underneath it, then add all nine up. Three \(3\times3\) windows fit across this patch — compute the top row only, positions 1, 2, and 3.

Position 1, worked for you: 0. Your output row — fill in positions 2 and 3.

Then Answer

  1. Why is position 1 zero when the pixels are clearly not zero?
  2. Which position gives the biggest number, and what is physically there?
  3. You get 160 and −160 at two places. Stored as uint8, what happens to −160?
  4. Rotate the kernel 90°. What does it detect now?

Explore Filters Interactively

Preview of the setosa.io 'Image Kernels Explained Visually' page: a grayscale input face photo, the sharpen kernel arithmetic for one pixel producing the value 192, and the resulting sharpened output face.

To build intuition beyond these static examples, try changing kernel values yourself and watch the output update live:

https://setosa.io/ev/image-kernels/

Common Setup Problems

conda: command not found

Restart the terminal or reload your shell:

source ~/.bashrc

Python imports fail

First check:

conda activate cv
which python

VS Code runs a different Python

Use:

Python: Select Interpreter

and select cv.

Windows paths and Linux paths are getting mixed

If you are using WSL, keep the course environment and projects inside the WSL/Linux filesystem.

After Class

Please go through any tutorials that cover tools you are not yet comfortable with:

https://kazimbalti.github.io/intelligent-vision-systems/tutorials/

In particular, make sure you can:

  • Activate the cv environment
  • Use basic Git commands
  • Open a project in VS Code
  • Run Python scripts and Jupyter notebooks
  • Work with basic NumPy arrays

You do not need to memorize every Git, Conda, or NumPy command. The tutorials are there as references throughout the semester.