Fix for font collector to build on wx 2.6.3.

Started to document FexTracker source. (Also see wiki.)

Originally committed to SVN as r586.
This commit is contained in:
Niels Martin Hansen 2006-12-21 08:43:27 +00:00
parent 4a79a056a2
commit d972e6e69c
4 changed files with 54 additions and 13 deletions

View File

@ -18,12 +18,12 @@ public:
FexImgPyramidLevel( int sx, int sy ); FexImgPyramidLevel( int sx, int sy );
~FexImgPyramidLevel(); ~FexImgPyramidLevel();
int sx, sy; int sx, sy; // dimensions of this level
float CoordMul; float CoordMul;
float* Img; float* Img; // actual image data
float* GradX; float* GradX; // X gradients
float* GradY; float* GradY; // Y gradients
void Fill( float* Img, float DetectSmoothSigma ); void Fill( float* Img, float DetectSmoothSigma );
void Scale( FexImgPyramidLevel* old ); void Scale( FexImgPyramidLevel* old );

View File

@ -56,21 +56,29 @@ FexTracker::~FexTracker()
void FexTracker::ProcessImage( float *Img, bool bFirst ) void FexTracker::ProcessImage( float *Img, bool bFirst )
{ {
// Receive new image to track
// This assumes it chronologically directly follows the previously processed image
if( bFirst || !CurImg ) if( bFirst || !CurImg )
{ {
// First image in series
// Initialise a few things
CurFrame = 0; CurFrame = 0;
CurImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels ); CurImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels );
nActiveFeatures = 0; nActiveFeatures = 0;
int tmp = nFeatures; int tmp = nFeatures;
nFeatures = 0; nFeatures = 0;
// Find initial features
FindFeatures( tmp ); FindFeatures( tmp );
} }
else else
{ {
// Check if we've lost too many features, and find some more if that's the case
CountActiveFeatures(); CountActiveFeatures();
if( nActiveFeatures<minFeatures ) if( nActiveFeatures<minFeatures )
FindFeatures( minFeatures ); FindFeatures( minFeatures );
// Build image pyramid
NextImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels ); NextImg = new FexImgPyramid( Img, SizX, SizY, Cfg.EdgeDetectSigma, Cfg.DetectSmoothSigma, PyramidSubsampling, PyramidMaxLevels );
// Now correlate the features to the new image
TrackFeatures(); TrackFeatures();
delete CurImg; delete CurImg;
CurImg = NextImg; CurImg = NextImg;
@ -90,6 +98,7 @@ void FexTracker::CountActiveFeatures()
nActiveFeatures = 0; nActiveFeatures = 0;
for( int i=0;i<nFeatures;i++ ) for( int i=0;i<nFeatures;i++ )
{ {
// If the feature has a known position for the active frame, it's active
if( lFeatures[i].StartTime + lFeatures[i].Pos.size() >= CurFrame ) if( lFeatures[i].StartTime + lFeatures[i].Pos.size() >= CurFrame )
nActiveFeatures++; nActiveFeatures++;
} }
@ -103,44 +112,58 @@ FexTrackingFeature* FexTracker::operator [] ( int i )
int FexTracker::GetEigenvalueForPoint( int px, int py ) int FexTracker::GetEigenvalueForPoint( int px, int py )
{ {
// Determine window in the image to process
int sx = px - Cfg.WindowX; int sx = px - Cfg.WindowX;
int ex = px + Cfg.WindowX; int ex = px + Cfg.WindowX;
int sy = py - Cfg.WindowY; int sy = py - Cfg.WindowY;
int ey = py + Cfg.WindowY; int ey = py + Cfg.WindowY;
// Clip against the edges of the image
if( sx<0 )sx=0; if( sx<0 )sx=0;
if( sy<0 )sy=0; if( sy<0 )sy=0;
if( ex>SizX-1 )ex=SizX-1; if( ex>SizX-1 )ex=SizX-1;
if( ey>SizY-1 )ey=SizY-1; if( ey>SizY-1 )ey=SizY-1;
// Stride for the image
int imgSX = CurImg->lLevels[0]->sx; int imgSX = CurImg->lLevels[0]->sx;
// Pointers to X and Y gradient vectors
float* gradx = CurImg->lLevels[0]->GradX; float* gradx = CurImg->lLevels[0]->GradX;
float* grady = CurImg->lLevels[0]->GradY; float* grady = CurImg->lLevels[0]->GradY;
// Accumulated entries into the correlation matrix [gxx gxy; gxy gyy]
register float gxx = 0, gyy = 0, gxy = 0; register float gxx = 0, gyy = 0, gxy = 0;
// Loop over points inside the window
for( int y=sy;y<ey;y++ ) for( int y=sy;y<ey;y++ )
{ {
for( int x=sx;x<ex;x++ ) for( int x=sx;x<ex;x++ )
{ {
// Get X and Y gradient values of this point
float gx = gradx[ imgSX*y + x ]; float gx = gradx[ imgSX*y + x ];
float gy = grady[ imgSX*y + x ]; float gy = grady[ imgSX*y + x ];
// Add to the matrix entries
gxx += gx*gx; gxx += gx*gx;
gyy += gy*gy; gyy += gy*gy;
gxy += gx*gy; gxy += gx*gy;
} }
} }
// Calculate the eigenvalue L for the correlation matrix
// 0 = det([gxx-L gxy; gxy gyy-L]) = (gxx-L)(gyy-L) - gxy*gxy = L*L + L*(-gxx-gyy) + gxx*gyy - gxy*gxy
// Only the smaller of the two eigenvalues has interest, and a factor 1/4 isn't relevant for comparison,
// so this is the smallest solution to the second-order polynomial.
float val = gxx + gyy - sqrtf((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy); float val = gxx + gyy - sqrtf((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy);
// Limit the value
if( val>(1<<30) ) val=(1<<30); if( val>(1<<30) ) val=(1<<30);
return (int) val; return (int) val;
} }
// An int triple (?!) denoting a coordinate pair and an eigenvalue for that position
typedef struct{ typedef struct{
int val, x, y; int val, x, y;
}littleFeature; }littleFeature;
// Swap two triples of ints (in reality two littleFeature)
#define SWAP3(list, i, j) \ #define SWAP3(list, i, j) \
{register int *pi, *pj, tmp; \ {register int *pi, *pj, tmp; \
pi=list+3*(i); pj=list+3*(j); \ pi=list+3*(i); pj=list+3*(j); \
@ -158,6 +181,7 @@ typedef struct{
*pj=tmp; \ *pj=tmp; \
} }
// Sort a list of int-triples (littleFeature structs)
void _quicksort(int *pointlist, int n) void _quicksort(int *pointlist, int n)
{ {
unsigned int i, j, ln, rn; unsigned int i, j, ln, rn;
@ -198,13 +222,17 @@ void _quicksort(int *pointlist, int n)
void FexTracker::FindFeatures( int minFeatures ) void FexTracker::FindFeatures( int minFeatures )
{ {
int nli=0; // Detect new features, so there's at least minFeatures available
// First calculate eigenvalues for each pixel in the image...
int nli=0; // Number of LIttle features
littleFeature *list = new littleFeature[SizX*SizY]; littleFeature *list = new littleFeature[SizX*SizY];
for( int y=0;y<SizY;y++ ) for( int y=0;y<SizY;y++ )
{ {
for( int x=0;x<SizX;x++ ) for( int x=0;x<SizX;x++ )
{ {
int v = GetEigenvalueForPoint( x, y ); int v = GetEigenvalueForPoint( x, y );
// ... if the eigenvalue for a pixel is larger than zero, include it in the list...
if( v>0 ) if( v>0 )
{ {
list[nli].val = v; list[nli].val = v;
@ -215,26 +243,36 @@ void FexTracker::FindFeatures( int minFeatures )
} }
} }
// ... and sort the list
_quicksort( (int*)list, nli ); _quicksort( (int*)list, nli );
// I'll call these "interest points", since they're just candidates for features...
int oldN = nFeatures; int oldN = nFeatures;
// Look through all newly found interest-points and add the most interesting to our
// list of features, until we have at least minFeatures
for( int i=0;i<nli && nActiveFeatures<minFeatures;i++ ) for( int i=0;i<nli && nActiveFeatures<minFeatures;i++ )
{ {
// Check if this interest point is too close to an existing feature, to avoid excessive clustering
int j; int j;
for( j=0;j<nFeatures;j++ ) for( j=0;j<nFeatures;j++ )
{ {
if( lFeatures[j].StartTime + lFeatures[j].Pos.size() < CurFrame ) continue; //feature was lost // Check that we didn't lose this feature
if( lFeatures[j].StartTime + lFeatures[j].Pos.size() < CurFrame ) continue;
// Calculate distance between the interest point of the outer loop and this feature
float dx = list[i].x - lFeatures[j].Pos[ CurFrame - lFeatures[j].StartTime ].x; 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 dy = list[i].y - lFeatures[j].Pos[ CurFrame - lFeatures[j].StartTime ].y;
float sqr = dx*dx+dy*dy; float sqr = dx*dx+dy*dy;
// And see if it's close enough
if( sqr < Cfg.MinDistanceSquare ) break; if( sqr < Cfg.MinDistanceSquare ) break;
} }
if( j!=nFeatures ) continue; if( j!=nFeatures ) continue; // Found an existing feature too close, so skip this interest point
// Check if we need to allocate more space for features
if( nFeatures >= mFeatures ) if( nFeatures >= mFeatures )
{ {
// Allocate new, larger feature list and copy old features into new list
mFeatures = nFeatures+9; mFeatures = nFeatures+9;
mFeatures -= mFeatures%8; mFeatures -= mFeatures%8;
FexTrackingFeature * nlFeatures = (FexTrackingFeature*) new FexTrackingFeature[mFeatures]; FexTrackingFeature * nlFeatures = (FexTrackingFeature*) new FexTrackingFeature[mFeatures];
@ -246,10 +284,12 @@ void FexTracker::FindFeatures( int minFeatures )
for( int cpy2=0;cpy2<lFeatures[ cpy ].Pos.size();cpy2++ ) for( int cpy2=0;cpy2<lFeatures[ cpy ].Pos.size();cpy2++ )
nlFeatures[ cpy ].Pos.Add( lFeatures[ cpy ].Pos[cpy2] ); nlFeatures[ cpy ].Pos.Add( lFeatures[ cpy ].Pos[cpy2] );
} }
// ... finally replacing the old list
delete [] lFeatures; delete [] lFeatures;
lFeatures = nlFeatures; lFeatures = nlFeatures;
} }
// Add this interest point to the end of the feature list
lFeatures[nFeatures].Eigenvalue = list[i].val; lFeatures[nFeatures].Eigenvalue = list[i].val;
vec2 pt; vec2 pt;
pt.x = (float)list[i].x; pt.x = (float)list[i].x;
@ -261,6 +301,7 @@ void FexTracker::FindFeatures( int minFeatures )
nActiveFeatures++; nActiveFeatures++;
} }
// Subtract 1 from the start time of all newly found features
for( int j=oldN;j<nFeatures;j++ ) for( int j=oldN;j<nFeatures;j++ )
lFeatures[j].StartTime = max(0,lFeatures[j].StartTime-1); lFeatures[j].StartTime = max(0,lFeatures[j].StartTime-1);

View File

@ -120,10 +120,10 @@ private:
void CountActiveFeatures(); void CountActiveFeatures();
//result //result
FexTrackingFeature* lFeatures; FexTrackingFeature* lFeatures; // list of allocated features
int nFeatures; int nFeatures; // current number of used feature slots
int nActiveFeatures; int nActiveFeatures; // number of features with motion data on current image
int mFeatures; int mFeatures; // number of features allocated space for
int CurFrame; int CurFrame;
}; };

View File

@ -345,7 +345,7 @@ void FontsCollectorThread::Collect() {
// For zipped files, enter a default name if none was given // For zipped files, enter a default name if none was given
else { else {
wxFileName dest(destination); wxFileName dest(destination);
if (!dest.IsFileWritable()) { if (!dest.FileExists()) {
wxFileName subsname(subs->filename); wxFileName subsname(subs->filename);
if (!dest.IsDir()) { if (!dest.IsDir()) {
destination = subsname.GetPath(); destination = subsname.GetPath();