`

opencv计算机视觉学习笔记七

 
阅读更多

第八章 目标跟踪

1检测目标的移动

基本的运动检测,示例代码如下:


import cv2
import numpy as np

# 捕获摄像头图像
camera = cv2.VideoCapture(0)
#
es = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
kernel = np.ones((5, 5), np.uint8)
background = None

while (True):
 ret, frame = camera.read()
 # 将第一帧设为图像的背景
 if background is None:
 # 转换颜色空间
 background = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 # 高斯模糊
 background = cv2.GaussianBlur(background, (21, 21), 0)
 continue
 # 转换颜色空间并作模糊处理
 gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 gray_frame = cv2.GaussianBlur(gray_frame, (21, 21), 0)

 # 取得差分图
 diff = cv2.absdiff(background, gray_frame)
 diff = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)[1]
 # 膨胀
 diff = cv2.dilate(diff, es, iterations=2)

 # 得到图像中目标的轮廓
 image, cnts, hierarchy = cv2.findContours(diff.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 for c in cnts:
 if cv2.contourArea(c) < 1500:
 continue
 # 计算矩形边框
 (x, y, w, h) = cv2.boundingRect(c)
 # 绘制矩形
 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
 # 显示图像
 cv2.imshow('contours', frame)
 cv2.imshow('dif', diff)
 if cv2.waitKey(int(1000 / 12)) & 0xFF == ord('q'):
 break
cv2.destroyAllWindows()
camera.release()

运行结果如下:

2背景分割器 knn mog2和GMG

Opencv3有三种背景分割器

K-nearest(knn)

Mixture of Gaussians(MOG2)

Geometric multigid(GMC)

backgroundSubtractor用于分割前景和背景

示例代码如下:


import cv2
import numpy as np

cv2.ocl.setUseOpenCL(False)

cap = cv2.VideoCapture(0)
mog = cv2.createBackgroundSubtractorMOG2()

while (True):
 ret, frame = cap.read()
 fgmask = mog.apply(frame)
 cv2.imshow('frame', fgmask)
 if cv2.waitKey(30) & 0xFF == ord('q'):
 break

cap.release()
cv2.destroyAllWindows()

运行结果如下:

使用backgroundSubtractorKNN来实现运动检测

示例代码如下:


import cv2

cv2.ocl.setUseOpenCL(False)

bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)
# 读取本地视频
camera = cv2.VideoCapture('../traffic.flv')

while (True):
 ret, frame = camera.read()
 fgmask = bs.apply(frame.copy())
 # 设置阈值
 th = cv2.threshold(fgmask, # 源图像
 244, # 阈值
 255, # 最大值
 cv2.THRESH_BINARY)[1] # 阈值类型
 # 膨胀
 dilated = cv2.dilate(th, # 源图像
 cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), # 内核
 iterations=2) # 腐蚀次数

 # 查找图像中的目标轮廓
 image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 for c in contours:
 if cv2.contourArea(c) > 1600:
 (x, y, w, h) = cv2.boundingRect(c)
 cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2)

 cv2.imshow('mog', fgmask) # 分割前景与背景
 cv2.imshow('thresh', th) #
 cv2.imshow('detection', frame) # 运动检测结果
 if cv2.waitKey(30) & 0xFF == 27:
 break
camera.release()
cv2.destroyAllWindows()

运行结果如下:

均值漂移meanShift

示例代码如下:


import cv2
import numpy as np

# 取得摄像头图像
cap = cv2.VideoCapture(0)
ret, frame = cap.read()

# 设置跟踪窗体大小
r, h, c, w = 10, 200, 10, 200
track_window = (c, r, w, h)

# 提取roi
roi = frame[r:r + h, c:c + w]
# 转换颜色空间
hsv_roi = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 根据阈值构建掩码
mask = cv2.inRange(hsv_roi, np.array((100., 30., 32.)), np.array((180., 120., 255.)))

# 计算roi图形的彩色直方图
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
# 指定停止条件
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)

while (True):
 ret, frame = cap.read()
 if ret == True:
 # 更换颜色空间
 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
 # histogram back projection calculation 直方图反向投影
 dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
 # 均值漂移
 ret, track_window = cv2.meanShift(dst, track_window, term_crit)

 # 绘制矩形显示图像
 x, y, w, h = track_window
 img2 = cv2.rectangle(frame, (x, y), (x + w, y + h), 255, 2)
 cv2.imshow('img2', img2)

 # esc退出
 if cv2.waitKey(60) & 0xFF == 27:
 break
 else:
 break
cv2.destroyAllWindows()
cap.release()

运行结果如下:

彩色直方图

calHist函数

函数原型:

def calcHist(images, #源图像
  channels, #通道列表
 mask,#可选的掩码
  histSize, #每个维度下直方图数组的大小
 ranges,#每一个维度下直方图bin的上下界的数组
  hist=None,#输出直方图是一个[]维稠密度的数组
  accumulate=None)#累计标志

Camshift

示例代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2016/12/15 16:48
# @Author : Retacn
# @Site : camshift实现物体跟踪
# @File : camshift.py
# @Software: PyCharm
__author__ = "retacn"
__copyright__ = "property of mankind."
__license__ = "CN"
__version__ = "0.0.1"
__maintainer__ = "retacn"
__email__ = "zhenhuayue@sina.com"
__status__ = "Development"

import cv2
import numpy as np

# 取得摄像头图像
cap = cv2.VideoCapture(0)
ret, frame = cap.read()

# 设置跟踪窗体大小
r, h, c, w = 300, 200, 400, 300
track_window = (c, r, w, h)

# 提取roi
roi = frame[r:r + h, c:c + w]
# 转换颜色空间
hsv_roi = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 根据阈值构建掩码
mask = cv2.inRange(hsv_roi, np.array((100., 30., 32.)), np.array((180., 120., 255.)))

# 计算roi图形的彩色直方图
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
# 指定停止条件
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)

while (True):
 ret, frame = cap.read()
 if ret == True:
 # 更换颜色空间
 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
 # histogram back projection calculation 直方图反向投影
 dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
 # 均值漂移
 ret, track_window = cv2.CamShift(dst, track_window, term_crit)

 # 绘制矩形显示图像
 pts = cv2.boxPoints(ret)
 pts = np.int0(pts)
 img2 = cv2.polylines(frame, [pts], True, 255, 2)
 cv2.imshow('img2', img2)

 # esc退出
 if cv2.waitKey(60) & 0xFF == 27:
 break
 else:
 break
cv2.destroyAllWindows()
cap.release()

运行结果如下:

4 卡尔曼滤波器

函数原型为:

def KalmanFilter(dynamParams=None,#状态的维度
  measureParams=None, #测量的维度
 controlParams=None,#控制的维度
  type=None)#矩阵的类型

示例代码如下:


import cv2
import numpy as np

# 创建空帧
frame = np.zeros((800, 800, 3), np.uint8)

# 测量坐标
last_measurement = current_measurement = np.array((2, 1), np.float32)
# 鼠标运动预测
last_prediction = current_predication = np.zeros((2, 1), np.float32)


def mousemove(event, x, y, s, p):
 # 设置全局变量
 global frame, measurements, current_measurement, last_measurement, current_predication, last_prediction
 last_prediction = current_predication
 last_measurement = current_measurement
 current_measurement = np.array([[np.float32(x)], [np.float32(y)]])
 kalman.correct(current_measurement)
 current_predication = kalman.predict()

 # 实际移动起始点
 lmx, lmy = last_measurement[0], last_measurement[1]
 cmx, cmy = current_measurement[0], current_measurement[1]
 # 预测线起止点
 lpx, lpy = last_prediction[0], last_prediction[1]
 cpx, cpy = current_predication[0], current_predication[1]

 # 绘制连线
 cv2.line(frame, (lmx, lmy), (cmx, cmy), (0, 100, 0)) # 绿色
 cv2.line(frame, (lpx, lpy), (cpx, cpy), (0, 0, 200)) # 红色


# 创建窗体
cv2.namedWindow('mouse_detection')
# 注册鼠标事件的回调函数
cv2.setMouseCallback('mouse_detection', mousemove)

# 卡尔曼滤波器
kalman = cv2.KalmanFilter(4, 2)
kalman.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32)
kalman.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
kalman.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32) * 0.03

while (True):
 cv2.imshow('mouse_detection', frame)
 if cv2.waitKey(30) & 0xFF == 27:
 break

cv2.destroyAllWindows()

运行结果如下:

一个基于行人跟踪的例子

示例代码如下:


import cv2
import numpy as np
import os.path as path
import argparse

font = cv2.FONT_HERSHEY_SIMPLEX

parser = argparse.ArgumentParser()
parser.add_argument("-a", "--algorithm",
 help="m (or nothing) for meanShift and c for camshift")
args = vars(parser.parse_args())


# 计算矩阵中心(行人位置)
def center(points):
 x = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4
 y = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4
 # print(np.array([np.float32(x), np.float32(y)], np.float32))
 # [ 588. 257.5]
 return np.array([np.float32(x), np.float32(y)], np.float32)


# 行人
class Pedestrian():
 def __init__(self, id, frame, track_window):
 self.id = int(id) # 行人id
 x, y, w, h = track_window # 跟踪窗体
 self.track_window = track_window
 # 更换颜色空间
 self.roi = cv2.cvtColor(frame[y:y + h, x:x + w], cv2.COLOR_BGR2HSV)
 # 计算roi图形的彩色直方图
 roi_hist = cv2.calcHist([self.roi], [0], None, [16], [0, 180])
 self.roi_hist = cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)

 # 设置卡尔曼滤波器
 self.kalman = cv2.KalmanFilter(4, 2)
 self.kalman.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32)
 self.kalman.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
 self.kalman.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
 np.float32) * 0.03
 # 测量坐标
 self.measurement = np.array((2, 1), np.float32)
 # 鼠标运动预测
 self.predication = np.zeros((2, 1), np.float32)
 # 指定停止条件
 self.term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
 self.center = None
 self.update(frame)

 def __del__(self):
 print('Pedestrian %d destroyed' % self.id)

 # 更新图像帧
 def update(self, frame):
 # 更换颜色空间
 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
 # histogram back projection calculation 直方图反向投影
 back_project = cv2.calcBackProject([hsv], [0], self.roi_hist, [0, 180], 1)

 # camshift
 if args.get('algorithm') == 'c':
 ret, self.track_window = cv2.CamShift(back_project, self.track_window, self.term_crit)
 # 绘制跟踪框
 pts = cv2.boxPoints(ret)
 pts = np.int0(pts)
 self.center = center(pts)
 cv2.polylines(frame, [pts], True, 255, 1)

 # 均值漂移
 if not args.get('algorithm') or args.get('algorithm') == 'm':
 ret, self.track_window = cv2.meanShift(back_project, self.track_window, self.term_crit)
 # 绘制跟踪框
 x, y, w, h = self.track_window
 self.center = center([[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
 cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2)

 self.kalman.correct(self.center)
 prediction = self.kalman.predict()
 cv2.circle(frame, (int(prediction[0]), int(prediction[1])), 4, (0, 255, 0), -1)
 # 计数器
 cv2.putText(frame, 'ID: %d --> %s' % (self.id, self.center), (11, (self.id + 1) * 25 + 1), font, 0.6, (0, 0, 0),
 1, cv2.LINE_AA)
 # 跟踪窗口坐标
 cv2.putText(frame, 'ID: %d --> %s' % (self.id, self.center), (10, (self.id + 1) * 25), font, 0.6, (0, 255, 0),
 1, cv2.LINE_AA)


def main():
 # 加载视频
 # camera = cv2.VideoCapture('../movie.mpg')
 # camera = cv2.VideoCapture('../traffic.flv')
 camera = cv2.VideoCapture('../768x576.avi')
 # 初始化背景分割器
 history = 20
 bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)

 # 创建显示主窗口
 cv2.namedWindow('surveillance')
 pedestrians = {} # 行人字典
 firstFrame = True
 frames = 0
 fourcc = cv2.VideoWriter_fourcc(*'XVID')
 out = cv2.VideoWriter('../output.avi', fourcc, 20.0, (640, 480))

 while (True):
 print('----------------------frmae %d----------------' % frames)
 grabbed, frane = camera.read()
 if (grabbed is False):
 print("failed to grab frame")
 break
 ret, frame = camera.read()
 fgmask = bs.apply(frame)

 if frames < history:
 frames += 1
 continue
 # 设置阈值
 th = cv2.threshold(fgmask.copy(), 127, 255, cv2.THRESH_BINARY)[1]
 # 腐蚀
 th = cv2.erode(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=2)
 # 膨胀
 dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 3)), iterations=2)
 # 查找轮廓
 image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

 counter = 0
 for c in contours:
 if cv2.contourArea(c) > 500:
 # 边界数组
 (x, y, w, h) = cv2.boundingRect(c)
 # 绘制矩形
 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 1)
 if firstFrame is True:
 pedestrians[counter] = Pedestrian(counter, frame, (x, y, w, h))
 counter += 1
 # 更新帧内容
 for i, p in pedestrians.items():
 p.update(frame)

 # false 只跟踪已有的行人
 # firstFrame = True
 firstFrame = False
 frames += 1

 # 显示
 cv2.imshow('surveillance', frame)
 out.write(frame)
 if cv2.waitKey(120) & 0xFF == 27: # esc退出
 break
 out.release()
 camera.release()


if __name__ == "__main__":
 main()

运行结果如下:

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics