So sánh cv và cv2 trong python năm 2024

Hello mọi người, trong bài viết này mình sẽ giới thiệu với các bạn một kỹ thuật object detection mà không sử dụng machine learning mang tên Template Matching.

Template matching cho phép chúng ta phát hiện vật thể trong ảnh đầu vào bằng cách sử dụng một ảnh tham chiếu (template) chứa vật thể cần phát hiện. Cách thuật toán hoạt động:

  • Trượt ảnh template trên ảnh đầu vào (giống tích chập 2D)
  • Ảnh template sẽ được so sánh với cửa sổ trượt tương ứng trên ảnh đầu vào bằng một công thức. Một số phương pháp so sánh được hỗ trợ trong opencv được cho ở hình dưới

So sánh cv và cv2 trong python năm 2024

Trong bảng trên, TT là ảnh template, II là ảnh đầu vào. Khi ta trượt ảnh template trên ảnh đầu vào, một metric sẽ được tính toán tại mỗi pixel của ma trận đầu ra RR. Ma trận RR sẽ có kích thước nhỏ hơn ảnh đầu vào (giống với kết quả khi thực hiện tích chập). Giá trị mỗi pixel của RR biểu diễn mức độ trùng khớp của ảnh template với vị trí tương ứng trên ảnh đầu vào. Từ đó, ta có thể chọn ra pixel có giá trị cao nhất (nếu muốn detect 1 vật thể) hoặc lấy threshold RR (nếu detect nhiều vật thể).

Ưu điểm:

  • Nhanh, đơn giản
  • Không tốn công làm data

Nhược điểm

  • Template phải rất giống với vật thể trong ảnh cả về kích thước độ nghiêng, ... Nếu khác biệt quá lớn sẽ không phát hiện được.

Template matching trong opencv

Đầu tiên các bạn cài đặt opencv đã nhé

pip install opencv-contrib-python

Opencv cung cấp sẵn hàm cv2.matchTemplate() cho thuật toán template matching. Hàm này nhận vào 3 tham số chính

  • Ảnh đầu vào input chứa vật thể cần detect
  • Ảnh template temp1
  • method: cách tính ma trận output RR

Để minh họa chạy thuật toán, ta sẽ cần 1 ảnh đầu vào và 1 ảnh template. Ở đây mình sẽ dùng 2 ảnh này. Ảnh template đã được mình crop ra từ 1 vùng của ảnh đầu vào để cho kết quả tốt nhất

So sánh cv và cv2 trong python năm 2024

So sánh cv và cv2 trong python năm 2024

Đầu tiên ta import các thư viện và đọc ảnh vào

import cv2 
import matplotlib.pyplot as plt
def imshow(img, figsize=(6, 6)):
    fig, ax = plt.subplots(1, 1, figsize=(figsize))
    ax.axis('off')
    ax.imshow(img)
img = cv2.imread('spade.png')

# Convert to grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('template.png', 0)
w, h = template.shape[1], template.shape[0]
imshow(img)

Tiếp theo, ta gọi hàm cv2.matchTemplate() với

import cv2 
import matplotlib.pyplot as plt
def imshow(img, figsize=(6, 6)):
    fig, ax = plt.subplots(1, 1, figsize=(figsize))
    ax.axis('off')
    ax.imshow(img)
img = cv2.imread('spade.png')

# Convert to grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('template.png', 0)
w, h = template.shape[1], template.shape[0]
imshow(img)

0 và

import cv2 
import matplotlib.pyplot as plt
def imshow(img, figsize=(6, 6)):
    fig, ax = plt.subplots(1, 1, figsize=(figsize))
    ax.axis('off')
    ax.imshow(img)
img = cv2.imread('spade.png')

# Convert to grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('template.png', 0)
w, h = template.shape[1], template.shape[0]
imshow(img)

1

res = cv2.matchTemplate(img_gray,template, cv2.TM_CCOEFF_NORMED)
imshow(res)

So sánh cv và cv2 trong python năm 2024

Ở trên mình visualize ma trận output RR. Những vị trí sáng hơn là những vị trí có độ tương đồng cao với ảnh template. Tiếp theo ta lấy threshold để lọc ra những vị trí này

THRESHOLD = 0.95
loc = np.where(res >= THRESHOLD)

# Draw boudning box
for y, x in zip(loc[0], loc[1]):
    cv2.rectangle(img, (x, y), (x + w, y + h), (255,0,0), 1)
imshow(img)

Và kết quả là:

So sánh cv và cv2 trong python năm 2024

Trông rất tốt đúng không nào! Nếu các bạn muốn phát hiện thêm những hình quân bích ở dưới thì có thể hạ threshold xuống, và tất nhiên các trường hợp false positive cũng sẽ tăng theo.

THRESHOLD = 0.6
loc = np.where(res >= THRESHOLD)

# Draw boudning box
for y, x in zip(loc[0], loc[1]):
    cv2.rectangle(img, (x, y), (x + w, y + h), (255,0,0), 1)
imshow(img)

So sánh cv và cv2 trong python năm 2024

Lý do có nhiều các đường bao dày lên như vậy là do có nhiều bounding box bị vẽ đè lên nhau. Để loại bỏ bớt các bạn có thể sử dụng thuật toán như Non Maximum Suppression. Và thật may mắn khi có bài viết rất hay về chủ đề này tại đây của tác giả Lê Minh Chiến.