目标追踪------HOG特征和KL散度

实验目的:进行目标追踪

实验过程:

1、使用HOG特征来表示要追踪的目标

2、根据目标在上一帧中的位置,来选定当前帧的可能位置,已此位置为圆心,step为半径获取一系列的候选目标。利用目标的移动历史数据推测出目标的移动方向,然后再推测树圆心。

3、用HOG特征表示候选目标。计算候选目标与追踪目标的相似度。相似度的计算使用KL散度

4、得到当前帧中追踪目标的位置,更新数据

5、重复2-4步

实验工具:Hog特征,KL散度( Kullback–Leibler divergence)

实验代码:

'''
Created on 201952日
@author: 17916
'''
import numpy as np
import cv2
import matplotlib.pyplot as pyplot
import random
import math
 
#视频地址
path = 'D:\\video\\DCTrim3.mp4'
#根据以下4个参数,获取视频第一帧中对应部分,当作追踪目标
width = 145
height = 160
cx = 494
cy = 216
#追踪目标的HOG特征
tarVector = None
 
start = False
#获取候选目标时的半径半径
step = 20
 
#追踪目标在视频中的一系列位置
history = []
def makeVideo(path):
    global start
    global cx,cy,width,height,tarVector,step,history
    cap = cv2.VideoCapture(path)  #地址
    
    fps = cap.get(cv2.CAP_PROP_FPS)
    size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),   
            int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))    
    
    videoWriter = cv2.VideoWriter('C:\\Users\\17916\\Desktop\\oto_other.avi', cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), fps, size)  
    while(True):
        success,frame = cap.read()
        if(success):
            if(start==False):
                history.insert(0, [cx,cy])
                #获取追踪目标
                srcImg = getImage(frame,cx,cy,width,height)
                #获取追踪目标的HOG特征
                tarVector = compute_hog(srcImg)
                start = True
            else:
                #根据历史数据预测追踪目标的可能位置
                cx,cy = predict(history,5,8)
                #获取候选目标与其对应的位置
                images,pos = getCandidateImage(frame,cx,cy,width,height,step)
                tarPos = reckonMostSimilar(tarVector,images)
                #更新目标位置
                cx = pos[tarPos][0]
                cy = pos[tarPos][1]
                
                history.insert(0, [cx,cy])
 
            labelTarget(frame,cx,cy,width,height)
            
            videoWriter.write(frame)
 
        else:
            break;
 
    
    cap.release()
    
#计算图像的Hog
def compute_hog(image):
    
    winSize = (32, 32)      # winSize = (64,64)
    blockSize = (8,8)       # blockSize = (16,16)
    blockStride = (4,4)
    cellSize = (4,4)
    nbins = 9
    hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins)
 
    winStride = (4,4)
    padding = (4,4)
    locations = ((10,20),(30,30),(50,50),(70,70),(90,90),(110,110),(130,130),(150,150),(170,170),(190,190))
    hist = hog.compute(image,winStride,padding,locations)
    return hist 
 
#计算KL散度,用来作为图像间的相似度
def compute_KL(arr1,arr2):
    if(len(arr1)!=len(arr2)):
        print("长度不一,无法计算KL")
    res = 0
    for i in range(len(arr1)):
        res += arr1[i]*abs(np.log(arr1[i]/arr2[i]))
    
    return res
#截取部分图像
def getImage(image,centerX,centerY,w,h):
    top = (int)(centerY - h/2)
    left = (int)(centerX - w/2)
    right = (int)(centerX + w/2)
    bottom = (int)(centerY + h/2)
    return image[top:bottom,left:right]
 
#获取候选目标
#image 表示视频中的当前帧
#centerX,centerY 表示在centerX,centerY位置获取一系列候选目标
#step 指示需要在某个半径内获取的目标
def getCandidateImage(image,centerX,centerY,w,h,step):
    images = []
    pos = []
    
    images.append(getImage(image,centerX,centerY,w,h))
    pos.append([centerX,centerY])
    
    #根据随机出来的位置获取候选目标
    points = getRandomPos(centerX,centerY,step,25)
    for i in range(len(points)):
        images.append(getImage(image, points[i][0], points[i][1],w,h))
        pos.append([points[i][0],points[i][1]])
        
    
    return images,pos
#在一系列的帧中,选出最有可能是目标的帧(给的是索引)
#tarVector 开始时标记的目标
#images  一系列的候选目标帧
def reckonMostSimilar(tarVector,images):
    score = np.zeros(len(images),dtype = np.float)
    for i in range(len(images)):
        #计算每个候选目标的hog
        temp = compute_hog(images[i])
        #计算候选目标与标记的目标的相似度
        score[i] = abs(compute_KL(tarVector+1,temp+1))
        
    #选取最相似的候选目标
    minScore = min(score)
    resIndic = -1
    print(minScore,score)
    #获取最相似的候选目标的索引
    for i in range(len(score)):
        if(minScore == score[i]):
            resIndic = i
    return resIndic
#标记目标
def labelTarget(frame,centerX,centerY,w,h):
    top = (int)(centerY - h/2)
    left = (int)(centerX - w/2)
    right = (int)(centerX + w/2)
    bottom = (int)(centerY + h/2)
    cv2.rectangle(frame,(left,top),(right,bottom),(0, 255, 0))
 
#预测目标的走向,下一帧要往那个方向移动,根据预测的目标的中心点px,py,去获得一系列候选图像
#history保存了整个移动过程,目标的中心点
#k表示根据前k帧,来预测目标的移动方向
#step用来推测出下一帧的中心点,step越大会在预测方向上移动越远,来预测目标
def predict(history,k,step):
    num = min(k,len(history))
    if(num==1):
        return history[0][0],history[0][1]
    vx = 0
    vy = 0
    #计算目标在目前时刻与上一时刻之间的向量(用向量和来估计目标的移动方向)
    for i in range(num):
        for j in range(i+1,num):
            if(history[i][0]==history[j][0] or history[i][1]==history[j][1]):
                continue
            vx += history[i][0] - history[j][0]
            vy += history[i][1] - history[j][1]
    #根据向量,计算出目标可能出现的地点
    if(vx==0 or vy == 0):
        return history[0][0],history[0][1]
    px =(int)( history[0][0] + step*reckonCos(vx,vy) )
    py =(int) ( history[0][1] + step*reckonSin(vx,vy) )
    return px,py
def reckonSin(x,y):
    return y/math.sqrt(x*x+y*y)
def reckonCos(x,y):
    return x/math.sqrt(x*x+y*y)
##在x,y点的周围获取num个候选点,每个点代表一个候选位置(可能包含目标图像)
def getRandomPos(x,y,radius,num):
    res = []
    for i in range(num):
        cx = random.randint(x-radius,x+radius)
        cy = random.randint(y-radius,y+radius)
        res.append([cx,cy])
    return res
 
makeVideo(path)

实验结果:
https://pan.baidu.com/s/19FprvGfhySjcZ5NSWglZyg
提取码:xwe8

这代码我跑了一下,效果并不是特别好,无法识别小目标,也不能抗抖动,丢包率高

我的部分结果如下:
链接:https://pan.baidu.com/s/1QffI9T3c_lGl3KdM-K-9zg
提取码:0i6q

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值