/* * This Software is the original work of Daniel TUNG * This Software is submitted in partial fulfillment of the * requirements for the degree of BCSE. * Dept. Computer Science, Monash University 2000 * * Copyright (c) 2000 beetung@cs.monash.edu.au * beetung@geocities.com */ #ifndef AUTONODE_H #define AUTONODE_H #include #include //#include "autoabs.h" #include "llist.h" /// /// Intensity on RGB, average the value of RGB to a single /// intensity value... /// #define iRGB(iX) \ \ (( ((iX >> 16)& 0xFF)+ \ ((iX >> 8)& 0xFF)+ \ ( iX & 0xFF)+ \ 0xff ) >>2) // performing --> ((RGB+0xFF)/4) //// //// Base AutoNode class. An AutoNode tracks the position //// of itself automatically //// template /////////////////////////////////////////////////// class BaseNode { /////////////////////////////////////////////////// // for our CCC project! private: enum { XMAX =384, YMAX =288, XMIN =0, YMIN =0, LAST_IN_LIST_NO_NEED_COMMA_AS_USUAL_WASTING_SPACE =-1 }; protected: enum NodeState { // -ve <-- o --> +ve UNTESTED =0, // NO_EDGE =-1, // no edge in range OUT_OF_BOUND =-1, // out of bound HAS_EDGE =1, // has edge in range? RESETED =-1 } nodeState; int xMax,yMax; // boundaries int xMin,yMin; // `' int _x,_y; // (x,y) point exact /// ::::NOTE POINT::::: /// these are statics, being shared across all nodes!! public: static int* baseFrame; // base frame pointer for all nodes to share public: /// /// set the base frame for all nodes to share /// //---------------- static bool setBaseFrame(int* fbuf) { //---------------- // its a static! BaseNode::baseFrame = fbuf; return true; } public: //----------------------------------------- BaseNode() : nodeState ( UNTESTED ), xMax(XMAX),yMax(YMAX),xMin(0),yMin(0) {;} //----------------------------------------- BaseNode(int yy, int xx,int ls =XMAX) : nodeState ( UNTESTED ), xMax(XMAX),yMax(YMAX),xMin(0),yMin(0), _x(xx), _y(yy) {;} //----------------------------------------- //------------------- inline bool isOutOfBound(void) { return nodeState == OUT_OF_BOUND; } inline void reset(void) { nodeState = RESET; } //------------------- virtual int getX () const { return _x; } virtual int getY () const { return _y; } virtual void draw (void) = 0; virtual bool swim (void) = 0; virtual bool findEdge (void) = 0; virtual int getCenter (void) {return 0;}; /// /// set our exact (_y,_x) position /// //----------------------------------------- virtual bool set(int iy,int ix) { //----------------------------------------- /* if ((iy>yMax) || (iy < yMin)) return false; if ((ix>xMax) || (ix < xMin)) return false; */ if ((iy>YMAX) || (iy < YMIN)) return false; if ((ix>XMAX) || (ix < XMIN)) return false; _x=ix; _y=iy; setBound(iy-1,ix-5, iy+1,ix+5); return true; } /// /// set the boundaries /// //----------------------------------------- virtual void setBound(int ys, int xs,int yd,int xd) { //----------------------------------------- // shouldnt it be between (XMIN-->XMAX) // dont miss use it, ok? xMax=(xd>XMAX)? XMAX : xd; xMin=(xsYMAX)? YMAX : yd; yMin=(ys& b) { //----------------------------------------- os << "\" (y,x) atPoint ("<< b._y <<","<< b._x << ") " " yMin,xMin (" << b.yMin << "," << b.xMin << ") " " yMax,xMax (" << b.yMax << "," << b.xMax << ")\"" << endl; /// print as normal // os.flags(ios::hex); for(int ys=b.yMin; ys !=b.yMax; ys++) { for (int xs=b.xMin;xs!=b.xMax;xs++) os << iRGB(b.baseFrame[(ys*b.XMAX)+xs]) << " "; os << endl; } return os; } // os.flags(ios::dec); }; #define PI 3.1416 const double s_8 =sin ( PI / 8.0 ); const double s3_8 =sin ( (3.0*PI) / 8.0 ); const double s_16 =sin ( PI / 16.0 ); const double s3_16 =sin ( (3.0*PI) / 16.0 ); const double s5_16 =sin ( (5.0*PI) / 16.0 ); const double s7_16 =sin ( (7.0*PI) / 16.0 ); const double c_4 = cos( PI / 4.0 ) ; const double c_8 = cos( PI / 8.0 ) ; const double c3_8 = cos( (3.0*PI) / 8.0 ) ; const double c_16 = cos( PI / 16.0 ) ; const double c3_16 = cos( (3.0*PI) / 16.0 ) ; const double c5_16 = cos( (5.0*PI) / 16.0 ) ; const double c7_16 = cos( (7.0*PI) / 16.0 ) ; //// //// //// template /////////////////////////////////////////////////// class AutoNode : public BaseNode { /////////////////////////////////////////////////// protected: int lOffset ; // left offset int rOffset ; // right offset int dxSize; // change in X directn from prev Pos. /// enums follow... /// enum { HEAD_TAIL_THRESHOLD =38 } ; // black -- white ==> -1 ... gradient direction // white -- black --> +1 enum EdgeGrad { // -ve <-- o --> +ve BLACK_ON_LEFT =-1, BLACK_ON_RIGHT =1 , UNTESTED =0 } gradDir; public: virtual ~AutoNode() {;} AutoNode(int iy, int ix) : BaseNode(iy,ix), gradDir(UNTESTED) { BaseNode::setBound(iy-1,ix-5, iy+1,ix+5); } //------------------- int getdX(void) { return dxSize; } //------------------- /// /// Look for an "edge" inside our bounded region /// using our "optimal" algorithm /// //------------------- virtual bool findEdge(void) { //------------------- // // we check to see if there we can identify an edge in this block straight // away 1st // int yOffset =(_y*XMAX); //// //// We start looking from left offset to right offset incrementally. //// ie: for DCT edge operator //// lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if ( !head_tail_Edge() ) { // // Can't gaurantee we have an edge here! // what we then do is // 1. start comparing inside-out from boundary // 2. apply few more operators to estimate a probably // that wheather we have an edge or not! swim(); } else { // // there is a high probability of having an edge here! // 1. double check with other operators // // fdct(); // nodeState = HAS_EDGE; } return (nodeState == HAS_EDGE); }// findEdge(); //// //// This function would adjust the (_y,_x) coordinates of the BaseNode //// by attempting to search for an edge position within the same "Y" //// axis. ie: only X is varying... //// //------------------- virtual bool swim(void) { //------------------- int step =1; // steps to move out from central positn. int xOrg =_x; // original x int xMinOrg =xMin, xMaxOrg =xMax ; bool maxReached =false, minReached =false ; int yOffset =(_y*XMAX); lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if ( head_tail_Edge() ) // check same location ; else // // we start searching on this current (y,xMin-xMax) spreading // outwards to estimate/evaluate a shift in our track. // while (1) { cerr << "." ; // search in +ve direction // xMin += step ; xMax += step ; lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if (xMax > XMAX-35) // within bound still? maxReached =true; else if ( head_tail_Edge() ) { _x +=step; // // apply 2nd operator here? // /* if ( fdct() ) // we have a high edge probability? */ dxSize = step; break; } xMin =xMinOrg; xMax =xMaxOrg; _x =xOrg; // search in -ve direction // xMin -= step ; xMax -= step ; // lOffset = BaseNode::buf[yOffset+xMin]; // left offset // rOffset = BaseNode::buf[yOffset+xMax]; // right offset lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if (xMin < XMIN+35) // within bound still? minReached =true; else if ( head_tail_Edge() ) { _x -=step; // // apply 2nd operator here? // /* if ( fdct() ) // we have a high edge probability? */ dxSize = -step; break; } // reset before break; // xMin =xMinOrg; xMax =xMaxOrg; _x =xOrg; if (maxReached & minReached) { nodeState = OUT_OF_BOUND; break; } step++; // step increment } // while (1) cout << "step : " << step << endl; return nodeState; // head_tail_edge set this one } //// //// This function would adjust the (_y,_x) coordinates of the BaseNode //// by attempting to search for an edge position within the same "Y" //// axis. ie: only X is varying... //// //------------------- virtual bool swimLeft(void) { //------------------- int step =1; // steps to move out from central positn. int xOrg =_x; // original x int xMinOrg =xMin, xMaxOrg =xMax ; bool minReached =false ; int yOffset =(_y*XMAX); lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset cout << " swimLeft" << endl; if ( head_tail_Edge() ) // check same location ; else // // we start searching on this current (y,xMin-xMax) spreading // outwards to estimate/evaluate a shift in our track. // while (1) { cerr << "." ; // search in -ve direction // xMin -= step ; xMax -= step ; lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if (xMin < XMIN+35) // within bound still? minReached =true; else if ( head_tail_Edge() ) { _x -=step; // // apply 2nd operator here? // /* if ( fdct() ) // we have a high edge probability? */ dxSize = -step; break; } // reset before break; // xMin =xMinOrg; xMax =xMaxOrg; _x =xOrg; if (minReached) { nodeState = OUT_OF_BOUND; dxSize = -step; break; } step++; // step increment } // while (1) cout << "step : " << step << endl; return nodeState; // head_tail_edge set this one } //// //// This function would adjust the (_y,_x) coordinates of the BaseNode //// by attempting to search for an edge position within the same "Y" //// axis. ie: only X is varying... //// //------------------- virtual bool swimRight(void) { //------------------- int step =1; // steps to move out from central positn. int xOrg =_x; // original x int xMinOrg =xMin, xMaxOrg =xMax ; bool maxReached =false ; int yOffset =(_y*XMAX); lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset cout << " swimRight" << endl; if ( head_tail_Edge() ) // check same location ; else // // we start searching on this current (y,xMin-xMax) spreading // outwards to estimate/evaluate a shift in our track. // while (1) { cerr << "." ; // search in +ve direction // xMin += step ; xMax += step ; lOffset = BaseNode::baseFrame[yOffset+xMin]; // left offset rOffset = BaseNode::baseFrame[yOffset+xMax]; // right offset if (xMax > XMAX-35) // within bound still? maxReached =true; else if ( head_tail_Edge() ) { _x +=step; // // apply 2nd operator here? // /* if ( fdct() ) // we have a high edge probability? */ dxSize = step; break; } // reset before break; // xMin =xMinOrg; xMax =xMaxOrg; _x =xOrg; if (maxReached ) { nodeState = OUT_OF_BOUND; dxSize = step; break; } step++; // step increment } // while (1) cout << "step : " << step << endl; return nodeState == HAS_EDGE; // head_tail_edge set this one } /// /// force upon a gradient direction /// //------------------- bool setGradDir(EdgeGrad d) { //------------------- if ((d !=BLACK_ON_LEFT) || (d !=BLACK_ON_RIGHT)) return false; else gradDir = d; return true; } private: //// //// This function implements the head_tail edge finding algorithm. //// Basically, it compares two values, at location xMin and xMax, and //// see if these two values are greater than a threshold. If it is so, //// then we can gaurantee that there is an Edge within this 1D search //// block. Otherwise, we cannot gaurantee and further testing can //// then be carried out! //------------------- virtual bool head_tail_Edge(void) { //------------------- // // this one on _y, not yMin, so we have 2 levels... // int val; EdgeGrad newGrad; // // val =head value - tail value // the shifting and masking are for RBG summation... // val= iRGB(lOffset) - iRGB(rOffset); if ( abs(val) > HEAD_TAIL_THRESHOLD ) { // set change of grad direction // black -- white ==> -1 BLACK_ON_LEFT // white -- black --> +1 BLACK_ON_RIGHT nodeState =HAS_EDGE; newGrad = (val>0) ? BLACK_ON_RIGHT : BLACK_ON_LEFT; /// if (we are given, an edge direction) /// then nodeState == HAS_EDGE, only if (newGrad matches gradDir) /// else if ( still untested) /// then set gradDir to newGrad. /// if (gradDir != newGrad) { if (gradDir !=UNTESTED) nodeState = NO_EDGE; else gradDir = newGrad; } // cout << "An Edge gauranteed!!! " << val<< endl; } else { nodeState = NO_EDGE ; // cout << "No Edge.. head_tail_Edge() " << val<< endl; } return (nodeState == HAS_EDGE); } #define PPB (8) /// /// Performs Fast DCT to enable Low frequency Edge Detection... /// Refer to my thesis for how and why it works this way. /// //------------------- bool fdct(void) { //------------------- int offset =(((yMin!=_y)?yMin:yMax)*XMAX) + _x; int x,y; int i,j; double pixel[PPB]; double aStage[8],bStage[8]; // int *data = &buf[offset-5]; Btype *idata =&BaseNode::baseFrame[offset-5]; // cp (char)data[] to (double) pixel[] j = 10; for (int xs=xMin,i=0; i!=PPB; xs++,i++) { pixel[i] = (double) iRGB(BaseNode::baseFrame[(_y*XMAX)+xs]); } /////////////////////////////////////////////// // [DCT] [Pixel list in (y)] (----) ...up pack /////////////////////////////////////////////// // 1st stage // - pack into vertical '||||' form... // - refer to following forLoop // for (x=0; x!=PPB; x++) { // '----' bStage[x] = (double)pixel[x]; } // 1st stage ...OK aStage[0] = bStage[0] + bStage[7]; aStage[1] = bStage[1] + bStage[6]; aStage[2] = bStage[2] + bStage[5]; aStage[3] = bStage[3] + bStage[4]; aStage[4] =-bStage[4] + bStage[3]; aStage[5] =-bStage[5] + bStage[2]; aStage[6] =-bStage[6] + bStage[1]; aStage[7] =-bStage[7] + bStage[0]; // 2nd stage ...OK bStage[0] = aStage[0] +aStage[3]; bStage[1] = aStage[1] +aStage[2]; bStage[2] =-aStage[2] +aStage[1]; bStage[3] =-aStage[3] +aStage[0]; bStage[4] = aStage[4] ; bStage[5] = (-c_4 *aStage[5]) +(c_4 *aStage[6]); bStage[6] = ( c_4 *aStage[6]) +(c_4 *aStage[5]); bStage[7] = aStage[7]; // 3rd stage aStage[0] = ( c_4 *bStage[0]) +( c_4 *bStage[1]); aStage[1] = (-c_4 *bStage[1]) +( c_4 *bStage[0]); aStage[2] = ( s_8 *bStage[2]) +( c_8 *bStage[3]); aStage[3] = ( c3_8 *bStage[3]) +(-s3_8 *bStage[2]); aStage[4] = ( bStage[4]) +( bStage[5]); aStage[5] = (-bStage[5]) +( bStage[4]); aStage[6] = (-bStage[6]) +( bStage[7]); aStage[7] = ( bStage[7]) +( bStage[6]); // 4th stage bStage[0] = aStage[0]; bStage[1] = aStage[1]; bStage[2] = aStage[2]; bStage[3] = aStage[3]; bStage[4] =( s_16 *aStage[4]) + ( c_16 *aStage[7]); bStage[5] =( s5_16 *aStage[5]) + ( c5_16 *aStage[6]); bStage[6] =( c3_16 *aStage[6]) + (-s3_16 *aStage[5]); bStage[7] =( c7_16 *aStage[7]) + (-s7_16 *aStage[4]); // final stage pixel[0] = bStage[0] * 0.5 ; pixel[1] = bStage[4] * 0.5 ; pixel[2] = bStage[2] * 0.5 ; pixel[3] = bStage[6] * 0.5 ; pixel[4] = bStage[1] * 0.5 ; pixel[5] = bStage[5] * 0.5 ; pixel[6] = bStage[3] * 0.5 ; pixel[7] = bStage[7] * 0.5 ; int dctSUM =0; cout << "DCT weighted terms: " ; cout << pixel[0] << " " ; // skipped pixel[0] in our inner loop!! // for (x=1; x!=PPB; x++) { // '----' cout << pixel[x] << " " ; } cout << endl; if (fabs(pixel[1]) > 79.0) { cout << " placing Edge in center, high probability for an EDGE ..."; } else { cout << " LOW probability for an EDGE ..."; } cout << endl; cout << endl; return (fabs(pixel[1]) > 79.0); } /* for (x=1; x!=PPB; x++) { // '----' cout << pixel[x] << " " ; if ((fabs(pixel[x]) - fabs(pixel[x-1])) > 10) dctSUM +=fabs(pixel[x]); } cout << endl; if (dctSUM > 40) { cout << " high probability for an EDGE ..."; } else { cout << " LOW probability for an EDGE ..."; } cout << endl; cout << endl; */ public: /// /// Draws *this point in the given buffer (x,y) /// by marking it permenantly. the buffer would /// be discarded when next frame arrive anyway. //------------------- virtual void draw(void) { //------------------- if (nodeState != HAS_EDGE) { cout <<" No Edge detected! Cant draw()!" << endl; return; } // Btype *idata =BaseNode::buf; Btype *idata =BaseNode::baseFrame; int offset =(_y*XMAX) + _x; /// offsetting idata to center location /// idata = &idata [offset]; /// Y span 3 pixels long /// ...XMAX as pixels_per_line /// RRGGBB idata[ (XMAX*2)] =0x0000FF00; idata[-(XMAX*2)] =0x0000FF00; idata[ (XMAX*3)] =0x0000FF00; idata[-(XMAX*3)] =0x0000FF00; idata[ (XMAX*4)] =0x0000FF00; idata[-(XMAX*4)] =0x0000FF00; /// X span (+2 --> -2) pixels long /// int j; idata = &idata[-XMAX*2]; // draw on 1 line before for(j=-5;j!=5;j++) { idata[j]= idata[ (XMAX*4)+j ] =0xFF00FF00; } idata = &idata[+XMAX*4]; // draw on 2 lines below /* for(j=-5;j!=5;j++) { idata[ j ]=0x0000FF00; } */ // close tag on gradient direction // // black -- white ==> -1 gradDir // white -- black --> +1 gradDir idata = &idata[-XMAX*2]; // back to central if (gradDir ==BLACK_ON_RIGHT) { // black --- white idata[-5] =0xFF00FF; idata[-5+XMAX] =0xFF00FF; idata[-5-XMAX] =0xFF00FF; } else if (gradDir == BLACK_ON_LEFT) { idata[+5] =0xFF00FF; idata[+5+XMAX] =0xFF00FF; idata[+5-XMAX] =0xFF00FF; } } // draw(...) /// /// Draws *this point in the given buffer (x,y) /// by marking it permenantly. the buffer would /// be discarded when next frame arrive anyway. //------------------- virtual void draw(int tagColor) { //------------------- if (nodeState != HAS_EDGE) { cout <<" No Edge detected! Cant draw()!" << endl; return; } Btype *idata =BaseNode::baseFrame; int offset =(_y*XMAX) + _x; /// offsetting idata to center location /// idata = &idata [offset]; /// Y span 3 pixels long /// ...XMAX as pixels_per_line /// RRGGBB idata[ (XMAX*2)] = idata[ (XMAX*3)] = idata[ (XMAX*4)] = \ idata[-(XMAX*2)] = idata[-(XMAX*3)] = idata[-(XMAX*4)] = tagColor; /// X span (+2 --> -2) pixels long /// int j; idata = &idata[-XMAX*2]; // draw on 1 line above for(j=-5;j!=5;j++) { idata[j]= idata[ (XMAX*4)+j ]=tagColor; } /* for(j=-5;j!=5;j++) { idata[j]= idata[ (XMAX*4)+j ]=tagColor; } */ idata = &idata[+XMAX*4]; // draw on 2 lines below prev Pos. // close tag on gradient direction // // black -- white ==> -1 gradDir // white -- black --> +1 gradDir idata = &idata[-XMAX*2]; // back to central if (gradDir ==BLACK_ON_RIGHT) { // where to put the dot? idata[-5] =0xFF00FF; idata[-5+XMAX] =0xFF00FF; idata[-5-XMAX] =0xFF00FF; } else if (gradDir == BLACK_ON_LEFT) { idata[+5] =0xFF00FF; idata[+5+XMAX] =0xFF00FF; idata[+5-XMAX] =0xFF00FF; } } // draw(...) }; //// //// //////////////////////////////////////// class FixedNode: public BaseNode { //////////////////////////////////////// ; }; #endif