1. 程式人生 > >MeanShift 目標跟蹤

MeanShift 目標跟蹤

MeanShift演算法,又稱為均值漂移演算法,採用基於顏色特徵的核密度估計,尋找區域性最優,使得跟蹤過程中對目標旋轉,小範圍遮擋不敏感。

文章目錄

MeanShift 原理

MeanShift的本質是一個迭代的過程,在一組資料的密度分佈中,使用無參密度估計尋找到區域性極值(不需要事先知道樣本資料的概率密度分佈函式,完全依靠對樣本點的計算)。

在d維空間中,任選一個點,然後以這個點為圓心,h為半徑做一個高維球,因為有d維,d可能大於2,所以是高維球。落在這個球內的所有點和圓心都會產生一個向量,向量是以圓心為起點落在球內的點位終點。然後把這些向量都相加。相加的結果就是下圖中黃色箭頭表示的MeanShift向量:

然後,再以這個MeanShift 向量的終點為圓心,繼續上述過程,又可以得到一個MeanShift 向量:

不斷地重複這樣的過程,可以得到一系列連續的MeanShift 向量,這些向量首尾相連,最終可以收斂到概率密度最大得地方(一個點):

從上述的過程可以看出,MeanShift 演算法的過程就是:從起點開始,一步步到達樣本特徵點的密度中心。

MeanShift 跟蹤步驟

1.獲取待跟蹤物件

獲取初始目標框(RoI)位置資訊(x,y,w,h),擷取 RoI影象區域

# 初始化RoI位置資訊 
track_window = (c,r,w,h) 
# 擷取圖片RoI
roi = img[r:r+h, c:c+w]

2.轉換顏色空間

將BGR格式的RoI影象轉換為HSV格式,對 HSV格式的影象進行濾波,去除低亮度和低飽和度的部分。

在 HSV 顏色空間中要比在 BGR 空間中更容易表示一個特定顏色。在 OpenCV 的 HSV 格式中,H(色度)的取值範圍是 [0,179], S(飽和度)的取值範圍 [0,255],V(亮度)的取值範圍 [0,255]。

# 轉換到HSV
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# 設定濾波的閥值
lower = np.array([0.,130.,32.])
upper = np.array([180.,255.,255.])
# 根據閥值構建掩模
mask = cv2.inRange(hsv,lower, upper)

3.獲取色調統計直方圖

# 獲取色調直方圖
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
# 直方圖歸一化
cv2.normalize(roi_hist,roi_hist,0,180,cv2.NORM_MINMAX)

cv2.calcHist的原型為:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]])  
  • images: 待統計的影象,必須用方括號括起來,

  • channels:用於計算直方圖的通道,這裡使用色度通道

  • mask:濾波掩模

  • histSize:表示這個直方圖分成多少份(即多少個直方柱)

  • ranges:表示直方圖中各個畫素的值的範圍

4.在新的一幀中尋找跟蹤物件

# 讀入目標圖片
ret, frame = cap.read()
# 轉換到HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 獲取目標圖片的反向投影
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)
# 定義迭代終止條件
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
# 計算得到迭代次數和目標位置
ret, track_window = cv2.meanShift(dst, track_window, term_crit)

meanShift 函式原型

def meanShift(probImage, window, criteria)
  • probImage:輸入反向投影直方圖

  • window:需要移動的矩形(ROI)

  • criteria:對meanshift迭代過程進行控制的初始參量

其中,criteria引數如下:

  • type:判定迭代終止的條件型別:

    • COUNT:按最大迭代次數作為求解結束標誌

    • EPS:按達到某個收斂的閾值作為求解結束標誌

    • COUNT + EPS:兩個條件達到一個就算結束

  • maxCount:具體的最大迭代的次數

  • epsilon:具體epsilon的收斂閾值

反向投影

反向投影圖輸出的是一張概率密度圖,與輸入影象大小相同,每一個畫素值代表了輸入影象上對應點屬於目標物件的概率,畫素點越亮,代表這個點屬於目標物體的概率越大。

跟蹤目標:

跟蹤目標在下一幀中的反向投影:

MeanShift 跟蹤器

import numpy as np
import cv2

class MeanShiftTracer:

    def __init__(self, id):
        # Stop criteria for the iterative search algorithm.
        self._term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
        self._roi_hist = None
        self.predict_count = 0
        self.frame = None
        self.frame_begin_id = id
        self.frame_end_id = id
        self.roi_xywh = None

    def _log_last_correct(self, frame, frame_id, xywh):
        x, y, w, h = xywh
        self.correct_box = (x, y, w, h)
        self.correct_img = frame[y:y + h, x:x + w]
        self.correct_id = frame_id

    def correct(self, frame, frame_id, xywh):
        self._log_last_correct(frame,frame_id, xywh)
        self._refresh_roi(frame, frame_id, xywh)
        self.predict_count = 0

    def predict(self, frame, frame_id):
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        dst = cv2.calcBackProject([hsv], [0], self._roi_hist, [0, 180], 1) 
        ret, track_window = cv2.meanShift(dst, self.roi_xywh, self._term_crit)

        self._refresh_roi(frame, frame_id, track_window)
        self.predict_count += 1
        return track_window

    def _refresh_roi(self, frame, frame_id, xywh):
        x, y, w, h = xywh
        roi = frame[y:y + h, x:x + w]
        hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv_roi, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
        roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
        cv2.normalize(roi_hist, roi_hist, 0, 180, cv2.NORM_MINMAX)

        self.roi_xywh = (x, y, w, h)
        self._roi_hist = roi_hist
        self.frame = frame
        self.frame_end_id = frame_id

    def get_roi_info(self):
        return {'correct_box': self.correct_box,
                'correct_img': self.correct_img,
                'correct_id': self.correct_id,
                'beginId': self.frame_begin_id,
                'endId': self.frame_end_id}

跟蹤管理器

import numpy as np
import cv2

class TracerManager:

    def __init__(self, image_shape, trace_tool, trace_margin, max_predict):
        """
        :param image_shape: (height,width)
        :param trace_tool: MeanShiftTracer
        :param trace_margin: (0,0,30,50)(px)(left,top,right,bottom)
        :param max_predict: 3 (times)
        """

        self._tracers = []
        self._trace_tool = trace_tool
        self._max_predict = max_predict
        self._image_shape = image_shape
        self.trace_margin = trace_margin

    def _calc_iou(self, A, B):
        """
        :param A: [x1, y1, x2, y2]
        :param B: [x1, y1, x2, y2]
        :return: IoU
        """

        IoU = 0
        iw = min(A[2], B[2]) - max(A[0], B[0])
        if iw > 0:
            ih = min(A[3], B[3]) - max(A[1], B[1])
            if ih > 0:
                A_area = (A[2] - A[0]) * (A[3] - A[1])
                B_area = (B[2] - B[0]) * (B[3] - B[1])
                uAB = float(A_area + B_area - iw * ih)
                IoU = iw * ih / uAB

        return IoU

    def box_in_margin(self, box):
        in_bottom = (self._image_shape[0] - (box[1] + box[3])) < self.trace_margin[3]
        in_right = (self._image_shape[1] - (box[0] + box[2])) < self.trace_margin[2]
        return in_bottom or in_right

    def _get_box_tracer_iou(self, A, B):
        a = (A[0], A[1], A[0] + A[2], A[1] + A[3])
        b = (B[0], B[1], B[0] + B[2], B[1] + B[3])
        return self._calc_iou(a, b)

    def _check_over_trace(self):
        remove_tracer = []
        trace_info = []

        for t in self._tracers:
            if t.predict_count > self._max_predict:
                remove_tracer.append(t)
                if t.frame_end_id != t.frame_begin_id:
                    trace_info.append(t.get_roi_info())

        for t in remove_tracer:
            self._tracers.remove(t)

        return trace_info

    def _get_tracer(self, box):
        tracer = None
        maxIoU = 0

        for t in self._tracers:
            iou = self._get_box_tracer_iou(box, t.roi_xywh)
            if iou > maxIoU:
                tracer = t
                maxIoU = iou

        return tracer

    def update_tracer(self, frame, frame_id, boxes):
        trace_info = self._check_over_trace()

        for box in boxes:
            if self.box_in_margin(box):
                continue

            tracer = self._get_tracer(box)

            if tracer is not None:
                tracer.correct(frame, frame_id, box)
            else:
                tracer = self._trace_tool(frame_id)
                tracer.correct(frame, frame_id, box)
                self._tracers.append(tracer)

        return trace_info

    def trace(self, frame, frame_id):
        track_windows = []

        for t in self._tracers:
            window = t.predict(frame, frame_id)
            track_windows.append(window)

        return track_windows

車輛監測與跟蹤

檢測與跟蹤以1:1的比例交替進行。

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

class car_detector:

    def __init__(self, cascade_file):
        if not os.path.isfile(cascade_file):
            raise RuntimeError("%s: not found" % cascade_file)
        self._cascade = cv2.CascadeClassifier(cascade_file)

    def _detect_cars(self, image):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        gray = cv2.equalizeHist(gray)
        cars = self._cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=15, minSize=(60, 60))
        return cars

    def _show_trace_object(self, infos):
        for info in infos:
            title = "%d - %d from frame: %d" % (info['beginId'], info['endId'], info['correct_id'])
            cv2.imshow(title, info['correct_img']) 
            cv2.waitKey(1)

    def _get_area_invalid_mark(self, img_shape, margin):
        area = np.zeros(img_shape,np.uint8)
        h, w = img_shape[:2]
        disable_bg_color = (0, 0, 80)
        disable_fg_color = (0, 0, 255)

        cv2.rectangle(area, (0, h-margin[3]), (w, h), disable_bg_color, -1)
        cv2.putText(area, "Invalid Region", (w-220, h-20), cv2.FONT_HERSHEY_SIMPLEX, 1, disable_fg_color, 2)
        return area

    def _show_trace_state(self, image, id, tracer, state, boxes, mark):
        image = cv2.addWeighted(mark, 0.5, image, 1, 0)
        title = 'frame : %s [%s]' % (state, id)
        colors = {'detect': (0, 255, 0), 'trace': (255, 255, 0), 'invalid': (150, 150, 150), 'title_bg': (0, 0, 0)}

        for (x, y, w, h) in boxes:
            if tracer.box_in_margin((x, y, w, h)):
                cv2.rectangle(image, (x, y), (x + w, y + h),colors['invalid'], 2)
            else:
                cv2.rectangle(image, (x, y), (x + w, y + h), colors[state], 2)

        cv2.rectangle(image, (10, 20), (250, 50), colors['title_bg'], -1)
        cv2.putText(image, title, (30, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.6, colors[state],2)
        cv2.imshow("result", image)
        cv2.waitKey(1)

    def trace_detect_video(self, video_path, trace_rate = 1):
        cap = cv2.VideoCapture(video_path)
        w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 

        start_frame = 0
        invalid_margin = (0, 0, 0, 100)
        mark = self._get_area_invalid_mark((h, w, 3), invalid_margin)
        tracer = Tracer.TracerManager((h, w), Tracer.MeanShiftTracer, invalid_margin, trace_rate + 5)
        warm = False
        while True:
            ret, image = cap.read()
            start_frame += 1
            if not ret: return
            result = image.copy()

            if not warm or start_frame % (trace_rate + 1) == 0:
                warm = True
                cars = self._detect_cars(image)
                self._show_trace_state(result, start_frame, tracer, 'detect', cars, mark)

                trace_obj = tracer.update_tracer(image, start_frame, cars)
                self._show_trace_object(trace_obj)
            else:
                cars = tracer.trace(image, start_frame)
                self._show_trace_state(result, start_frame, tracer, 'trace', cars, mark)


if __name__ == "__main__"
            
           

相關推薦

MeanShift 目標跟蹤

MeanShift演算法,又稱為均值漂移演算法,採用基於顏色特徵的核密度估計,尋找區域性最優,使得跟蹤過程中對目標旋轉,小範圍遮擋不敏感。 文章目錄 MeanShift 原理 MeanShift 跟蹤步驟 meanShift 函式原型

meanshift目標跟蹤到粒子濾波

本文一開始總結我對meanshift演算法在影象分割、視訊目標跟蹤的一些粗淺認識,進一步引申到粒子濾波在目標跟蹤中如何應用,由於本人學術水平尚淺,必然有很多認識有誤,希望得到大家的批評指正,不勝感激。 在初學均值漂移演算法的時候,有個總體印象,就是演算法希望通過尋找密度最大的位置作為收斂位置,用白話講,

Python+OpenCV學習(13)---meanshift目標跟蹤

利用python學習OpenCV,個人感覺比較方便。函式的形式與C++基本相同,所以切換過來還是比較好的,對於像我這種對python不太熟練的人,使用python的整合開發環境PyCharm進行學習,可以設定斷點除錯,有助於我這類初學者理解掌握。 下面是利用python

影象處理之其他雜項(一)之MeanShift目標跟蹤演算法opencv c++程式碼 VS2015+opencv3.2

//#include "stdafx.h" //#include "cv.h" //#include "highgui.h" #include<opencv.hpp> #define u_char unsigned char #define DIST 0.5 #define

Opencv目標跟蹤—CamShift和meanshift演算法

meanshift原理: meanshift演算法思想其實很簡單:利用概率密度的梯度爬升來尋找區域性最優。它要做的就是輸入一個在影象的範圍,然後一直迭代(朝著重心迭代)直到滿足你的要求為止。但是他是怎麼用於做影象跟蹤的呢?這是我自從學習meanshift以來,一直的困惑。

學習OpenCV2——MeanShift目標跟蹤

        前面學習了MeanShift用於目標檢測,現在來看看MeanShift如何用於目標跟蹤。         OpenCV裡的MeanShift跟蹤方法涉及影象矩和反向投影的知識,如果不清楚可以先看我的另一篇博文“影象的幾何矩” 1. MeanShift( )

隨時更新———個人喜歡的關於模式識別、機器學習、推薦系統、圖像特征、深度學習、數值計算、目標跟蹤等方面個人主頁及博客

lam c++源代碼 for 閾值處理 mmc 閾值 align sources 回歸算法 目標檢測、識別、分類、特征點的提取David Lowe:Sift算法的發明者,天才。Rob Hess:sift的源代碼OpenSift的作者,個人主頁上有openSift的下載鏈接

目標跟蹤2017-6-19文獻總結

learn 得出 統計 鏈接 成功 復雜 構建 .cn 損失函數 文獻[1],交互多模型粒子濾波器 提出了一個新的方法:基於馬爾科夫交換系統的多模型粒子濾波器。該濾波器利用交互式模型過濾器(IMM)和正則化粒子濾波器(正則化粒子濾波器概率密度是高斯概率密度的混合)的相互作用

目標跟蹤--CamShift

矩形 顏色 hsv顏色空間 方法 邊界 攝像頭 stream i++ 可選 轉載請註明出處!!!http://blog.csdn.net/zhonghuan1992 目標跟蹤--CamShift CamShift

TLD視覺目標跟蹤框架原理與實踐

圖像 視頻 tld comm rec 計算機 認識 實踐 計算 最近花了不少時間,仔細的做了一個有關TLD視覺目標跟蹤框架的視頻課程,希望能夠幫助一些對計算機視覺感興趣的人,通過對該課程的學習,能夠對計算機視覺技術中的一些基本問題有一定的認識和理解,進而達到技術進階的目的。

目標跟蹤積累總結

eid lan msg 霍夫變換 erro trac shift pan mode 在過去的一年半裏嘗試了一些簡單的目標跟蹤算法,現總結如下: 1、 采用霍夫變換提取圓輪廓,對目標進行跟蹤。 2、 利用顏色直方圖,選擇合適的閾值,提取目標的顏色特征進行跟蹤。 3、 采

OpenCV學習總結(4)- 目標跟蹤

opened 背景 key font sin mic 目標 mil cap 視覺算法原理:背景提取  1. 打開視頻(文件或攝像頭)  2. 從視頻中提取當前幀  3. 計算背景:以前多幀求取平均  4. 根據背景得到運動目標(當前幀 - 背景)  5. 返回2,程序不斷循

cv2實現基於粒子濾波的目標跟蹤

目標跟蹤過程分為2部分,即目標特徵提取和目標跟蹤演算法。       其中目標特徵提取又包括以下幾種:1. 各種色彩空間直方圖,利用色彩空間的直方圖分佈作為目標跟蹤的特徵,可以減少物體遠近距離的影響,因為其顏色分佈大致相同。2.輪廓特徵,提取目標的輪廓特徵,可以加快

Online Object Tracking Benchmark(OTB)目標跟蹤系統評估方式

主要涉及到一些評估方式的講解: 評估資料集: OTB50和OTB100(OTB50這裡指OTB-2013,OTB100這裡指OTB-2015) Wu Y, Lim J, Yang M H. Online object tracking: A benchmark [C]// CVPR

VITAL目標跟蹤

VITAL目標跟蹤原文:VITAL: VIsual Tracking via Adversarial Learning GitHub:程式碼             &nb

STRCF目標跟蹤

STRCF目標跟蹤原文:Learning Spatial-Temporal Regularized Correlation Filters for Visual Tracking GitHub:程式碼        &nb

機器學習之----目標檢測與目標跟蹤的區別

1.目標檢測就是檢測出一個圖片或者一個視訊中目標的位置(靜態或者動態)如yolo檢測目標 2.目標追蹤是給視訊中第一幀目標以及它的位置,然後跟蹤這個目標,以及預測它的軌跡,(如果出現一些遮擋,也可以根據軌跡來跟蹤這個目標,假如是yolo檢測出的目標,有時候還會出現丟幀的情況,如果用了跟蹤演算法,

目標識別、目標跟蹤演算法總結

想自學影象處理的相關知識,正好實驗室師兄做過兩個關於紅外目標跟蹤的專案,因此從mean-shift 、SR、RP、PF開始學習。但是查閱資料的時候,發現對各種演算法理解非常 利用影象處理演算法,實現的功能一般包括: 目標的檢測、識別、跟蹤。常見的問題包括:人臉

深度多目標跟蹤演算法綜述

導言 基於深度學習的演算法在影象和視訊識別任務中取得了廣泛的應用和突破性的進展。從影象分類問題到行人重識別問題,深度學習方法相比傳統方法表現出極大的優勢。與行人重識別問題緊密相關的是行人的多目標跟蹤問題。 在多目標跟蹤問題中,演算法需要根據每一幀影象中目標的檢測結果,匹配已有的目標軌跡;對於

【小白筆記】目標跟蹤 Real-Time MDNet

文章目錄 1.主要貢獻 2.知識準備 2.1 MDNet 2.2 ROIAlign 3.改進 3.1 網路結構 3.2 自適應的ROIAlign 3.