opencv計算機視覺學習筆記七

 

第八章 目標跟蹤python

 

1檢測目標的移動數組

基本的運動檢測,示例代碼以下:app


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

 

 

運行結果以下:ide

 

2背景分割器 knn mog2和GMG函數

Opencv3有三種背景分割器ui

K-nearest(knn)spa

Mixture of Gaussians(MOG2)rest

Geometric multigid(GMC)orm

 

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

 

 

運行結果以下:

相關文章
相關標籤/搜索