目标跟踪之Lukas-Kanade光流法(转)
光流是图像亮度的运动信息描述。光流法计算最初是由Horn和Schunck于1981年提出的,创造性地将二维速度场与灰度相联系,引入光流约束方程,得到光流计算的基本算法.光流计算基于物体移动的光学特性提出了2个假设:
①运动物体的灰度在很短的间隔时间内保持不变;
②给定邻域内的速度向量场变化是缓慢的。
算法原理
假设图像上一个像素点(x,y),在t时刻的亮度为E(x+Δx,y+Δy,t+Δt),同时用u(x,y0和v(x,y)来表示该点光流在水平和垂直方向上的移动分量:
u=dx/dt
v=dy/dt
在经过一段时间间隔Δt后该点对应点亮度为E(x+Δx,y+Δy,t+Δt),当Δt很小趋近于0时,我们可以认为该点亮度不变,所以可以有:
E(x,y,t)=E(x+Δx,y+Δy,t+Δt)
当该点的亮度有变化时,将移动后点的亮度由Taylor公式展幵,可得:
忽略其二阶无穷小,由于Δt趋近于0时,有:
式中w=(u,v),所以上式就是基本的光流约束方程。
其中令表示图像中像素点灰度沿x,y,t方向的梯度,可将上式改写成:
Lucas-Kanade是一种广泛使用的光流估计的差分方法,这个方法是由Bruce D. Lucas和Takeo Kanade发明的。它假设光流在像素点的邻域是一个常数,然后使用最小二乘法对邻域中的所有像素点求解基本的光流方程。
通过结合几个邻近像素点的信息,卢卡斯-金出方法(简称为L-K方法)通常能够消除光流方程里的多义性。而且,与逐点计算的方法相比,L-K方法对图像噪声不敏感。不过,由于这是一种局部方法,所以在图像的均匀区域内部,L-K方法无法提供光流信息。
Lucas-Kanade改进算法
在实际场景中图像I和图像J可以代表前后两帧图像。对于图像特征点金字塔跟踪来说的目的是:对于前一帧的图像I上一点u(ux,uy),要在后一帧图像J上找到一点v(ux+dx,uy+dy)与之相匹配,即灰度值最接近。那么向量d=[dx,dy]就是图像在点u处的运动速度,也就是所说像素点u的光流。为了进一步说明向量d的含义。我们假设前一帧图像经历了仿射变换到后一帧图像,定义变换矩阵为
定义误差
典型的wx和wy取值为1,2,3,4,5,6,7个像素,相似度的函数被在(2ωx+1, 2ωy+1)的区域内定义。注意在金字塔各层窗口的大小是保持恒定的尺寸
金字塔的建立
令I0 = I 是第 0 层的图像,它是金字塔图像中分辨率最高的图像,图像的宽度和高度分别定义为nx0 = nx 和 ny0 = ny 。以一种递归的方式建立金字塔:从I0中计算I1,从I1中计算I2 ,···。令L =1, 2,...代表金字塔的层数,L通常取2,3,4。IL−1 是第L−1层的图像,nxL−1 和 nyL−1分别是图像IL−1 的宽度和高度。图像IL可按如下方式由IL−1 求得:
即用一个[0.25 0.5 0.25]的低通滤波器对IL-1进行卷积。
金字塔跟踪
总体来讲,金字塔特征跟踪算法描述如下:首先,光流和仿射变换矩阵在最高一层的图像上计算出;将上一层的计算结果作为初始值传递给下一层图像,这一层的图像在这个初始值的基础上,计算这一层的光流和仿射变化矩阵;再将这一层的光流和仿射矩阵作为初始值传递给下一层图像,直到传递给最后一层,即原始图像层,这一层计算出来的光流和仿射变换矩阵作为最后的光流和仿射变换矩阵的结果。
对于L=0,1,2,…L,定义是图像中像素点u在第L层对应点的坐标。根据上一步中图像金字塔的定义,可以计算出
我们用数学的思想重新描述在L层和L+1层迭代运算,假定在第L层有对被跟踪目标的位置有个大致估计,而从第L+1层传递到L层的运动矢量,即光流计算初值为(后面会对gL做一个解释)并且对于最上层的变换矩阵猜测
为了在L层上计算光流和仿射变换矩阵,需要重新定义在L层上的匹配误差ξL:
其中图像和是原始图像在L层上采样出来的图像,基于这层中的光流和仿射矩阵初值gL和GL可以计算出两个对应图像和:
这里用L+1层得到的最初估计gL对L层作预平移,L层在gL的基础上求该层的光流dL,这样求得的残余光流向量dL= [dLx, dLy]T就足够小,因此能够通过标准的光流法来求出这个运动矢量。然后得到的dL结合gL又可以对L-1层的gL-1做估计。最终的光流和就是在所有层的分段光流d的叠加。使用金字塔图像计算光流的一个明显的好处是,对于一个有着较大的像素偏移的矢量d,可以通过计算几个比较小的残余光流来得到。这里就是金字塔跟踪算法的核心。
接下来就是计算该层上的光流dL和变换矩阵AL,我们将在下一步中谈论。现在,假设在这一层上的光流和变换矩阵己经计算出来。接着将结果传递给下一层,计算出下一层的假设初值:
将gL-1和GL-1作为初值,重新循环上面的步骤,直到最上一层,计算出光流d和仿射变换矩阵A。
由于金字塔的缩放减小了光流值,最高层的光流估计值可以设为0,设顶层时的初始为:
这种算法最明显的优势在于对于每一层的光流都会保持很小,但是最终计算来的光流可以进行累积,便于有效地跟踪特征点。
迭代过程
这一步是算法的核心步骤。在金字塔的每一层,目标是计算出光流dL和仿射变换矩阵AL从而使误差ξL最小。由于每一层的迭代过程是相同的,所以我们就描述从一层到下一层的迭代过程。首先将上一层的光流u和A传给这一层,计算这一帧图像中像素点的光照,同时计算出图像在该点x方向和y方向上的偏导
Ix=[I(x+1,y)-I(x-1,y)]/2
Iy=[I(x,y+1)-I(x,y-1)]/2
在此基础上,计算出空间梯度矩阵:
更新光流v=2*v
迭代过程:计算后一帧图像中对应像素点的灰度,计算两
帧图像间相同位置点的灰度值之差,在计算图像之间的误差
向量:
最后计算针对仿射光流
,
更新跟踪结果
直到某个阈值,结束在这一层的迭代过程。
特征点选择
因此,可按照以下的步骤选择特征点:
1、计算图像 I 中每一个像素的矩阵G和最小特征值λm。
2、寻找整副图像中最小特征值 λm 中的最大特征值λmax。
3、保留最小特征值 λm 大于给定阈值的像素点。阈值通常取5% λmax ~10% λmax 。
4、保留 λm 局部最大值的像素:像素特征值 λm 大于其3*3 邻域中其他像素的特征值 λm 。
5、剔除像素密集区域中的一些像素,确保图像中相邻像素的距离都大于给定的阈值(常取5~10 pixels)。
上述操作完成后,图像 I 中剩下的像素即为选择的特征点,并作为跟踪特征点。特征点选择算法的步骤5 确保了特征点间的最小距离。
没有必要取一个大的综合窗口选择特征点(或计算矩阵G)。大量实验证明,wx = wy =1的 3*3 大小的综合窗口能够取得满意的效果。
金字塔高度的选择
在大多数的情况下,超过4的金字塔图像层次没有太大的意义。
有时为了简化可以将仿射变换矩阵G简化为单位矩阵。
算法流程
下面是我的实现。
- #ifndef _LKOF_
- #define _LKOF_
- /***********Lucas-Kanade optical flow track**********/
- /*****************author Marshall********************/
- /**********************2015.10.14********************/
- /******************version 1.0***********************/
- class LucasKanadeTracker
- {
- struct DBPoint
- {
- double x;
- double y;
- DBPoint(const double X, const double Y):x(X),y(Y){
- }
- DBPoint(){}
- };
- int*height;
- int*width;
- private:
- unsigned int max_pyramid_layer;
- unsigned int original_imgH;
- unsigned int original_imgW;
- unsigned int window_radius;
- BYTE**pre_pyr;//the pyramid of previous frame image,img1_pyr[0] is of max size
- BYTE**next_pyr;//the frame after img1_pyr
- bool isusepyramid;
- DBPoint*target,*endin;
- int numofpoint;
- private:
- void build_pyramid(BYTE**&original_gray);
- void lucaskanade(BYTE**&frame_pre, BYTE**&frame_cur, DBPoint*& start,
- DBPoint*& finish, unsigned int point_nums, char*state);
- void get_max_pyramid_layer();
- void pyramid_down(BYTE*&src_gray_data, const int src_h,
- const int src_w, BYTE*& dst, int&dst_h, int&dst_w);
- void lowpass_filter(BYTE*&src, const int H, const int W, BYTE*&smoothed);
- double get_subpixel(BYTE*&src, int h, int w, const DBPoint& point);
- // caculate the inverse mareix of pMatrix,the result is put into _pMatrix
- void ContraryMatrix(double *pMatrix, double * _pMatrix, int dim);
- bool matrixMul(double *src1, int height1, int width1, double *src2, int height2, int width2, double *dst);
- public:
- LucasKanadeTracker(const int windowRadius, bool usePyr);
- ~LucasKanadeTracker();
- void get_pre_frame(BYTE*&gray);//use only at the beginning
- void discard_pre_frame();
- //set the next frame as pre_frame,must dicard pre_pyr in advance
- void get_pre_frame();
- //use every time,must after using get_pre_frame(BYTE**pyr)
- void get_next_frame(BYTE*&gray);
- void get_info(const int nh, const int nw);
- void get_target(POINT*target, int n);
- void run_single_frame();
- POINT get_result();
- BYTE*&get_pyramid(int th);
- int get_pyrH(int th){ return height[th]; }
- int get_pyrW(int th){ return width[th]; }
- };
- #endif
- #include "stdafx.h"
- #include "LucasKanadeTracker.h"
- using namespace std;
- LucasKanadeTracker::LucasKanadeTracker(const int windowRadius, bool usePyr)
- :window_radius(windowRadius), isusepyramid(usePyr)
- {
- }
- LucasKanadeTracker::~LucasKanadeTracker()
- {
- for (int i = 0; i < max_pyramid_layer; i++)
- {
- if (pre_pyr[i])
- delete[]pre_pyr[i];
- if (next_pyr[i])
- delete[]next_pyr[i];
- }
- delete[]pre_pyr;
- delete[]next_pyr;
- if (height)
- delete[]height;
- if (width)
- delete[]width;
- }
- void LucasKanadeTracker::lowpass_filter(BYTE*&src, const int H, const int W, BYTE*&smoothed)
- {
- //tackle with border
- for (int i = 0; i < H; i++)
- {
- smoothed[i*W] = src[i*W];
- smoothed[i*W + W - 1] = src[i*W + W - 1];
- }
- for (int i = 0; i < W; i++)
- {
- smoothed[i] = src[i];
- smoothed[(H - 1)*W + i] = src[(H - 1)*W + i];
- }
- for (int i = 1; i < H - 1; i++)
- for (int j = 1; j < W - 1; j++)
- {
- double re = 0;
- re += src[i*W + j] * 0.25;
- re += src[(i - 1)*W + j] * 0.125;
- re += src[i*W + j + 1] * 0.125;
- re += src[i*W + j - 1] * 0.125;
- re += src[(i + 1)*W + j] * 0.125;
- re += src[(i - 1)*W + j - 1] * 0.0625;
- re += src[(i + 1)*W + j - 1] * 0.0625;
- re += src[(i - 1)*W + j + 1] * 0.0625;
- re += src[(i + 1)*W + j + 1] * 0.0625;
- smoothed[i*W + j] = BYTE(re);
- }
- delete[]src;
- src = smoothed;
- }
- void LucasKanadeTracker::get_info(const int nh, const int nw)
- {
- original_imgH = nh;
- original_imgW = nw;
- if (isusepyramid)
- get_max_pyramid_layer();
- else
- max_pyramid_layer = 1;
- pre_pyr = new BYTE*[max_pyramid_layer];
- next_pyr = new BYTE*[max_pyramid_layer];
- height = new int[max_pyramid_layer];
- width = new int[max_pyramid_layer];
- height[0] = nh;
- width[0] = nw;
- }
- void LucasKanadeTracker::get_target(POINT*target, int n)
- {
- this->target = new DBPoint[n];
- endin = new DBPoint[n];
- for (int i = 0; i < n; i++)
- {
- this->target[i].x = target[i].x;
- this->target[i].y = target[i].y;
- }
- numofpoint = n;
- }
- BYTE*&LucasKanadeTracker::get_pyramid(int th)
- {
- return pre_pyr[th];
- }
- POINT LucasKanadeTracker::get_result()
- {
- POINT pp;
- pp.x = target[0].x;
- pp.y = target[0].y;
- return pp;
- }
- void LucasKanadeTracker::get_pre_frame(BYTE*&gray)//use only at the beginning
- {
- pre_pyr[0] = gray;
- build_pyramid(pre_pyr);
- //save_gray("1.bmp", pre_pyr[1], height[1], width[1]);
- }
- void LucasKanadeTracker::discard_pre_frame()
- {
- //we don't new memory for original data,so we don't delete it here
- for (int i = 0; i < max_pyramid_layer; i++)
- delete[]pre_pyr[i];
- }
- //set the next frame as pre_frame,must dicard pre_pyr in advance
- void LucasKanadeTracker::get_pre_frame()
- {
- for (int i = 0; i < max_pyramid_layer; i++)
- pre_pyr[i] = next_pyr[i];
- }
- //use every time,must after using get_pre_frame(BYTE**pyr)
- void LucasKanadeTracker::get_next_frame(BYTE*&gray)
- {
- next_pyr[0] = gray;
- build_pyramid(next_pyr);
- //save_gray("1.bmp", next_pyr[1], height[1], width[1]);
- }
- void LucasKanadeTracker::pyramid_down(BYTE*&src_gray_data,
- const int src_h, const int src_w, BYTE*& dst, int&dst_h, int&dst_w)
- {
- dst_h = src_h / 2;
- dst_w = src_w / 2;
- int ii = height[1];
- int hh = width[1];
- assert(dst_w > 3 && dst_h > 3);
- //BYTE*smoothed = new BYTE[src_h*src_w];
- dst = new BYTE[dst_h*dst_w];
- //lowpass_filter(src_gray_data, src_h, src_w,smoothed);
- for (int i = 0; i < dst_h - 1; i++)
- for (int j = 0; j < dst_w - 1; j++)
- {
- int srcY = 2 * i + 1;
- int srcX = 2 * j + 1;
- double re = src_gray_data[srcY*src_w + srcX] * 0.25;
- re += src_gray_data[(srcY - 1)*src_w + srcX] * 0.125;
- re += src_gray_data[(srcY + 1)*src_w + srcX] * 0.125;
- re += src_gray_data[srcY*src_w + srcX - 1] * 0.125;
- re += src_gray_data[srcY*src_w + srcX + 1] * 0.125;
- re += src_gray_data[(srcY - 1)*src_w + srcX + 1] * 0.0625;
- re += src_gray_data[(srcY - 1)*src_w + srcX - 1] * 0.0625;
- re += src_gray_data[(srcY + 1)*src_w + srcX - 1] * 0.0625;
- re += src_gray_data[(srcY + 1)*src_w + srcX + 1] * 0.0625;
- dst[i*dst_w + j] = re;
- }
- for (int i = 0; i < dst_h; i++)
- dst[i*dst_w + dst_w - 1] = dst[i*dst_w + dst_w - 2];
- for (int i = 0; i < dst_w; i++)
- dst[(dst_h - 1)*dst_w + i] = dst[(dst_h - 2)*dst_w + i];
- }
- //bilinear interplotation
- double LucasKanadeTracker::get_subpixel(BYTE*&src, int h, int w, const DBPoint& point)
- {
- int floorX = floor(point.x);
- int floorY = floor(point.y);
- double fractX = point.x - floorX;
- double fractY = point.y - floorY;
- return ((1.0 - fractX) * (1.0 - fractY) * src[floorX + w* floorY])
- + (fractX * (1.0 - fractY) * src[floorX + 1 + floorY*w])
- + ((1.0 - fractX) * fractY * src[floorX + (floorY + 1)*w])
- + (fractX * fractY * src[floorX + 1 + (floorY + 1)*w]);
- }
- void LucasKanadeTracker::get_max_pyramid_layer()
- {
- int layer = 0;
- int windowsize = 2 * window_radius + 1;
- int temp = original_imgH > original_imgW ?
- original_imgW : original_imgH;
- if (temp > ((1 << 4) * 2 * windowsize))
- {
- max_pyramid_layer = 5;
- return;
- }
- temp = double(temp) / 2;
- while (temp > 2 * windowsize)
- {
- layer++;
- temp = double(temp) / 2;
- }
- max_pyramid_layer = layer;
- }
- void LucasKanadeTracker::build_pyramid(BYTE**&pyramid)
- {
- for (int i = 1; i < max_pyramid_layer; i++)
- {
- pyramid_down(pyramid[i - 1], height[i - 1],
- width[i - 1], pyramid[i], height[i], width[i]);
- }
- }
- void LucasKanadeTracker::run_single_frame()
- {
- char*state = NULL;
- lucaskanade(pre_pyr, next_pyr, target, endin, numofpoint, state);
- for (int i = 0; i < numofpoint; i++)
- {
- target[i].x = endin[i].x;
- target[i].y = endin[i].y;
- }
- }
- void LucasKanadeTracker::lucaskanade(BYTE**&frame_pre, BYTE**&frame_cur,
- DBPoint*& start, DBPoint*& finish, unsigned int point_nums, char*state)
- {
- double*derivativeXs = new double
- [(2 * window_radius + 1)*(2 * window_radius + 1)];
- double*derivativeYs = new double
- [(2 * window_radius + 1)*(2 * window_radius + 1)];
- for (int i = 0; i < point_nums; i++)
- {
- double g[2] = { 0 };
- double finalopticalflow[2] = { 0 };
- memset(derivativeXs, 0, sizeof(double)*
- (2 * window_radius + 1)*(2 * window_radius + 1));
- memset(derivativeYs, 0, sizeof(double)*
- (2 * window_radius + 1)*(2 * window_radius + 1));
- for (int j = max_pyramid_layer - 1; j >= 0; j--)
- {
- DBPoint curpoint;
- curpoint.x = start[i].x / pow(2.0, j);
- curpoint.y = start[i].y / pow(2.0, j);
- double Xleft = curpoint.x - window_radius;
- double Xright = curpoint.x + window_radius;
- double Yleft = curpoint.y - window_radius;
- double Yright = curpoint.y + window_radius;
- double gradient[4] = { 0 };
- int cnt = 0;
- for (double xx = Xleft; xx < Xright + 0.01; xx += 1.0)
- for (double yy = Yleft; yy < Yright + 0.01; yy += 1.0)
- {
- assert(xx < 1000 && yy < 1000 && xx >= 0 && yy >= 0);
- double derivativeX = get_subpixel(frame_pre[j],
- height[j], width[j], DBPoint(xx + 1.0, yy)) -
- get_subpixel(frame_pre[j], height[j],
- width[j], DBPoint(xx - 1.0, yy));
- derivativeX /= 2.0;
- double t1 = get_subpixel
- (frame_pre[j], height[j], width[j], DBPoint(xx, yy + 1.0));
- double t2 = get_subpixel(frame_pre[j], height[j],
- width[j], DBPoint(xx, yy - 1.0));
- double derivativeY = (t1 - t2) / 2.0;
- derivativeXs[cnt] = derivativeX;
- derivativeYs[cnt++] = derivativeY;
- gradient[0] += derivativeX * derivativeX;
- gradient[1] += derivativeX * derivativeY;
- gradient[2] += derivativeX * derivativeY;
- gradient[3] += derivativeY * derivativeY;
- }
- double gradient_inv[4] = { 0 };
- ContraryMatrix(gradient, gradient_inv, 2);
- double opticalflow[2] = { 0 };
- int max_iter = 50;
- double opticalflow_residual = 1;
- int iteration = 0;
- while (iteration<max_iter&&opticalflow_residual>0.00001)
- {
- iteration++;
- double mismatch[2] = { 0 };
- cnt = 0;
- for (double xx = Xleft; xx < Xright + 0.001; xx += 1.0)
- for (double yy = Yleft; yy < Yright + 0.001; yy += 1.0)
- {
- assert(xx < 1000 && yy < 1000 && xx >= 0 && yy >= 0);
- double nextX = xx + g[0] + opticalflow[0];
- double nextY = yy + g[1] + opticalflow[1];
- assert(nextX < 1000 && nextY < 1000 && nextX >= 0 && nextY >= 0);
- double pixelDifference = (get_subpixel(frame_pre[j],
- height[j], width[j], DBPoint(xx, yy))
- - get_subpixel(frame_cur[j], height[j],
- width[j], DBPoint(nextX, nextY)));
- mismatch[0] += pixelDifference*derivativeXs[cnt];
- mismatch[1] += pixelDifference*derivativeYs[cnt++];
- }
- double temp_of[2];
- matrixMul(gradient_inv, 2, 2, mismatch, 2, 1, temp_of);
- opticalflow[0] += temp_of[0];
- opticalflow[1] += temp_of[1];
- opticalflow_residual = abs(temp_of[0]) + abs(temp_of[1]);
- }
- if (j == 0)
- {
- finalopticalflow[0] = opticalflow[0];
- finalopticalflow[1] = opticalflow[1];
- }
- else
- {
- g[0] = 2 * (g[0] + opticalflow[0]);
- g[1] = 2 * (g[1] + opticalflow[1]);
- }
- }
- finalopticalflow[0] += g[0];
- finalopticalflow[1] += g[1];
- finish[i].x = start[i].x + finalopticalflow[0];
- finish[i].y = start[i].y + finalopticalflow[1];
- }
- delete[]derivativeXs, derivativeYs;
- }
- //matrix inverse
- void LucasKanadeTracker::ContraryMatrix(double *pMatrix, double * _pMatrix, int dim)
- {
- double *tMatrix = new double[2 * dim*dim];
- for (int i = 0; i < dim; i++){
- for (int j = 0; j < dim; j++)
- tMatrix[i*dim * 2 + j] = pMatrix[i*dim + j];
- }
- for (int i = 0; i < dim; i++){
- for (int j = dim; j < dim * 2; j++)
- tMatrix[i*dim * 2 + j] = 0.0;
- tMatrix[i*dim * 2 + dim + i] = 1.0;
- }
- //Initialization over!
- for (int i = 0; i < dim; i++)//Process Cols
- {
- double base = tMatrix[i*dim * 2 + i];
- if (fabs(base) < 1E-300){
- // AfxMessageBox("求逆矩阵过程中被零除,无法求解!" );
- _ASSERTE(-1);//throw exception
- exit(0);
- }
- for (int j = 0; j < dim; j++)//row
- {
- if (j == i) continue;
- double times = tMatrix[j*dim * 2 + i] / base;
- for (int k = 0; k < dim * 2; k++)//col
- {
- tMatrix[j*dim * 2 + k] = tMatrix[j*dim * 2 + k] - times*tMatrix[i*dim * 2 + k];
- }
- }
- for (int k = 0; k < dim * 2; k++){
- tMatrix[i*dim * 2 + k] /= base;
- }
- }
- for (int i = 0; i < dim; i++)
- {
- for (int j = 0; j < dim; j++)
- _pMatrix[i*dim + j] = tMatrix[i*dim * 2 + j + dim];
- }
- delete[] tMatrix;
- }
- bool LucasKanadeTracker::matrixMul(double *src1, int height1, int width1, double *src2, int height2, int width2, double *dst)
- {
- int i, j, k;
- double sum = 0;
- double *first = src1;
- double *second = src2;
- double *dest = dst;
- int Step1 = width1;
- int Step2 = width2;
- if (src1 == NULL || src2 == NULL || dest == NULL || height2 != width1)
- return false;
- for (j = 0; j < height1; j++)
- {
- for (i = 0; i < width2; i++)
- {
- sum = 0;
- second = src2 + i;
- for (k = 0; k < width1; k++)
- {
- sum += first[k] * (*second);
- second += Step2;
- }
- dest[i] = sum;
- }
- first += Step1;
- dest += Step2;
- }
- return true;
- }
下面是两帧图像间特征点的跟踪
参考文献:Pyramidal Implementation of the AÆne Lucas Kanade Feature Tracker Description of the algorithm
An Iterative Image Registration Technique with an Application to Stereo Vision
Detection and Tracking of Point Features
Good Features to Track
Derivation of Kanade-Lucas-Tomasi Tracking Equation
目标跟踪之Lukas-Kanade光流法(转)的更多相关文章
- 目标跟踪之klt---光流跟踪法
近来在研究跟踪,跟踪的方法其实有很多,如粒子滤波(pf).meanshift跟踪,以及KLT跟踪或叫Lucas光流法,这些方法各自有各自的有点,对于粒子滤波而言,它能够比较好的在全局搜索到最优解,但其 ...
- 目标跟踪ObjectT综述介绍
此文也很详细:http://blog.csdn.net/maochongsandai110/article/details/11530045 原文链接:http://blog.csdn.net/pp5 ...
- 目标跟踪之Lukas-Kanade光流法
转载自:http://blog.csdn.net/u014568921/article/details/46638557 光流是图像亮度的运动信息描述.光流法计算最初是由Horn和Schunck于19 ...
- 光流法跟踪fast角点思路
光流法需要include<opencv2/video/tracking.hpp>,用到列表,所以要include<list><vector>1.读取文件定义图像存储 ...
- 【图像处理】openCV光流法追踪运动物体
openCV光流法追踪运动物体 email:chentravelling@163.com 一.光流简单介绍 摘自:zouxy09 光流的概念是Gibson在1950年首先提出来的.它是空间运动物体在观 ...
- 【Matlab】运动目标检测之“光流法”
光流(optical flow) 1950年,Gibson首先提出了光流的概念,所谓光流就是指图像表现运动的速度.物体在运动的时候之所以能被人眼发现,就是因为当物体运动时,会在人的视网膜上形成一系列的 ...
- Lucas–Kanade光流算法学习
Lucas–Kanade光流算法是一种两帧差分的光流估计算法.它由Bruce D. Lucas 和 Takeo Kanade提出. 光流(Optical flow or optic f ...
- Video Target Tracking Based on Online Learning—TLD单目标跟踪算法详解
视频目标跟踪问题分析 视频跟踪技术的主要目的是从复杂多变的的背景环境中准确提取相关的目标特征,准确地识别出跟踪目标,并且对目标的位置和姿态等信息精确地定位,为后续目标物体行为分析提供足 ...
- 光流法(optical flow)
光流分为稠密光流和稀疏光流 光流(optic flow)是什么呢?名字很专业,感觉很陌生,但本质上,我们是最熟悉不过的了.因为这种视觉现象我们每天都在经历.从本质上说,光流就是你在这个运动着的世界里感 ...
随机推荐
- 跟着马哥学python-day02
1. 运算符 计算机可以进行的运算有很多种,可不只加减乘除这么简单,运算按种类可分为算数运算.比较运算.逻辑运算.赋值运算.成员运算.身份运算.位运算. 1.1 算数运算 以下假设变量:a=10,b= ...
- Linux IO多路复用 poll
Linux IO多路复用 poll 之前曾经提到过 select poll 跟select类似,poll改进了select的一个确定,就是poll没有监听上限 不过poll还是需要遍历以及频繁的把数组 ...
- 关于makefile中自动产生依赖的理解
本博文是在学习了<GNU Make中文手册>后记录下来的自己的关于自动产生makefile依赖的语句的理解,向大家分享. <GNU make中文手册>中的相关章节见一下链接: ...
- 解决 mysql in 查询排序问题
select id,title from za_item where -- id ,) 返回的结果第一条是对应id是1000,第二条是1003. 如果我们想让结果和in里面的排序一致,可以这么做. s ...
- R的数据库访问-MySQL
目录 1 RMySQL 2 环境与安装 3 建立通信 1 RMySQL R作为一款数据分析的工具,,而MySQL是一款常用的开源关系型数据库软件,非常适用于中小型的数据存储,当二者相互结合时才能爆发出 ...
- XAF-物料管理信息工作日志
前段时间已经开始了第一阶段验收了,客户方并未把重点放在业务流程上面,一直在调整一些界面问题.有点小纠结. 今天要调一下菜单位置. 没修改时,是这样的: 到了列表界面,会多一个全文检索出来. 后来,客户 ...
- 在tomcat5中发布项目时,用IP地址+端口不能访问项目,而用localhost加端口时可以访问成功
最近在开发项目中,遇到的一个问题是: 在 tomcat中发布一个web项目,但是发布成功后,只能用http://localhost:8080/fm访问项目,不能用 http://127.0.0.1:8 ...
- 韦大仙--LoadRunner压力测试:详细操作流程
一. 录制脚本 1.安装完毕后,创建脚本: 点击OK之后,会弹出网址,之后创建Action,每进一个页面添加一个Action,录制结束后,终止录制. 二. 修改脚本 1.脚本参数化 将登录的用户名密码 ...
- Python之requests的安装
在 windows 系统下,只需要输入命令 pip install requests ,即可安装. 在 linux 系统下,只需要输入命令 sudo pip install requests ,即可安 ...
- 合并SQL 调优
SELECT le.equipcode,sum(case when wo.ordertype=0 then 1 else 0 END) as wxcount,sum(case when wo.orde ...