Python single target, multi-target, multi-scale, user-defined characteristics of the KCF tracking algorithm (example code)

Time:2021-6-16

Single target tracking:

Directly call the tracker encapsulated in OpenCV.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 5 17:50:47 2020
Chapter 4 KCF tracking
@author: youxinlin
"""
import cv2
from items import MessageItem
import time
import numpy as np
'''
Monitor module, responsible for intrusion detection, target tracking
'''
class WatchDog(object):
 #Intrusion detector module, for intrusion detection
 def __init__(self,frame=None):
  #Motion detector constructor
  self._background = None
  if frame is not None:
   self._background = cv2.GaussianBlur(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY),(21,21),0)
  self.es = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
 def isWorking(self):
  #Does the motion detector work
  return self._background is not None
 def startWorking(self,frame):
  #The motion detector is working
  if frame is not None:
   self._background = cv2.GaussianBlur(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), (21, 21), 0)
 def stopWorking(self):
  #The motion detector is finished
  self._background = None
 def analyze(self,frame):
  #Motion detection
  if frame is None or self._background is None:
   return
  sample_frame = cv2.GaussianBlur(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY),(21,21),0)
  diff = cv2.absdiff(self._background,sample_frame)
  diff = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)[1]
  diff = cv2.dilate(diff, self.es, iterations=2)
  image, cnts, hierarchy = cv2.findContours(diff.copy(),cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  coordinate = []
  bigC = None
  bigMulti = 0
  for c in cnts:
   if cv2.contourArea(c) < 1500:
    continue
   (x,y,w,h) = cv2.boundingRect(c)
   if w * h > bigMulti:
    bigMulti = w * h
    bigC = ((x,y),(x+w,y+h))
  if bigC:
   cv2.rectangle(frame, bigC[0],bigC[1], (255,0,0), 2, 1)
  coordinate.append(bigC)
  message = {"coord":coordinate}
  message['msg'] = None
  return MessageItem(frame,message)
class Tracker(object):
 '''
 Tracker module, used to track the specified target
 '''
 def __init__(self,tracker_type = "BOOSTING",draw_coord = True):
  '''
  Initialize tracker type
  '''
  #Get opencv version
  (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
  self.tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN']
  self.tracker_type = tracker_type
  self.isWorking = False
  self.draw_coord = draw_coord
  #Construct tracker
  if int(minor_ver) < 3:
   self.tracker = cv2.Tracker_create(tracker_type)
  else:
   if tracker_type == 'BOOSTING':
    self.tracker = cv2.TrackerBoosting_create()
   if tracker_type == 'MIL':
    self.tracker = cv2.TrackerMIL_create()
   if tracker_type == 'KCF':
    self.tracker = cv2.TrackerKCF_create()
   if tracker_type == 'TLD':
    self.tracker = cv2.TrackerTLD_create()
   if tracker_type == 'MEDIANFLOW':
    self.tracker = cv2.TrackerMedianFlow_create()
   if tracker_type == 'GOTURN':
    self.tracker = cv2.TrackerGOTURN_create()
 def initWorking(self,frame,box):
  '''
  Tracker work initialization
  Frame: initialize tracking screen
  Box: tracking area
  '''
  if not self.tracker:
   Raise exception ("tracker not initialized")
  status = self.tracker.init(frame,box)
  if not status:
   raise Exception("Tracker work initialization失败")
  self.coord = box
  self.isWorking = True
 def track(self,frame):
  '''
  Turn on tracking
  '''
  message = None
  if self.isWorking:
   status,self.coord = self.tracker.update(frame)
   if status:
    message = {"coord":[((int(self.coord[0]), int(self.coord[1])),(int(self.coord[0] + self.coord[2]), int(self.coord[1] + self.coord[3])))]}
    if self.draw_coord:
     p1 = (int(self.coord[0]), int(self.coord[1]))
     p2 = (int(self.coord[0] + self.coord[2]), int(self.coord[1] + self.coord[3]))
     cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
     message['msg'] = "is tracking"
  return MessageItem(frame,message)
class ObjectTracker(object):
 def __init__(self,dataSet):
  self.cascade = cv2.CascadeClassifier(dataSet)
 def track(self,frame):
  gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
  faces = self.cascade.detectMultiScale(gray,1.03,5)
  for (x,y,w,h) in faces:
   cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2)
  return frame
if __name__ == '__main__' :
# tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN']
 tracker = Tracker(tracker_type="KCF")
# video = cv2.VideoCapture(0)
# video = cv2.VideoCapture("complex1.mov")
 video = cv2.VideoCapture(r"/Users/youxinlin/Desktop/video_data/complex1.MOV") 
 ok, frame = video.read()
 bbox = cv2.selectROI(frame, False)
 tracker.initWorking(frame,bbox)
 while True:
  _,frame = video.read();
  if(_):
   item = tracker.track(frame);
   cv2.imshow("track",item.getFrame())
   k = cv2.waitKey(1) & 0xff
   if k == 27:
    break

With items.py, put it in the same folder:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 5 17:51:04 2020
@author: youxinlin
"""
import json
from utils import IOUtil
'''
Information encapsulation
'''
class MessageItem(object):
 #Class used to encapsulate information, including pictures and other information
 def __init__(self,frame,message):
  self._frame = frame
  self._message = message
 def getFrame(self):
  #Picture information
  return self._frame
 def getMessage(self):
  #Text message, JSON format
  return self._message
 def getBase64Frame(self):
  #Return the image in Base64 format and convert BGR image into RGB image
  jepg = IOUtil.array_to_bytes(self._frame[...,::-1])
  return IOUtil.bytes_to_base64(jepg)
 def getBase64FrameByte(self):
  #Returns the bytes of Base64 format image
  return bytes(self.getBase64Frame())
 def getJson(self):
  #Get JSON data format
  dicdata = {"frame":self.getBase64Frame().decode(),"message":self.getMessage()}
  return json.dumps(dicdata)
 def getBinaryFrame(self):
  return IOUtil.array_to_bytes(self._frame[...,::-1])

Utils.py: also in the same folder.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 5 17:51:40 2020
@author: youxinlin
"""
import time
import numpy
import base64
import os
import logging
import sys
from PIL import Image
from io import BytesIO
#Tools
class IOUtil(object):
 #Stream operation tool class
 @staticmethod
 def array_to_bytes(pic,formatter="jpeg",quality=70):
  '''
  Static method, the numpy array into a binary stream
  : parampic: numpy array
  : param format: picture format
  : param quality: compression ratio. The higher the compression ratio, the shorter the binary data
  :return: 
  '''
  stream = BytesIO()
  picture = Image.fromarray(pic)
  picture.save(stream,format=formatter,quality=quality)
  jepg = stream.getvalue()
  stream.close()
  return jepg
 @staticmethod
 def bytes_to_base64(byte):
  '''
  Static method, bytes to Base64 encoding
  :param byte: 
  :return: 
  '''
  return base64.b64encode(byte)
 @staticmethod
 def transport_rgb(frame):
  '''
  Convert BGR image to RGB image, or convert RGB image to BGR image
  '''
  return frame[...,::-1]
 @staticmethod
 def byte_to_package(bytes,cmd,var=1):
  '''
  The binary data of the picture stream of each frame is packet
  : param byte: binary
  : param CMD: Command
  :return: 
  '''
  head = [ver,len(byte),cmd]
  headPack = struct.pack("!3I", *head)
  senddata = headPack+byte
  return senddata
 @staticmethod
 def mkdir(filePath):
  '''
  create folder
  '''
  if not os.path.exists(filePath):
   os.mkdir(filePath)
 @staticmethod
 def countCenter(box):
  '''
  Calculate the center of a rectangle
  '''
  return (int(abs(box[0][0] - box[1][0])*0.5) + box[0][0],int(abs(box[0][1] - box[1][1])*0.5) +box[0][1])
 @staticmethod
 def countBox(center):
  '''
  We calculate x, y, C, R from two points
  '''
  return (center[0][0],center[0][1],center[1][0]-center[0][0],center[1][1]-center[0][1])
 @staticmethod
 def getImageFileName():
  return time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime())+'.png'

Multi target tracking:

Similar to single target, use multitracker instead_ create()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 5 18:02:33 2020

manytarget tracking

@author: youxinlin
"""import numpy as np
import cv2
import sys
'''
if len(sys.argv) != 2:
 print('Input video name is missing')
 exit()
'''
print('Select multiple tracking targets') 
cv2.namedWindow("tracking")
camera = cv2.VideoCapture(r"/Users/youxinlin/Desktop/video_data/complex6.MOV") 
#camera = cv2.VideoCapture(0)
tracker = cv2.MultiTracker_ Create ()? Multi target tracking
a= cv2.Tracker_c
init_once = False
ok, image=camera.read()
if not ok:
 print('Failed to read video')
 exit()
bbox1 = cv2.selectROI('tracking', image)
bbox2 = cv2.selectROI('tracking', image)
bbox3 = cv2.selectROI('tracking', image)
while camera.isOpened():
 ok, image=camera.read()
 if not ok:
  print ('no image to read')
  break
 if not init_once:
  ok = tracker.add(cv2.TrackerKCF_create(),image,bbox1)
  ok = tracker.add(cv2.TrackerKCF_create( ),image, bbox2)
  ok = tracker.add(cv2.TrackerKCF_create(),image, bbox3)
  init_once = True
 ok, boxes = tracker.update(image)
 for newbox in boxes:
  p1 = (int(newbox[0]), int(newbox[1]))
  p2 = (int(newbox[0] + newbox[2]), int(newbox[1] + newbox[3]))
  cv2.rectangle(image, p1, p2, (0,0,255))
 cv2.imshow('tracking', image)
 k = cv2.waitKey(1)
 if k == 27 : break # esc pressed

KCF of multi-scale detection, KCF of user-defined features

In some scenarios, if you don’t want to use the default hog feature tracking or need to compare the tracking effects of different features, the encapsulated method seems not to be available. You need to roll out a wave of KCF code to use your own set features.

summary

The above is a small series to introduce you to achieve single target, multi-target, multi-scale, user-defined features of the KCF tracking algorithm, I hope to help you, if you have any questions please leave me a message, small series will reply to you in time. Thank you very much for your support to developer! If you think this article is helpful to you, please reprint, please indicate the source, thank you!