#|OpenCV学习笔记-MeanShift


一、原理 假设我们有一堆点(比如直方图反向投影得到的点),和一个小的圆形窗口,我们要完成的任务就是将这个窗口移动到最大灰度密度处(也就是点最多的地方)。如下图所示:
#|OpenCV学习笔记-MeanShift
文章图片
初始窗口是蓝色的C1,它的圆心为蓝色方框的C1_o,而窗口中所有点质心却是C1_r,很明显圆心和点的质心没有重合。所以移动圆心C1_o到质心C1_r,这样我们就得到了一个新的窗口。这时又可以找到新的窗口内所以点的质心,大多数情况下还是不重合,所以重复上面的操作直到:将新窗口的圆心和它所包含的点的质心重合,这样我们的窗口会落在像素值(和)最大的地方。如上图C2是窗口的最后位置,它包含的像素点最多。

具体数学原理,参考 MeanShift原理, MeanShift数学公式 二、实现步骤

1、读入参考图像,设置感兴趣区域(ROI) 2、获取感兴趣区域的色调直方图

3、读取新图像计算色调直方图的反向投影 4、使用meanshift算法在反向投影中定位 【#|OpenCV学习笔记-MeanShift】

三、函数及代码

meanShift(probImage, window, criteria)

probImage: 概率分布图像,也就是ROI色调直方图的反向投影 window: 初始搜索窗口,就是定义ROI的rect

criteria:确定窗口搜索停止的准则, 迭代次数达到设置的最大值;窗口中心的漂移值小于某个设定的限值。
由于OpenCV官方文档中的实例运行出错,所以需要自己设置参数,视频和代码已上传:下载地址

import cv2 as cv import numpy as np from matplotlib import pyplot as pltcap = cv.VideoCapture('img/slow.flv') #读取第一帧图像 ret, frame = cap.read() cv.imwrite('img/shift/car.jpg', frame) #设置初始窗口参数 r, h, c, w = 190, 30, 300, 90 track_window = (c, r, w, h)#获取ROI roi = frame[r:r+h, c:c+w] cv.rectangle(frame, (c, r), (c+w, r+h), (0, 255, 0), 2) cv.imshow('img', frame) cv.imshow('roi', roi) #转成HSV格式 hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV) # 将低亮度的值忽略掉 lower_hsv = np.array([0, 0, 0]) upper_hsv = np.array([180, 255, 46]) #黑色 mask = cv.inRange(hsv_roi, lowerb=lower_hsv, upperb=upper_hsv) #颜色直方图 roi_hist = cv.calcHist([hsv_roi], [0], mask, [180], [0, 180])#归一化 cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX) #确定窗口搜索停止的准则,迭代次数达到设置的最大值,或者窗口中心的漂移值小于设定值 term_crit = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1)while True: ret, frame = cap.read()if ret is True: hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) #直方图反向投影 dst = cv.calcBackProject([hsv], [0], roi_hist, [0, 180], 1) #返回迭代次数和更新后的边框 ret, track_window = cv.meanShift(dst, track_window, term_crit) print(ret) #在图像中画出 x, y, w, h = track_window img2 = cv.rectangle(frame, (x, y), (x+w, y+h), 255, 2) cv.imshow('img2', img2)k = cv.waitKey(60)& 0xff if k == 27: break # else: #cv.imwrite('img/shift/'+chr(k)+'.jpg', img2) else: breakcv.waitKey(0) cv.destroyAllWindows() cap.release()


#|OpenCV学习笔记-MeanShift
文章图片

    推荐阅读