Vì sao gốc tọa độ ảnh ở góc trên bên trái?
OpenCV - Tut 1.3: Vì sao gốc tọa độ ảnh nằm ở góc trên bên trái?

Tut 1.3: Vì sao gốc tọa độ ảnh ở góc trên bên trái?
Hi mọi người, lại là Minh đây. Trong Tut 1.1: Cấu trúc dữ liệu ảnh trong OpenCV. Pixel là gì? ta đã biết rằng gốc tọa độ của ảnh được đặt ở góc trên bên trái. Điều này khá khác với hệ trục tọa độ quen thuộc trong Toán học.
Điều này thật bất tiện khi mỗi lần tính quỹ đạo di chuyển ta phải thực hiện chuyển đổi trục y=height-y, để nó trở về hệ trục tọa độ trong toán học quen thuộc. Nhiều bạn hỏi Minh: "Ủa vì sao lại như vậy?" — nên ở Tut 1.3 này ta cùng mổ xẻ cho ra ngô ra khoai lý do nha.
👉 Câu trả lời ngắn gọn là: gốc tọa độ ảnh nằm ở góc trên bên trái vì lý do lịch sử, thực tiễn và cách tổ chức bộ nhớ.
Ảnh được lưu trong bộ nhớ máy tính như thế nào?
Ảnh số gần như luôn được lưu dưới dạng mảng 1 chiều theo "row-major order":
- Bắt đầu từ dòng trên cùng (row 0).
- Pixel được lưu từ trái qua phải trên cùng một dòng.
- Sau đó chuyển xuống dòng tiếp theo, rồi lặp lại.
Do đó, cách ánh xạ trong bộ nhớ sẽ tự nhiên trở thành:
- (x=0, y=0) = pixel ở góc trên bên trái
- y tăng dần theo hướng đi xuống
Cách này phù hợp với hầu hết định dạng ảnh phổ biến (PNG, JPEG, và phần lớn bitmap buffer khi load vào bộ nhớ) cũng như cách GPU / texture memory được tổ chức. Nếu ta cố đảo ngược lại thì mỗi lần load ảnh hoặc hiển thị ảnh đều sẽ cần thêm bước xử lý không cần thiết.
BMP là một trường hợp hơi đặc biệt về mặt lịch sử. File BMP kiểu cũ mặc định lưu các dòng ảnh theo thứ tự từ dưới lên trên (giá trị
biHeightdương trong header nghĩa là bottom-up). Tuy nhiên, đa số thư viện ảnh sẽ âm thầm đảo nó lại thành top-down buffer trong lúc giải mã. Vì vậy tới lúc code của ta đọc pixel ra thì nó vẫn hoạt động giống PNG/JPEG — tức là gốc ở góc trên bên trái.
Đây là lý do cốt lõi của vị trí gốc tọa độ ảnh đặt góc trên bên trái.

Nguồn gốc lịch sử (từ trước thời đồ họa máy tính)
- Tivi và màn hình CRT (khoảng 1930s–1980s): chùm electron quét từ trên xuống dưới, từ trái qua phải. Dòng tín hiệu đầu tiên chính là dòng trên cùng. Cách làm này dần trở thành chuẩn de-facto.
- Text terminal và framebuffer đời đầu cũng đi theo đúng quy ước đó (line 0 = phía trên).
- Khi bitmap graphics xuất hiện (1970s–80s), chúng kế thừa trực tiếp thứ tự quét này. Nếu đổi ngược lại thì sẽ phá vỡ tính tương thích với phần cứng lúc bấy giờ.
Vì sao trong Toán học lại khác?
Trong hệ tọa độ Descartes tiêu chuẩn:
- y tăng dần theo hướng đi lên
- Gốc tọa độ thường được đặt ở góc dưới bên trái (đặc biệt khi vẽ đồ thị)
Điều này phù hợp với trực giác vật lý của con người (đi lên là dương) và được các nhà toán học chọn để phục vụ hình học, cơ học, vật lý.
Trong khi đó, máy tính ưu tiên hiệu năng và sự thuận tiện cho phần cứng hơn là "vẻ đẹp hình thức" của Toán học.
So sánh trực quan
| System | Origin | X direction | Y direction | Reason |
|---|---|---|---|---|
| Toán học (tiêu chuẩn) | Góc dưới bên trái | Phải | Lên trên | Trực giác vật lý, hình học |
| Ảnh số / Tọa độ pixel | Góc trên bên trái | Phải | Đi xuống | Cách lưu bộ nhớ + cách màn hình quét |
| Một số graphics APIs | Góc dưới bên trái | Phải | Lên trên | Ví dụ: OpenGL với "normalized coordinates / UV texture coordinates". Tuy nhiên DirectX, Vulkan và Metal lại dùng quy ước top-left trong nhiều ngữ cảnh, nên chỗ này còn tùy API cụ thể. |
Cách xử lý linh hoạt ở thời hiện đại
- Graphics libraries hiện đại thường hỗ trợ cả hai kiểu hệ trục:
- Tọa độ pixel: top-left (0,0)
- "Normalized device coordinates / UV texture coords": thường là bottom-left (0,0)
- Bạn hoàn toàn có thể tự lật trục y khi cần (ví dụ thường gặp trong shader:
y = height - y). - Các công cụ như Matplotlib, Processing, … cũng cho phép ta chọn hệ trục tọa độ phù hợp.
Tóm lại: gốc tọa độ ở góc trên bên trái là một quyết định kỹ thuật rất thực dụng. Nó khớp với cách màn hình hoạt động và cách bộ nhớ được tổ chức. Toán học tối ưu cho trực giác của con người; máy tính tối ưu cho tốc độ và sự đơn giản khi hiện thực. Vì vậy, quy ước này ngày nay gần như xuất hiện ở khắp nơi trong xử lý ảnh, thị giác máy tính (computer vision), web (Canvas), và cả game engines.
Nếu đọc tới đây mà bạn thấy "à ha, hiểu rồi đó", hãy quay lại xem lại các ví dụ indexing pixel trong Tut 1.1 — lúc đó thứ tự img[y, x] sẽ trở nên dễ hiểu hơn rất nhiều 🤗 :)~
Kết nối lại với các bài OpenCV
Kiến thức về gốc tọa độ ảnh không phải để biết cho vui đâu nha, mà nó sẽ đụng trực tiếp tới hầu hết thao tác cơ bản trong OpenCV:
- Khi đọc một pixel, ta dùng
img[y, x]chứ không phảiimg[x, y]vì ma trận ảnh được tổ chức theo height x width. - Khi lấy ROI (Region of Interest), cú pháp đúng sẽ là
img[y_from:y_to, x_from:x_to]. - Khi crop ảnh, bản chất vẫn chỉ là cắt theo trục y trước, rồi mới tới trục x.
- Khi resize ảnh, kích thước ảnh có thay đổi nhưng quy ước gốc tọa độ vẫn giữ nguyên ở góc trên bên trái.
Nắm chắc chỗ này rồi thì sang Tut 2: Xử lý ảnh - OpenCV resize, crop và padding hình ảnh (code Python và C++) hoặc Tut 4: Xử lý ảnh - OpenCV vùng quan tâm (ROI) là gì? (code Python) bạn sẽ đỡ bị nhầm trục hơn rất nhiều.
Bài viết tiếp theo Tut 2: Xử lý ảnh - OpenCV resize, crop và padding hình ảnh (code Python và C++)
Cảm ơn bạn đã theo dõi bài viết. Hãy kết nối với tớ nhé!
- Minh: https://www.facebook.com/minhng.info
- Khám phá xử lý ảnh - GVGroup: https://www.facebook.com/groups/ip.gvgroup
Khám phá xử lý ảnh - GVGroup
Danh sách bài viết series OpenCV:
- Hashtag #OpenCV
- Tut 1: Xử lý ảnh - OpenCV đọc ghi hình ảnh (code Python và C++)
- Tut 1.1: Xử lý ảnh - Cấu trúc dữ liệu ảnh trong OpenCV. Pixel là gì?
- Tut 1.2: Xử lý ảnh - Chuyển đổi ảnh OpenCV sang Pillow và ngược lại
- Tut 1.3: Vì sao gốc tọa độ ảnh ở góc trên bên trái?
- Tut 2: Xử lý ảnh - OpenCV resize, crop và padding hình ảnh (code Python và C++)
- Tut 3: Xử lý ảnh - OpenCV biến đổi mức sáng hình ảnh (code Python)
- Tut 4: Xử lý ảnh - OpenCV vùng quan tâm (ROI) là gì? (code Python)
- Tut 4.1: Xử lý ảnh - OpenCV: vẽ văn bản, đường thẳng, mũi tên, hình chữ nhật, hình tròn, ellipse, đa giác
- Tut 4.2: Xử lý ảnh - Pha trộn ảnh trong OpenCV (blending)
- Tut 5: Xử lý ảnh - OpenCV ảnh nhị phân
- Tut 6: Xử lý ảnh - OpenCV cân bằng sáng (histogram equalization)
- Tut 7: Xử lý ảnh - OpenCV kỹ thuật cửa sổ trượt (sliding window)
- Tut 8: Xử lý ảnh - Convolution là gì?
- Tut 9: Xử lý ảnh - Làm mờ ảnh (blur)
- Tut 10: Xử lý ảnh - Gradient của ảnh là gì?
- Tut 11: Xử lý ảnh - Phát hiện cạnh Canny (Canny Edge Detection)
- Tut 12: Xử lý ảnh - Phát hiện đường thẳng bằng Hough Transform (Hough Line)
- Tut 13: Xử lý ảnh - Hiện thực phát hiện đoạn thẳng dùng Hough Transform (Hough Line)
- Tut 14: Xử lý ảnh - Giải thuật phân vùng Region Growing trên ảnh màu
- Tut 15: Xử lý ảnh - Giải thuật Background Subtraction trên ảnh màu
- Tut 16: Xử lý ảnh - Frame Subtraction để phát hiện chuyển động trong video
- Tut 17: Xử lý ảnh - HOG - Histograms of Oriented Gradients
- Tut 18: Xử lý ảnh - HOG - Huấn luyện mô hình phân loại người
- Tut 19: Xử lý ảnh - HOG - Phát hiện người
- Tut 20: Xử lý ảnh - Tổng hợp kinh nghiệm xử lý ảnh (End)
- Tut 21: Xử lý ảnh - Hiện thực trích đặc trưng Local Binary Patterns (LBP)
- Tut 22: Xử lý ảnh - Trích đặc trưng Gabor filters