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

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

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

14:23 - 18/01/2022

Ở phần này chúng ta sẽ tìm hiểu về thuật toán Meanshift và Camshift để tìm và theo dõi các đối tượng trong video.

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 5 Phần 3: Tìm đối tượng thông qua so khớp và phép chiếu hình học

Meanshift

Thuật toán Meanshift có thể được hiểu đơn giản như sau: Giả sử bạn có một tập hợp các điểm (có thể là một dạng phân phối pixel giống như biểu đồ), bạn được cung cấp một cửa sổ nhỏ (có thể là một hình tròn) và bạn phải di chuyển cửa sổ đó đến vùng có mật độ điểm ảnh tối đa (hoặc số điểm tối đa). Xem minh họa trong hình ảnh đơn giản dưới đây:

 

 

Cửa sổ ban đầu được hiển thị trong vòng tròn màu xanh với tên “C1”. Tâm ban đầu của nó được đánh dấu bằng hình chữ nhật màu xanh lam, có tên là “C1_o”. Nếu bạn tìm tâm của các điểm bên trong cửa sổ đó sẽ nhận được kết quả tâm thực sự của các điểm bên trong hình tròn là “C1_r” (được đánh dấu trong vòng tròn nhỏ màu xanh lam). Chắc chắn là hai tâm này không khớp nhau. Do đó, cần di chuyển cửa sổ sao cho vòng tròn của cửa sổ mới khớp với tâm các điểm tìm được trước đó. Một lần nữa tìm centroid mới. Kết quả sẽ tiếp tục không khớp, cần di chuyển cửa sổ một lần nữa và tiếp tục lặp lại sao cho tâm cửa sổ và tâm của các điểm ảnh bên trong nó nằm trên cùng một vị trí (hoặc với một lỗi nhỏ mong muốn). Cuối cùng, những gì bạn nhận được là một cửa sổ có phân phối pixel tối đa. Nó được đánh dấu bằng vòng tròn màu xanh lá cây, được đặt tên là “C2”. Như bạn có thể thấy trong hình, nó có số điểm tối đa.

Meanshift trong OpenCV

Để sử dụng thuật toán meanshift trong OpenCV, trước tiên chúng ta cần thiết lập mục tiêu, tìm biểu đồ của nó để chúng ta có thể dự đoán lại mục tiêu trên mỗi khung hình để tính toán meanshift. Chúng ta cũng cần cung cấp vị trí ban đầu của cửa sổ. Đối với biểu đồ, chỉ có thang màu Hue được xem xét ở đây. Ngoài ra, để tránh các giá trị sai do ánh sáng yếu, các giá trị ánh sáng yếu sẽ bị loại bỏ bằng cách sử dụng hàm cv2.inRange():

  1. import numpy as np
  2. import cv2
  3. cap = cv2.VideoCapture('slow.flv')
  4. # take first frame of the video
  5. ret, frame = cap.read()
  6. # setup initial location of window
  7. r,h,c,w = 200, 30, 300, 80 # simply hardcoded the values
  8. track_window = (c, r, w, h)
  9. # set up the ROI for tracking
  10. roi = frame[r:r+h, c:c+w]
  11. hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
  12.  mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
  13. roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0,180])
  14. cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
  15. # Setup the termination criteria, either 10 iteration or move by atleast 1 pt
  16. term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
  17. while(1):
  18.     ret, frame = cap.read()
  19.     if ret == True:
  20.          hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
  21.          dst = cv2.calcBackProject([hsv], [0], roi_hist, [0,180], 1)
  22.          # apply meanshift to get the new location
  23.          ret, track_window = cv2.meanShift(dst, track_window, term_crit)
  24.          # Draw it on image
  25.          x,y,w,h = track_window
  26.          img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255, 2)
  27.          cv2.imshow('img2', img2)
  28.          k = cv2.waitKey(60) & 0xff
  29.          if k == 27:
  30.               break
  31.          else:
  32.               cv2.imwrite(chr(k) + ".jpg", img2)
  33.     else:
  34.          break
  35. cv2.destroyAllWindows()
  36. cap.release()

Kết quả:

 

 

Camshift

Hãy xem xét kỹ kết quả cuối cùng. Có một vấn đề, đó là cửa sổ luôn có cùng kích thước khi ô tô ở xa hơn hay ở rất gần camera. Điều đó không ổn. Chúng ta cần điều chỉnh kích thước cửa sổ với kích thước và sự quay của mục tiêu. Giải pháp được gọi là CAMshift (Dịch chuyển liên tục thích ứng) do Gary Bradsky năm 1988.

Đầu tiên là áp dụng meanshift. Sau khi meanshift hội tụ, nó sẽ cập nhật kích thước của cửa sổ và tính toán hướng của hình elip phù hợp nhất với nó. Một lần nữa, áp dụng meanshift với cửa sổ tìm kiếm được chia tỷ lệ mới và vị trí cửa sổ trước đó. Quá trình được tiếp tục cho đến khi đáp ứng được độ chính xác yêu cầu.

Camshift trong OpenCV

Camshift gần giống như meanhift, chỉ khác là trả về một hình chữ nhật xoay và các tham số được sử dụng để chuyển làm cửa sổ tìm kiếm trong lần lặp tiếp theo. Xem code bên dưới:

  1. import numpy as np
  2. import cv2
  3. cap = cv2.VideoCapture('slow.flv')
  4. # take first frame of the video
  5. ret, frame = cap.read()
  6. # setup initial location of window
  7. r,h,c,w = 200,30,300,80 # simply hardcoded the values
  8. track_window = (c,r,w,h)
  9. # set up the ROI for tracking
  10. roi = frame[r:r+h, c:c+w]
  11. hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
  12.  mask = cv2.inRange(hsv_roi, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
  13. roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0,180])
  14. cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
  15. # Setup the termination criteria, either 10 iteration or move by atleast 1 pt
  16. term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
  17. while(1):
  18.     ret, frame = cap.read()
  19.     if ret == True:
  20.          hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
  21.          dst = cv2.calcBackProject([hsv], [0], roi_hist, [0,180], 1)
  22.          # apply meanshift to get the new location
  23.          ret, track_window = cv2.CamShift(dst, track_window, term_crit)
  24.          # Draw it on image
  25.          pts = cv2.boxPoints(ret)
  26.          pts = np.int0(pts)
  27.          img2 = cv2.polylines(frame, [pts], True, 255, 2)
  28.          cv2.imshow('img2', img2)
  29.          k = cv2.waitKey(60) & 0xff
  30.          if k == 27:
  31.               break
  32.          else:
  33.               cv2.imwrite(chr(k)+".jpg", img2)
  34.     else:
  35.          break
  36. cv2.destroyAllWindows()
  37. cap.release()

Kết quả:

 

Ở phần tiếp theo chúng ta sẽ cùng tìm hiểu "phép trừ nền" để tách đối tượng chuyển động trong video.

 

 (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