Vẽ hình với OpenCV

Công nghệ

Ở bài trước, bạn đọc hẳn đã nắm được cách tương tác cơ bản với ảnh, đơn giản hơn là tương tác các phần tử trong mảng, ma trận. Nhắc lại một chút, ta có ma trận a = [2, 1, 4, 5] có phần tử: a[0] = 2, a[1] = 1, a[2] = 4, a[3] = 5 do chỉ số phần tử bắt đầu từ 0. Ngoài ra, ta có thể chọn nhiều phần tử a[0:3] = [2,1,4], hay tạo hình chữ nhật, hình vuông như ở bài viết trước. Tuy nhiên, làm thế nào để ta có thể vẽ đường thẳng, hoặc đường tròn khi mà thư viện Numpy không hỗ trợ chúng ta? Dễ dàng thay, OpenCV đã hộ trợ thuận tiện cho người dùng qua các hàm vẽ hình khối. Trong bài viết này, bạn đọc cùng tôi sẽ tìm hiểu ba phương thức vẽ hình đơn giản lần lượt là: cv2.line (vẽ đường thẳng), cv2.rectangle (vẽ đa giác), và cv2.circle (vẽ đường tròn)

1.Vẽ đường thẳng và đa giác

Để có thể bắt đầu vẽ đường thẳng, hay đa giác sử dụng OpenCV thì trước hết chúng ta cần định nghĩa khung giới hạn. Bạn đọc có thể tưởng tượng như quá trình chúng ta vẽ một bức tranh thì trước đó ta cần chuẩn bị giấy mực và khung cố định. Ở đây, bút và mực là các hàm hỗ trợ trong OpenCV còn khung tranh là cửa sổ ta định nghĩa khi khởi tạo. Ở các bài học trước, chúng ta đã đọc ảnh trực tiếp từ tệp có sẵn, tuy nhiên, ta cũng có thể tạo một bức ảnh cho riêng mình bằng việc xuất phát từ định nghĩa khung bằng cách sử dụng định nghĩa mảng trong Numpy. Bạn đọc tham khảo mã nguồn sau:

Bạn đọc hẳn đã quen với ngôn ngữ lập trình Python, ở dòng 1-2 ta thực hiện khai báo thư viện sử dụng gồm numpy và opencv, trong đó numpy có thể sử dụng qua cách viết tắt là np. Dòng 4 thực hiện khởi tạo khung tranh có kích thước là 300 dòng và 300 cột cùng 3 kênh màu RGB. Bên cạnh đó, np.zeros khởi tạo một mảng có giá trị ban đầu là 0. Như vậy, chúng ta đã tạo ra một bức ảnh có độ phân giải 300×300 được tạo thành từ các số 0.

Nhắc lại một chút, ở dòng 5 mình chọn thay đổi giá trị bức ảnh ở diện tích 100×100 đầu tiên từ giá trị 0 thành 255, thu được kết quả như sau:

Ta có thể thấy rằng, hình vuông 100×100 nằm trong khung 300×300 có màu trắng có giá trị là 255 và phần còn lại trong khung có giá trị là 0. Bên cạnh đó, bạn đọc nên chú ý phương thức khởi tạo ma tận np.zeros: gồm có kiểu dữ liệu viết là dtype. Khi chúng ta xử lý ảnh với ảnh là RGB và giá trị điểm ảnh trong khoảng [0, 255], kiểu dữ liệu được khai báo là uint8 – ta dùng 8-bit số nguyên để biểu diễn. Ngoài ra còn có rất nhiều kiểu dữ liệu khác có thể tùy chọn sử dụng (32-bit nguyên, 32-bit hoặc 64-bit số thực), nhưng trong các ví dụ sắp tới, chúng ta sẽ chủ yếu sử dụng uint8.

Sau khi khởi tạo khung thành công, chúng ta bắt đầu những hình vẽ đầu tiên với xuất phát từ việc tạo ra một đường thẳng:

Ở dòng 5 và dòng 9, ta định nghĩa 2 màu là xanh và đỏ để tạo màu cho đường thẳng ta định vẽ. Tiếp đó, ta vẽ đường màu xanh với điểm bắt đầu có tọa độ là (0,0) và điểm kết thúc có tọa độ là (300,300). Ta nhận thấy rằng hàm cv2.line nhận vào các tham số: khung, tạo độ điểm bắt đầu, tọa độ điểm kết thúcmàu sắc và độ dày của đường thẳng. Kết quả thu được:

Như vậy, bạn đọc đã nắm được cách vẽ đường thẳng vô cùng đơn giản cùng OpenCV. Chúng ta sẽ tiếp tục với vẽ đa giác qua hàm cv2.rectangle

Để có thể vẽ đa giác, ở dòng 15, phương thức cv2.rectangle nhận vào các tham số lần lượt là: khung, tọa độ bắt đầu, tọa độ kết thúc, màu sắc sử dụng và cuối cùng là độ dày viền. Tọa độ bắt đầu của đa giác là (10,10), kết thúc là (60,60) ta thu được đa giác có 50×50 điểm ảnh. Ngoài ra, với độ dày là -1, hàm cv2.rectangle sẽ tạo đa giác với toàn bộ diện tích theo màu được định nghĩa

Mã nguồn đầy đủ cho phần vẽ đường thẳng và đa giác:

2.Vẽ đường tròn

Chúng ta sẽ bắt đầu vẽ đường tròn bằng cách khởi tạo khung nền đen mới như sau:

Ở dòng 29, ta định nghĩa cX, xY đại diện cho tọa độ (x,y) trung tâm của khung ảnh. Bạn đọc tìm được tâm của bức ảnh đơn giản qua việc chia đôi chiều dài và chiều rộng của khung khởi tạo, ta sẽ có tọa độ trung tâm, trong đó khung.shape[1] là chiều ngang và khung.shape[0] là chiều dọc. Tiếp đó, ta định nghĩa màu trắng để lên màu cho đường tròn định vẽ. Ở dòng 32, bạn đọc thấy vòng lặp từ 0 tới 175 với bước nhảy 25 mỗi vòng. Hàm cv2.circle dòng 36 nhận vào các tham số: khung, tọa độ tâm đường tròn, bán kính và màu sắc. Bán kính tăng lên qua mỗi vòng lặp, ta thu được kết quả:

Với ba giá trị: bán kính, tọa độ và màu sắc, hẳn bạn đọc đã có thể tự vẽ cho bản thân một hay nhiều đường tròn. Sau đây, chúng ta sẽ cùng nhau thử sáng tạo nghệ thuật bằng cách tạo ra ngẫu nhiên các đường tròn

Ở dòng 38, chúng ta lặp 10 lần, có nghĩa là ta sẽ vẽ 10 đường tròn ngẫu nhiên có giá trị nguyên ngẫu nhiên sinh bởi hàm np.random.randint. Trong đó, bán kính ngẫu nhiên nằm ở khoảng giá trị [5,200] – dòng 39. Màu sắc ngẫu nhiên – dòng 37, như chúng ta đã biết thì một điểm ảnh RGB bao gồm 3 giá trị trong khoản [0,255]. Và để sinh 3 giá trị ngẫu nhiên, từ khóa size=(3,) sẽ hướng dẫn Numpy trả về 3 giá trị nguyên ngẫu nhiên. Cuối cùng là tọa độ ngẫu nhiên của đường tròn trong khoảng [0,300]. Bên cạnh đó, giá trị -1 trong hàm vẽ cv2.circle tô toàn bộ diện tích đường tròn với màu chỉ định. Tác phẩm nghệ thuật mà chúng ta thu được:

Như vậy, sau bạn đọc đã nắm được một số thao tác cơ bản để có thể tự tương tác với một bức ảnh, hay tạo ra chúng. Ở bài học tiếp, chúng ta sẽ cùng nhau đi tìm hiểu các phép xử lý ảnh cùng những ứng dụng thú vị mà các phép toán này đem lại.