Thị giác máy tính với OpenCV-Python Bài 4, Phần 6: Thuật toán Canny phát hiện cạnh

Thị giác máy tính với OpenCV-Python Bài 4, Phần 6: Thuật toán Canny phát hiện cạnh

Thị giác máy tính với OpenCV-Python Bài 4, Phần 6: Thuật toán Canny phát hiện cạnh

10:58 - 04/01/2022

Trong phần này chúng ta sẽ tìm hiểu cách phát hiện các cạnh trong hình ảnh sử dụng thuật toán Canny thông qua hàm cv2.Canny().

Thị giác máy tính với OpenCV-Python Bài 7 Phần 3: Nhận diện khuôn mặt
Thị giác máy tính với OpenCV-Python Bài 7 Phần 2: Phát hiện người đi bộ trong video
Thị giác máy tính với OpenCV-Python Bài 7 Phần 1: Phát hiện người đi bộ trong hình ảnh
Thị giác máy tính với OpenCV-Python Bài 6 Phần 2: Phép trừ nền
Thị giác máy tính với OpenCV-Python Bài 6 Phần 1: Bắt bám đối tượng với Meanshift và Camshift

1. Thuật toán Canny

Loạt bài hướng dẫn này chủ yếu liên quan đến các thao tác thực hành là chính, do đó, phần lý thuyết sẽ chỉ mang tính chất giới thiệu.

Canny Edge Detection là một thuật toán phát hiện cạnh được sử dụng rộng rãi và được phát triển bởi John F. Canny. Đây là một thuật toán gồm nhiều bước như sau:

- Giảm nhiễu: Vì tính năng phát hiện cạnh dễ bị ảnh hưởng bởi nhiễu trong hình ảnh, do đó bước đầu tiên là phải loại bỏ nhiễu bằng bộ lọc Gaussian 5x5 (xem các phần trước để rõ hơn về thao tác lọc nhiễu hình ảnh).

- Tìm độ dốc cường độ của hình ảnh: Bước tiếp theo, hình ảnh đã làm mịn được lọc bằng nhân Sobel theo cả hướng ngang và dọc. Từ hai hình ảnh này, chúng ta có thể tìm thấy độ dốc và hướng của cạnh cho mỗi pixel. Hướng của độ dốc (gradient) luôn vuông góc với các cạnh và được làm tròn thành một trong bốn góc đại diện cho các hướng dọc, ngang và hai đường chéo.

- Loại bỏ các pixel không thuộc về cạnh trong hình ảnh: Sau khi nhận được độ lớn và hướng của gradient, quá trình quét toàn bộ hình ảnh được thực hiện để loại bỏ bất kỳ pixel nào có thể không tạo thành cạnh. Xem ví minh họa ở hình dưới đây:

 

 

Điểm A nằm trên cạnh (theo phương thẳng đứng). Gradient hướng vuông góc với cạnh. Điểm B và C theo hướng gradient. Điểm A được kiểm tra với điểm B và C để xem nó có tạo thành cực đại cục bộ hay không. Nếu đúng, nó được xem xét cho bước tiếp theo, nếu không, nó sẽ bị loại bỏ (gán giá trị 0). Kết quả sau cùng nhận được là một hình ảnh nhị phân với “các cạnh mỏng”.

- Ngưỡng phân loại cạnh: Bước này quyết định xem đâu thực sự là cạnh và đâu không phải. Để thực hiện bước này, chúng ta cần hai giá trị ngưỡng: minVal và maxVal. Bất kỳ cạnh nào có gradient cường độ lớn hơn maxVal chắc chắn là cạnh và những cạnh dưới minVal chắc chắn không phải là cạnh, do đó, sẽ bị loại bỏ. Nằm giữa hai ngưỡng này được phân loại các cạnh hoặc không phải cạnh dựa trên khả năng kết nối của chúng. Nếu chúng được kết nối với các pixel “chắc chắn”, chúng được coi là một phần của các cạnh. Nếu không, chúng cũng bị loại bỏ. Xem hình ảnh minh họa bên dưới:

 

 

Cạnh A nằm trên maxVal, do đó được coi là “cạnh chắc chắn”. Mặc dù cạnh C nằm dưới maxVal, nhưng nó được nối với cạnh A, vì vậy đó cũng được coi là cạnh hợp lệ và chúng ta có được đường cong đầy đủ của cạnh. Nhưng cạnh B, mặc dù nó nằm trên minVal và nằm trong cùng vùng với cạnh C, nhưng nó không được kết nối với bất kỳ “cạnh chắc chắn” nào, vì vậy nó sẽ bị loại bỏ. Như vậy, điều rất quan trọng là chúng ta phải chọn minVal và maxVal cho phù hợp để có kết quả chính xác.

Bước này cũng cho phép loại bỏ pixel nhiễu nhỏ với giả định rằng các cạnh là các đường dài. Kết quả cuối cùng nhận được là các cạnh rõ nét trong hình ảnh.

2. Thực hành phát hiện cạnh trong OpenCV

OpenCV đưa tất cả những điều trên trong một hàm duy nhất: cv2.Canny().

Cú pháp: cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradient)

Chúng ta sẽ xem cách sử dụng nó. Đối số đầu tiên là hình ảnh đầu vào, đối số thứ hai và thứ ba lần lượt là minVal và maxVal. Đối số thứ tư là kích thước của nhân Sobel được sử dụng để tìm độ dốc hình ảnh, theo mặc định là 3. Đối số cuối cùng, L2gradient chỉ định phương trình tìm độ lớn gradient. Xem ví dụ đoạn code bên dưới:

  1. import cv2
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. img = cv2.imread('Lampard.jpg', 0)
  5. edges = cv2.Canny(img, 100, 200)
  6. plt.subplot(121), plt.imshow(img, cmap = 'gray')
  7. plt.title('Original Image'), plt.xticks([]), plt.yticks([])
  8. plt.subplot(122), plt.imshow(edges, cmap = 'gray')
  9. plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
  10. plt.show()

Kết quả:

 

 Ở phần tiếp theo chúng ta sẽ tìm hiểu cách tìm và vẽ các đường viền trong hình ảnh.

 

(Sưu tầm)
VIỆN IMC
Tòa nhà IMC Tower, Số 176 Trường Chinh, Phường Khương
Thượng, Quận Đống Đa, Thành phố Hà Nội, Việt Nam
Tel/Fax : (+84) 24 3566 6232 / 24 3566 6234
Email: contact@imc.org.vn   Website: https://imc.org.vn