Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages | Examples

VisualVector.cpp

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00002 /*! \file VisualVector.cpp
00003 *  \brief Implementation of the VisualVector class
00004 *  \author $Author: lljones $
00005 *  \version $Revision: 1.1 $
00006 *  \date    $Date: 2007/03/29 23:03:43 $
00007 *//////////////////////////////////////////////////////////////////////////////////////////////////
00008 /*!
00009 */
00010 //////////////////////////////////////////////////////////////////////////////////////////////////
00011 
00012 
00013 #include "VisualVector.h"
00014 //#include "cv.h"               // Open CV headers
00015 //#include "cxcore.h"   // Open CV headers
00016 
00017 
00018 ///////////////////////////////////////////////////////////////////////
00019 // Construction/Destruction                                          //
00020 ///////////////////////////////////////////////////////////////////////
00021 
00022 /*! \brief Default Constructor
00023 */
00024 
00025 VisualVector::VisualVector()
00026 {
00027         WorkingImage = NULL;
00028         RawImage = NULL;
00029         Debug = false;
00030 
00031         capture = cvCaptureFromCAM(CV_CAP_ANY);
00032         if (!capture)
00033         {
00034                 cout << "no capture device available" << endl;
00035                 exit(1);
00036         }
00037 
00038         cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
00039         cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 240);
00040 
00041 }
00042 
00043 VisualVector::VisualVector(bool debug)
00044 {
00045         WorkingImage = NULL;
00046         RawImage = NULL;
00047         Debug = debug;
00048 
00049         capture = cvCaptureFromCAM(CV_CAP_ANY);
00050         if (!capture)
00051         {
00052                 cout << "no capture device available" << endl;
00053                 exit(1);
00054         }
00055 
00056         cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
00057         cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 240);
00058 
00059         
00060 }
00061 
00062 
00063 VisualVector::~VisualVector()
00064 {
00065         // clean up objects
00066         cvReleaseCapture(&capture);
00067 
00068 }
00069 
00070 /////////////////////////////////////////////////////////////////////////
00071 // Get Measurements                                                    //
00072 /////////////////////////////////////////////////////////////////////////
00073 
00074 /*! \brief Function to return scalar measurement (not currently used)
00075 */
00076 Measurement VisualVector::GetMeasurement()
00077 {
00078 // leave me blank
00079 return 0;
00080 }
00081 
00082 /*! \brief Function to return Visual Vector measurement in the form of a vector
00083 */
00084 Vector VisualVector::GetVectorMeasurement()
00085 {
00086         int check;
00087         float a1,a2;
00088         long double a3;
00089         double a1deg,a2deg,a3deg;       //hold degree values of a1,a2,a3 angles
00090         int pixelheight,pixelwidth;     //store height and width of WorkingImage (in pixels)
00091 
00092         const int CENTZEROTILT[2] = {140,154};  //zero-tilt location of centroid
00093         const double RUNIT = 17.2;              //inches to camera
00094         const double HUNIT = 88.25;             //inches to ceiling
00095         const double PI = 3.1415926535897932384626433832795028841971693993751;
00096 
00097         // get WorkingImage from capture object
00098         RawImage = cvQueryFrame(capture);
00099         if (!RawImage)
00100         {
00101                 cout << "no WorkingImage captured" << endl;
00102                 exit(1);
00103         }
00104 
00105         WorkingImage = cvCreateImage(cvSize(RawImage->width,RawImage->height),IPL_DEPTH_8U,1);
00106 
00107         cvConvertImage(RawImage,WorkingImage,CV_CVTIMG_FLIP);
00108 
00109         pixelheight = WorkingImage->height;
00110         pixelwidth = WorkingImage->width;
00111 
00112         check = FindVertex();
00113 
00114         if (check != 0)
00115         {
00116                 if (check == 1)
00117                         cout << "Error within FindVertex:  Equilateral Triangle Inputted.\n";
00118                 else if (check == 2)
00119                         cout << "Error within FindVertex:  Area mismatch - is whole triangle present?\n";
00120                 else if (check == 3)
00121                         cout << "Error within FindVertex:  Intensity mismatch - are lights on?\n";
00122                 else if (check == 4)
00123                         cout << "Error within FindVertex:  Vertex Index out of Image\n";
00124                 else
00125                         cout << "Error within FindVertex:  Unknown Error\n";
00126                 return 0;
00127         }
00128 
00129 
00130         //cleanup WorkingImage (do NOT clean RawImage b/c derived from capture)
00131         cvReleaseImage(&WorkingImage);
00132         WorkingImage = NULL;
00133         RawImage = NULL;
00134         //is this neccessary?
00135         capture = NULL;
00136 
00137         // Running functions
00138         a3 = RotationAngleFunc(pixelwidth, pixelheight);
00139         a3deg = (180 * a3) / PI;
00140         
00141         a1 = TiltAngle1Func(a3, pixelheight, pixelwidth, CENTZEROTILT,  RUNIT, HUNIT);
00142         a1deg = (a1 * 180) / PI;
00143 
00144         a2 = TiltAngle2Func(a3, pixelheight, pixelwidth, CENTZEROTILT, RUNIT, HUNIT);
00145         a2deg = (a2 * 180) / PI;
00146 
00147         if (Debug == true)
00148         {
00149                 cout << endl << "Corner Locations (furthest vertex listed first):\nx1: "
00150                         << vertex[0] << "\ty1: " << vertex[1] << "\nx2: " << vertex[2]
00151                         << "\ty2: "     << vertex[3] << "\nx3: " << vertex[4] << "\ty3: "
00152                         << vertex[5] << endl << "Centroid:\n  x: " << centroid[0]
00153                         << "\n  y: " << centroid[1] << endl << endl;
00154         
00155                 cout << "Angle about the N1 axis (deg) = " << a1deg << endl;
00156                 cout << "Angle about the N2 axis (deg) = " << a2deg << endl;
00157                 cout << "Angle about the N3 axis (deg) = " << a3deg << endl << endl;
00158         }
00159 
00160         Vector AngleVals(3);
00161         AngleVals(1) = a1deg;
00162         AngleVals(2) = a2deg;
00163         AngleVals(3) = a3deg; 
00164         return AngleVals;
00165 }
00166 
00167 //////////////////////////////////////////////////////////////////////////
00168 // Included Functions                                                   //
00169 ////////////////////////////////////////////////////////////////////////// 
00170 
00171 /*! \brief Visual Vector Vertex Finder
00172 */
00173 int VisualVector::FindVertex()
00174 {
00175         const double MIN_DISTANCE = 45;         //minimum Euclidean distance between pixels
00176         const double QUALITY = 0.01;            //minimum quality of features (based on eigenvals)
00177         //const double AREA_MIN = 1400;         //minimum value of triangle area (pixels)
00178         //const double AREA_MAX = 6000;         //maximum value of triangle area (pixels)
00179         const int MAX_COUNT = 3;                //maximum number of detected features/points
00180         int corner_count;                       //will have value <= MAX_COUNT to indicate points found
00181         int check;                              //if non-zero, error in function present
00182         double area;                            //area of triangle
00183 
00184         IplImage *temp = NULL, *eigenval = NULL;
00185 
00186         corner_count = MAX_COUNT;
00187         CvPoint2D32f corners[3];
00188 
00189         eigenval = cvCreateImage(cvSize(WorkingImage->width,WorkingImage->height),32,1);
00190         temp     = cvCreateImage(cvSize(WorkingImage->width,WorkingImage->height),32,1);
00191 
00192         //Precursor to corner detection - finds eigenvals
00193         cvCornerMinEigenVal(WorkingImage, eigenval,3,3);
00194         //detects strong corners/features.  Note that parameters following NULL are optional.
00195         cvGoodFeaturesToTrack(WorkingImage, eigenval, temp, corners, &corner_count, QUALITY, MIN_DISTANCE, NULL, 3, 0, 0.04);
00196 
00197         //cleanup unneeded images
00198         cvReleaseImage(&temp); cvReleaseImage(&eigenval);
00199         temp = NULL; eigenval = NULL;
00200 
00201         vertex[0] = int(corners[0].x); vertex[1] = int(corners[0].y); vertex[2] = int(corners[1].x);
00202         vertex[3] = int(corners[1].y); vertex[4] = int(corners[2].x); vertex[5] = int(corners[2].y);
00203 
00204         check = VertexSwitch();
00205         if (check != 0)
00206                 return 1;       //error indicating equilateral triangle detected
00207 
00208         //Calculate area of Triangle
00209         area = (vertex[0]*vertex[5]-vertex[0]*vertex[3]+vertex[2]*vertex[1]-vertex[2]*vertex[5]
00210                 +vertex[4]*vertex[3]-vertex[4]*vertex[1])/2;
00211         area = fabs(area);
00212 
00213         //area error check
00214         //if ((area <= AREA_MIN) || (area >= AREA_MAX))
00215         //      return 2;  //<Error2>  area mismatch
00216 
00217         //intensity error check
00218 
00219         /*
00220                 ADD THIS LATER
00221         */
00222 
00223         //determine centroid
00224         centroid[0] = double(vertex[0]+vertex[2]+vertex[4])/3;
00225         centroid[1] = double(vertex[1]+vertex[3]+vertex[5])/3;
00226         
00227         if (Debug == true)
00228         {
00229         //      cout << "area: " << area << endl;
00230                 //create color picture
00231                 IplImage *color = NULL;
00232                 //define colors
00233                 CvScalar red;   red.val[0] = 0; red.val[1] = 0; red.val[2] = 255;
00234                 CvScalar blue;  blue.val[0] = 255; blue.val[1] = 0; blue.val[2] = 0;
00235                 CvScalar black; black.val[0] = 0; black.val[1] = 0; black.val[2] = 0;
00236                 //create color image holder of same dimensions
00237                 color = cvCreateImage(cvSize(WorkingImage->width,WorkingImage->height),8, 3);
00238                 //copy B&W image to color-enabled picture
00239                 cvCvtColor(WorkingImage,color,CV_GRAY2RGB);
00240                 //show verticies in red and centroid in blue
00241                 cvSet2D(color,int(corners[0].y),int(corners[0].x),red);
00242                 cvSet2D(color,int(corners[1].y),int(corners[1].x),red);
00243                 cvSet2D(color,int(corners[2].y),int(corners[2].x),red);
00244                 cvSet2D(color,int(centroid[1]),int(centroid[0]),blue);
00245                 //Save Image with Verticies and Centroid superimposed
00246                 cvSaveImage("ImageFeatures.bmp",color);
00247                 cvReleaseImage(&color);
00248                 color = NULL;
00249         }
00250 
00251         return 0;
00252 }
00253 
00254 
00255 /*! \brief Visual Vector Vertex Sorter
00256 */
00257 int VisualVector::VertexSwitch()
00258 {
00259         int tempVertex;                 //temporarily stores vertex values for swapping
00260         double dist1,dist2,dist3;       //holds returns of distance function for swapping
00261 
00262         //distance formula between points
00263         dist1 = sqrt(pow(double(vertex[0] - vertex[2]),2) + pow(double(vertex[1] - vertex[3]),2));
00264         dist2 = sqrt(pow(double(vertex[0] - vertex[4]),2) + pow(double(vertex[1] - vertex[5]),2));
00265         dist3 = sqrt(pow(double(vertex[2] - vertex[4]),2) + pow(double(vertex[3] - vertex[5]),2));
00266 
00267         if ((dist3 < dist1) && (dist3 <= dist2)); //side 3 shortest: 0,1 furthest vertex/no change
00268         else if ((dist2 < dist1) && (dist2 <= dist3)) //side 2 is shortest: 2,3 is furthest vertex
00269         {       //switch 2,3 and 0,1
00270                 tempVertex = vertex[0];
00271                 vertex[0] = vertex[2];
00272                 vertex[2] = tempVertex;
00273                 tempVertex = vertex[1];
00274                 vertex[1] = vertex[3];
00275                 vertex[3] = tempVertex;
00276         }
00277         else if ((dist1 < dist2) && (dist1 <= dist3))   //side 1 is shortest, 4,5 is furthest vertex
00278         {       //switch 4,5 and 0,1
00279                 tempVertex = vertex[0];
00280                 vertex[0] = vertex[4];
00281                 vertex[4] = tempVertex;
00282                 tempVertex = vertex[1];
00283                 vertex[1] = vertex[5];
00284                 vertex[5] = tempVertex;
00285         }
00286         else    //3 verticies are the same length from each other/Equilateral Triangle
00287                 return 1;
00288 
00289         return 0;       //no-error return
00290 }
00291 
00292 /*! \brief Visual Vector Rotation Angle Calculations
00293 */
00294 long double VisualVector::RotationAngleFunc(int pixelwidth, int pixelheight)
00295 {
00296         // v1  represents the vertex farthest from the centroid
00297         // cent represents the centroid
00298         // pixelwidth and pixelheight are the size of the overall WorkingImage
00299 
00300         const double PI = 3.1415926535897932384626433832795028841971693993751;
00301 
00302         if (centroid[0] < 0 || centroid[1] < 0 || vertex[0] < 0 || vertex[1] < 0){
00303                 cout << "Invalid inputs for the centroid or vertex" << endl;
00304         }
00305 
00306         // Setting up the camera frame vector
00307         int cox = pixelwidth/2;                 // Camera origin x coordinate
00308         int coy = pixelheight/2;                // Camera origin y coordinate
00309         int c1ex = pixelwidth;                  // Endpoint of c1 axis x coordinate
00310         int c1ey = pixelheight/2;               // Enpoint of c1 axis y coordinate
00311         int c1x = c1ex - cox;                   // X component of c1/ b1
00312         int c1y = c1ey - coy;                   // Y component of c1/ b1
00313 
00314 
00315         // Setting up the inertial frame vector
00316         double n1x = vertex[0] - centroid[0];           // X component of n1
00317         double n1y = vertex[1] - centroid[1];           // Y component of n1
00318 
00319         // Calculating the rotation angle
00320         double dot = c1x*n1x+c1y*n1y;   // Dot product of c1 and n1
00321         double normc1 = sqrt( pow((double)c1x,2) + pow((double)c1y,2) ); // Converting to double to shut up compiler
00322         double normn1 = sqrt( pow((double)n1x,2) + pow((double)n1y,2) ); // Converting to double to shut up compiler
00323         double tpart = dot/( normc1 * normn1 );
00324         long double theta = acos(tpart);
00325 
00326         // Quadrant correction
00327         if  (vertex[1] > centroid[1]){
00328                 theta = (PI - theta) + PI;
00329         }
00330 
00331         long double an3 = theta ;
00332         return an3;
00333 }
00334 
00335 /*! \brief Visual Vector Tilt Angle Calculations
00336 */
00337 float VisualVector::TiltAngle1Func(long double RotAngle,int pixelheight, int pixelwidth, const int centzerotilt[], double runit,double hunit)
00338 {
00339         // cent represents the centroid
00340         // RotAngle is the rotation angle calculated with the RotationAngle code
00341         // pixelheight is the number of pixels high the WorkingImage is
00342         // pixelwidth is the number of pixel across th WorkingImage is
00343         // centzerotilt is the location of the centroid when the Whorl is untilted
00344         // runit is the distance in (meters/feet) from the center of Whorl I's
00345         //    n3 rotation to the center of the camera lens
00346         // hunit is the number of (meters/feet) from the center of Whorl I's
00347         //    rotation to the centroid of the triangle (theoretically a vertical
00348         //    distance
00349 
00350         // This code deals with the change in y position only
00351 
00352         // Changing coordinate frames
00353         double Xdiff = centroid[0] - centzerotilt[0];
00354         double Ydiff = centroid[1] - centzerotilt[1];
00355 
00356         double Yhyp = Ydiff / sin(RotAngle);
00357         double Yleg = Yhyp * cos(RotAngle);
00358 
00359         double Y_Nframe = (Xdiff - Yleg) * sin(RotAngle);
00360         double Xhyp = Xdiff - Yleg;
00361         double Xleg = Xhyp * cos(RotAngle);
00362 
00363         double X_Nframe = Yhyp + Xleg;
00364 
00365         // Correcting for Undefined Values
00366         if (sin(RotAngle) == 0){
00367               Y_Nframe = Ydiff;
00368               X_Nframe = Xdiff;
00369         }
00370 
00371         // Finding Distance Relative to N-Frame
00372         double intern1 = pow((pixelheight / 2 - centzerotilt[1]), 2.0);
00373         double intern2 = pow((pixelwidth / 2 - centzerotilt[0]), 2.0);
00374         double rpix = sqrt(intern1 + intern2);
00375 
00376         // Finding Tilt Angle
00377         double hpix = (rpix / runit) * hunit;
00378         float phiy = atan(Y_Nframe / hpix);
00379         float an1 = phiy ;
00380         return an1;
00381 }
00382 
00383 float VisualVector::TiltAngle2Func(long double RotAngle,int pixelheight, int pixelwidth, const int centzerotilt[], double runit, double hunit)
00384 {
00385        // centx  represents the x coordinate of the centroid
00386         // RotAngle is the rotation angle calculated in RotationAngle code
00387         // pixelheight is the number of pixels high the WorkingImage is
00388         // pixelwidth is the number of pixel across th WorkingImage is
00389         // centzerotilt is the location of the centroid when the Whorl is at zero tilt
00390         // runit is the distance in (meters/feet) from the center of Whorl I's
00391         //    n3 rotation to the center of the camera lens
00392         // hunit is the number of (meters/feet) from the center of Whorl I's
00393         //    rotation to the centroid of the triangle (theoretically a vertical
00394         //    distance
00395 
00396         // This code deals with the change in x position only
00397 
00398         // Changing coordinate frames
00399         double Xdiff = centroid[0] - centzerotilt[0];
00400         double Ydiff = centroid[1] - centzerotilt[1];
00401 
00402         double Yhyp = Ydiff / sin(RotAngle);
00403         double Yleg = Yhyp * cos(RotAngle);
00404 
00405         double Y_Nframe = (Xdiff - Yleg) * sin(RotAngle);
00406         double Xhyp = Xdiff - Yleg;
00407         double Xleg = Xhyp * cos(RotAngle);
00408 
00409         double X_Nframe = Yhyp + Xleg;
00410 
00411         // Correcting for Undefined Values
00412         if (sin(RotAngle) == 0){
00413               Y_Nframe = Ydiff;
00414               X_Nframe = Xdiff;
00415         }
00416         
00417         // Finding Distances Relative to N-frame
00418         double intern1 = pow((pixelheight / 2 - centzerotilt[1]), 2.0);
00419         double intern2 = pow((pixelwidth / 2 - centzerotilt[0]), 2.0);
00420         double rpix = sqrt(intern1 + intern2);
00421 
00422         // Finding Tilt Angle
00423         double hpix = (rpix / runit) * hunit;
00424         float phix = atan(X_Nframe/hpix);
00425         float an2 = phix ;
00426         return an2;
00427 
00428 }
00429 
00430 //////////////////////////////////////////////////////////////////////////
00431 // Header File, for reference                                           //
00432 //////////////////////////////////////////////////////////////////////////
00433 //
00434 //-----------------------------------------------------------------------------------------------------------------------
00435 //#ifndef __VISUAL_VECTOR_H__
00436 //#define __VISUAL_VECTOR_H__
00437 //
00438 //#include <Base/Sensor.h>
00439 //#include <matrix/Matrix.h>
00440 //#include "dsacssinterface.h"
00441 //
00442 //class IplImage;
00443 //
00444 //using namespace O_SESSAME;
00445 //
00446 //class VisualVector : public Sensor
00447 //{
00448 //public:
00449 //        // Contructors/Deconstructors
00450 //        VisualVector();
00451 //        virtual ~VisualVector();
00452 //
00453 //        // Facilitators
00454 //
00455 //        // Inspectors
00456 //        Measurement GetMeasurement();
00457 //        Vector GetVectorMeasurement();
00458 //
00459 //private:
00460 //        int FindVertex(IplImage *WorkingImage, int vertex[],double centroid[]);
00461 //        int VertexSwitch(int vertex[]);
00462 //        
00463 //        long double RotationAngleFunc(int v1[], double cent[], int pixelwidth, int pixelheight);
00464 //        float TiltAngle1Func(double cent[], long double RotAngle,int pixheight, int pixwidth, int centzerotilt[], double runit,double hunit);
00465 //        float TiltAngle2Func(double cent[], long double RotAngle,int pixheight, int pixwidth, int centzerotilt[], double runit, double hunit);
00466 //
00467 //
00468 //};
00469 //
00470 //#endif
00471 //---------------------------------------------------------------------------------------------------------------------------------------------
00472 

Generated on Wed Sep 5 12:54:27 2007 for DSACSS Operational Code by  doxygen 1.3.9.1