• 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()

    运行结果如下:

  • 相关阅读:
    thinkphp5.0与thinkphp3.2之间的区别
    比较数组大小
    PHP语言开发微信公众平台(订阅号)之curl命令(补充)
    ThinkPHP3.2.3快速入门:基础篇
    phpcms利用表单向导创建留言板(可以回复)
    Vijos P1782 借教室 ( 前缀和&&差分序列)
    HDU2648:Shopping(DKBR_hash)
    Codeforces Round #375 (Div. 2)
    BestCoder Round #88
    Codeforces Round #373 (Div. 2)
  • 原文地址:https://www.cnblogs.com/retacn-yue/p/6194151.html
Copyright © 2020-2023  润新知