#!/usr/bin/env python'''
Camshift tracker
================该程序展示了如何使用meanShift(或者CamShift)算法跟踪目标物体
目标物体通过鼠标自左上角至右下角两点框选区域选取Usage:
------camshift.py [<video source>]Keys:
-----ESC - 退出b - 切换反向投影概率可视化
'''# Python 2/3 compatibility # 兼容性检查
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3if PY3:xrange = rangeimport numpy as np
import cv2 as cv# local module
import video # video不是内置程序包,而是自开发相机程序,opencv官网slmple中可以找到
from video import presetsclass App(object):def __init__(self, video_src):self.cam = video.create_capture(video_src, presets['cube'])_ret, self.frame = self.cam.read() # 读取cv.namedWindow('camshift')cv.setMouseCallback('camshift', self.onmouse) # 显示self.selection = None # 初始化鼠标self.drag_start = Noneself.show_backproj = False # 初始化反投影self.track_window = None # 初始化显示窗口def onmouse(self, event, x, y, flags, param): # 鼠标选择函数if event == cv.EVENT_LBUTTONDOWN:self.drag_start = (x, y)self.track_window = Noneif self.drag_start:xmin = min(x, self.drag_start[0]) # 区域选择ymin = min(y, self.drag_start[1])xmax = max(x, self.drag_start[0])ymax = max(y, self.drag_start[1])self.selection = (xmin, ymin, xmax, ymax)if event == cv.EVENT_LBUTTONUP: # 鼠标事件出发self.drag_start = Noneself.track_window = (xmin, ymin, xmax - xmin, ymax - ymin)def show_hist(self): # 直方图显示(无计算)bin_count = self.hist.shape[0]bin_w = 24img = np.zeros((256, bin_count*bin_w, 3), np.uint8)for i in xrange(bin_count):h = int(self.hist[i])cv.rectangle(img, (i*bin_w+2, 255), ((i+1)*bin_w-2, 255-h), (int(180.0*i/bin_count), 255, 255), -1)img = cv.cvtColor(img, cv.COLOR_HSV2BGR)cv.imshow('hist', img)def run(self):while True:_ret, self.frame = self.cam.read() # 读取相机vis = self.frame.copy() hsv = cv.cvtColor(self.frame, cv.COLOR_BGR2HSV) # 转化为HSV mask = cv.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.))) # 设置mask(掩膜)if self.selection:x0, y0, x1, y1 = self.selection # 触发鼠标事件hsv_roi = hsv[y0:y1, x0:x1]mask_roi = mask[y0:y1, x0:x1]hist = cv.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] ) # 计算直方图cv.normalize(hist, hist, 0, 255, cv.NORM_MINMAX)# 归一化直方图self.hist = hist.reshape(-1)self.show_hist()vis_roi = vis[y0:y1, x0:x1]cv.bitwise_not(vis_roi, vis_roi) # 通过反转图像创建掩码(因为不希望背景影响叠加)vis[mask == 0] = 0if self.track_window and self.track_window[2] > 0 and self.track_window[3] > 0:self.selection = Noneprob = cv.calcBackProject([hsv], [0], self.hist, [0, 180], 1) # 反投影prob &= maskterm_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 ) # 启动迭代track_box, self.track_window = cv.CamShift(prob, self.track_window, term_crit) # 注意使用CamShift是返回box结果,box也参与迭代if self.show_backproj:vis[:] = prob[...,np.newaxis] # 可视化try:cv.ellipse(vis, track_box, (0, 0, 255), 2)except:print(track_box)cv.imshow('camshift', vis)ch = cv.waitKey(5)if ch == 27:breakif ch == ord('b'):self.show_backproj = not self.show_backprojcv.destroyAllWindows()if __name__ == '__main__':print(__doc__) # 打印说明import sys try:video_src = sys.argv[1] # 读取视频except:video_src = 0 # 否则打开0号相机App(video_src).run() # 运行主程序
可参考资料:
1.cv.calcBackProject:opencv学习(三十九)之反向投影calcBackProject()_烟雨博客-CSDN博客
2.bitwise_not:OpenCV之bitwise_and、bitwise_not等图像基本运算及掩膜_小伟锅的博客-CSDN博客_bitwise_not