meanshift原理与代码详解

什么是目标跟踪:在图像中跟踪某个目标,说白一点,就是在图像内跟踪这个图像内的一个小图像。记住我说的这个图像和小图像的概念,那么我们开始了。 

meanshift原理

meanshift的原理是根据概率密度梯度爬升来寻找局部最优。

概率密度

想了解概率密度就得先了解什么是概率?

显然,这个概率就是图像内的某一像素点在小图像内的概率。

那么什么是概率密度?

不需要了解太多,因为我们只是需要概率密度来做个判断的媒介。

简单记住,概率较高的那片区域概率密度比较大。

比如上图,右上角的概率密度就比左下角的概率密度大。

梯度爬升

什么是梯度爬升?

根据上述的概率密度知识,现在我们要追踪这个小图像了,所以我们肯定是从概率密度小的地方追到概率密度大的地方嘛(毕竟概率密度越大,意味着这些像素点在小图像的概率越大,意味着小图像在图像这个概率越大),对不对~

用别的东西来举例一下梯度爬升吧

看看下面的点图,怎么找到点最集中的位置呢?

先随便找点圈一个圆,寻找圆内点最多的地方(称为质点),然后将圆心移动至该质点的位置,这样就完成了一个迭代。最终要迭代至圆心与质点重合或者圆心与质点的距离至少小于某个阈值。

将像素值转化为概率值

读完了上面两节,我们明白了现在的主要矛盾就是怎么将图像的各个像素点的像素值转化为概率值。 一旦转化为概率值后只要迭代梯度爬升自然就完成了目标追踪,一切问题迎刃而解!

转化方法:直方图反投影

我个人认为,直方图反投影这句话说的更具体一点应该是:图像的像素值根据小图像的归一化直方图反投影成概率值。

用一个例子来说明吧:

1.这是图像中的某一部分的像素值:

2.这是小图像的归一化直方图:

PS:不懂归一化直方图的可以看看这篇:《直方图》,或者csdn上随便找找哈。

3.那么根据小图像的归一化直方图转化来的图像部分变成了:

挺简单吧以上就是原理了~

OpenCv中的meanshift

import numpy as np
import cv2 as cv

# 读取视频
cap = cv.VideoCapture('car.mp4')

# 第一步:得到小图像的归一化直方图
ret,frame = cap.read()
x, y, w, h = 100, 325, 100, 50
roi = frame[y:y+h, x:x+w]                                                   # ROI也就是小图像了。
hsv_roi =  cv.cvtColor(roi, cv.COLOR_BGR2HSV)                               # 将ROI转化为HSV颜色空间
mask = cv.inRange(hsv_roi, np.array((0, 60,32)), np.array((180,255,255)))   # 去掉POI中颜色过亮或过暗的位置
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])                    # ROI直方图
cv.normalize(roi_hist,roi_hist,0,180,cv.NORM_MINMAX)                        # ROI直方图归一化

# 设置追踪窗口(第二步先备条件)
track_window = (x, y, w, h)
# 设置终止条件,可以是10次迭代,也可以至少移动1 pt(第二步先备条件)
term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )

# 第二步,直方图反投影
while(1):
    ret, frame = cap.read()
    if ret == True:
        
        # 原始图像转HSV
        hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

        # 在ROI直方图归一化的基础上进行直方图反投影
        dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1)

        # 应用meanshift来获取新位置
        ret, track_window = cv.meanShift(dst, track_window, term_crit)

        # 在图像上绘制追踪小图像的框框
        x,y,w,h = track_window
        img = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2)

        cv.namedWindow('img', 0)
        cv.imshow('img',img)
        k = cv.waitKey(30) & 0xff
        if k == 27:
            break
    else:
        break

注意:上例代码中转化为HSV颜色空间了,这是因为要找到小图像肯定是根据颜色特征来找,而RGB颜色空间得用3通道才能表明颜色,而HSV颜色空间只需用单通道(H通道)就可以表示清楚颜色了。

以上是个人学习后的学习理解,若存在错误请指点!

因此禁止转载!若有需要请私信。

posted @ 2022-06-17 22:47  东东咚咚东  阅读(108)  评论(0编辑  收藏  举报