轨迹跟踪——二维轨迹跟踪

原创 2016年04月25日 11:30:03

转载请注明原作者t1234xy4:http://blog.csdn.net/t1234xy4/article/details/51241032

在读研期间,由于导师与水环研究生水生物有项目交叉,我主要研究视频跟踪技术。用来提取鱼类的轨迹以及鱼类的微动作。其中鱼类的轨迹提取我已做了两部分工作,二维视频跟踪,提取鱼类的轨迹;另一部分工作是重建三维鱼类游动轨迹。鱼类微特征提取还没有动工(惭愧)。
----------

二维的视频跟踪

在做这项工作之前我们花费了很大的力气去获取实验数据。购买了三个汉邦高科的摄像头,水箱,摄像头支架等。搭建好实验装置。(由于主要说视频跟踪,具体与鱼相关的就带过)
注意:
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     16

VIBE::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结果:
这里写图片描述

局部搜索:
这里写图片描述

跟踪结果:
这里写图片描述

如有疑问,可以联系我。
等我的论文录用后,再深入讨论三维轨迹跟踪方法。

相关文章推荐

Canvas轨迹

http://mapv.baidu.com/examples/#baidu-map-forceEdgeBundling.html主要用到的就2个关键技术点: ctx.globalAlpha = ‘0....

打造高大上的Canvas粒子动画

首先来看下我们准备要做的粒子动画效果是怎么样的~ 是这样: 或者是这样: 甚至是这样: 很酷炫! ...
  • yeana1
  • yeana1
  • 2016年09月07日 16:03
  • 2356

Android——BroadCaseReceiver,跟踪轨迹获取稳定的GPS

因为在跟踪GPS轨迹的时候开启了一个新的service来记录GPS数据,将结果显示在主页面,采用的是在service中使用broadCastReceiver发送广播在activity中收到广播后更新界...
  • iliupp
  • iliupp
  • 2017年05月06日 21:34
  • 663

Python+OpenCV学习(15)---Lucas Kanade 角点光流轨迹跟踪

利用python学习OpenCV,个人感觉比较方便。函数的形式与C++基本相同,所以切换过来还是比较好的,对于像我这种对python不太熟练的人,使用python的集成开发环境PyCharm进行学习,...

进程运行轨迹的跟踪与统计

在做这次实验的时候,一定要耐心一点。我当时做的时候就因为在修改的过程中出现了一点小小的失误,导致了整个实验重新来过一遍。为了避免这样的情况发生,一定要记住修改的时候,要注意修改的内...

自适应轨迹跟踪算法

  • 2017年06月27日 09:56
  • 3KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:轨迹跟踪——二维轨迹跟踪
举报原因:
原因补充:

(最多只允许输入30个字)