Một số phương pháp xử lý ảnh cơ bản (Phần 3)

Công nghệ

Trong bài học này, chúng ta sẽ tìm hiểu về thao tác bit trên ảnh và ứng dụng của các thao tác này vào kỹ thuật masking – mặt nạ, cho phép chúng ta lọc ra vùng quan trọng, xác định vật thể trong ảnh.

1.Thao tác bit trong xử lý ảnh

Bạn đọc chắc hẳn không hề xa lạ gì khi nhắc tới các phép toán với bit. Trong trường hợp bạn là người mới tìm hiểu, thao tác bit gồm 4 phép toán sau: AND, OR, XOR và NOT. Thao tác bit hoạt động với các phép toán nhị phân gồm hai kết quả là 0, hoặc 1. Chúng ta có thể hình dung với điểm ảnh “tắt” khi giá trị của nó bằng 0, và điểm ảnh “bật” khi giá trị điểm ảnh lớn hơn 0. Chúng ta sẽ bắt đầu tìm hiểu kỹ hơn qua ví dụ sau:

dòng 1-2, ta thực hiện khai báo thư viện sử dụng, bao gồm: opencv và numpy. Tiếp đó, chúng ta khởi tạo một ma trận số 0 có kích thước 300×300 qua dòng 4. Sau đó, ta vẽ một hình vuông màu trắng có kích thước 250×250, (275 – 25 = 250), ở trung tâm bức hình. Hàm vẽ hình này đã được trình bày trong các bài viết hướng dẫn vẽ hình. Chúng ta thực hiện tương tự khi vẽ hình tròn ở dòng 8-10. Kết quả của đoạn mã:

Nhắc lại một chút về phép toán trên bit, bạn đọc có thể theo dõi qua bảng kết quả sau:

AND OR XOR
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

 

NOT
0 1
1 0

 

Ở phần tiếp sau đây, chúng ta sẽ sử dụng ví dụ phía trên về hình vuông và hình tròn để thực hiện các phép toán bit

Như mình đã đề cập ở trên, điểm ảnh “bật” nếu nó có giá trị lớn hơn 0, và “tắt” khi giá trị bằng 0. Các hàm tính bit trong opencv thực hiện dựa trên các điều kiện này. Để có thể thực hiện phép tính bit, ta giả định (phần lớn trường hợp) thực hiện qua việc so sánh hai điểm ảnh (ngoại lệ duy nhất ở phép NOT). Chúng ta sẽ so sánh mỗi điểm ảnh và thực hiện biểu diễn bit như sau:

+AND: trả về là đúng – true, nếu cả hai giá trị điểm ảnh đều lớn hơn 0

+OR: trả về là đúng – true, nếu một trong hai giá trị điểm ảnh lớn hơn 0

+XOR: trả về là đúng – true, khi một trong hai giá trị điểm ảnh lớn hơn không, không bao gồm cả hai.

+NOT: thực hiện đảo ngược giá trị “bật” và “tắt” điểm ảnh

dòng 11, ta thực hiện hàm cv2.bitwise_and, phép AND giữa hình vuông và hình tròn. Như vậy, hàm này trả về là đúng khi và chỉ khi cả hai giá trị điểm ảnh đều lớn hơn 0. Kết quả bạn đọc có thể theo dõi qua hình dưới với cửa sổ AND. Chúng ta thấy rằng là các góc của hình vuông mất đi, thay thế bằng đường tròn – 0 AND 0 = 0. Kế đó là phép OR với kết quả thu được là hình vuông và hình tròn màu trắng kết hợp lại với nhau. Hai phép toán còn lại, bạn sẽ theo dõi được qua kết quả dưới đây:

 

2.Kỹ thuật mặt nạ – masking

Trong phần tìm hiểu phía trên, chúng ta đã cùng nhau tìm hiểu các hàm thao tác bit. Bây giờ, chúng ta đã sẵn sàng đi vào kỹ thuật masking – một kỹ thuật đơn giản mà vô cùng hiệu quả, phổ biến trong xử lý ảnh. Sử dụng mặt nạ cho phép chúng ta chú ý duy nhất vào một vùng trên bức ảnh. Để có thể dễ dàng hình dung hơn, hãy giả sử rằng bạn đọc muốn xây dựng một hệ thống nhận diện khuôn mặt. Vùng trên ảnh mà chúng ta muốn thu được chính là vùng chứa khuôn mặt. Do đó, việc xây dựng một mặt nạ – mask, cho phép ta hiển thị duy nhất hình ảnh khuôn mặt. Chúng ta sẽ đi vào chi tiết hơn qua ví dụ sau:

Với bức ảnh ở góc trên cùng bên trái, bạn đọc có thể thấy rằng có khá nhiều vật thể, khung cảnh diễn ra. Tuy nhiên, mình chỉ muốn lấy ra tổng quan nội dung như căn nhà cổ cùng một vài cây hoa phượng. Chúng ta có thể dễ dàng sử dụng phương pháp cắt ảnh ở bài học trước để trích xuất ra khu vực này, hoặc, chúng ta có thể sử dụng mặt nạ vào đây.

Bức ảnh trên cùng phía bên phải là mặt nạ mà mình sẽ sử dụng – hình vuông trắng ở giữa ảnh. Bằng cách sử dụng mặt nạ, chúng ta sẽ thu được bức ảnh ở phía dưới bao gồm ngôi nhà cũ kèm theo một ít hoa phượng.

Chúng ta sẽ cùng nhau xem xét đoạn mã sau đây:

Dòng 1-13, ta thực hiện các thao tác quen thuộc: khai báo thư viện, định nghĩa tham số truyền vào, và hiển thị bức ảnh.

Tiếp đó, chúng ta tạo một mặt nạ – mask, với kích thước như bức ảnh truyền vào – dòng 15. Để có thể vẽ được hình vuông, trước hết chúng ta cần tính tọa độ tâm của hình ảnh đầu vào bằng cách chia đôi chiều ngang và chiều dọc qua dòng 16. Cuối cùng, ta vẽ tứ giác ở dòng 17.

Bạn đọc nhớ lại hàm bitwise_and ở phần 1, đây là một hàm được sử dụng thường xuyên khi chúng ta đặt mặt nạ vào bức ảnh cần xử lý – thực hiện tại dòng 21. Phép AND trả về là true – đúng, với tất cả giá trị trong ảnh gốc, tuy nhiên, phần quan trọng là từ khóa mask. Bằng cách sử dụng từ khóa mask, cv2.bitwise_and sẽ xử lý điểm ảnh “bật” trong mặt nạ – trong ví dụ là phần hình vuông màu trắng trong mặt nạ. Chúng ta sẽ theo dõi thêm một ví dụ nữa tương tự khi thay phần “bật” trong mặt nạ thành hình tròn:

Như vậy, ảnh thu được sau khi áp dụng mặt nạ có thể là đa giác, mà cũng có thể là hình tròn tùy theo việc bạn đọc cài đặt điểm “bật” trong mặt nạ. Kỹ thuật này hiện tại có vẻ không thú vị lắm so với việc ta có thể sử dụng ngay phương pháp cắt ảnh, tuy nhiên bạn đọc sẽ quay lại đây khi chúng ta bàn luận tới histograms. Các điểm quan trọng trong mặt nạ giúp việc tính toán vào vùng mà chúng ta chọn lựa dễ dàng hơn rất nhiều ở các bài học tiếp theo.