Thị giác máy tính với OpenCV-Python Bài 4, Phần 12: Đối sánh mẫu

Thị giác máy tính với OpenCV-Python Bài 4, Phần 12: Đối sánh mẫu

Thị giác máy tính với OpenCV-Python Bài 4, Phần 12: Đối sánh mẫu

11:03 - 07/01/2022

Trong phần này chúng ta sẽ cùng tìm hiểu cách tìm ra các đối tượng trong một hình ảnh bằng cách đối sánh mẫu, sử dụng các hàm cv2.matchTemplate() và  cv2.minMaxLoc().

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

Khái niệm

Đối sánh mẫu (hay: So khớp mẫu, Template matching) là phương pháp tìm kiếm hình ảnh mẫu bên trong một hình ảnh lớn hơn. OpenCV cung cấp hàm cv2.matchTemplate() cho mục đích này, trong đó hàm đơn giản là chiếu hình ảnh mẫu lên hình ảnh đầu vào (như trong tích chập 2D) và so sánh mẫu với hình ảnh đầu vào. Kết quả trả về một hình ảnh thang độ xám, trong đó mỗi pixel biểu thị mức độ phù hợp của vùng lân cận của pixel đó với mẫu.

Nếu hình ảnh đầu vào có kích thước (WxH) và hình ảnh mẫu có kích thước (wxh), hình ảnh đầu ra sẽ có kích thước là (W-w + 1, H-h + 1). Sau khi nhận được kết quả, bạn có thể sử dụng hàm cv2.minMaxLoc() để tìm đâu là giá trị lớn nhất/nhỏ nhất, rồi lấy nó làm góc trên bên trái của hình chữ nhật, lấy (w, h) làm chiều rộng và chiều cao của hình chữ nhật. Hình chữ nhật đó là vùng ảnh mẫu cần tìm.

Đối sánh mẫu trong OpenCV

Lấy ví dụ đơn giản, chúng ta sẽ tìm kiếm khuôn mặt của Lampard trong ảnh. Đây là hình ảnh mẫu:

 

Chúng ta sẽ thử tất cả các phương pháp so sánh để xem kết quả của chúng như thế nào:

  1. import cv2
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. img = cv2.imread('Lampard.jpg', 0)
  5. img2 = img.copy()
  6. template = cv2.imread('template.jpg', 0)
  7. w, h = template.shape[::-1]
  8. # All the 6 methods for comparison in a list
  9. methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
  10. 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
  11. for meth in methods:
  12.      img = img2.copy()
  13.      method = eval(meth)
  14.      # Apply template Matching
  15.      res = cv2.matchTemplate(img, template, method)
  16.      min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
  17.      # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
  18.      if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
  19.           top_left = min_loc
  20.      else:
  21.           top_left = max_loc
  22.      bottom_right = (top_left[0] + w, top_left[1] + h)
  23.      cv2.rectangle(img, top_left, bottom_right, 255, 2)
  24.      plt.subplot(121), plt.imshow(res, cmap = 'gray')
  25.      plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
  26.      plt.subplot(122), plt.imshow(img, cmap = 'gray')
  27.      plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
  28.      plt.suptitle(meth)
  29.      plt.show()

Xem kết quả bên dưới:

cv2.TM_CCOEFF: 

 

cv2.TM_CCOEFF_NORMED: 

 

cv2.TM_CCORR: 

 

cv2.TM_CCORR_NORMED: 

 

cv2.TM_SQDIFF: 

 

cv2.TM_SQDIFF_NORMED: 

Có thể thấy rằng kết quả sử dụng cv2.TM_CCORR không tốt như chúng ta mong đợi.

Đối sánh mẫu với nhiều đối tượng

Ở trên khuôn mặt của Lampard chỉ xuất hiện một lần trong hình ảnh. Giả sử bạn đang tìm kiếm một đối tượng xuất hiện nhiều lần, cv2.minMaxLoc() sẽ không cung cấp cho bạn tất cả các vị trí đó. Trong trường hợp này, chúng ta cần sử dụng ngưỡng. Xem ví dụ bên dưới về việc tìm các đồng xu trong hình ảnh:

  1. import cv2
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. img_rgb = cv2.imread('coins.jpg')
  5. img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
  6. template = cv2.imread('template_coin.jpg', 0)
  7. w, h = template.shape[::-1]
  8. res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
  9. threshold = 0.8
  10. loc = np.where( res >= threshold)
  11. for pt in zip(*loc[::-1]):
  12.      cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
  13. cv2.imshow('Result', img_rgb)
  14. cv2.waitKey(0)
  15. cv2.destroyAllWindows()

 Kết quả:

 

 

Ghi chú: Nếu chúng ta giảm giá trị threshold (lấy ví dụ xuống còn 0,5), sẽ có thêm một số đồng xu nữa được phát hiện, tuy nhiên, nếu giảm threshold nhiều hơn nữa sẽ dẫn đến tỉ lệ phát hiện chồng lấn hoặc nhầm tương đối cao.

Ở phần tiếp theo chúng ta sẽ cùng tìm hiểu cách sử dụng Biến đổi Hough để tìm các đường kẻ 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