mirror of https://github.com/odrling/Aegisub
little tenfex interface change
+ moved FexTracker to OPEN SOURCE :) Originally committed to SVN as r194.
This commit is contained in:
parent
12363b6dc5
commit
cd6beca548
|
@ -0,0 +1,78 @@
|
|||
#include <math.h>
|
||||
#include "FexGenericFilter_Include.h"
|
||||
|
||||
FexFilter::FexFilter()
|
||||
{
|
||||
Width = 3;
|
||||
}
|
||||
FexFilter::~FexFilter()
|
||||
{
|
||||
}
|
||||
double FexFilter::Filter( double t )
|
||||
{
|
||||
return t/Width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
f(x) = e^(-x^2 / (2 s^2) )
|
||||
f(x) = e^(-x^2 / t)
|
||||
|
||||
width:
|
||||
SOLVE(0.1 = f(x), x, Real)
|
||||
x = - sqrt(t LN(10) ? x = sqrt(t LN(10)
|
||||
|
||||
sum:
|
||||
|
||||
Integral from -sqrt(t LN(10) to sqrt(t LN(10) of f(x) dx
|
||||
1.715955662·sqrt(t)
|
||||
*/
|
||||
|
||||
FexFilter_Gauss::FexFilter_Gauss( double sigma )
|
||||
{
|
||||
Sigma = sigma;
|
||||
TwoSigmaSq = 2*sigma*sigma;
|
||||
Width = sqrt( TwoSigmaSq*log(10) );
|
||||
Normalize = 1.0 / (1.715955662 * sqrt( TwoSigmaSq ));
|
||||
}
|
||||
FexFilter_Gauss::~FexFilter_Gauss()
|
||||
{
|
||||
}
|
||||
|
||||
double FexFilter_Gauss::Filter( double t )
|
||||
{
|
||||
return exp( -t*t / TwoSigmaSq ) * Normalize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
f(x) = -x * e^(-x^2 / (2 s^2) )
|
||||
f(x) = -x * e^(-x^2 / t)
|
||||
|
||||
width:
|
||||
use the width of gauss since i'm clueless here
|
||||
|
||||
sum:
|
||||
|
||||
Integral from -sqrt(t LN(10) to sqrt(t LN(10) of -x*f(x) dx
|
||||
0.7062351183·t^1.5
|
||||
*/
|
||||
|
||||
FexFilter_GaussDerivation::FexFilter_GaussDerivation( double sigma )
|
||||
{
|
||||
Sigma = sigma;
|
||||
TwoSigmaSq = 2*sigma*sigma;
|
||||
Width = sqrt( TwoSigmaSq*log(10) );
|
||||
Normalize = 1.0 / (0.7062351183 * pow( TwoSigmaSq, 1.5 ));
|
||||
}
|
||||
|
||||
FexFilter_GaussDerivation::~FexFilter_GaussDerivation()
|
||||
{
|
||||
}
|
||||
|
||||
double FexFilter_GaussDerivation::Filter( double t )
|
||||
{
|
||||
return -t * exp( -t*t / TwoSigmaSq ) * Normalize;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include "stdio.h"
|
||||
#include "math.h"
|
||||
#include "memory.h"
|
||||
#include "FexGenericFilter_Include.h"
|
||||
|
||||
|
||||
void BaseFloatImage_Filter( float* in, int inSx, int inSy, FexFilter* filter, float* out, int outSx, int outSy )
|
||||
{
|
||||
#define FilterWidth (filter->Width)
|
||||
#define FilterWeight(t) (filter->Filter(t))
|
||||
|
||||
float* tmp = new float[outSx*inSy];
|
||||
#include "FexGenericFilter_BaseFloatImageApply.h"
|
||||
delete []tmp;
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
}
|
||||
|
||||
void BaseFloatImage_FilterSeperate( float* in, int inSx, int inSy, FexFilter* filterX, FexFilter* filterY, float* out, int outSx, int outSy )
|
||||
{
|
||||
float* tmp = new float[outSx*inSy];
|
||||
|
||||
#define FilterWidth (filterX->Width)
|
||||
#define FilterWeight(t) (filterX->Filter(t))
|
||||
#define FILTER_NO_Y
|
||||
|
||||
#include "FexGenericFilter_BaseFloatImageApply.h"
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
#undef FILTER_NO_Y
|
||||
|
||||
#define FilterWidth (filterY->Width)
|
||||
#define FilterWeight(t) (filterY->Filter(t))
|
||||
#define FILTER_NO_X
|
||||
|
||||
#include "FexGenericFilter_BaseFloatImageApply.h"
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
#undef FILTER_NO_X
|
||||
|
||||
delete []tmp;
|
||||
}
|
||||
|
||||
|
||||
void BaseFloatImage_GaussEdgeDetect( float* Img, int sizx, int sizy, float sigma, float* GradX, float* GradY )
|
||||
{
|
||||
FexFilter_Gauss gauss (sigma);
|
||||
FexFilter_GaussDerivation gaussDeriv (sigma);
|
||||
|
||||
BaseFloatImage_FilterSeperate( Img, sizx, sizy, &gaussDeriv, &gauss, GradX, sizx, sizy );
|
||||
BaseFloatImage_FilterSeperate( Img, sizx, sizy, &gauss, &gaussDeriv, GradY, sizx, sizy );
|
||||
}
|
||||
|
||||
void BaseFloatImage_GaussSmooth( float* Img, int sizx, int sizy, float sigma, float* Out )
|
||||
{
|
||||
FexFilter_Gauss gauss (sigma);
|
||||
BaseFloatImage_Filter( Img, sizx,sizy, &gauss, Out, sizx, sizy );
|
||||
}
|
||||
|
||||
#include <math.h>
|
||||
inline double sinc( double x )
|
||||
{
|
||||
x *= 3.1415;
|
||||
if( x != 0 )
|
||||
return( sin(x) / x );
|
||||
return( 1.0 );
|
||||
}
|
||||
inline double RescaleFilter( double t )
|
||||
{
|
||||
if( t < 0 )
|
||||
t = -t;
|
||||
if( t < 3.0 )
|
||||
return( sinc(t) * sinc(t/3.0) );
|
||||
return( 0.0 );
|
||||
}
|
||||
|
||||
void BaseFloatImage_LanczosRescale( float* in, int inSx, int inSy, float* out, int outSx, int outSy )
|
||||
{
|
||||
#define FilterWidth (3)
|
||||
#define FilterWeight(t) (RescaleFilter(t))
|
||||
|
||||
float* tmp = new float[outSx*inSy];
|
||||
#include "FexGenericFilter_BaseFloatImageApply.h"
|
||||
delete []tmp;
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
#define PixelType float
|
||||
#define PixelMin 0
|
||||
#define PixelMax 255
|
||||
#define ImagePlanes 1
|
||||
|
||||
//do filtering + scaling in x-dir
|
||||
#define ImageInSX (inSx)
|
||||
#define ImageInSY (inSy)
|
||||
#define ImageIn(x,y,p) (in[ (y*inSx+x) ])
|
||||
#define ImageOutSX (outSx)
|
||||
#define ImageOut(x,y,p) (tmp[ (y*outSx+x) ])
|
||||
|
||||
#ifndef FILTER_NO_X
|
||||
#include "FexGenericFilter_FilteringCore.h"
|
||||
#endif
|
||||
|
||||
#undef ImageInSX
|
||||
#undef ImageInSY
|
||||
#undef ImageIn
|
||||
#undef ImageOutSX
|
||||
#undef ImageOut
|
||||
|
||||
//do filtering + scaling in y-dir by using transposed image
|
||||
|
||||
#define ImageInSX (inSy)
|
||||
#define ImageInSY (outSx)
|
||||
#define ImageIn(y,x,p) (tmp[ (y*outSx+x) ])
|
||||
#define ImageOutSX (outSy)
|
||||
#define ImageOut(y,x,p) (out[ (y*outSx+x) ])
|
||||
|
||||
#ifndef FILTER_NO_Y
|
||||
#include "FexGenericFilter_FilteringCore.h"
|
||||
#endif
|
||||
|
||||
#undef ImageInSX
|
||||
#undef ImageInSY
|
||||
#undef ImageIn
|
||||
#undef ImageOutSX
|
||||
#undef ImageOut
|
||||
|
||||
#undef PixelType
|
||||
#undef PixelMin
|
||||
#undef PixelMax
|
||||
#undef ImagePlanes
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
double width = FilterWidth;
|
||||
#ifdef CONTRIB_XSCALE
|
||||
width /= XScale;
|
||||
double fscale = 1.0 / XScale;
|
||||
#endif
|
||||
|
||||
for(int i=0;i<ImageOutSX;++i)
|
||||
{
|
||||
double center = (double) i / XScale;
|
||||
FexFilterContribution* cc = &Contrib[i];
|
||||
int left = (int) ceil(center - width);
|
||||
int right = (int) (floor(center + width) + 0.1);
|
||||
|
||||
cc->xMin = left;
|
||||
cc->xMax = right;
|
||||
if( cc->xMin < 0 ) cc->xMin = 0;
|
||||
if( cc->xMax > ImageInSX-1 ) cc->xMax = ImageInSX - 1;
|
||||
|
||||
int len = cc->xMax-cc->xMin+1;
|
||||
cc->Weight = new double[ len ];
|
||||
memset( cc->Weight, 0x00, sizeof(double)*len );
|
||||
|
||||
for(int j=left;j<=right;++j) {
|
||||
double weight = center - (double) j;
|
||||
#ifdef CONTRIB_XSCALE
|
||||
weight = FilterWeight(weight / fscale) / fscale;
|
||||
#else
|
||||
weight = FilterWeight(weight);
|
||||
#endif
|
||||
int n;
|
||||
if(j < 0) n=0;
|
||||
else if(j >= ImageInSX) n = ImageInSX - 1;
|
||||
else n = j;
|
||||
cc->Weight[n-cc->xMin] += weight;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#include "stdafx.h"
|
||||
#include "FexSystem.h"
|
||||
#include "ext\imdebug.h"
|
||||
|
||||
|
||||
void FexImage_Filter( FexImage* in, FexFilter* filter, FexImage* out )
|
||||
{
|
||||
#define FilterWidth (filter->Width)
|
||||
#define FilterWeight(t) (filter->Filter(t))
|
||||
|
||||
#include "FexGenericFilter_FexImageApply.h"
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include <math.h>
|
||||
inline double sinc( double x )
|
||||
{
|
||||
x *= 3.1415;
|
||||
if( x != 0 )
|
||||
return( sin(x) / x );
|
||||
return( 1.0 );
|
||||
}
|
||||
inline double RescaleFilter( double t )
|
||||
{
|
||||
if( t < 0 )
|
||||
t = -t;
|
||||
if( t < 3.0 )
|
||||
return( sinc(t) * sinc(t/3.0) );
|
||||
return( 0.0 );
|
||||
}
|
||||
|
||||
|
||||
void FexImage_Rescale( FexImage* in, FexImage* out )
|
||||
{
|
||||
#define FilterWidth (3)
|
||||
#define FilterWeight(t) (RescaleFilter(t))
|
||||
|
||||
#include "FexGenericFilter_FexImageApply.h"
|
||||
|
||||
#undef FilterWidth
|
||||
#undef FilterWeight
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
#define PixelType BYTE
|
||||
#define PixelMin 0
|
||||
#define PixelMax 255.9
|
||||
#define ImagePlanes 4
|
||||
|
||||
FexImage* tmp = new FexImage(out->sx,in->sy);
|
||||
|
||||
//do filtering + scaling in x-dir
|
||||
#define ImageInSX (in->sx)
|
||||
#define ImageInSY (in->sy)
|
||||
#define ImageIn(x,y,p) (in->data[ (y*in->sx+x)*4 + p ])
|
||||
#define ImageOutSX (tmp->sx)
|
||||
#define ImageOut(x,y,p) (tmp->data[ (y*tmp->sx+x)*4 + p ])
|
||||
|
||||
#include "FexGenericFilter_FilteringCore.h"
|
||||
|
||||
#undef ImageInSX
|
||||
#undef ImageInSY
|
||||
#undef ImageIn
|
||||
#undef ImageOutSX
|
||||
#undef ImageOut
|
||||
|
||||
//do filtering + scaling in y-dir by using transposed image
|
||||
|
||||
#define ImageInSX (tmp->sy)
|
||||
#define ImageInSY (tmp->sx)
|
||||
#define ImageIn(y,x,p) (tmp->data[ (y*tmp->sx+x)*4 + p ])
|
||||
#define ImageOutSX (out->sy)
|
||||
#define ImageOut(y,x,p) (out->data[ (y*out->sx+x)*4 + p ])
|
||||
|
||||
#include "FexGenericFilter_FilteringCore.h"
|
||||
|
||||
#undef ImageInSX
|
||||
#undef ImageInSY
|
||||
#undef ImageIn
|
||||
#undef ImageOutSX
|
||||
#undef ImageOut
|
||||
|
||||
delete tmp;
|
||||
|
||||
#undef PixelType
|
||||
#undef PixelMin
|
||||
#undef PixelMax
|
||||
#undef ImagePlanes
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
FexFilterContribution* Contrib = new FexFilterContribution[ ImageOutSX ];
|
||||
double XScale = (double)ImageOutSX / (double) ImageInSX;
|
||||
|
||||
//calculate contributions
|
||||
|
||||
if( XScale < 1.0 )
|
||||
{
|
||||
#define CONTRIB_XSCALE
|
||||
#include "FexGenericFilter_Contribution.h"
|
||||
#undef CONTRIB_XSCALE
|
||||
}
|
||||
else
|
||||
{
|
||||
#include "FexGenericFilter_Contribution.h"
|
||||
}
|
||||
|
||||
|
||||
#include "FexGenericFilter_StaticFor.h"
|
||||
//apply filter
|
||||
|
||||
for( int y=0;y<ImageInSY;++y)
|
||||
{
|
||||
for( int x=0;x<ImageOutSX;++x )
|
||||
{
|
||||
FexFilterContribution* cc = &Contrib[x];
|
||||
|
||||
double Sum[ImagePlanes];
|
||||
#define DOFOR(i) Sum[i] = 0.0;
|
||||
STATIC_FOR
|
||||
#undef DOFOR
|
||||
|
||||
for( int lx=cc->xMin;lx<=cc->xMax;++lx )
|
||||
{
|
||||
#define DOFOR(i) Sum[i] += ((double)ImageIn(lx,y,i))*cc->Weight[lx-cc->xMin];
|
||||
STATIC_FOR
|
||||
#undef DOFOR
|
||||
}
|
||||
|
||||
#define DOFOR(i) {if(Sum[i]<PixelMin)Sum[i]=PixelMin;if(Sum[i]>PixelMax)Sum[i]=PixelMax;}
|
||||
STATIC_FOR
|
||||
#undef DOFOR
|
||||
|
||||
#define DOFOR(i) ImageOut(x,y,i) = (PixelType) Sum[i];
|
||||
STATIC_FOR
|
||||
#undef DOFOR
|
||||
}
|
||||
}
|
||||
|
||||
for( int x=0;x<ImageOutSX;++x )
|
||||
delete []Contrib[x].Weight;
|
||||
delete []Contrib;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
class FexFilter {
|
||||
public:
|
||||
FexFilter();
|
||||
~FexFilter();
|
||||
|
||||
virtual double Filter( double t );
|
||||
|
||||
double Width;
|
||||
};
|
||||
|
||||
class FexFilter_Gauss : public FexFilter {
|
||||
public:
|
||||
FexFilter_Gauss( double sigma );
|
||||
~FexFilter_Gauss();
|
||||
|
||||
double Filter( double t );
|
||||
|
||||
double Sigma;
|
||||
double TwoSigmaSq;
|
||||
double Normalize;
|
||||
};
|
||||
|
||||
class FexFilter_GaussDerivation : public FexFilter {
|
||||
public:
|
||||
FexFilter_GaussDerivation( double sigma );
|
||||
~FexFilter_GaussDerivation();
|
||||
|
||||
double Filter( double t );
|
||||
|
||||
double Sigma;
|
||||
double TwoSigmaSq;
|
||||
double Normalize;
|
||||
};
|
||||
|
||||
struct FexFilterContribution {
|
||||
int xMin, xMax;
|
||||
double* Weight;
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
#if ImagePlanes==1
|
||||
#define STATIC_FOR {DOFOR(0)}
|
||||
#elif ImagePlanes==3
|
||||
#define STATIC_FOR {DOFOR(0) DOFOR(1) DOFOR(2)}
|
||||
#elif ImagePlanes==4
|
||||
#define STATIC_FOR {DOFOR(0) DOFOR(1) DOFOR(2) DOFOR(3)}
|
||||
#else
|
||||
#define STATIC_FOR {for( int dofori=0;dofori<ImagePlanes;++doforti ){DOFOR(i)}}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// FexImgPyramid.cpp: implementation of the FexImgPyramid class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FexImgPyramid.h"
|
||||
#include "../FexGenericFilter/FexGenericFilter_Include.h"
|
||||
|
||||
void BaseFloatImage_GaussEdgeDetect( float* Img, int sizx, int sizy, float sigma, float* GradX, float* GradY );
|
||||
void BaseFloatImage_GaussSmooth( float* Img, int sizx, int sizy, float sigma, float* Out );
|
||||
void BaseFloatImage_LanczosRescale( float* in, int inSx, int inSy, float* out, int outSx, int outSy );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
FexImgPyramidLevel::FexImgPyramidLevel( int isx, int isy )
|
||||
{
|
||||
sx = isx;
|
||||
sy = isy;
|
||||
Img = new float[ sx*sy ];
|
||||
GradX = new float[ sx*sy ];
|
||||
GradY = new float[ sx*sy ];
|
||||
}
|
||||
|
||||
FexImgPyramidLevel::~FexImgPyramidLevel()
|
||||
{
|
||||
delete [] Img;
|
||||
delete [] GradX;
|
||||
delete [] GradY;
|
||||
}
|
||||
|
||||
void FexImgPyramidLevel::Fill( float* iImg, float DetectSmoothSigma )
|
||||
{
|
||||
/*
|
||||
for( int y=0;y<sy;y++ )
|
||||
for( int x=0;x<sx;x++ )
|
||||
Img[ sx*y + x ] = iImg[ sx*y + x ];
|
||||
*/
|
||||
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", sx, sy, iImg);
|
||||
BaseFloatImage_GaussSmooth( iImg, sx, sy, DetectSmoothSigma, Img );
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", sx, sy, Img);
|
||||
}
|
||||
|
||||
void FexImgPyramidLevel::Scale( FexImgPyramidLevel* old )
|
||||
{
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", old->sx, old->sy, old->Img);
|
||||
BaseFloatImage_LanczosRescale( old->Img, old->sx, old->sy, Img, sx, sy );
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", sx, sy, Img);
|
||||
}
|
||||
|
||||
void FexImgPyramidLevel::Calc( float EdgeDetectSigma )
|
||||
{
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", sx, sy, Img);
|
||||
BaseFloatImage_GaussEdgeDetect( Img, sx, sy, EdgeDetectSigma, GradX, GradY );
|
||||
imdebug("lum b=32f w=%d h=%d %p /2", sx, sy, GradX);
|
||||
imdebug("lum b=32f w=%d h=%d %p /2", sx, sy, GradY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FexImgPyramid::FexImgPyramid( float* Img, int SizX, int SizY, float EdgeDetectSigma, float DetectSmoothSigma, int iSubsampling, int Levels )
|
||||
{
|
||||
int i;
|
||||
|
||||
Subsampling = iSubsampling;
|
||||
|
||||
if( Levels == -1 ) Levels = 999;
|
||||
int mLvl = 0;
|
||||
int tsm = min(SizX,SizY);
|
||||
while( tsm>1 && tsm%2==0 )
|
||||
{
|
||||
tsm/=Subsampling;
|
||||
++mLvl;
|
||||
}
|
||||
if( Levels > mLvl ) Levels = mLvl;
|
||||
if( Levels < 1 ) Levels = 1;
|
||||
|
||||
nLevels = Levels;
|
||||
lLevels = new FexImgPyramidLevel*[ nLevels ];
|
||||
|
||||
lLevels[0] = new FexImgPyramidLevel( SizX, SizY );
|
||||
lLevels[0]->Fill( Img, DetectSmoothSigma );
|
||||
for( i=1;i<nLevels;i++ )
|
||||
{
|
||||
SizX /= Subsampling;
|
||||
SizY /= Subsampling;
|
||||
lLevels[i] = new FexImgPyramidLevel( SizX, SizY );
|
||||
lLevels[i]->Scale( lLevels[i-1] );
|
||||
}
|
||||
|
||||
float cmul = 1.f;
|
||||
for( i=0;i<nLevels;i++ )
|
||||
{
|
||||
lLevels[i]->CoordMul = cmul;
|
||||
lLevels[i]->Calc( EdgeDetectSigma );
|
||||
cmul /= Subsampling;
|
||||
}
|
||||
}
|
||||
|
||||
FexImgPyramid::~FexImgPyramid()
|
||||
{
|
||||
for( int i=0;i<nLevels;i++ )
|
||||
delete lLevels[i];
|
||||
delete [] lLevels;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// FexImgPyramid.h: interface for the FexImgPyramid class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_FEXIMGPYRAMID_H__B289955E_6660_483D_AF51_CE78F2D03944__INCLUDED_)
|
||||
#define AFX_FEXIMGPYRAMID_H__B289955E_6660_483D_AF51_CE78F2D03944__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
class FexImgPyramidLevel
|
||||
{
|
||||
public:
|
||||
FexImgPyramidLevel( int sx, int sy );
|
||||
~FexImgPyramidLevel();
|
||||
|
||||
int sx, sy;
|
||||
float CoordMul;
|
||||
|
||||
float* Img;
|
||||
float* GradX;
|
||||
float* GradY;
|
||||
|
||||
void Fill( float* Img, float DetectSmoothSigma );
|
||||
void Scale( FexImgPyramidLevel* old );
|
||||
void Calc( float EdgeDetectSigma );
|
||||
};
|
||||
|
||||
class FexImgPyramid
|
||||
{
|
||||
public:
|
||||
FexImgPyramid( float* Img, int SizX, int SizY, float EdgeDetectSigma, float DetectSmoothSigma, int Subsampling, int Levels );
|
||||
~FexImgPyramid();
|
||||
|
||||
int Subsampling;
|
||||
|
||||
FexImgPyramidLevel** lLevels;
|
||||
int nLevels;
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_FEXIMGPYRAMID_H__B289955E_6660_483D_AF51_CE78F2D03944__INCLUDED_)
|
|
@ -0,0 +1,94 @@
|
|||
// FexMovement.cpp: implementation of the FexMovement class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "stdio.h"
|
||||
#include <conio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
//#include <mmsystem.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
FexMovement::FexMovement()
|
||||
{
|
||||
FileName = 0;
|
||||
}
|
||||
|
||||
FexMovement::~FexMovement()
|
||||
{
|
||||
if( FileName ) delete []FileName;
|
||||
}
|
||||
|
||||
FEXTRACKER_API FexMovement* CreateMovement()
|
||||
{
|
||||
return new FexMovement();
|
||||
}
|
||||
|
||||
FEXTRACKER_API void LoadMovement( FexMovement* me, const unsigned short* Filename )
|
||||
{
|
||||
me->Frames.nVal = 0;
|
||||
|
||||
me->FileName = new WCHAR[ wcslen(Filename)+1 ];
|
||||
wcscpy( me->FileName, Filename );
|
||||
|
||||
FILE *fi = _wfopen( Filename, L"rt" );
|
||||
if( !fi ) return;
|
||||
int CurFeat = -1;
|
||||
char Line[512];
|
||||
while( !feof(fi) )
|
||||
{
|
||||
Line[0]=0;
|
||||
fgets( Line, 510, fi );
|
||||
if( !Line[0] ) break;
|
||||
FexMovementFrame f;
|
||||
int r = sscanf( Line, "(%f %f)(%f %f %f)(%f %f)",
|
||||
&f.Pos.x, &f.Pos.y,
|
||||
&f.Rot.x, &f.Rot.y, &f.Rot.z,
|
||||
&f.Scale.x, &f.Scale.y );
|
||||
if( r != 7 ) continue;
|
||||
me->Frames.Add( f );
|
||||
}
|
||||
fclose( fi );
|
||||
}
|
||||
FEXTRACKER_API void SaveMovement( FexMovement* me, const unsigned short* Filename )
|
||||
{
|
||||
FILE *fi = _wfopen( Filename, L"wt" );
|
||||
if( !fi ) return;
|
||||
for( int i=0;i<me->Frames.size();i++ )
|
||||
{
|
||||
const FexMovementFrame f = me->Frames[i];
|
||||
fprintf( fi, "(%f %f)(%f %f %f)(%f %f)\n",
|
||||
f.Pos.x, f.Pos.y,
|
||||
f.Rot.x, f.Rot.y, f.Rot.z,
|
||||
f.Scale.x, f.Scale.y );
|
||||
}
|
||||
fclose( fi );
|
||||
}
|
||||
/*
|
||||
const WCHAR* FEXTRACKER_API GetUniqueName()
|
||||
{
|
||||
static WCHAR Name[512];
|
||||
time_t long_time;
|
||||
time( &long_time );
|
||||
|
||||
swprintf( Name, L"%x%x\n", timeGetTime(), long_time );
|
||||
|
||||
for( DWORD i=0;i<wcslen(Name);i++ )
|
||||
{
|
||||
Name[i] = towlower( Name[i] );
|
||||
if( Name[i]<'a' || Name[i]>'z' )
|
||||
Name[i] = '_';
|
||||
}
|
||||
wcscat( Name, L".fexmove" );
|
||||
return Name;
|
||||
}
|
||||
*/
|
||||
FEXTRACKER_API void DeleteMovement( FexMovement* delme )
|
||||
{
|
||||
delete delme;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// FexMovement.h: interface for the FexMovement class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_FEXMOVEMENT_H__63D8ADD8_4EA1_4C56_8D6F_7B587A1A61A4__INCLUDED_)
|
||||
#define AFX_FEXMOVEMENT_H__63D8ADD8_4EA1_4C56_8D6F_7B587A1A61A4__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec2 Pos;
|
||||
vec3 Rot;
|
||||
vec2 Scale;
|
||||
}FexMovementFrame;
|
||||
|
||||
#include "tenlist.h"
|
||||
|
||||
class FexMovement
|
||||
{
|
||||
public:
|
||||
FexMovement();
|
||||
~FexMovement();
|
||||
WCHAR* FileName;
|
||||
|
||||
tenlist<FexMovementFrame> Frames;
|
||||
};
|
||||
|
||||
FEXTRACKER_API FexMovement* CreateMovement();
|
||||
FEXTRACKER_API void LoadMovement( FexMovement* me, const unsigned short* Filename );
|
||||
FEXTRACKER_API void SaveMovement( FexMovement* me, const unsigned short* Filename );
|
||||
FEXTRACKER_API void DeleteMovement( FexMovement* delme );
|
||||
//WCHAR* FEXTRACKER_API GetUniqueName();
|
||||
|
||||
#endif // !defined(AFX_FEXMOVEMENT_H__63D8ADD8_4EA1_4C56_8D6F_7B587A1A61A4__INCLUDED_)
|
|
@ -0,0 +1,479 @@
|
|||
// FexTracker.cpp : Defines the entry point for the DLL application.
|
||||
//
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "stdio.h"
|
||||
//#include "mmsystem.h"
|
||||
|
||||
FexTracker::FexTracker( int sx, int sy, int inFeatures )
|
||||
{
|
||||
printf( "[ using FexTracker (c)2006 Hajo Krabbenhoft ]\n" );
|
||||
|
||||
nFeatures = inFeatures;
|
||||
minFeatures = 0;
|
||||
mFeatures = 8;
|
||||
lFeatures = (FexTrackingFeature*) new FexTrackingFeature[mFeatures];
|
||||
SizX = sx;
|
||||
SizY = sy;
|
||||
CurImg = 0;
|
||||
CurFrame = 0;
|
||||
|
||||
bDebug = 0;
|
||||
|
||||
float subsampling = float(Cfg.SearchRange) / min(Cfg.WindowX,Cfg.WindowY);
|
||||
|
||||
if (subsampling < 1.0) { /* 1.0 = 0+1 */
|
||||
PyramidMaxLevels = 1;
|
||||
} else if (subsampling <= 3.0) { /* 3.0 = 2+1 */
|
||||
PyramidMaxLevels = 2;
|
||||
PyramidSubsampling = 2;
|
||||
} else if (subsampling <= 5.0) { /* 5.0 = 4+1 */
|
||||
PyramidMaxLevels = 2;
|
||||
PyramidSubsampling = 4;
|
||||
} else if (subsampling <= 9.0) { /* 9.0 = 8+1 */
|
||||
PyramidMaxLevels = 2;
|
||||
PyramidSubsampling = 8;
|
||||
} else {
|
||||
/* The following lines are derived from the formula:
|
||||
search_range =
|
||||
window_halfwidth * \sum_{i=0}^{nPyramidLevels-1} 8^i,
|
||||
which is the same as:
|
||||
search_range =
|
||||
window_halfwidth * (8^nPyramidLevels - 1)/(8 - 1).
|
||||
Then, the value is rounded up to the nearest integer. */
|
||||
float val = (float) (log(7.0*subsampling+1.0)/log(8.0));
|
||||
PyramidMaxLevels = (int) (val + 0.99);
|
||||
PyramidSubsampling = 8;
|
||||
}
|
||||
/*
|
||||
PyramidMaxLevels = 2;
|
||||
PyramidSubsampling = 2;
|
||||
*/
|
||||
}
|
||||
FexTracker::~FexTracker()
|
||||
{
|
||||
delete [] lFeatures;
|
||||
if( CurImg ) delete CurImg;
|
||||
}
|
||||
|
||||
void FexTracker::ProcessImage( float *Img, bool bFirst )
|
||||
{
|
||||
//DWORD t = timeGetTime();
|
||||
if( bFirst || !CurImg )
|
||||
{
|
||||
CurFrame = 0;
|
||||
CurImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels );
|
||||
nActiveFeatures = 0;
|
||||
int tmp = nFeatures;
|
||||
nFeatures = 0;
|
||||
FindFeatures( tmp );
|
||||
}
|
||||
else
|
||||
{
|
||||
CountActiveFeatures();
|
||||
if( nActiveFeatures<minFeatures )
|
||||
FindFeatures( minFeatures );
|
||||
NextImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels );
|
||||
TrackFeatures();
|
||||
delete CurImg;
|
||||
CurImg = NextImg;
|
||||
NextImg = 0;
|
||||
}
|
||||
CurFrame++;
|
||||
//DWORD t2 = timeGetTime();
|
||||
//printf( "ProcessImage: %d ms\n", (t2-t) );
|
||||
}
|
||||
|
||||
void FexTracker::ProcessingDone()
|
||||
{
|
||||
if( CurImg ) delete CurImg;
|
||||
CurImg = 0;
|
||||
}
|
||||
|
||||
void FexTracker::CountActiveFeatures()
|
||||
{
|
||||
nActiveFeatures = 0;
|
||||
for( int i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( lFeatures[i].StartTime + lFeatures[i].Pos.size() >= CurFrame )
|
||||
nActiveFeatures++;
|
||||
}
|
||||
}
|
||||
|
||||
FexTrackingFeature* FexTracker::operator [] ( int i )
|
||||
{
|
||||
if( i<0 || i>=nFeatures ) return 0;
|
||||
return & lFeatures[i];
|
||||
}
|
||||
|
||||
int FexTracker::GetEigenvalueForPoint( int px, int py )
|
||||
{
|
||||
int sx = px - Cfg.WindowX;
|
||||
int ex = px + Cfg.WindowX;
|
||||
int sy = py - Cfg.WindowY;
|
||||
int ey = py + Cfg.WindowY;
|
||||
if( sx<0 )sx=0;
|
||||
if( sy<0 )sy=0;
|
||||
if( ex>SizX-1 )ex=SizX-1;
|
||||
if( ey>SizY-1 )ey=SizY-1;
|
||||
|
||||
int imgSX = CurImg->lLevels[0]->sx;
|
||||
float* gradx = CurImg->lLevels[0]->GradX;
|
||||
float* grady = CurImg->lLevels[0]->GradY;
|
||||
|
||||
register float gxx = 0, gyy = 0, gxy = 0;
|
||||
for( int y=sy;y<ey;y++ )
|
||||
{
|
||||
for( int x=sx;x<ex;x++ )
|
||||
{
|
||||
float gx = gradx[ imgSX*y + x ];
|
||||
float gy = grady[ imgSX*y + x ];
|
||||
gxx += gx*gx;
|
||||
gyy += gy*gy;
|
||||
gxy += gx*gy;
|
||||
}
|
||||
}
|
||||
|
||||
float val = gxx + gyy - sqrtf((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy);
|
||||
if( val>(1<<30) ) val=(1<<30);
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
|
||||
typedef struct{
|
||||
int val, x, y;
|
||||
}littleFeature;
|
||||
|
||||
|
||||
|
||||
#define SWAP3(list, i, j) \
|
||||
{register int *pi, *pj, tmp; \
|
||||
pi=list+3*(i); pj=list+3*(j); \
|
||||
\
|
||||
tmp=*pi; \
|
||||
*pi++=*pj; \
|
||||
*pj++=tmp; \
|
||||
\
|
||||
tmp=*pi; \
|
||||
*pi++=*pj; \
|
||||
*pj++=tmp; \
|
||||
\
|
||||
tmp=*pi; \
|
||||
*pi=*pj; \
|
||||
*pj=tmp; \
|
||||
}
|
||||
|
||||
void _quicksort(int *pointlist, int n)
|
||||
{
|
||||
unsigned int i, j, ln, rn;
|
||||
|
||||
while (n > 1)
|
||||
{
|
||||
SWAP3(pointlist, 0, n/2);
|
||||
for (i = 0, j = n; ; )
|
||||
{
|
||||
do
|
||||
--j;
|
||||
while (pointlist[3*j] < pointlist[0]);
|
||||
do
|
||||
++i;
|
||||
while (i < j && pointlist[3*i] > pointlist[0]);
|
||||
if (i >= j)
|
||||
break;
|
||||
SWAP3(pointlist, i, j);
|
||||
}
|
||||
SWAP3(pointlist, j, 0);
|
||||
ln = j;
|
||||
rn = n - ++j;
|
||||
if (ln < rn)
|
||||
{
|
||||
_quicksort(pointlist, ln);
|
||||
pointlist += 3*j;
|
||||
n = rn;
|
||||
}
|
||||
else
|
||||
{
|
||||
_quicksort(pointlist + 3*j, rn);
|
||||
n = ln;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SWAP3
|
||||
|
||||
|
||||
void FexTracker::FindFeatures( int minFeatures )
|
||||
{
|
||||
int nli=0;
|
||||
littleFeature *list = new littleFeature[SizX*SizY];
|
||||
for( int y=0;y<SizY;y++ )
|
||||
{
|
||||
for( int x=0;x<SizX;x++ )
|
||||
{
|
||||
int v = GetEigenvalueForPoint( x, y );
|
||||
if( v>0 )
|
||||
{
|
||||
list[nli].val = v;
|
||||
list[nli].x = x;
|
||||
list[nli].y = y;
|
||||
nli++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_quicksort( (int*)list, nli );
|
||||
|
||||
int oldN = nFeatures;
|
||||
|
||||
for( int i=0;i<nli && nActiveFeatures<minFeatures;i++ )
|
||||
{
|
||||
for( int j=0;j<nFeatures;j++ )
|
||||
{
|
||||
if( lFeatures[j].StartTime + lFeatures[j].Pos.size() < CurFrame ) continue; //feature was lost
|
||||
|
||||
float dx = list[i].x - lFeatures[j].Pos[ CurFrame - lFeatures[j].StartTime ].x;
|
||||
float dy = list[i].y - lFeatures[j].Pos[ CurFrame - lFeatures[j].StartTime ].y;
|
||||
float sqr = dx*dx+dy*dy;
|
||||
if( sqr < Cfg.MinDistanceSquare ) break;
|
||||
}
|
||||
if( j!=nFeatures ) continue;
|
||||
|
||||
if( nFeatures >= mFeatures )
|
||||
{
|
||||
mFeatures = nFeatures+9;
|
||||
mFeatures -= mFeatures%8;
|
||||
FexTrackingFeature * nlFeatures = (FexTrackingFeature*) new FexTrackingFeature[mFeatures];
|
||||
for( int cpy=0;cpy<nFeatures;cpy++ )
|
||||
{
|
||||
nlFeatures[ cpy ].Eigenvalue = lFeatures[ cpy ].Eigenvalue;
|
||||
nlFeatures[ cpy ].StartTime = lFeatures[ cpy ].StartTime;
|
||||
nlFeatures[ cpy ].Influence = lFeatures[ cpy ].Influence;
|
||||
for( int cpy2=0;cpy2<lFeatures[ cpy ].Pos.size();cpy2++ )
|
||||
nlFeatures[ cpy ].Pos.Add( lFeatures[ cpy ].Pos[cpy2] );
|
||||
}
|
||||
delete [] lFeatures;
|
||||
lFeatures = nlFeatures;
|
||||
}
|
||||
|
||||
lFeatures[nFeatures].Eigenvalue = list[i].val;
|
||||
vec2 pt;
|
||||
pt.x = (float)list[i].x;
|
||||
pt.y = (float)list[i].y;
|
||||
lFeatures[nFeatures].Pos.Add( pt );
|
||||
lFeatures[nFeatures].StartTime = CurFrame;
|
||||
lFeatures[nFeatures].Influence = 0;
|
||||
nFeatures++;
|
||||
nActiveFeatures++;
|
||||
}
|
||||
|
||||
for( int j=oldN;j<nFeatures;j++ )
|
||||
lFeatures[j].StartTime = max(0,lFeatures[j].StartTime-1);
|
||||
|
||||
|
||||
delete []list;
|
||||
}
|
||||
|
||||
void FexTracker::TrackFeatures()
|
||||
{
|
||||
for( int i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( lFeatures[i].StartTime + lFeatures[i].Pos.size() < CurFrame ) continue; //feature was lost
|
||||
|
||||
int FeatureFrame = CurFrame - lFeatures[i].StartTime;
|
||||
|
||||
float orig_px = lFeatures[i].Pos[FeatureFrame-1].x;
|
||||
float orig_py = lFeatures[i].Pos[FeatureFrame-1].y;
|
||||
|
||||
vec2 op;
|
||||
op.x = orig_px * CurImg->lLevels[ CurImg->nLevels-1 ]->CoordMul / CurImg->Subsampling;
|
||||
op.y = orig_py * CurImg->lLevels[ CurImg->nLevels-1 ]->CoordMul / CurImg->Subsampling;
|
||||
vec2 np;
|
||||
np = op;
|
||||
|
||||
for( int l=CurImg->nLevels-1;l>=0;l-- )
|
||||
{
|
||||
op.x *= CurImg->Subsampling;
|
||||
op.y *= CurImg->Subsampling;
|
||||
np.x *= CurImg->Subsampling;
|
||||
np.y *= CurImg->Subsampling;
|
||||
if( !TrackOneFeature( l, op, np ) ) break;
|
||||
}
|
||||
if( l!=-1 ) continue; //we aborted
|
||||
|
||||
if( np.x<0 || np.y<0 || np.x>SizX || np.y>SizY ) continue;
|
||||
|
||||
lFeatures[i].Pos.Add( np );
|
||||
}
|
||||
}
|
||||
|
||||
bool FexTracker::TrackOneFeature( int lvl, vec2 op, vec2& np )
|
||||
{
|
||||
static float bordereps = 1.1f;
|
||||
if( op.x - Cfg.WindowX < bordereps || op.x + Cfg.WindowX > CurImg->lLevels[lvl]->sx - bordereps ) return 0;
|
||||
if( op.y - Cfg.WindowY < bordereps || op.y + Cfg.WindowY > CurImg->lLevels[lvl]->sy - bordereps ) return 0;
|
||||
if( np.x - Cfg.WindowX < bordereps || np.x + Cfg.WindowX > CurImg->lLevels[lvl]->sx - bordereps ) return 0;
|
||||
if( np.y - Cfg.WindowY < bordereps || np.y + Cfg.WindowY > CurImg->lLevels[lvl]->sy - bordereps ) return 0;
|
||||
|
||||
int isx = (Cfg.WindowX*2+1);
|
||||
int imsiz = isx*(Cfg.WindowY*2+1);
|
||||
float *diff = new float[imsiz];
|
||||
float *gradx = new float[imsiz];
|
||||
float *grady = new float[imsiz];
|
||||
|
||||
bool bOk = 1;
|
||||
for( int iteration=0;iteration<Cfg.MaxIterations;iteration++ )
|
||||
{
|
||||
GetDiffForPointset( lvl, op, np, diff );
|
||||
GetGradForPointset( lvl, op, np, gradx, grady );
|
||||
/*
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", isx, imsiz/isx, diff);
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", isx, imsiz/isx, gradx);
|
||||
imdebug("lum b=32f w=%d h=%d %p /255", isx, imsiz/isx, grady);
|
||||
*/
|
||||
register float gx, gy, di;
|
||||
|
||||
float gxx = 0, gyy = 0, gxy = 0, ex = 0, ey = 0;
|
||||
for( int i=0;i<imsiz;i++ )
|
||||
{
|
||||
di = diff[i];
|
||||
gx = gradx[i];
|
||||
gy = grady[i];
|
||||
|
||||
gxx += gx*gx;
|
||||
gyy += gy*gy;
|
||||
gxy += gx*gy;
|
||||
ex += di*gx;
|
||||
ey += di*gy;
|
||||
}
|
||||
|
||||
float det = gxx*gyy - gxy*gxy;
|
||||
if( det < Cfg.MinDeterminant )
|
||||
{
|
||||
bOk = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
float dx = (gyy*ex - gxy*ey)/det;
|
||||
float dy = (gxx*ey - gxy*ex)/det;
|
||||
np.x += dx;
|
||||
np.y += dy;
|
||||
|
||||
if( ( np.x - Cfg.WindowX < bordereps || np.x + Cfg.WindowX > CurImg->lLevels[lvl]->sx - bordereps )
|
||||
|| ( np.y - Cfg.WindowY < bordereps || np.y + Cfg.WindowY > CurImg->lLevels[lvl]->sy - bordereps ) )
|
||||
{
|
||||
bOk = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if( fabs(dx) < Cfg.MinDisplacement && fabs(dy) < Cfg.MinDisplacement )break;
|
||||
}
|
||||
delete [] gradx;
|
||||
delete [] grady;
|
||||
|
||||
if( bOk )
|
||||
{
|
||||
GetDiffForPointset( lvl, op, np, diff );
|
||||
|
||||
float sum = 0;
|
||||
for( int i=0;i<imsiz;i++ )
|
||||
sum += fabsf( diff[i] );
|
||||
|
||||
if( sum / float(imsiz) > Cfg.MaxResidue ) bOk = 0;
|
||||
}
|
||||
|
||||
delete [] diff;
|
||||
return bOk;
|
||||
}
|
||||
|
||||
inline float Interpolate( float *img, int ImgSX, float x, float y )
|
||||
{
|
||||
int xt = (int) x; /* coordinates of top-left corner */
|
||||
int yt = (int) y;
|
||||
float ax = x - xt;
|
||||
float ay = y - yt;
|
||||
float *ptr = img + (ImgSX*yt) + xt;
|
||||
|
||||
return ( (1-ax) * (1-ay) * *ptr +
|
||||
ax * (1-ay) * *(ptr+1) +
|
||||
(1-ax) * ay * *(ptr+(ImgSX)) +
|
||||
ax * ay * *(ptr+(ImgSX)+1) );
|
||||
}
|
||||
|
||||
void FexTracker::GetDiffForPointset( int lvl, vec2 op, vec2 np, float* diff )
|
||||
{
|
||||
float* img1 = CurImg->lLevels[lvl]->Img;
|
||||
int isx1 = CurImg->lLevels[lvl]->sx;
|
||||
float* img2 = NextImg->lLevels[lvl]->Img;
|
||||
int isx2 = NextImg->lLevels[lvl]->sx;
|
||||
for( int y = -Cfg.WindowY; y <= Cfg.WindowY; y++ )
|
||||
{
|
||||
for( int x = -Cfg.WindowX; x <= Cfg.WindowX; x++ )
|
||||
{
|
||||
*diff++ = Interpolate(img1,isx1,op.x+x,op.y+y) - Interpolate(img2,isx2,np.x+x,np.y+y);
|
||||
}
|
||||
}
|
||||
}
|
||||
void FexTracker::GetGradForPointset( int lvl, vec2 op, vec2 np, float* gradx, float* grady )
|
||||
{
|
||||
int isx = CurImg->lLevels[lvl]->sx;
|
||||
|
||||
float* gx1 = CurImg->lLevels[lvl]->GradX;
|
||||
float* gx2 = NextImg->lLevels[lvl]->GradX;
|
||||
|
||||
float* gy1 = CurImg->lLevels[lvl]->GradY;
|
||||
float* gy2 = NextImg->lLevels[lvl]->GradY;
|
||||
|
||||
for( int y = -Cfg.WindowY; y <= Cfg.WindowY; y++ )
|
||||
{
|
||||
for( int x = -Cfg.WindowX; x <= Cfg.WindowX; x++ )
|
||||
{
|
||||
*gradx++ = Interpolate(gx1,isx,op.x+x,op.y+y) + Interpolate(gx2,isx,np.x+x,np.y+y);
|
||||
*grady++ = Interpolate(gy1,isx,op.x+x,op.y+y) + Interpolate(gy2,isx,np.x+x,np.y+y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
static float _minEigenvalue(float gxx, float gxy, float gyy)
|
||||
{
|
||||
return (float) ((gxx + gyy - sqrt((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy))/2.0f);
|
||||
}
|
||||
|
||||
//gen eigenvalue matrix:
|
||||
gxx = 0; gxy = 0; gyy = 0;
|
||||
for (yy = y-window_hh ; yy <= y+window_hh ; yy++)
|
||||
{
|
||||
for (xx = x-window_hw ; xx <= x+window_hw ; xx++)
|
||||
{
|
||||
gx = *(gradx->data + ncols*yy+xx);
|
||||
gy = *(grady->data + ncols*yy+xx);
|
||||
gxx += gx * gx;
|
||||
gxy += gx * gy;
|
||||
gyy += gy * gy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//get eigenvalue number
|
||||
val = _minEigenvalue(gxx, gxy, gyy);
|
||||
|
||||
|
||||
for every frame:
|
||||
for every feature:
|
||||
through all pyramid levels from lowres to highres:
|
||||
|
||||
calculate diff, gradx, grady
|
||||
gen eigenvalue matrix
|
||||
error vector = [gradx, grady]*imdiff
|
||||
|
||||
float det = gxx*gyy - gxy*gxy;
|
||||
if (det < small) return KLT_SMALL_DET;
|
||||
*dx = (gyy*ex - gxy*ey)/det;
|
||||
*dy = (gxx*ey - gxy*ex)/det;
|
||||
|
||||
add [dx,dy] to search position
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
// The following ifdef block is the standard way of creating macros which make exporting
|
||||
// from a DLL simpler. All files within this DLL are compiled with the FEXTRACKER_EXPORTS
|
||||
// symbol defined on the command line. this symbol should not be defined on any project
|
||||
// that uses this DLL. This way any other project whose source files include this file see
|
||||
// FEXTRACKER_API functions as being imported from a DLL, wheras this DLL sees symbols
|
||||
// defined with this macro as being exported.
|
||||
#ifdef FEXTRACKER_EXPORTS
|
||||
#define FEXTRACKER_API __declspec(dllexport)
|
||||
#else
|
||||
#define FEXTRACKER_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class FEXTRACKER_API FexTrackerConfig
|
||||
{
|
||||
public:
|
||||
inline FexTrackerConfig() :
|
||||
FeatureNumber(0),
|
||||
EdgeDetectSigma(1.f),
|
||||
WindowX(3), WindowY(3),
|
||||
SearchRange(15),
|
||||
MaxIterations(10),
|
||||
MinDeterminant(0.01f),
|
||||
MinDisplacement(0.1f),
|
||||
MaxResidue(10.f),
|
||||
IgnoreLightning(0),
|
||||
DetectSmoothSigma(0.9f),
|
||||
MinDistanceSquare(100.f)
|
||||
{};
|
||||
|
||||
int FeatureNumber;
|
||||
|
||||
int WindowX, WindowY; //static const int window_size = 7;
|
||||
int SearchRange;
|
||||
|
||||
float DetectSmoothSigma; //static const float pyramid_sigma_fact = 0.9f;
|
||||
float EdgeDetectSigma; //static const float grad_sigma = 1.0f;
|
||||
|
||||
int MaxIterations; //static const int max_iterations = 10;
|
||||
float MinDeterminant; //static const float min_determinant = 0.01f;
|
||||
float MinDisplacement; //static const float min_displacement = 0.1f;
|
||||
float MaxResidue; //static const float max_residue = 10.0f;
|
||||
|
||||
bool IgnoreLightning; //static const KLT_BOOL lighting_insensitive = FALSE;
|
||||
|
||||
float MinDistanceSquare; //static const int mindist = 10;
|
||||
|
||||
//static const int min_eigenvalue = 1;
|
||||
//static const float smooth_sigma_fact = 0.1f;
|
||||
//static const KLT_BOOL sequentialMode = FALSE;
|
||||
///* for affine mapping*/
|
||||
//static const int affineConsistencyCheck = -1;
|
||||
//static const int affine_window_size = 15;
|
||||
//static const int affine_max_iterations = 10;
|
||||
//static const float affine_max_residue = 10.0;
|
||||
//static const float affine_min_displacement = 0.02f;
|
||||
//static const float affine_max_displacement_differ = 1.5f;
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
float x, y;
|
||||
}vec2;
|
||||
|
||||
typedef struct{
|
||||
float x, y, z;
|
||||
}vec3;
|
||||
|
||||
class FexImgPyramid;
|
||||
class FexTrackingFeature;
|
||||
class FexMovement;
|
||||
|
||||
class FEXTRACKER_API FexTracker
|
||||
{
|
||||
public:
|
||||
FexTracker( int sx, int sy, int nFeatures );
|
||||
~FexTracker();
|
||||
//config
|
||||
FexTrackerConfig Cfg;
|
||||
//work
|
||||
void ProcessImage( float *Img, bool bFirst=0 ); //we assume grayscale image here
|
||||
void ProcessingDone(); // call after last call to ProcessImage to clear temporary storage
|
||||
|
||||
//point -> movement
|
||||
void InfluenceFeatures( int Frame, float x, float y, float off );
|
||||
FexMovement* GetMovement();
|
||||
|
||||
//feature access
|
||||
FexTrackingFeature* operator [] ( int i );
|
||||
inline int GetCount(){ return nFeatures; };
|
||||
inline int GetFrame(){ return CurFrame; };
|
||||
inline int GetSizeX(){ return SizX; };
|
||||
inline int GetSizeY(){ return SizY; };
|
||||
|
||||
bool bDebug;
|
||||
int minFeatures;
|
||||
private:
|
||||
int SizX, SizY;
|
||||
int PyramidSubsampling;
|
||||
int PyramidMaxLevels;
|
||||
FexImgPyramid* CurImg;
|
||||
FexImgPyramid* NextImg;
|
||||
|
||||
void FindFeatures( int minFeatures );
|
||||
void TrackFeatures();
|
||||
|
||||
bool TrackOneFeature( int lvl, vec2 op, vec2& np );
|
||||
int GetEigenvalueForPoint( int px, int py );
|
||||
void GetDiffForPointset( int lvl, vec2 op, vec2 np, float* diff );
|
||||
void GetGradForPointset( int lvl, vec2 op, vec2 np, float* gradx, float* grady );
|
||||
|
||||
void CountActiveFeatures();
|
||||
|
||||
//result
|
||||
FexTrackingFeature* lFeatures;
|
||||
int nFeatures;
|
||||
int nActiveFeatures;
|
||||
int mFeatures;
|
||||
|
||||
int CurFrame;
|
||||
};
|
||||
|
||||
|
||||
|
||||
FEXTRACKER_API void FexBaseResize( float* out, int newx, int newy, float* in, int sizx, int sizy );
|
||||
FEXTRACKER_API void GaussKernelWidths( float sigma, int *gauss_width, int *gaussderiv_width );
|
||||
FEXTRACKER_API void GaussEdgeDetect( float* Img, int sizx, int sizy, float sigma, float* GradX, float* GradY );
|
||||
FEXTRACKER_API void GaussSmooth( float* Img, int sizx, int sizy, float sigma, float* Out );
|
||||
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
// FexTrackerMovement.cpp
|
||||
//
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "stdio.h"
|
||||
//#include "mmsystem.h"
|
||||
|
||||
|
||||
|
||||
void FexTracker::InfluenceFeatures( int Frame, float x, float y, float off )
|
||||
{
|
||||
for( int i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( Frame < lFeatures[i].StartTime ) continue;
|
||||
|
||||
int FeatureFrame = Frame - lFeatures[i].StartTime;
|
||||
|
||||
if( lFeatures[i].Pos.size() < FeatureFrame ) continue; //feature was lost
|
||||
|
||||
vec2 p = lFeatures[i].Pos[ FeatureFrame ];
|
||||
|
||||
float dist = sqrtf( (p.x-x)*(p.x-x)+(p.y-y)*(p.y-y) );
|
||||
float infl = 1/(dist+1);
|
||||
if( infl < 0.1 ) continue;
|
||||
lFeatures[i].Influence += infl * off;
|
||||
if( lFeatures[i].Influence<0 ) lFeatures[i].Influence = 0;
|
||||
if( lFeatures[i].Influence>1 ) lFeatures[i].Influence = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void LineTracing( haAssLine *c, vec2& TracePos, vec2& TraceScale, int Frame, vec2 InScreenPlace )
|
||||
{
|
||||
TracePos = vec2(0,0);
|
||||
TraceScale = vec2(0,0);
|
||||
|
||||
vec2 Sum1Pos = vec2(0,0);
|
||||
vec2 Sum2Pos = vec2(0,0);
|
||||
float TraceScaleV=0;
|
||||
|
||||
float wsum = 0;
|
||||
|
||||
for( int i=0;i<c->FeatureIdList.GetSize();i++ )
|
||||
{
|
||||
tenFeatureLink l = c->FeatureIdList[i];
|
||||
tenFeature f = Trace_GetFeatureByID( l.id, Frame );
|
||||
if( f.id < 0 || l.weight<0.01 )
|
||||
continue;
|
||||
Sum1Pos += vec2(
|
||||
(f.x)/float(ncols)*float(AssRes[0]),
|
||||
(f.y)/float(nrows)*float(AssRes[1])
|
||||
)*l.weight;
|
||||
Sum2Pos += vec2(
|
||||
(l.sub.x)/float(ncols)*float(AssRes[0]),
|
||||
(l.sub.y)/float(nrows)*float(AssRes[1])
|
||||
)*l.weight;
|
||||
wsum += l.weight;
|
||||
}
|
||||
if( wsum>0.01 )
|
||||
{
|
||||
Sum1Pos /= wsum;
|
||||
Sum2Pos /= wsum;
|
||||
TracePos = Sum1Pos - Sum2Pos;
|
||||
|
||||
wsum = 0;
|
||||
CArray<float, float&> DistList;
|
||||
CArray<float, float&> WeightList;
|
||||
|
||||
//now we know weighted mid point, gen vectors from points to mid
|
||||
for( int i=0;i<c->FeatureIdList.GetSize();i++ )
|
||||
{
|
||||
tenFeatureLink l = c->FeatureIdList[i];
|
||||
tenFeature f = Trace_GetFeatureByID( l.id, Frame );
|
||||
if( f.id < 0 || l.weight<0.01 )
|
||||
continue;
|
||||
vec2 mid = vec2(
|
||||
(f.x)/float(ncols)*float(AssRes[0]),
|
||||
(f.y)/float(nrows)*float(AssRes[1])
|
||||
);
|
||||
vec2 midToMe = mid - Sum1Pos;
|
||||
vec2 stdMidToMe = vec2(
|
||||
(l.sub.x)/float(ncols)*float(AssRes[0]),
|
||||
(l.sub.y)/float(nrows)*float(AssRes[1])
|
||||
) - Sum2Pos;
|
||||
|
||||
float stdlen = sqrtf( stdMidToMe.x*stdMidToMe.x + stdMidToMe.y*stdMidToMe.y );
|
||||
if( stdlen < 3 )
|
||||
{//too much error amplification.skip
|
||||
continue;
|
||||
}
|
||||
|
||||
float len = sqrtf( midToMe.x*midToMe.x + midToMe.y*midToMe.y );
|
||||
float scale = len/stdlen;
|
||||
// TRACE( "%f\n", scale );
|
||||
float addme = scale*l.weight;
|
||||
TraceScaleV += addme;
|
||||
DistList.Add( scale );
|
||||
WeightList.Add( l.weight );
|
||||
wsum += l.weight;
|
||||
}
|
||||
TraceScaleV /= wsum;
|
||||
|
||||
float TraceScaleV2=0;
|
||||
for( i=0;i<DistList.GetSize();i++ )
|
||||
{
|
||||
TraceScaleV2 += ((DistList[i]-TraceScaleV)*0.5f+TraceScaleV)*WeightList[i];
|
||||
}
|
||||
TraceScaleV2 /= wsum;
|
||||
|
||||
TraceScale = vec2(1,1)*TraceScaleV2;
|
||||
|
||||
vec2 MidToItemStd = InScreenPlace - Sum2Pos;
|
||||
TracePos += MidToItemStd*(TraceScaleV2-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
TracePos = vec2(0,0);
|
||||
TraceScale = vec2(1,1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#define VEC2LEN(a) sqrtf( (a).x*(a).x+(a).y*(a).y )
|
||||
|
||||
FexMovement* FexTracker::GetMovement()
|
||||
{
|
||||
FILE *log = fopen( "movementlog.txt", "wt" );
|
||||
|
||||
int i;
|
||||
for( i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( lFeatures[i].Influence>0.01 )
|
||||
fprintf( log, "Feature(%.2f): %d - %d\n", lFeatures[i].Influence, lFeatures[i].StartTime, lFeatures[i].StartTime+lFeatures[i].Pos.size() );
|
||||
}
|
||||
|
||||
FexMovement *m = new FexMovement();
|
||||
FexMovementFrame f;
|
||||
|
||||
float FirstInfluenceSum = 0;
|
||||
vec2 FirstPos;
|
||||
FirstPos.x = FirstPos.y = 0;
|
||||
|
||||
for( i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( 0 < lFeatures[i].StartTime ) continue;
|
||||
if( lFeatures[i].Pos.size() <= 0 ) continue;
|
||||
|
||||
vec2 p = lFeatures[i].Pos[ 0 ];
|
||||
|
||||
FirstPos.x += p.x * lFeatures[i].Influence;
|
||||
FirstPos.y += p.y * lFeatures[i].Influence;
|
||||
FirstInfluenceSum += lFeatures[i].Influence;
|
||||
}
|
||||
FirstPos.x /= FirstInfluenceSum;
|
||||
FirstPos.y /= FirstInfluenceSum;
|
||||
|
||||
float FirstLen = 1;
|
||||
|
||||
|
||||
vec2* MidOffset = (vec2*) new vec2[nFeatures];
|
||||
float* MidOffsetLen = (float*) new float[nFeatures];
|
||||
for( int Frame = 0; Frame < CurFrame; Frame ++ )
|
||||
{
|
||||
//set feature offset
|
||||
for( i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( Frame == lFeatures[i].StartTime )
|
||||
{
|
||||
MidOffset[i].x = FirstPos.x - lFeatures[i].Pos[0].x;
|
||||
MidOffset[i].y = FirstPos.y - lFeatures[i].Pos[0].y;
|
||||
//realOffLen / MidOffLen = FirstLen
|
||||
// => MidOffLen /= FirstLen;
|
||||
MidOffset[i].x /= FirstLen;
|
||||
MidOffset[i].y /= FirstLen;
|
||||
MidOffsetLen[i] = VEC2LEN( MidOffset[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//accumulate position
|
||||
float NextLen = 0;
|
||||
float NextInfluenceSum = 0;
|
||||
vec2 NextPos;
|
||||
NextPos.x = NextPos.y = 0;
|
||||
|
||||
for( i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( Frame < lFeatures[i].StartTime ) continue;
|
||||
int FeatureFrame = Frame - lFeatures[i].StartTime;
|
||||
if( lFeatures[i].Pos.size() <= FeatureFrame ) continue; //feature was lost
|
||||
|
||||
vec2 p = lFeatures[i].Pos[ FeatureFrame ];
|
||||
|
||||
NextPos.x += (p.x+MidOffset[i].x*FirstLen) * lFeatures[i].Influence;
|
||||
NextPos.y += (p.y+MidOffset[i].y*FirstLen) * lFeatures[i].Influence;
|
||||
NextInfluenceSum += lFeatures[i].Influence;
|
||||
}
|
||||
|
||||
if( NextInfluenceSum > 0.01 )
|
||||
{
|
||||
NextPos.x /= NextInfluenceSum;
|
||||
NextPos.y /= NextInfluenceSum;
|
||||
}
|
||||
else
|
||||
NextPos = FirstPos; //take over last one
|
||||
|
||||
for( i=0;i<nFeatures;i++ )
|
||||
{
|
||||
if( Frame < lFeatures[i].StartTime ) continue;
|
||||
int FeatureFrame = Frame - lFeatures[i].StartTime;
|
||||
if( lFeatures[i].Pos.size() <= FeatureFrame ) continue; //feature was lost
|
||||
|
||||
vec2 p = lFeatures[i].Pos[ FeatureFrame ];
|
||||
|
||||
vec2 realMidOff;
|
||||
realMidOff.x = NextPos.x-p.x;
|
||||
realMidOff.y = NextPos.y-p.y;
|
||||
float realMidOffLen = VEC2LEN( realMidOff );
|
||||
|
||||
NextLen += realMidOffLen/MidOffsetLen[i] *lFeatures[i].Influence;
|
||||
}
|
||||
|
||||
if( NextInfluenceSum > 0.01 )
|
||||
{
|
||||
NextLen /= NextInfluenceSum;
|
||||
}
|
||||
else
|
||||
NextLen = FirstLen; //take over last one
|
||||
|
||||
f.Pos = NextPos;
|
||||
f.Rot.x = 0;
|
||||
f.Rot.y = 0;
|
||||
f.Rot.z = 0;
|
||||
f.Scale.x = NextLen;
|
||||
f.Scale.y = NextLen;
|
||||
m->Frames.Add( f );
|
||||
|
||||
FirstPos = NextPos;
|
||||
FirstLen = NextLen;
|
||||
}
|
||||
|
||||
delete []MidOffset;
|
||||
delete []MidOffsetLen;
|
||||
|
||||
fclose( log );
|
||||
|
||||
return m;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// FexTrackingFeature.cpp: implementation of the FexTrackingFeature class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
FexTrackingFeature::FexTrackingFeature()
|
||||
{
|
||||
}
|
||||
|
||||
FexTrackingFeature::~FexTrackingFeature()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// FexTrackingFeature.h: interface for the FexTrackingFeature class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_FEXTRACKINGFEATURE_H__23B42013_9F11_467C_A0F6_F9E647D45CEB__INCLUDED_)
|
||||
#define AFX_FEXTRACKINGFEATURE_H__23B42013_9F11_467C_A0F6_F9E647D45CEB__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "tenlist.h"
|
||||
class FexTrackingFeature
|
||||
{
|
||||
public:
|
||||
FexTrackingFeature();
|
||||
~FexTrackingFeature();
|
||||
|
||||
int Eigenvalue;
|
||||
tenlist<vec2> Pos;
|
||||
|
||||
int StartTime;
|
||||
|
||||
float Influence;
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_FEXTRACKINGFEATURE_H__23B42013_9F11_467C_A0F6_F9E647D45CEB__INCLUDED_)
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// FexTracker.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,34 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__7E36ECD6_3192_4C7E_88C9_742CCCFA5057__INCLUDED_)
|
||||
#define AFX_STDAFX_H__7E36ECD6_3192_4C7E_88C9_742CCCFA5057__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
|
||||
// Insert your headers here
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "FexTracker.h"
|
||||
#include "FexImgPyramid.h"
|
||||
#include "FexTrackingFeature.h"
|
||||
#include "FexMovement.h"
|
||||
|
||||
#include "ext/imdebug.h"
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__7E36ECD6_3192_4C7E_88C9_742CCCFA5057__INCLUDED_)
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
template< class type >
|
||||
class tenlist {
|
||||
public:
|
||||
int nVal;
|
||||
int mVal;
|
||||
type* lVal;
|
||||
|
||||
inline tenlist()
|
||||
{
|
||||
mVal = 0;
|
||||
nVal = 0;
|
||||
lVal = 0;
|
||||
//zero everything since we well over-zero it anyway
|
||||
}
|
||||
inline ~tenlist()
|
||||
{
|
||||
free( lVal );
|
||||
}
|
||||
|
||||
inline int size()
|
||||
{
|
||||
return nVal;
|
||||
}
|
||||
|
||||
inline void Add( type t )
|
||||
{
|
||||
if( nVal+1 >= mVal )
|
||||
{
|
||||
mVal += 8;
|
||||
lVal = (type*)realloc( lVal, sizeof(type)*mVal );
|
||||
memset( lVal+nVal, 0x00, sizeof(type)*(mVal-nVal) ); //lVal+nVal, since it'll be multiplied by sizeof(type) due to lVal being a type*
|
||||
}
|
||||
lVal[nVal++] = t;
|
||||
}
|
||||
|
||||
inline void AddStr( type t )
|
||||
{
|
||||
if( nVal+1 >= mVal )
|
||||
{
|
||||
mVal += 8;
|
||||
lVal = (type*)realloc( lVal, sizeof(type)*mVal );
|
||||
memset( lVal+nVal, 0x00, sizeof(type)*(mVal-nVal) ); //lVal+nVal, since it'll be multiplied by sizeof(type) due to lVal being a type*
|
||||
}
|
||||
strcpy( lVal[nVal++], t );
|
||||
}
|
||||
|
||||
inline void Rem( int n )
|
||||
{
|
||||
if( n>=nVal )
|
||||
{
|
||||
nVal = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for( int i=0;i<nVal;i++ )
|
||||
{
|
||||
lVal[i] = lVal[i+n];
|
||||
}
|
||||
}
|
||||
|
||||
type& operator[]( int i ) const
|
||||
{ return lVal[i]; }
|
||||
};
|
|
@ -193,6 +193,15 @@ bool AssDialogue::Parse(wxString rawData, bool IsSSA) {
|
|||
Effect.Trim(true);
|
||||
Effect.Trim(false);
|
||||
|
||||
#ifndef NO_FEX
|
||||
if( Effect.BeforeFirst(':')==_T("FexMovement") )
|
||||
{
|
||||
if( Movement ) DeleteMovement( Movement );
|
||||
Movement = CreateMovement();
|
||||
LoadMovement( Movement, (unsigned short*) Effect.AfterFirst(':').c_str() );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get text
|
||||
Text = tkn.GetNextToken();
|
||||
while (tkn.HasMoreTokens()) {
|
||||
|
|
|
@ -48,6 +48,8 @@ void FrameMain::OnVideoTrackerMenu(wxCommandEvent &event) {
|
|||
// Movement Menu
|
||||
void FrameMain::OnVideoTrackerMenu2(wxCommandEvent &event) {
|
||||
wxMenu menu( _("FexMovement") );
|
||||
AppendBitmapMenuItem(&menu, Video_Track_Movement_Empty, _("Generate empty movement"), _T(""), wxBITMAP(button_track_move));
|
||||
menu.AppendSeparator();
|
||||
AppendBitmapMenuItem(&menu, Video_Track_Movement_MoveAll, _("Move subtitle"), _T(""), wxBITMAP(button_track_move));
|
||||
menu.AppendSeparator();
|
||||
AppendBitmapMenuItem(&menu, Video_Track_Movement_MoveBefore, _("Move subtitle (this frame and preceeding frames)"), _T(""), wxBITMAP(button_track_move));
|
||||
|
@ -55,6 +57,8 @@ void FrameMain::OnVideoTrackerMenu2(wxCommandEvent &event) {
|
|||
AppendBitmapMenuItem(&menu, Video_Track_Movement_MoveAfter, _("Move subtitle (this frame and following frames)"), _T(""), wxBITMAP(button_track_move));
|
||||
menu.AppendSeparator();
|
||||
AppendBitmapMenuItem(&menu, Video_Track_Split_Line, _("Split line for movement"), _T(""), wxBITMAP(button_track_split_line));
|
||||
menu.AppendSeparator();
|
||||
AppendBitmapMenuItem(&menu, Video_Track_Link_File, _("Link movement file"), _T(""), wxBITMAP(button_track_move));
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
|
@ -193,6 +197,49 @@ void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
///////////////////
|
||||
// generate empty movement
|
||||
void FrameMain::OnVideoTrackMovementEmpty(wxCommandEvent &event) {
|
||||
// Get line
|
||||
AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen);
|
||||
if (!curline) return;
|
||||
if( curline->Movement ) DeleteMovement( curline->Movement );
|
||||
curline->Movement = CreateMovement();
|
||||
|
||||
// Create split lines
|
||||
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
|
||||
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
|
||||
|
||||
FexMovementFrame f;
|
||||
memset( &f, 0x00, sizeof(f) );
|
||||
f.Scale.x = f.Scale.y = 1;
|
||||
|
||||
for( int i=StartFrame;i<EndFrame;i++ )
|
||||
curline->Movement->Frames.Add( f );
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
// link line to move file
|
||||
void FrameMain::OnVideoTrackLinkFile(wxCommandEvent &event) {
|
||||
videoBox->videoDisplay->Stop();
|
||||
|
||||
// Get line
|
||||
AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen);
|
||||
if (!curline) return;
|
||||
|
||||
wxString link = wxGetTextFromUser(_("Link name:"), _("Link line to movement file"), curline->Movement?curline->Movement->FileName:_T(""), this);
|
||||
if( link.empty() ) curline->Effect = _T("");
|
||||
else curline->Effect = _T("FexMovement:")+link;
|
||||
|
||||
curline->UpdateData();
|
||||
|
||||
if( !curline->Effect.empty() && curline->Movement )
|
||||
SaveMovement( curline->Movement, (unsigned short*) curline->Effect.AfterFirst(':').c_str() );
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
// Increase Influence
|
||||
void FrameMain::OnVideoTrackPointAdd(wxCommandEvent &event) {
|
||||
|
|
|
@ -118,6 +118,8 @@ private:
|
|||
void OnVideoTrackMovementMoveBefore(wxCommandEvent &event);
|
||||
void OnVideoTrackMovementMoveAfter(wxCommandEvent &event);
|
||||
void OnVideoTrackSplitLine(wxCommandEvent &event);
|
||||
void OnVideoTrackLinkFile(wxCommandEvent &event);
|
||||
void OnVideoTrackMovementEmpty(wxCommandEvent &event);
|
||||
|
||||
void OnKeyDown(wxKeyEvent &event);
|
||||
|
||||
|
@ -352,6 +354,8 @@ enum {
|
|||
Video_Track_Movement_MoveBefore,
|
||||
Video_Track_Movement_MoveAfter,
|
||||
Video_Track_Split_Line,
|
||||
Video_Track_Link_File,
|
||||
Video_Track_Movement_Empty,
|
||||
|
||||
Menu_File_Recent = 2000,
|
||||
Menu_Video_Recent = 2200,
|
||||
|
|
|
@ -104,6 +104,8 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame)
|
|||
EVT_MENU(Video_Track_Movement_MoveBefore, FrameMain::OnVideoTrackMovementMoveBefore)
|
||||
EVT_MENU(Video_Track_Movement_MoveAfter, FrameMain::OnVideoTrackMovementMoveAfter)
|
||||
EVT_MENU(Video_Track_Split_Line, FrameMain::OnVideoTrackSplitLine)
|
||||
EVT_MENU(Video_Track_Link_File, FrameMain::OnVideoTrackLinkFile)
|
||||
EVT_MENU(Video_Track_Movement_Empty, FrameMain::OnVideoTrackMovementEmpty)
|
||||
#endif
|
||||
|
||||
EVT_CLOSE(FrameMain::OnCloseWindow)
|
||||
|
|
Loading…
Reference in New Issue