Trong xử lý ảnh, việc phát hiện đường biên (edge detection) đóng vai trò quan trọng trong nhiều bài toán như nhận diện vật thể, phân đoạn ảnh và nén dữ liệu. Một trong những thuật toán phổ biến và hiệu quả nhất để phát hiện đường biên là Canny Edge Detection, được phát triển bởi John F. Canny vào năm 1986. Phương pháp này không chỉ giúp xác định rõ ràng ranh giới của vật thể mà còn giảm nhiễu tốt hơn các kỹ thuật trước đó.
Nếu bạn từng tìm hiểu Tách nền ảnh đơn giản bằng OpenCV, Xử lý ảnh nhiễu bằng OpenCV trong đồ án hay Cách làm đồ án nhận diện khuôn mặt bằng OpenCV, bạn sẽ thấy rằng phát hiện đường biên là bước nền tảng mà các kỹ thuật cao hơn đều dựa vào. Bài viết này sẽ giúp bạn hiểu cách hoạt động của thuật toán Canny và áp dụng nó để xử lý bộ dữ liệu ảnh mẫu, từng bước giải thích để ngay cả người mới cũng có thể thực hiện.
Tập dữ liệu sử dụng
Để minh họa, chúng ta sẽ sử dụng một tập dữ liệu nhỏ gồm các ảnh vật thể thông thường như cốc, bút, và xe hơi từ bộ dữ liệu COCO subset hoặc các ảnh có sẵn trong OpenCV. Bạn có thể tải một tập ảnh mẫu tại đây:
👉 OpenCV Sample Images
Các ảnh này có độ phân giải thấp vừa phải, thuận tiện cho việc xử lý nhanh trên máy tính cá nhân.
Tổng quan về Canny Edge Detection
Cách hoạt động của Canny
Thuật toán Canny bao gồm 5 bước chính:
- Làm mờ ảnh (Gaussian Blur) để giảm nhiễu.
- Tính gradient để phát hiện vùng có sự thay đổi cường độ sáng mạnh.
- Non-maximum suppression để làm mảnh đường biên.
- Double threshold để phân biệt đường biên mạnh và yếu.
- Edge tracking by hysteresis để kết nối các đường biên mạnh và yếu hợp lệ.
Nhờ các bước này, Canny tạo ra một bản đồ đường biên rõ ràng và ít bị nhiễu hơn các phương pháp như Sobel hay Laplacian.
Đọc và hiển thị ảnh
Trước tiên, chúng ta cần đọc ảnh từ file và hiển thị nó để đảm bảo dữ liệu được nạp thành công. OpenCV cung cấp hàm cv2.imread() để đọc và cv2.imshow() để hiển thị. Tuy nhiên, trong Jupyter Notebook hoặc Google Colab, bạn nên dùng Matplotlib để hiển thị ảnh.
import cv2
import matplotlib.pyplot as plt
# Đọc ảnh từ file
image = cv2.imread('object.jpg', cv2.IMREAD_COLOR)
# Chuyển từ BGR (OpenCV mặc định) sang RGB (Matplotlib yêu cầu)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Hiển thị ảnh
plt.imshow(image_rgb)
plt.title('Ảnh gốc')
plt.axis('off')
plt.show()
Tiền xử lý ảnh
Trước khi áp dụng Canny, cần chuyển ảnh sang thang độ xám để giảm số kênh màu và làm mờ ảnh bằng Gaussian Blur để loại bỏ nhiễu nhỏ. Nếu không xử lý trước, ảnh đầu ra có thể chứa nhiều đường biên giả.
# Chuyển ảnh sang grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Áp dụng Gaussian Blur
blurred = cv2.GaussianBlur(gray, (5, 5), 1.4)
# Hiển thị ảnh grayscale và ảnh làm mờ
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(gray, cmap='gray')
axs[0].set_title('Grayscale')
axs[0].axis('off')
axs[1].imshow(blurred, cmap='gray')
axs[1].set_title('Gaussian Blur')
axs[1].axis('off')
plt.show()
Áp dụng thuật toán Canny
Hàm cv2.Canny() yêu cầu hai ngưỡng: ngưỡng thấp và ngưỡng cao. Các cạnh có gradient lớn hơn ngưỡng cao chắc chắn là cạnh, còn các cạnh giữa hai ngưỡng sẽ được giữ lại nếu chúng nối với cạnh mạnh.
# Áp dụng Canny Edge Detection
edges = cv2.Canny(blurred, threshold1=50, threshold2=150)
# Hiển thị kết quả
plt.imshow(edges, cmap='gray')
plt.title('Kết quả Canny Edge Detection')
plt.axis('off')
plt.show()
Tinh chỉnh tham số và so sánh kết quả
Việc lựa chọn ngưỡng phù hợp rất quan trọng. Ngưỡng quá thấp sẽ phát hiện nhiều cạnh giả, ngưỡng quá cao có thể bỏ sót các cạnh quan trọng. Bạn nên thử nghiệm nhiều giá trị để tìm ra thông số tối ưu cho từng loại ảnh.
# So sánh với các cặp ngưỡng khác nhau
fig, axs = plt.subplots(1, 3, figsize=(15, 5))
for ax, (t1, t2) in zip(axs, [(30, 100), (50, 150), (100, 200)]):
edges = cv2.Canny(blurred, t1, t2)
ax.imshow(edges, cmap='gray')
ax.set_title(f'Thresholds: {t1}-{t2}')
ax.axis('off')
plt.show()
Bảng so sánh: Ưu và nhược điểm của Canny
| Ưu điểm | Nhược điểm |
|---|---|
| Phát hiện đường biên mượt, rõ ràng | Cần tinh chỉnh ngưỡng để đạt kết quả tốt |
| Giảm nhiễu tốt nhờ Gaussian Blur | Hiệu suất giảm với ảnh có ánh sáng phức tạp |
| Hỗ trợ kết nối cạnh yếu qua hysteresis | Không phát hiện tốt các cạnh mờ |
Kết luận
Canny Edge Detection là một công cụ mạnh mẽ và dễ sử dụng cho người mới bắt đầu xử lý ảnh. Khi kết hợp với các kỹ thuật khác như lọc nhiễu hoặc tách nền, nó có thể trở thành bước nền tảng trong nhiều ứng dụng Computer Vision, từ phân đoạn ảnh đến nhận diện vật thể. Với kiến thức và ví dụ thực hành ở trên, bạn hoàn toàn có thể thử áp dụng Canny vào đồ án hoặc dự án của riêng mình.

