void RobotDemo::camera_test() { #if CAMERA image = camera->GetImage(); cout << image << endl; delete image; #endif }
bool tracking (bool use_alternate_score) //camera tracking function { //takes one camera frame and turns towards tallest target //returns true if target is within deadzone, returns false otherwise Threshold tapeThreshold(0, 255, 0, 90, 220, 255); //red hsl as of 20110303, this is the hue, saturation and luminosicity ranges that we want BinaryImage *tapePixels;// Image *convexHull; BinaryImage *convexHullBinaryImage; ParticleAnalysisReport par;//analyzed blob (pre convex hull) ParticleAnalysisReport convexpar;// ONE filled-in blob vector<ParticleAnalysisReport>* pars;//where many analyzed blob goes (pre) vector<ParticleAnalysisReport>* convexpars; //where MANY filled-in blobs go bool foundAnything = false; double best_score = 120; double best_speed; double particle_score; ImageType t; int bs; img = cam->GetImage(); printf("cam->GetImage() returned frame %d x %d\n",img->GetWidth(),img->GetHeight()); tapePixels = img->ThresholdHSL(tapeThreshold); imaqGetBorderSize(tapePixels->GetImaqImage(),&bs); imaqGetImageType(tapePixels->GetImaqImage(),&t); convexHull = imaqCreateImage(t,bs); convexHullBinaryImage = new BinaryImageWrapper(convexHull); convexHullBinaryImage->GetOrderedParticleAnalysisReports(); //tapePixels = img->ThresholdHSL(int 0,int 50,int -100,int -50,int luminenceLow,int luminanceHigh); pars = tapePixels->GetOrderedParticleAnalysisReports(); imaqConvexHull(convexHull,tapePixels->GetImaqImage(),true); convexHullBinaryImage = new BinaryImageWrapper(convexHull); convexpars = convexHullBinaryImage->GetOrderedParticleAnalysisReports(); //imaqGetParticleInfo() //convexpars = convexHull->GetOrderedParticleAnalysisReports(); for (int i=0;i < convexHullBinaryImage->GetNumberParticles();i++) { //par = (*pars)[0]; //convexpar = (*convexpars)[i]; convexpar = convexHullBinaryImage->GetParticleAnalysisReport(i); par = tapePixels->GetParticleAnalysisReport(i); if((convexpar.boundingRect.width < 10) || (convexpar.boundingRect.height < 7)) { continue; } // printf("%d par:%f convex:%f particle area\n",i,par.particleArea,convexpar.particleArea); if ((par.particleArea/convexpar.particleArea > 0.4)) { printf("%d skip max fillness ratio\n",i); continue; } if ((par.particleArea/convexpar.particleArea < 0.10)) { printf("%d skip min fillness ratio\n",i); continue; } if((double)(convexpar.boundingRect.width)/(double)(convexpar.boundingRect.height)>1.8) { printf("%d skip max aspect ratio\n",i); continue; } if((double)(convexpar.boundingRect.width)/(double)(convexpar.boundingRect.height)<.8) { printf("%d skip min aspect ratio\n",i); continue; } //printf("%f center of mass x\n",par.center_mass_x_normalized); //printf("%f center of mass y\n",par.center_mass_y_normalized); distanceInInches = (18.0*179.3)/(convexpar.boundingRect.height); double pwidth = convexpar.boundingRect.width; double mwidth = ((double)convexpar.boundingRect.left+(double)convexpar.boundingRect.width*0.5); double angle = ((180.0/3.14159)*acos (pwidth * distanceInInches/179.3/24.0) ); if(angle != angle) angle = 0.0; // if angle is NaN, set to zero printf("%f distance in inches\n",distanceInInches); //printf("%f angle\n",(180.0/3.14159)*acos (pwidth * distanceInInches/415.0/24.0) ); printf("%d BBctrX:%f CMX:%f\n", i, (double)convexpar.boundingRect.left + (double)convexpar.boundingRect.width*0.5, (double)par.center_mass_x); //printf("%f angle2\n",(((pwidth * distanceInInches)/415.0)/24.0)); //printf("%f center of mass x\n",par.center_mass_x_normalized); printf("%d %f %f center of mass x\n",i,convexpar.center_mass_x_normalized,par.center_mass_x_normalized); printf("%d %f %f center of mass y\n",i,convexpar.center_mass_y_normalized,par.center_mass_y_normalized); printf("%d %f %f rectangle score\n",i,(convexpar.particleArea)/((convexpar.boundingRect.width)*(convexpar.boundingRect.height))*(100),(par.particleArea)/((par.boundingRect.width)*(par.boundingRect.height))*(100)); printf("%d %f fillness ratio\n",i,par.particleArea/convexpar.particleArea); printf("%d %d %d width and height\n",i,(convexpar.boundingRect.width),(convexpar.boundingRect.height)); printf("%d %f aspect ratio\n",i,((convexpar.boundingRect.width)/(double)(convexpar.boundingRect.height))); if ((double)(par.center_mass_x)>mwidth) { angle=angle*(-1.0); } printf("%f true angle\n",angle); //Wait(1.0); double aiming_target_offset = 0.0; //aiming_target_offset = pwidth * angle * (-0.5 / 45.0); numbers are iffy -> NaN double speed = trackingFeedbackFunction(mwidth + aiming_target_offset - 80.0); printf("%f aiming_target_offset due to %f degree angle\n", aiming_target_offset, angle); printf("%f x offset \n",mwidth + aiming_target_offset - 80.0); printf("%f speed \n", speed); foundAnything = true; if (use_alternate_score == false){ particle_score = convexpar.center_mass_y; } else{ particle_score = 2.0*fabs((double)convexpar.center_mass_y - 60.0) + fabs((double)convexpar.center_mass_x - 80.0); } // keep track of the *lowest* score if (best_score > particle_score) { best_score = particle_score; best_speed = speed; } } if(foundAnything == false) { myRobot->TankDrive(0.0, 0.0); } else { myRobot->TankDrive(-best_speed,best_speed); } delete img; delete tapePixels; delete pars; delete convexHullBinaryImage; delete convexpars; //imaqDispose(convexHull); if (foundAnything && best_speed == 0.0){ return true; } else { return false; } }
Vision_Out Run(Vision_In in) { Vision_Out out; //read file in from disk. For this example to run you need to copy image.jpg from the SampleImages folder to the //directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp //imaqError = imaqReadFile(frame, "//home//lvuser//SampleImages//image.jpg", NULL, NULL); imaqError = camera->GetImage(frame); //Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished. /* RING_HUE_RANGE.minValue = SmartDashboard::GetNumber("Tote hue min", RING_HUE_RANGE.minValue); RING_HUE_RANGE.maxValue = SmartDashboard::GetNumber("Tote hue max", RING_HUE_RANGE.maxValue); RING_SAT_RANGE.minValue = SmartDashboard::GetNumber("Tote sat min", RING_SAT_RANGE.minValue); RING_SAT_RANGE.maxValue = SmartDashboard::GetNumber("Tote sat max", RING_SAT_RANGE.maxValue); RING_VAL_RANGE.minValue = SmartDashboard::GetNumber("Tote val min", RING_VAL_RANGE.minValue); RING_VAL_RANGE.maxValue = SmartDashboard::GetNumber("Tote val max", RING_VAL_RANGE.maxValue); */ if(in.shouldProcess) { //Threshold the image looking for ring light color imaqError = imaqColorThreshold(binaryFrame, frame, 255, IMAQ_HSV, &RING_HUE_RANGE, &RING_SAT_RANGE, &RING_VAL_RANGE); //Send particle count to dashboard int numParticles = 0; imaqError = imaqCountParticles(binaryFrame, 1, &numParticles); SmartDashboard::PutNumber("Masked particles", numParticles); //Send masked image to dashboard to assist in tweaking mask. SendToDashboard(binaryFrame, imaqError); //filter out small particles float areaMin = SmartDashboard::GetNumber("Area min %", AREA_MINIMUM); criteria[0] = {IMAQ_MT_AREA_BY_IMAGE_AREA, areaMin, 100, false, false}; imaqError = imaqParticleFilter4(binaryFrame, binaryFrame, criteria, 1, &filterOptions, NULL, NULL); //Send particle count after filtering to dashboard imaqError = imaqCountParticles(binaryFrame, 1, &numParticles); SmartDashboard::PutNumber("Filtered particles", numParticles); if(numParticles > 0) { //Measure particles and sort by particle size std::vector<ParticleReport> particles; for(int particleIndex = 0; particleIndex < numParticles; particleIndex++) { ParticleReport par; imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA_BY_IMAGE_AREA, &(par.PercentAreaToImageArea)); imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_AREA, &(par.Area)); imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_TOP, &(par.BoundingRectTop)); imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_LEFT, &(par.BoundingRectLeft)); imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_BOTTOM, &(par.BoundingRectBottom)); imaqMeasureParticle(binaryFrame, particleIndex, 0, IMAQ_MT_BOUNDING_RECT_RIGHT, &(par.BoundingRectRight)); particles.push_back(par); } sort(particles.begin(), particles.end(), CompareParticleSizes); //This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise //for the reader. Note that this scores and reports information about a single particle (single L shaped target). To get accurate information //about the location of the tote (not just the distance) you will need to correlate two adjacent targets in order to find the true center of the tote. scores.Aspect = AspectScore(particles.at(0)); SmartDashboard::PutNumber("Aspect", scores.Aspect); scores.Area = AreaScore(particles.at(0)); SmartDashboard::PutNumber("Area", scores.Area); bool isTarget = scores.Area > SCORE_MIN && scores.Aspect > SCORE_MIN; //Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote SmartDashboard::PutBoolean("IsTarget", isTarget); double distance = computeDistance(binaryFrame, particles.at(0)); SmartDashboard::PutNumber("Distance", computeDistance(binaryFrame, particles.at(0))); out.returnDistanceToTote = distance; out.returnIsTote = true; return out; } else { out.returnIsTote = false; SmartDashboard::PutBoolean("IsTarget", false); } } return out; }