Coordinate Systems & Pixel Access
If there is one topic that causes 90% of bugs for beginners, it is Coordinate Systems.
OpenCV and NumPy speak slightly different languages when it comes to coordinates. One talks in Geometry (x, y), and the other talks in Matrices [row, col]. mixing them up will crash your code or—worse—silently edit the wrong pixels.
This guide is your Rosetta Stone.
The Coordinate System
Section titled “The Coordinate System”In standard mathematics (Cartesian), the origin (0, 0) is usually at the bottom-left or center.
In Computer Vision (and most computer graphics), the origin (0, 0) is at the Top-Left.
- X-axis: goes from Left to Right.
- Y-axis: goes from Top to Bottom.
(0,0) ------> X (Width) | | v Y (Height)The Great Divide: (x, y) vs [y, x]
Section titled “The Great Divide: (x, y) vs [y, x]”Here is the rule you must memorize:
- Function Arguments use
(x, y).- Example:
cv2.resize(img, (width, height)) - Example:
cv2.circle(img, (x, y), ...)
- Example:
- Matrix Access uses
[y, x](or[row, col]).- Example:
pixel = img[y, x] - Example:
crop = img[y1:y2, x1:x2]
- Example:
Accessing & Modifying Pixels
Section titled “Accessing & Modifying Pixels”Since images are NumPy arrays, accessing a pixel is just array indexing.
import cv2import numpy as np
img = cv2.imread("photo.jpg")
# 1. Access a pixel# Remember: [y, x]y, x = 50, 100pixel = img[y, x]print(f"Pixel at y={y}, x={x} is {pixel}")
# 2. Modify a pixel# Make it White (255, 255, 255)img[y, x] = [255, 255, 255]Regions of Interest (ROI) & Slicing
Section titled “Regions of Interest (ROI) & Slicing”A ROI is just a sub-section of an image. You might want to detect a face and then just work on that square face region.
In NumPy, we use Slicing: array[start:stop:step].
Basic Crop
Section titled “Basic Crop”To crop a rectangular region, you need the start and end coordinates for both Y (Rows) and X (Cols).
# Defined coordinatesx_start, y_start = 100, 50x_end, y_end = 300, 250
# Crop logic: [y_start:y_end, x_start:x_end]roi = img[y_start:y_end, x_start:x_end]
cv2.imshow("Cropped ROI", roi)ROI arithmetic
Section titled “ROI arithmetic”Here is a practical example: “I want to put a black square in the center of the image”.
# 1. Create a blank canvasimg = np.zeros((400, 400, 3), dtype="uint8")
# 2. Define the region# Center 100x100 squarecenter_y, center_x = 200, 200offset = 50
# 3. Modify the region directly# We are selecting a range of pixels and assigning a value to ALL of them at onceimg[center_y-offset:center_y+offset, center_x-offset:center_x+offset] = [255, 255, 255] # White squareCopy vs View
Section titled “Copy vs View”This is a critical Python concept. When you slice an array, NumPy usually returns a View, not a Copy.
- View: If you modify the
roi, the originalimgALSO changes. - Copy: If you modify the
roi, the originalimgstays the same.
# VIEW exampleroi = img[0:100, 0:100]roi[:] = [0, 0, 255] # Make the ROI Red# Result: Top-left of 'img' is now Red!
# COPY exampleroi_copy = img[0:100, 0:100].copy()roi_copy[:] = [0, 255, 0] # Make the copy Green# Result: 'img' is NOT changed.Advanced Indexing
Section titled “Advanced Indexing”Negative Indexing
Section titled “Negative Indexing”Just like standard Python lists, you can use negative numbers to count from the end.
# Get the last rowlast_row = img[-1, :]
# Crop the bottom-right 10x10 cornercorner = img[-10:, -10:]Striding (Stepping)
Section titled “Striding (Stepping)”The third argument in slicing is the step. You can use this to downsample an image trivially (though without anti-aliasing).
# [start:end:step]# Take every 2nd pixel in both directions (half size)small_img = img[::2, ::2]Summary Reference
Section titled “Summary Reference”| Operation | Syntax | Logic |
|---|---|---|
| Pixel Access | img[y, x] | Matrix Row/Col |
| Drawing | cv2.line(img, (x, y), ...) | Cartesian Point |
| Resizing | cv2.resize(img, (w, h)) | Cartesian Dimensions |
| Shape | (h, w, c) | Matrix Dimensions |
| Cropping | img[y1:y2, x1:x2] | Matrix Slicing |