MeanShift 目标跟踪

article/2025/11/6 14:10:24

MeanShift算法,又称为均值漂移算法,采用基于颜色特征的核密度估计,寻找局部最优,使得跟踪过程中对目标旋转,小范围遮挡不敏感。

文章目录

    • MeanShift 原理
    • MeanShift 跟踪步骤
    • meanShift 函数原型
    • 反向投影
    • MeanShift 跟踪器
    • 跟踪管理器
    • 车辆监测与跟踪
    • MeanShift 算法的优缺点

MeanShift 原理

MeanShift的本质是一个迭代的过程,在一组数据的密度分布中,使用无参密度估计寻找到局部极值(不需要事先知道样本数据的概率密度分布函数,完全依靠对样本点的计算)。

在d维空间中,任选一个点,然后以这个点为圆心,h为半径做一个高维球,因为有d维,d可能大于2,所以是高维球。落在这个球内的所有点和圆心都会产生一个向量,向量是以圆心为起点落在球内的点位终点。然后把这些向量都相加。相加的结果就是下图中黄色箭头表示的MeanShift向量:

然后,再以这个MeanShift 向量的终点为圆心,继续上述过程,又可以得到一个MeanShift 向量:

不断地重复这样的过程,可以得到一系列连续的MeanShift 向量,这些向量首尾相连,最终可以收敛到概率密度最大得地方(一个点):

从上述的过程可以看出,MeanShift 算法的过程就是:从起点开始,一步步到达样本特征点的密度中心。

MeanShift 跟踪步骤

1.获取待跟踪对象

获取初始目标框(RoI)位置信息(x,y,w,h),截取 RoI图像区域

# 初始化RoI位置信息 
track_window = (c,r,w,h) 
# 截取图片RoI
roi = img[r:r+h, c:c+w]

2.转换颜色空间

将BGR格式的RoI图像转换为HSV格式,对 HSV格式的图像进行滤波,去除低亮度和低饱和度的部分。

在 HSV 颜色空间中要比在 BGR 空间中更容易表示一个特定颜色。在 OpenCV 的 HSV 格式中,H(色度)的取值范围是 [0,179], S(饱和度)的取值范围 [0,255],V(亮度)的取值范围 [0,255]。

# 转换到HSV
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# 设定滤波的阀值
lower = np.array([0.,130.,32.])
upper = np.array([180.,255.,255.])
# 根据阀值构建掩模
mask = cv2.inRange(hsv,lower, upper)

3.获取色调统计直方图

# 获取色调直方图
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
# 直方图归一化
cv2.normalize(roi_hist,roi_hist,0,180,cv2.NORM_MINMAX)

cv2.calcHist的原型为:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]])  
  • images: 待统计的图像,必须用方括号括起来,

  • channels:用于计算直方图的通道,这里使用色度通道

  • mask:滤波掩模

  • histSize:表示这个直方图分成多少份(即多少个直方柱)

  • ranges:表示直方图中各个像素的值的范围

4.在新的一帧中寻找跟踪对象

# 读入目标图片
ret, frame = cap.read()
# 转换到HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 获取目标图片的反向投影
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)
# 定义迭代终止条件
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
# 计算得到迭代次数和目标位置
ret, track_window = cv2.meanShift(dst, track_window, term_crit)

meanShift 函数原型

def meanShift(probImage, window, criteria)
  • probImage:输入反向投影直方图

  • window:需要移动的矩形(ROI)

  • criteria:对meanshift迭代过程进行控制的初始参量

其中,criteria参数如下:

  • type:判定迭代终止的条件类型:

    • COUNT:按最大迭代次数作为求解结束标志

    • EPS:按达到某个收敛的阈值作为求解结束标志

    • COUNT + EPS:两个条件达到一个就算结束

  • maxCount:具体的最大迭代的次数

  • epsilon:具体epsilon的收敛阈值

反向投影

反向投影图输出的是一张概率密度图,与输入图像大小相同,每一个像素值代表了输入图像上对应点属于目标对象的概率,像素点越亮,代表这个点属于目标物体的概率越大。

跟踪目标:

跟踪目标在下一帧中的反向投影:

MeanShift 跟踪器

import numpy as np
import cv2class MeanShiftTracer:def __init__(self, id):# Stop criteria for the iterative search algorithm.self._term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)self._roi_hist = Noneself.predict_count = 0self.frame = Noneself.frame_begin_id = idself.frame_end_id = idself.roi_xywh = Nonedef _log_last_correct(self, frame, frame_id, xywh):x, y, w, h = xywhself.correct_box = (x, y, w, h)self.correct_img = frame[y:y + h, x:x + w]self.correct_id = frame_iddef correct(self, frame, frame_id, xywh):self._log_last_correct(frame,frame_id, xywh)self._refresh_roi(frame, frame_id, xywh)self.predict_count = 0def predict(self, frame, frame_id):hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)dst = cv2.calcBackProject([hsv], [0], self._roi_hist, [0, 180], 1) ret, track_window = cv2.meanShift(dst, self.roi_xywh, self._term_crit)self._refresh_roi(frame, frame_id, track_window)self.predict_count += 1return track_windowdef _refresh_roi(self, frame, frame_id, xywh):x, y, w, h = xywhroi = frame[y:y + h, x:x + w]hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)mask = cv2.inRange(hsv_roi, np.array((0., 60., 32.)), np.array((180., 255., 255.)))roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])cv2.normalize(roi_hist, roi_hist, 0, 180, cv2.NORM_MINMAX)self.roi_xywh = (x, y, w, h)self._roi_hist = roi_histself.frame = frameself.frame_end_id = frame_iddef get_roi_info(self):return {'correct_box': self.correct_box,'correct_img': self.correct_img,'correct_id': self.correct_id,'beginId': self.frame_begin_id,'endId': self.frame_end_id}

跟踪管理器

import numpy as np
import cv2class TracerManager:def __init__(self, image_shape, trace_tool, trace_margin, max_predict):""":param image_shape: (height,width):param trace_tool: MeanShiftTracer:param trace_margin: (0,0,30,50)(px)(left,top,right,bottom):param max_predict: 3 (times)"""self._tracers = []self._trace_tool = trace_toolself._max_predict = max_predictself._image_shape = image_shapeself.trace_margin = trace_margindef _calc_iou(self, A, B):""":param A: [x1, y1, x2, y2]:param B: [x1, y1, x2, y2]:return: IoU"""IoU = 0iw = min(A[2], B[2]) - max(A[0], B[0])if iw > 0:ih = min(A[3], B[3]) - max(A[1], B[1])if ih > 0:A_area = (A[2] - A[0]) * (A[3] - A[1])B_area = (B[2] - B[0]) * (B[3] - B[1])uAB = float(A_area + B_area - iw * ih)IoU = iw * ih / uABreturn IoUdef box_in_margin(self, box):in_bottom = (self._image_shape[0] - (box[1] + box[3])) < self.trace_margin[3]in_right = (self._image_shape[1] - (box[0] + box[2])) < self.trace_margin[2]return in_bottom or in_rightdef _get_box_tracer_iou(self, A, B):a = (A[0], A[1], A[0] + A[2], A[1] + A[3])b = (B[0], B[1], B[0] + B[2], B[1] + B[3])return self._calc_iou(a, b)def _check_over_trace(self):remove_tracer = []trace_info = []for t in self._tracers:if t.predict_count > self._max_predict:remove_tracer.append(t)if t.frame_end_id != t.frame_begin_id:trace_info.append(t.get_roi_info())for t in remove_tracer:self._tracers.remove(t)return trace_infodef _get_tracer(self, box):tracer = NonemaxIoU = 0for t in self._tracers:iou = self._get_box_tracer_iou(box, t.roi_xywh)if iou > maxIoU:tracer = tmaxIoU = ioureturn tracerdef update_tracer(self, frame, frame_id, boxes):trace_info = self._check_over_trace()for box in boxes:if self.box_in_margin(box):continuetracer = self._get_tracer(box)if tracer is not None:tracer.correct(frame, frame_id, box)else:tracer = self._trace_tool(frame_id)tracer.correct(frame, frame_id, box)self._tracers.append(tracer)return trace_infodef trace(self, frame, frame_id):track_windows = []for t in self._tracers:window = t.predict(frame, frame_id)track_windows.append(window)return track_windows

车辆监测与跟踪

检测与跟踪以1:1的比例交替进行。

import cv2
import numpy as np
import os.path
import Tracerclass car_detector:def __init__(self, cascade_file):if not os.path.isfile(cascade_file):raise RuntimeError("%s: not found" % cascade_file)self._cascade = cv2.CascadeClassifier(cascade_file)def _detect_cars(self, image):gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)gray = cv2.equalizeHist(gray)cars = self._cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=15, minSize=(60, 60))return carsdef _show_trace_object(self, infos):for info in infos:title = "%d - %d from frame: %d" % (info['beginId'], info['endId'], info['correct_id'])cv2.imshow(title, info['correct_img']) cv2.waitKey(1)def _get_area_invalid_mark(self, img_shape, margin):area = np.zeros(img_shape,np.uint8)h, w = img_shape[:2]disable_bg_color = (0, 0, 80)disable_fg_color = (0, 0, 255)cv2.rectangle(area, (0, h-margin[3]), (w, h), disable_bg_color, -1)cv2.putText(area, "Invalid Region", (w-220, h-20), cv2.FONT_HERSHEY_SIMPLEX, 1, disable_fg_color, 2)return areadef _show_trace_state(self, image, id, tracer, state, boxes, mark):image = cv2.addWeighted(mark, 0.5, image, 1, 0)title = 'frame : %s [%s]' % (state, id)colors = {'detect': (0, 255, 0), 'trace': (255, 255, 0), 'invalid': (150, 150, 150), 'title_bg': (0, 0, 0)}for (x, y, w, h) in boxes:if tracer.box_in_margin((x, y, w, h)):cv2.rectangle(image, (x, y), (x + w, y + h),colors['invalid'], 2)else:cv2.rectangle(image, (x, y), (x + w, y + h), colors[state], 2)cv2.rectangle(image, (10, 20), (250, 50), colors['title_bg'], -1)cv2.putText(image, title, (30, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.6, colors[state],2)cv2.imshow("result", image)cv2.waitKey(1)def trace_detect_video(self, video_path, trace_rate = 1):cap = cv2.VideoCapture(video_path)w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) start_frame = 0invalid_margin = (0, 0, 0, 100)mark = self._get_area_invalid_mark((h, w, 3), invalid_margin)tracer = Tracer.TracerManager((h, w), Tracer.MeanShiftTracer, invalid_margin, trace_rate + 5)warm = Falsewhile True:ret, image = cap.read()start_frame += 1if not ret: returnresult = image.copy()if not warm or start_frame % (trace_rate + 1) == 0:warm = Truecars = self._detect_cars(image)self._show_trace_state(result, start_frame, tracer, 'detect', cars, mark)trace_obj = tracer.update_tracer(image, start_frame, cars)self._show_trace_object(trace_obj)else:cars = tracer.trace(image, start_frame)self._show_trace_state(result, start_frame, tracer, 'trace', cars, mark)if __name__ == "__main__":car_cascade_lbp_21 = './train/cascade_lbp_21/cascade.xml'video_path = "./test.mp4"detect = car_detector(car_cascade_lbp_21)detect.trace_detect_video(video_path)

MeanShift 算法的优缺点

优点:

  • 算法计算量不大,在目标区域已知的情况下完全可以做到实时跟踪;

  • 采用核函数直方图模型,对边缘遮挡、目标旋转、变形和背景运动不敏感。

缺点:

  • 跟踪过程中由于窗口宽度大小保持不变,框出的区域不会随着目标的扩大(或缩小)而扩大(或缩小);

  • 当目标速度较快时,跟踪效果不好;

  • 直方图特征在目标颜色特征描述方面略显匮乏,缺少空间信息;


http://chatgpt.dhexx.cn/article/XIARPUZj.shtml

相关文章

MeanShift跟踪MATLAB实现

一、简介 核跟踪方法是目标跟踪的主要方法, 应用非常广泛。例如Meashift、Camshift 算法, 它直接运用最速下降法的原理, 向梯度下降方向对目标模板逐步迭代, 直到迭代到最优位置。它的核心就是一步一步迭代寻找最优点, 在跟踪中, 就是为了寻找相似度值最大的候选区间。 本文主…

OpenCV每日函数 对象追踪模块 Meanshift算法

1、meanshift的基本思想 meanshift 背后的直觉很简单。考虑你有一组点。(它可以是像直方图反投影这样的像素分布)。您有一个小窗口(可能是一个圆圈),您必须将该窗口移动到最大像素密度(或最大点数)的区域。如下图所示: 2、meanshift的原理简述 均值偏移和模式发现技术,…

meanshift算法学习(二):opencv中的meanshift

0.前言 接着上一篇文章点击打开链接说&#xff0c;opencv中提供的meanshift可以用来实现跟踪&#xff0c;其基本原理是迭代求解概率分布的“局部极值”。这一篇内容&#xff0c;我只讲opencv中的meanshift的用法和源代码分析。因为&#xff1a;&#xff08;1&#xff09;具体的…

聚类算法之Mean Shift

Mean Shift聚类算法 1. 基本原理 对于Mean Shift算法&#xff0c;是一个迭代得步骤&#xff0c;即每次迭代的时候&#xff0c;都是找到圆里面点的平均位置作为新的圆心位置。说的简单一点&#xff0c;使得圆心一直往数据密集度最大的方向移动。 2. 基本的Mean Shift向量形式…

meanshift跟踪算法

以下是用meanshift实现目标跟踪的实验报告&#xff08;包含源码&#xff09;&#xff0c;实验中详细介绍了meanshift跟踪算法的原理&#xff0c;结合OTB100跟踪数据集对meanshift跟踪效果进行了分析。 目 录 一.实验名称 二.实验目的 三.实验原理 3.1 前言 3.2 meanshift …

传统目标跟踪——MeanShift算法

目录 一、均值漂移&#xff08;MeanShift&#xff09; 二、流程 三、代码 3.1 meanshift&#xff0b;固定框的代码 3.2 优化&#xff1a;meanshift鼠标选择 3.3 meanshift自己实现函数 四、补充知识 4.1 直方图 4.2 归一化 4.3 直方图反投影 一、均值漂移&#xff08;…

Mean Shift 聚类算法

原文&#xff1a;https://blog.csdn.net/hjimce/article/details/45718593 一、mean shift 算法理论 Mean shift 算法是基于核密度估计的爬山算法&#xff0c;可用于聚类、图像分割、跟踪等&#xff0c;因为最近搞一个项目&#xff0c;涉及到这个算法的图像聚类实现&#xff…

mean shift聚类matlab,机器学习:Mean Shift聚类算法

今天的文章介绍如何利用Mean Shift算法的基本形式对数据进行聚类操作。而有关Mean Shift算法加入核函数计算漂移向量部分的内容将不在本文讲述范围内。实际上除了聚类&#xff0c;Mean Shift算法还能用于计算机视觉等场合&#xff0c;有关该算法的理论知识请参考这篇文章。 Mea…

Python 实现MeanShift算法

原理 大家自行百度吧&#xff0c;我懒得码字了 推荐一下原理原理https://blog.csdn.net/jinshengtao/article/details/30258833 代码 直接上代码了&#xff0c;看不懂&#xff0c;就参照一下原理 # author: wdq # contact: 1920132572qq.com # datetime:2022/3/15 17:40 # …

Sklearn聚类算法之meanshift

以二维来说明可能更容易理解&#xff0c;下图中的很多的红点就是我们的样本特征点&#xff0c;meanshift就是在这些点中的任意一个点为圆心&#xff0c;然后以半径R画一个圆&#xff08;在opencv中是一个矩形&#xff09;&#xff0c;然后落在这个圆中的所有点和圆心都会对应的…

Python实现Mean Shift聚类算法

Mean Shift算法&#xff0c;又称均值聚类算法&#xff0c;聚类中心是通过在给定区域中的样本均值确定的&#xff0c;通过不断更新聚类中心&#xff0c;直到聚类中心不再改变为止&#xff0c;在聚类、图像平滑、分割和视频跟踪等方面有广泛的运用。 Mean Shift向量 对于给定的…

mean shift 跟踪算法

说明一&#xff1a; Mean Shift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束. 1. Meanshift推导 给定d维空间Rd的n个样本点 ,i1,…,n,在空间中任选一点x&#xff0c;那么Mean Shift向量…

Python实现Mean Shift算法

声明&#xff1a;代码的运行环境为Python3。Python3与Python2在一些细节上会有所不同&#xff0c;希望广大读者注意。本博客以代码为主&#xff0c;代码中会有详细的注释。相关文章将会发布在我的个人博客专栏《Python从入门到深度学习》&#xff0c;欢迎大家关注~ 在K-Means算…

meanshift算法 java_Meanshift,聚类算法

记得刚读研究生的时候&#xff0c;学习的第一个算法就是meanshift算法&#xff0c;所以一直记忆犹新&#xff0c;今天和大家分享一下Meanshift算法&#xff0c;如有错误&#xff0c;请在线交流。 Mean Shift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其…

保边滤波之Mean shift filter

Mean shift filter 目录 Mean shift filter 一、算法原理 二、练手实现的算法代码如下&#xff1a; 三、实现结果 一、算法原理 在OpenCV中&#xff0c;meanshift filter函数为 pyrMeanShiftFiltering&#xff0c; 它的函数调用格式如下&#xff1a; C: void pyrMeanShif…

mean shift

参考&#xff1a; http://blog.csdn.net/google19890102/article/details/51030884 http://www.cvvision.cn/5778.html https://wenku.baidu.com/view/5862334827d3240c8447ef40.html http://blog.csdn.net/qq_23968185/article/details/51804574 https://www.cnblogs.com…

机器学习算法原理与实践(二)、meanshift算法图解以及在图像聚类、目标跟踪中的应用

【原创】Liu_LongPo 转载请注明出处 【CSDN】http://blog.csdn.net/llp1992 最近在关注跟踪这一块的算法&#xff0c;对于meanshift的了解也是来自论文和博客&#xff0c;本博客将对meanshift算法进行总结&#xff0c;包括meanshift算法原理以及公式推导&#xff0c;图解&…

基于MeanShift的目标跟踪算法及实现

这次将介绍基于MeanShift的目标跟踪算法&#xff0c;首先谈谈简介&#xff0c;然后给出算法实现流程&#xff0c;最后实现了一个单目标跟踪的MeanShift算法【matlab/c两个版本】 csdn贴公式比较烦&#xff0c;原谅我直接截图了… 一、简介 首先扯扯无参密度估计理论&#xff0c…

聚类算法:Mean Shift

目录 简介 mean shift 算法理论 Mean Shift算法原理 算法步骤 算法实现 其他 聚类算法之Mean Shift Mean Shift算法理论 Mean Shift向量 核函数 引入核函数的Mean Shift向量 聚类动画演示 Mean Shift的代码实现 算法的Python实现 scikit-learn MeanShift演示 s…

meanshift算法通俗讲解

这几天学习《学习OpenCV》中的第十章运动跟踪&#xff0c;里面讲到了meanshift算法&#xff0c;根据书上所讲实在难以理解&#xff0c;meanshift在运动跟踪这个过程中到底起到什么作用&#xff0c;于是经过几天不断地看相关资料和别人的博客文章&#xff0c;慢慢思路清晰了&…