Computer Vision

Color-based Object Tracking in Video with CamShift

Xin chào, hôm nay chúng ta sẽ tìm hiểu về Color-based Tracking với OpenCV 3.

SIMPLE COLOR-BASED TRACKING

Chúng ta sẽ tìm hiểu cách tracking đơn giản nhất, sử dụng function cv2.inRange(), cv2.erode() và cv2.dilate().

Đầu tiên, hình ảnh sẽ được chuyển sang hệ màu HSV và nhị phân hóa bởi function cv2.inRange(), sau đó chúng ta sử dụng function cv2.erode() và cv2.dilate() để loại bỏ nhiễu. Cuối cùng chúng ta áp dụng function cv2.findContours().

Function:

thresholded = cv2.inRange(hsvImage, lowThres, highThres)

Trong đó:

  • thresholded – output image đã được nhị phân hóa;
  • hsvImage – input image với hệ màu HSV;
  • lowThres, highThres – khoảng màu được dùng để nhị phân hóa hình ảnh.

Example 1: Simple color-based tracking (OpenCV 3)

import cv2
import numpy as np

camera = cv2.VideoCapture(0)
kernel = np.ones((5,5), dtype="uint8")
colorSet = False

def selectColor(event, x, y, flags, param):
	global colorLower, colorUpper, colorSet

	if event == cv2.EVENT_LBUTTONDOWN:
		color = hsv[y,x]
		colorLower = np.array([color[0]-5, color[1]-10, color[2]-10])
		colorUpper = np.array([color[0]+5, 255, 255])
		colorSet = True
		print(colorLower, colorUpper)

cv2.namedWindow("Tracking")
cv2.setMouseCallback("Tracking", selectColor)

while True:
	global hsv

	grabbed, frame = camera.read()

	if not grabbed:
		continue

	hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
	blurred = cv2.GaussianBlur(hsv, (3,3), 0)

	if colorSet:
		mask = cv2.inRange(hsv, colorLower, colorUpper)

		mask = cv2.erode(mask, kernel, iterations=2)
		mask = cv2.dilate(mask, kernel, iterations=2)

		(_,cnts,_) = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

		if len(cnts) > 0:
			cnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

			rect = np.int32(cv2.boxPoints(cv2.minAreaRect(cnt)))
			cv2.drawContours(frame, [rect], -1, (0,255,0), 2)

			cv2.imshow("Binary", mask)

	cv2.imshow("Tracking", frame)

	if cv2.waitKey(1) & 0xFF == ord("q"):
		break

camera.release()
cv2.destroyAllWindows()

Output:

simpleTracking
Bằng cách click chuột vào một vùng màu sắc bất kỳ, chúng ta có thể nhị phân hóa bức ảnh theo màu sắc đó.

Ở phần tiếp theo chúng ta sẽ tìm hiểu một phương pháp color-based tracking chính xác hơn dựa trên Histogram Backprojection và CamShift algorithm.


COLOR-BASED TRACKING WITH CAMSHIFT

Đầu tiên chúng ta chuyển hình ảnh về hệ màu HSV, sau đó chọn vùng hình ảnh (Range Of Image – ROI) chứa đối tượng cần theo dõi và tính 2D-color histogram của nó ở hệ màu HSV.

Chúng ta áp dụng function cv2.calcBackProject() để tính toán Histogram Backprojection cho toàn bộ bức ảnh. Kết quả nhận được sẽ được đưa vào function cv2.CamShift().

Function:

backproject = cv2.calcBackProject([image], [channels], roiHist, [ranges], scale)

It creates an image of the same size (but single channel) as that of our input image, where each pixel corresponds to the probability of that pixel belonging to our object. In more simpler worlds, the output image will have our object of interest in more white compared to remaining part.

That is, similarly to calcHist , at each location (x, y) the function collects the values from the selected channels in the input images and finds the corresponding histogram bin. But instead of incrementing it, the function reads the bin value, scales it by scale , and stores in backProject(x,y).

Trong đó:

  • image – input image;
  • channels – các kênh màu được dùng để tính toán;
  • roiHist – color histogram của vùng hình ảnh chứa đối tượng cần theo dõi, chú ý: roiHist cần được normalize trước khi được truyền vào calcBackProject function;
  • ranges – khoảng giá trị tương ứng với từng channel, H – [0, 180], S – [0, 255], V – [0, 255];
  • scale – lấy giá trị là 1.

retval, roiBox = cv2.CamShift(backproject, roiBox, termination)

Trong đó:

  • retval – “return value”, được sử dụng để xác định vị trí của đối tương;
  • roiBox – Initial search window, ở dạng (x, y, width, height);
  • termination – điều kiện kết thúc của CamShift algorithm, thường là (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1): khi tâm của đối tượng theo dõi không thay đổi nhiều hơn 1 pixel hoặc khi đã có 10 iterations.

Example 2 – Colored-based Tracking with CamShift

import numpy as np
import argparse
import cv2

frame = None
roiPts = []
inputMode = False

def selectROI(event, x, y, flags, param):
	global frame, roiPts, inputMode

	if inputMode and event == cv2.EVENT_LBUTTONDOWN and len(roiPts) < 4:
		roiPts.append((x,y))
		cv2.circle(frame, (x,y), 4, (0,255,0), -1)
		cv2.imshow("frame", frame)

def main():
	global frame, roiPts, inputMode

	camera = cv2.VideoCapture(0)
	cv2.namedWindow("frame")
	cv2.setMouseCallback("frame", selectROI)

	termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
	roiBox = None

	while True:
		grabbed, frame = camera.read()

		if not grabbed:
			continue

		if roiBox is not None:
			hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
			backProj = cv2.calcBackProject([hsv], [0,1], roiHist, [0,180,0,256], 1)

			cv2.imshow("backProj", backProj)
			(r, roiBox) = cv2.CamShift(backProj, roiBox, termination)
			pts = np.int0(cv2.boxPoints(r))
			cv2.polylines(frame, [pts], True, (0,255,0), 2)

		cv2.imshow("frame", frame)
		key = cv2.waitKey(1) & 0xFF

		if key == ord("i") and len(roiPts) < 4:
			inputMode = True
			orig = frame.copy()

			while len(roiPts) < 4:
				cv2.imshow("frame", frame)
				cv2.waitKey(0)

			roiPts = np.array(roiPts)
			s = roiPts.sum(axis = 1)
			topleft = roiPts[np.argmin(s)]
			botright = roiPts[np.argmax(s)]

			roi = orig[topleft[1]:botright[1], topleft[0]:botright[0]]
			roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

			roiHist = cv2.calcHist([roi], [0,1], None, [32,32], [0,180,0,256])
			roiHist = cv2.normalize(roiHist, roiHist, 0, 255, cv2.NORM_MINMAX)
			roiBox = (topleft[0], topleft[1], botright[0]-topleft[0], botright[1]-topleft[1])

		elif key == ord("q"):
			break

	camera.release()
	cv2.destroyAllWindows()

if __name__ == "__main__":
	main()

Output:

camshift

Trong ví dụ trên chúng ta đã tính 2D-histogram cho hình ảnh ở hệ màu HSV, sau đó tính Histogram Backproject và CamShift.

Kết quả tracking cũng phụ thuộc nhiều vào tham số histSize khi tính toán histogram cho roiHist. Điều chỉnh tham số này phụ thuộc nhiều vào khía cạnh, trong đó bao gồm cả điều kiện ánh sáng. Chúng ta sẽ cần căn chỉnh tham số này cho phù hợp với ứng dụng của mình.

Để bắt đầu, nhấn phím ‘i’ và click 4 điểm trên hình ảnh để chọn đối tượng. Tiếp theo, nhấn một phím bất kỳ và tận hưởng nhé!


KẾT LUẬN

Mặc dù đơn giản nhưng CamShift khá mạnh mẽ cho object tracking, đặc biệt khi chúng ta chỉ xem xét sử dụng Color Histogram.

Cảm ơn các bạn đã theo dõi bài viết.

Thân ái và quyết thắng.

Reference:
[1] Tutorial: Using CamShift to Track Objects in Video.
[2] OpenCV meanShift, camShift, BackProject.
[3] Histogram Backprojection.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s