การ Object Tracking with Mean shift Algorithms using OpenCV
Tags: ai, machinelearning
Published: 2024-04-14 08:54:19

ถ้าเราต้องการ tracking วัตถุจาก video หนึ่งในวิธีที่เหมาะสมที่ใช้สำหรับการ tracking ข้อมูลแบบนี้ คือ การใช้ Mean shift  Algorithms using OpenCV

บทความนี้ จะดูเกี่ยวกับ Object Tracking ใน Python โดยเราจะใช้ visual studio code ในการรันโค้ด โดย dataset ที่เราจะใช้เป็นตัวอย่างคือ example-video ซึ่งเป็นข้อมูล mp4 ได้มาจาก siromer จาก github
link:
https://github.com/siromermer/Object-Tracker-Meanshift-Camshift-Algorithm

## **ขั้นตอนที่ 1 นำเข้าข้อมูล**

```
import cv2
import numpy as np 
 
"""
    How it works ? 
    when user run this script there is gonna be screen that displays first frame of video , by pressing mouse right  button user defines first point pair and after one more press to
    right button user defines second point , and there is gonna be rectangle created by this point 
    program tries to track this rectangle , if image inside of that rectangle is contains one color , program  runs more accurately 
    after defining rectangle press esc key and video will be shown to you
    there is 6 color option for now : red , orange,yellow,green,blue,violet
"""


# STEP 1 : User choices object with rectangle from first frame of video  , press mouse right button for first point pair and same button for second point pair

# path to video  
video_path="Hiphop.mp4"  # yellow.mp4 ve "plane.mp4" , helicopter.mp4
video = cv2.VideoCapture(video_path)

# read only first frame for drawing rectangle for desired object
ret,frame = video.read()

#  i am giving  big random numbers for x_min and y_min because if you initialize them as zeros whatever coordinate you go minimum will be zero 
x_min,y_min,x_max,y_max=36000,36000,0,0
 

# function for choosing min and max coordinates 
def coordinat_chooser(event,x,y,flags,param):
    global go , x_min , y_min, x_max , y_max

    # when you click right button it is gonna give variables some coordinates
    if event==cv2.EVENT_RBUTTONDOWN:
        
        # if current coordinate of x lower than the x_min it will be new x_min , same rules apply for y_min 
        x_min=min(x,x_min) 
        y_min=min(y,y_min)

         # if current coordinate of x higher than the x_max it will be new x_max , same rules apply for y_max
        x_max=max(x,x_max)
        y_max=max(y,y_max)

        # draw rectangle
        cv2.rectangle(frame,(x_min,y_min),(x_max,y_max),(0,255,0),1)


    """
        if you didnt like your rectangle (maybe if you did some misscliks) ,  reset coordinates with middle button of your mouse
        if you press middle button of your mouse coordinate will reset and you can give new 2 point pair for your rectangle
    """
    if event==cv2.EVENT_MBUTTONDOWN:
        print("reset coordinate  data")
        x_min,y_min,x_max,y_max=36000,36000,0,0


cv2.namedWindow('coordinate_screen')
# Set mouse handler for the specified window , in this case "coordinate_screen" window
cv2.setMouseCallback('coordinate_screen',coordinat_chooser)


while True:
    cv2.imshow("coordinate_screen",frame) # show only first frame 
    
    k = cv2.waitKey(5) & 0xFF # after drawing rectangle press esc   
    if k == 27:
        break
```
ตัวอย่างผลที่ได้จาก code

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/131xxpsn3pg4g5vpb1cb.png)
เป็นการนำข้อมูลเข้ามาโดยจะสร้างเฟรมเพิ่มมา และ สร้างกรอบจากการกด คลิ๊กขวาเพื่อไปใช้คำนวนต่อ

## **ขั้นตอนที่ 2 หาสีภายในพื้นที่กรอบสี่เหลี่ยมอยู่**

```
# STEP 2 : Program finds color of object that user choose  

# inside of rectangle that user draw 
object_image=frame[y_min:y_max,x_min:x_max,:]

hsv_object=cv2.cvtColor(object_image,cv2.COLOR_BGR2HSV)    

# cx and cy are center of rectangle that user choose 
height, width, _ = hsv_object.shape
cx = int(width / 2)
cy = int(height / 2)

# take center pixel to find out which color of rectangle
pixel_center = hsv_object[cy, cx]
hue_value = pixel_center[0] # axis 0 is hue values 

# from hue_value find color
color =str()
if hue_value < 5:
    color = "red"
elif hue_value < 22:
    color = "orange"
elif hue_value < 33:
    color = "yellow"
elif hue_value < 78:
    color = "green"
elif hue_value < 131:
    color = "blue"
elif hue_value < 170:
    color = "violet"
else:
    color = "red"


# hue dict 
hue_dict={ "red":[[[0, 100, 100]],[10, 255, 255]],
           "orange":[[10, 100, 100],[20, 255, 255]],
           "yellow":[[20, 100, 100],[30, 255, 255]],
           "green":[[50, 100, 100],[70, 255, 255]],
           "blue":[[110,50,50],[130,255,255]],
           "violet":[[140, 50, 50],[170, 255, 255]]}

# find upper and lower  bound of image's color
lower_bound , upper_bound = np.asarray(hue_dict[color][0]) , np.asarray(hue_dict[color][1]) # lower and upper bound sequentially

print(f"detected color : {color}" )
```
เป็นการหาสีภายในกรอบสี่เหลี่ยม

## **ขั้นตอนที่ 3 Tracking  object**

```
# STEP 3 : Tracking  object 

# this time display all video  , not just first frame (in first part only first frame displayed in screen because user was choosing object by drawing rectangle)   
video=cv2.VideoCapture(video_path)

# we need first frame for creating roi(region of interest)
ret,cap = video.read()

# coordinates that user give with his mouse 
x=x_min
y=y_min
w=x_max-x_min
h=y_max-y_min

track_window = (x, y, w, h)

# set up the ROI for tracking
roi = cap[y:y+h, x:x+w]

hsv_roi =  cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

# use lower_bound and upper_bound  inside of inRange function
mask = cv2.inRange(hsv_roi, lower_bound,upper_bound )
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)

# Setup the termination criteria, either 10 iteration or move by at least 1 pt
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
 
while True:

    ret, frame = video.read()

    cv2.putText(frame,f"detected color : {color}" , (25,25),cv2.FONT_HERSHEY_SIMPLEX ,1,(0,0,255),1)


    if ret == True:
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)

        # apply meanshift to get the new location
        ret, track_window = cv2.meanShift(dst, track_window, term_crit)
        
        # Draw it on image
        x,y,w,h = track_window
        img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2)
        cv2.imshow('img2',img2)
        
        k = cv2.waitKey(30) & 0xff
        if k == 27:
            break


```
ตัวอย่างผลที่ได้จาก code

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cyxuqqp97fx2m565xauh.gif)
ส่วนนี้จะเป็นในส่วนของการติดตามวัตถุ
โดยโค้ดจะวนลูปทำงานจนกว่าผู้ใช้จะกดปุ่ม 'ESC' เพื่อออกจากโปรแกรม และในแต่ละเฟรมจะแสดงสีของวัตถุที่ติดตามได้ด้วยการแสดงข้อความบนเฟรม 

สรุปผล
โดยโค้ดข้างต้นเป็นวาดกรอบสี่เหลี่ยมโดยนำค่าสีจากในกรอบสี่เหลี่ยม ในเฟรมแรกของ video โดยโปรแกรมจะพยายามติดตามสี่เหลี่ยมนี้ในวิดีโอ หากภาพภายในสี่เหลี่ยมนั้นมีเฉพาะสีเดียวกัน โปรแกรมจะทำงานได้แม่นยำมากขึ้น แต่ถ้าหากกรเคลื่อนไหวภายใน video เร็วเกินไปอาจทำให้เกิดคลาดเคลื่อนของการ tranking ได้