Contour

- Phạm Duy Tùng
Mình dang làm một số đề tài về xử lý ảnh, và đang muốn áp dụng các thuật toán xử lý ảnh cổ điển (không dùng đến deep learning và machine learning) để giải quyết bài toán của mình. Bài viết này nằm trong seria bài viết của mình về đề tài xử lý ảnh sử dụng các kỹ thuật cơ bản. Bài đầu tiên là giới thiệu về contours và sử dụng opencv để rút ra các contour .

Contour là gì

Các bạn có thể hiểu contour là “tập các điểm-liên-tục tạo thành một đường cong (curve) (boundary), và không có khoảng hở trong đường cong đó, đặc điểm chung trong một contour là các các điểm có cùng /gần xấu xỉ một giá trị màu, hoặc cùng mật độ. Contour là một công cụ hữu ích được dùng để phân tích hình dạng đối tượng, phát hiện đối tượng và nhận dạng đối tượng”.

Để tìm contour chính xác, chúng ta cần phải nhị phân hóa bức ảnh (nhớ là ảnh nhị phân nha các bạn, không phải ảnh grayscale đâu). Các kỹ thuật nhị phân hóa ảnh ở xử lý ảnh cơ bản có thể liệt kê đến là đặt ngưỡng, hoặc candy edge detection. Chúng ta sẽ không bàn kỹ về các cách đặt ngưỡng ( mặc dù có khá nhiều cách đặt ngưỡng, và trong opencv cũng có implement một vài phương pháp, nhưng nó không phải là mục tiêu của bài này, nên mình không đề cập ở đây) hoặc edge detection ở bài viết này, mà chúng ta sẽ đi vào các tìm contours bằng các sử dụng opencv luôn.

Trong opencv, việc tìm một contour là việc tìm một đối tượng có màu trắng trên nền đen. Cho nên, các bạn hãy nhớ rằng hãy set đối tượng thành màu trắng và để nền là màu đen, đừng làm ngược lại nha.

Một lưu ý nhỏ là tại thời điểm mình viết bài viết này, mình sử dụng phiên bản opencv3.6. Các bạn có thể sử dụng phiên bản opencv mới hơn, nhưng có thể những sample code mình để bên dưới sẽ không work, do không tương thích.

Sử dụng contour trong opencv

Opencv hỗ trợ cho chúng ta hàm để tìm contour của một bức ảnh

modifiedImage, contours, hierarchy = cv2.findContours(binaryImage, typeofContour, methodofContour)

Trong đó:

  • contours: Danh sách các contour có trong bức ảnh nhị phân. Mỗi một contour được lưu trữ dưới dạng vector các điểm

  • hierarchy: Danh sách các vector, chứa mối quan hệ giữa các contour.

  • modifiedImage: Ảnh sau khi sử dụng contour, thường chúng ta không xài đối số này

  • binaryImage: Ảnh nhị phân gốc. Một chú ý quan trọng ở đây là sau khi sử dụng hàm findContours thì giá trị của binaryImage cũng thay đổi theo, nên khi sử dụng bạn có thể áp dụng binaryImage.copy() để không làm thay đổi giá trị của binaryImage

  • typeofContour: có các dạng sau: RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE, RETR_FLOODFILL.

  • methodofContour: Có các phương thức sau: CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS.

Ví dụ về các sử dụng hàm


import numpy as np
import cv2

im = cv2.imread('test.jpg') # đọc ảnh màu
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)  # chuyển ảnh màu sang dạng grayscale
ret,thresh = cv2.threshold(imgray,127,255,0) # nhị phân hóa bức ảnh bằng cách đặt ngưỡng, với giá trị của ngưỡng là 127
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) # tìm contour

Opencv hỗ trợ chúng ta hàm để vẽ contor lên bức ảnh, giúp chúng ta nhìn rõ ràng hơn

cv2.drawContours(image, contours, contourIndex, colorCode, thickness)

Với:

  • imgage: ảnh, có thể là ảnh grayscale hoặc ảnh màu.

  • contours: danh sách các contour, là vector, nếu bạn muốn vẽ một contour, thì bạn phải cho nó vào trong một list.

  • contourIndex Vị trí của contor, thông thường chúng ta để -1

  • colorCode: Giá trị màu của contour chúng ta muốn vẽ, ở dạng BGR, nếu bạn muốn vẽ contour màu xanh lá cây thì set là (0,255,0).

  • thickness : độ dày của đường contour cần vẽ, giá trị thickness càng lớn thì đường contor vẽ càng bự

Ví dụ: Đếm số lượng quả bóng bay trong hình

Giả sử chúng ta có bức ảnh Hình ảnh Bong bóng bay

Chúng ta thực hiện tìm contour của ảnh trên bằng cách


import numpy as np
import cv2

im = cv2.imread('colorfull_ballon.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) # chuyển ảnh xám thành ảnh grayscale
thresh = cv2.Canny(imgray, 127, 255) # nhị phân hóa ảnh
_, contours, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

cv2.drawContours(im, contours, -1, (0, 255, 0), 2) # vẽ lại ảnh contour vào ảnh gốc

# show ảnh lên
cv2.imshow("ballons", im)
cv2.waitKey(0)

Kết quả:

Hình ảnh Contour màu xanh là đường curve bao quanh dữ liệu được rút trích được

Cảm ơn các bạn đã theo dõi. Hẹn gặp bạn ở những bài viết tiếp theo.


Bài viết khác
comments powered by Disqus