軌跡跟蹤——二維軌跡跟蹤

來源:互聯網
上載者:User

標籤:

在讀研期間,由於導師與水環研究生水生物有項目交叉,我主要研究視頻跟蹤技術。用來提取魚類的軌跡以及魚類的微動作。其中魚類的軌跡提取我已做了兩部分工作,二維視頻跟蹤,提取魚類的軌跡;另一部分工作是重建三維魚類遊動軌跡。魚類微特徵提取還沒有動工(慚愧)。----------

二維的視頻跟蹤

在做這項工作之前我們花費了很大的力氣去擷取實驗資料。購買了三個漢邦高科的網路攝影機,水箱,網路攝影機支架等。搭建好實驗裝置。(由於主要說視頻跟蹤,具體與魚相關的就帶過)注意:1、網路攝影機要固定住,這樣拍攝的視訊框架才有固定的攝像機座標,最後才好轉換成統一的現實座標。2、擷取的視頻盡量減少運動背景的幹擾,熟悉前景檢測的人都應該知道。3、注意光線,不要太暗了,也不要太刺眼,有光圈亮點。

前景跟蹤演算法過程

首先都是查看文獻來著,大概看了20多篇文獻資料。其實起指導作用的文獻還是只有那麼幾篇。我就列出來:[1].Zhang Z.A flexible new technique for camera calibration[J].Transactions on Pattern Analysis and Machine Intelligence,2000(11):1330-1334.[2]Olivier Barnich, Marc Van Droogenbroeck. ViBe: A universal background subtraction algorithm for video sequences[J]. IEEE Transactions on Image Processing, 20(6):1709-1724, June 2011.[3]Robust Fragments-based Tracking using the Integral Histogram.還有很多文獻,就不一一列出來了。對我用C++來實現這些演算法的啟蒙文獻應該是文獻[3]:第[3]篇文獻:是一種改進的模板匹配方法,把模板和目標都分成多個字塊,然後分別匹配,這樣可以避免部分被遮擋就丟失目標的情況。(有源碼可以查看)文獻[1]很經典,我是直接用的,用來消除網路攝影機的扭曲形變。文獻[2]是我們方法的基礎,我直接將它的源碼移植過來了。也許你們會問我做了什麼,都是別人的東西,確實,是這樣的。

我的工作

1、主要是從前景檢測的結果中用一種更優的方法找出魚類所在的位置。能夠更加精確、即時的提取魚類軌跡。2、將軌跡做平滑處理,使用了基於平方的方法,效果很不錯。3、開發二維軌跡跟蹤軟體,確實只是小軟體,我只用了3個星期不到的時間做完,當然還有很多需要完善的地方。其實也有之前做三維魚類軌跡跟蹤系統的基礎。很多複用了之前的代碼。

二維估計跟蹤演算法:
原始幀->去失真->vibe->局部搜尋->二維軌跡
vibe演算法不是我的原創,是已經很成熟的演算法,故不詳細說明。貼出它的源碼吧,希望大家可以直接借鑒學習。
二次封裝之後的vibe.hxx:

#ifndef _VIBE_HXX_#define _VIBE_HXX_class VIBE {public:    VIBE();    ~VIBE();    void initialize();    void update();    inline void setCurrentFrame( unsigned char* i ) { _image = i; }    inline void setSegmentMap( unsigned char* i ) { _segMap = i; }    inline void setFrameWidth( int w ) { _frameWidth = w; }    inline void setFrameHeight( int h ) { _frameHeight = h; }    inline void setFrameWidthStrip( int s ) { _frameWidthStrip = s; }    inline bool isInitilized() { return _samples; }private:    int getRandomSample();    int getRandomSubSample();    int getRandomNeightXCoordinate( int x );    int getRandomNeightYCoordinate( int y );private:    int _frameWidth;    int _frameHeight;    int _frameWidthStrip;    int _sphereRadius;    int _pixelSamples;    int _backgroundThreshold;    int _subSampling;    int _borderWidth;    unsigned char* _image;    unsigned char* _segMap;    unsigned char** _samples;};#endif
#include "stdafx.h"#include <assert.h>#include<stdlib.h>#include <time.h>#include <math.h>#include "VIBE.hxx"#define N 25#define R 15#define ZMIN    3#define PHI     16VIBE::VIBE(){    _frameWidth = 0;    _frameHeight = 0;    _frameWidthStrip = 0;    _sphereRadius = R;    _pixelSamples = N;    _backgroundThreshold = ZMIN;    _subSampling = PHI;    _image = 0;    _segMap = 0;    _samples = 0;    _borderWidth = 0;}VIBE::~VIBE(){    if( _samples )    {        for( int i = 0; i < _pixelSamples; i ++ )            if( _samples[ i ] )            {                delete [] _samples[ i ];                _samples[ i ] = 0;            }        delete [] _samples;        _samples = 0;    }}void VIBE::initialize(){    assert( (_frameWidth < 1 || _frameHeight < 1 || _frameWidthStrip < 1) || "Please set frame info for initialize...\n");    srand((int)time(0));    _samples = new unsigned char*[ _pixelSamples ];    for( int i = 0; i < _pixelSamples; i ++ )        _samples[ i ] = new unsigned char[ _frameHeight * _frameWidthStrip ];    int tq = sqrtf( _pixelSamples );    _borderWidth = tq / 2;    for( int y = _borderWidth; y < _frameHeight - _borderWidth; y ++ )    {        for( int x = _borderWidth; x < _frameWidth - _borderWidth; x ++ )        {            int c = 0;             for( int i = -_borderWidth; i <= _borderWidth && c < _pixelSamples ; i ++ )            {                for( int j = -_borderWidth; j <= _borderWidth && c < _pixelSamples; j ++ )                    if( c < _pixelSamples - _backgroundThreshold )                        *(_samples[ c++ ] + y * _frameWidthStrip + x) = *(_image + ( y + i ) * _frameWidthStrip + ( x + j ));                    else                        *(_samples[ c++ ] + y * _frameWidthStrip + x) = *(_image +  y * _frameWidthStrip + x);            }        }    }}void VIBE::update(){    for( int x = 0; x < _frameWidth; x ++ )    {        for( int y = 0; y < _frameHeight; y ++ )        {            int count = 0, index = 0, dist = 0;            if( y < _borderWidth || x < _borderWidth || x >= _frameWidth - _borderWidth || y >= _frameHeight - _borderWidth )            {                *(_segMap + y * _frameWidthStrip + x ) = 0;                continue;            }            while( count < _backgroundThreshold && index < _pixelSamples )            {                dist = abs( *(_image + y * _frameWidthStrip + x) -                    *(_samples[ index ] + y * _frameWidthStrip + x ) );                if( dist < _sphereRadius )                    count ++;                index ++;            }            if( count >= _backgroundThreshold )            {                *(_segMap + y * _frameWidthStrip + x ) = 0;                int rand = getRandomSubSample();                //if( rand == 0 )              if( rand < 6)                {                    rand = getRandomSample();                    *(_samples[ rand ] + y * _frameWidthStrip + x ) = *( _image + y * _frameWidthStrip + x );                }                rand = getRandomSubSample();                //if( rand == 0 )               if( rand < 6 )                {                    int xg, yg;                    xg = getRandomNeightXCoordinate(x);                    yg = getRandomNeightYCoordinate(y);                    rand = getRandomSample();                    *(_samples[ rand ] + yg * _frameWidthStrip + xg ) = *( _image + y * _frameWidthStrip + x );                }            }            else            {                *(_segMap  + y * _frameWidthStrip + x ) = 255;            }        }    }}int VIBE::getRandomSample(){    int val = _pixelSamples * 1.0 * rand() / RAND_MAX;    if( val == _pixelSamples )        return val - 1;    else        return val;}int VIBE::getRandomSubSample(){    int val = _subSampling * 1.0 * rand() / RAND_MAX;    if( val == _subSampling )        return val - 1;    else        return val;}int VIBE::getRandomNeightXCoordinate( int x ){    int val = 4 * 1.0 * rand() / RAND_MAX - 2;    if( x + val >= _frameWidth || x + val < 0 )        return x;    else        return x + val;}int VIBE::getRandomNeightYCoordinate( int y ){    int val = 4 * 1.0 * rand() / RAND_MAX - 2;    if( y + val >= _frameWidth || y + val < 0 )        return y;    else        return y + val;}

調用這個VIBE這個類的方法:

VIBE vibe;    vibe.setFrameWidth(image->width);    vibe.setFrameHeight(image->height);    vibe.setFrameWidthStrip(segImage->widthStep);    vibe.setSegmentMap( (unsigned char*)(segImage->imageData));    vibe.setCurrentFrame((unsigned char*)grayImage->imageData);    vibe.initialize();    ……    //更新vibe.setCurrentFrame( (unsigned char*)grayImage->imageData );vibe.update();

不會用多看看類的源碼吧。“多折騰”,我導師的原話。

局部搜尋以及平滑處理
設k為幀數,R為搜尋半徑,P(x,y)為在 (x,y)處的像素值。設第 幀的座標為(xk,yk) ,可以得到第k+1 幀的位置為 :

平滑處理過程:
設平滑視窗的寬度為W1,視窗中每一幀的權重為:
原理為每一位局當前位置距離的平方,最遠處為1^2,……,當前最大2^k

平滑結果:

效果展示:
VIBE結果:

局部搜尋:

跟蹤結果:

如有疑問,可以聯絡我。
等我的論文錄用後,再深入討論三維軌跡跟蹤方法。

軌跡跟蹤——二維軌跡跟蹤

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.