$search
00001 00005 #include "calibrator.hpp" 00006 00007 int main(int argc, char** argv) { 00008 00009 00010 ROS_INFO("Node launched."); 00011 00012 ros::init(argc, argv, "mm_calibrator"); 00013 00014 ros::NodeHandle private_node_handle("~"); 00015 00016 calibratorData startupData; 00017 00018 startupData.read_addr = argv[0]; 00019 startupData.read_addr = startupData.read_addr.substr(0, startupData.read_addr.size()-11); 00020 00021 bool inputIsValid = startupData.obtainStartingData(private_node_handle); 00022 00023 if (!inputIsValid) { 00024 ROS_ERROR("Configuration invalid."); 00025 } 00026 00027 ROS_INFO("Startup data processed."); 00028 00029 00030 ros::NodeHandle nh; 00031 00032 calibratorNode calib_node(nh, startupData); 00033 //boost::shared_ptr < calibratorNode > calib_node (new calibratorNode (nh, startupData)); 00034 //globalNodePtr = &calib_node; 00035 00036 signal(SIGINT, mySigintHandler); 00037 00038 00039 00040 ROS_INFO("Node configured."); 00041 00042 while (calib_node.isStillCollecting()) { 00043 ros::spinOnce(); 00044 } 00045 00046 ROS_INFO("Patterns captured."); 00047 00048 00049 if (calib_node.wantsIntrinsics()) { 00050 calib_node.preparePatternSubsets(); 00051 calib_node.performIntrinsicCalibration(); 00052 calib_node.writeResults(); 00053 ROS_INFO("Calibration completed."); 00054 00055 } else { 00056 calib_node.assignIntrinsics(); 00057 } 00058 00059 if (calib_node.wantsExtrinsics()) { 00060 00061 ROS_INFO("Performing extrinsics..."); 00062 00063 //HGH 00064 if(!startupData.useMutex){ 00065 //determine valid frame pairs 00066 calib_node.determineValidPairs(); 00067 //evaluate frame frames 00068 calib_node.evaluateFrames(); 00069 } 00070 00071 while (calib_node.isVerifying()) { 00072 ros::spinOnce(); 00073 } 00074 00075 calib_node.prepareExtrinsicPatternSubsets(); 00076 calib_node.performExtrinsicCalibration(); 00077 calib_node.writeResults(); 00078 } 00079 00080 calib_node.set_ready_for_output(); 00081 00082 if (calib_node.wantsToUndistort() || (calib_node.wantsToRectify())) { 00083 calib_node.getAverageTime(); 00084 } 00085 00086 if (calib_node.wantsToUndistort()) { 00087 00088 if (calib_node.wantsIntrinsics()) { 00089 ROS_INFO("Publishing undistorted images..."); 00090 00091 calib_node.startUndistortionPublishing(); 00092 00093 while (calib_node.wantsToUndistort()) { 00094 ros::spinOnce(); 00095 } 00096 00097 ROS_INFO("Publishing complete."); 00098 } 00099 } 00100 00101 if (calib_node.wantsToRectify()) { 00102 if (calib_node.wantsExtrinsics()) { 00103 00104 ROS_INFO("Publishing rectified images..."); 00105 00106 calib_node.startRectificationPublishing(); 00107 00108 while (calib_node.wantsToRectify()) { 00109 ros::spinOnce(); 00110 } 00111 00112 ROS_INFO("Publishing complete."); 00113 00114 } 00115 00116 00117 00118 } 00119 00120 return 0; 00121 00122 } 00123 00124 void calibratorNode::prepareExtrinsicPatternSubsets() { 00125 00126 ROS_WARN("prepareExtrinsicPatternSubsets..."); 00127 00128 if(!configData.useMutex){ 00129 00130 //HGH - use all extrinsics point sets! 00131 extrinsicCandidateSets[0] = extrinsicsPointSets[0]; 00132 extrinsicCandidateSets[1] = extrinsicsPointSets[1]; 00133 extrinsicTestingSets[0] = extrinsicsPointSets[0]; 00134 extrinsicTestingSets[1] = extrinsicsPointSets[1]; 00135 00136 }else{ 00137 00139 srand((unsigned)time(0)); 00140 00141 vector<vector<Point2f> > tmpSet[MAX_CAMS]; 00142 00143 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00144 00145 for (int iii = 0; iii < extrinsicsPointSets[xxx].size(); iii++) { 00146 tmpSet[xxx].push_back(extrinsicsPointSets[xxx].at(iii)); 00147 } 00148 00149 } 00150 00151 // While the candidate quantity is insufficient 00152 while (((double) extrinsicCandidateSets[0].size()) < configData.candidatePatternSampleRate*double(extrinsicsPointSets[0].size())) { 00153 00154 unsigned int randomIndex = rand() % tmpSet[0].size(); 00155 00156 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00157 extrinsicCandidateSets[xxx].push_back(tmpSet[xxx].at(randomIndex)); 00158 tmpSet[xxx].erase(tmpSet[xxx].begin() + randomIndex); 00159 } 00160 00161 } 00162 00163 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00164 tmpSet[xxx].clear(); 00165 } 00166 00167 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00168 00169 for (int iii = 0; iii < extrinsicsPointSets[xxx].size(); iii++) { 00170 tmpSet[xxx].push_back(extrinsicsPointSets[xxx].at(iii)); 00171 } 00172 00173 } 00174 00175 // While the testing quantity is insufficient 00176 while (((double) extrinsicTestingSets[0].size()) < configData.testPatternSampleRate*double(extrinsicsPointSets[0].size())) { 00177 00178 unsigned int randomIndex = rand() % tmpSet[0].size(); 00179 00180 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00181 extrinsicTestingSets[xxx].push_back(tmpSet[xxx].at(randomIndex)); 00182 tmpSet[xxx].erase(tmpSet[xxx].begin() + randomIndex); 00183 } 00184 00185 } 00186 //*/ 00187 } 00188 00189 } 00190 00191 void calibratorNode::preparePatternSubsets() { 00192 00193 ROS_WARN("preparePatternSubsetss..."); 00194 00195 srand((unsigned)time(0)); 00196 00197 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00198 vector<vector<Point2f> > tmpSet; 00199 00200 for (int iii = 0; iii < pointSets[xxx].size(); iii++) { 00201 tmpSet.push_back(pointSets[xxx].at(iii)); 00202 } 00203 00204 // While the candidate quantity is insufficient 00205 while (((double) candidateSets[xxx].size()) < configData.candidatePatternSampleRate*double(pointSets[xxx].size())) { 00206 00207 unsigned int randomIndex = rand() % tmpSet.size(); 00208 00209 candidateSets[xxx].push_back(tmpSet.at(randomIndex)); 00210 00211 tmpSet.erase(tmpSet.begin() + randomIndex); 00212 00213 } 00214 00215 tmpSet.clear(); 00216 00217 for (int iii = 0; iii < pointSets[xxx].size(); iii++) { 00218 tmpSet.push_back(pointSets[xxx].at(iii)); 00219 } 00220 00221 // While the testing quantity is insufficient 00222 while (((double) testingSets[xxx].size()) < configData.testPatternSampleRate*double(pointSets[xxx].size())) { 00223 00224 unsigned int randomIndex = rand() % tmpSet.size(); 00225 00226 testingSets[xxx].push_back(tmpSet.at(randomIndex)); 00227 00228 tmpSet.erase(tmpSet.begin() + randomIndex); 00229 00230 } 00231 00232 } 00233 00234 } 00235 00236 void calibratorNode::prepareForTermination() { 00237 return; 00238 } 00239 00240 void mySigintHandler(int sig) { 00241 wantsToShutdown = true; 00242 ROS_WARN("Requested shutdown... terminating feeds..."); 00243 00244 (*globalNodePtr)->prepareForTermination(); 00245 } 00246 00247 void calibratorNode::assignIntrinsics() { 00248 00249 configData.K1.copyTo(cameraMatrices[0]); 00250 configData.K2.copyTo(cameraMatrices[1]); 00251 configData.distCoeffs1.copyTo(distCoeffVecs[0]); 00252 configData.distCoeffs2.copyTo(distCoeffVecs[1]); 00253 00254 } 00255 00256 bool calibratorNode::wantsIntrinsics() { 00257 if (configData.calibType == "single") { 00258 return true; 00259 } else { 00260 if (configData.wantsIntrinsics) { 00261 return true; 00262 } else { 00263 return false; 00264 } 00265 } 00266 } 00267 00268 bool calibratorNode::wantsExtrinsics() { 00269 if (configData.calibType == "stereo") { 00270 return true; 00271 } else { 00272 return false; 00273 } 00274 } 00275 00276 void calibratorNode::writeResults() { 00277 00278 00279 if (wantsIntrinsics()) { 00280 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00281 00282 updateIntrinsicMap(xxx); 00283 00284 stringstream ss; 00285 ss << (xxx+1); 00286 string outputName = configData.outputFolder + "/" + "intrinsics-" + ss.str() + ".yml"; 00287 00288 FileStorage fs(outputName, FileStorage::WRITE); 00289 00290 Mat imageSize(1, 2, CV_16UC1); 00291 imageSize.at<unsigned short>(0,0) = imSize[xxx].width; 00292 imageSize.at<unsigned short>(0,1) = imSize[xxx].height; 00293 fs << "imageSize" << imageSize; 00294 fs << "cameraMatrix" << cameraMatrices[xxx]; 00295 fs << "distCoeffs" << distCoeffVecs[xxx]; 00296 fs << "newCamMat" << newCamMat[xxx]; 00297 fs << "alpha" << configData.alpha; 00298 00299 fs << "reprojectionError" << reprojectionError_intrinsics[xxx]; 00300 fs << "generalisedError" << extendedReprojectionError_intrinsics[xxx]; 00301 00302 fs << "patternsUsed" << ((int) subselectedTags_intrinsics[xxx].size()); 00303 00304 fs.release(); 00305 00306 ROS_WARN("Wrote intrinsics calibration data to:\n %s", outputName.c_str()); 00307 00308 } 00309 00310 } 00311 00312 if (wantsExtrinsics()) { 00313 00314 string outputName = configData.outputFolder + "/" + "stereo-extrinsics" + ".yml"; 00315 00316 FileStorage fs(outputName, FileStorage::WRITE); 00317 00318 string tmpString; 00319 char tmp[64]; 00320 00321 sprintf(tmp, "reprojectionErr"); 00322 tmpString = string(tmp); 00323 fs << tmpString << stereoError; 00324 00325 sprintf(tmp, "generalisedMRE"); 00326 tmpString = string(tmp); 00327 fs << tmpString << extendedExtrinsicReprojectionError; 00328 00329 00330 for (int i = 0; i < numCams; i++) { 00331 00332 sprintf(tmp, "R%d", i); 00333 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00334 tmpString = string(tmp); 00335 fs << tmpString << R[i]; 00336 00337 sprintf(tmp, "Rvec%d", i); 00338 tmpString = string(tmp); 00339 fs << tmpString << Rv[i]; 00340 00341 sprintf(tmp, "T%d", i); 00342 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00343 tmpString = string(tmp); 00344 fs << tmpString << T[i]; 00345 00346 sprintf(tmp, "R_%d", i); 00347 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00348 tmpString = string(tmp); 00349 fs << tmpString << R_[i]; 00350 00351 sprintf(tmp, "P_%d", i); 00352 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00353 tmpString = string(tmp); 00354 fs << tmpString << P_[i]; 00355 00356 sprintf(tmp, "cameraMatrix%d", i); 00357 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00358 tmpString = string(tmp); 00359 fs << tmpString << cameraMatrices[i]; 00360 00361 sprintf(tmp, "distCoeffs%d", i); 00362 //printf("%s << tmp = %s.\n", __FUNCTION__, tmp); 00363 tmpString = string(tmp); 00364 fs << tmpString << distCoeffVecs[i]; 00365 } 00366 00367 fs << "E" << E[1]; 00368 fs << "F" << F[1]; 00369 00370 //HGH 00371 fs << "R" << R[1]; 00372 fs << "T" << T[1]; 00373 fs << "alpha" << configData.alpha; 00374 00375 fs << "Q1" << Q1; 00376 fs << "Q2" << Q2; 00377 00378 00379 00380 fs.release(); 00381 00382 ROS_WARN("Wrote extrinsic calibration data to:\n %s", outputName.c_str()); 00383 00384 } 00385 00386 00387 } 00388 00389 bool calibratorNode::wantsToUndistort() { 00390 return configData.undistortImages; 00391 } 00392 00393 bool calibratorNode::wantsToRectify() { 00394 return configData.rectifyImages; 00395 } 00396 00397 void calibratorNode::getAverageTime() { 00398 00399 int divisorFrames = max(frameCount, frameCount_1); 00400 avgTime /= ((double) divisorFrames - 1); 00401 ROS_INFO("Average time per frame: (%f)", avgTime); 00402 00403 } 00404 00405 void calibratorNode::startUndistortionPublishing() { 00406 00407 00408 //Rect* validPixROI = 0; 00409 00410 //bool centerPrincipalPoint = true; 00411 00412 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00413 updateIntrinsicMap(xxx); 00414 //newCamMat[xxx] = getOptimalNewCameraMatrix(cameraMatrices[xxx], distCoeffVecs[xxx], imSize[xxx], configData.alpha, imSize[xxx], validPixROI, centerPrincipalPoint); 00415 //initUndistortRectifyMap(cameraMatrices[xxx], distCoeffVecs[xxx], default_R, newCamMat[xxx], imSize[xxx], CV_32FC1, map1[xxx], map2[xxx]); 00416 } 00417 00418 00419 // Set up timer 00420 timer = ref->createTimer(ros::Duration(avgTime / 1000.0), &calibratorNode::publishUndistorted, this); 00421 00422 } 00423 00424 void calibratorNode::startRectificationPublishing() { 00425 00426 00427 Rect* validPixROI = 0; 00428 00429 00430 bool centerPrincipalPoint = true; 00431 00432 Point pt1, pt2; 00433 vector<Point2f> rectangleBounds, newRecBounds; 00434 00435 00436 00437 Mat blankCoeffs(1, 8, CV_64F); 00438 00439 /* 00440 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00441 newCamMat[xxx] = getOptimalNewCameraMatrix(cameraMatrices[xxx], distCoeffVecs[xxx], imSize[xxx], alpha, imSize[xxx], validPixROI, centerPrincipalPoint); 00442 initUndistortRectifyMap(cameraMatrices[xxx], distCoeffVecs[xxx], R[xxx], newCamMat[xxx], imSize[xxx], CV_32FC1, map1[xxx], map2[xxx]); 00443 } 00444 */ 00445 00446 for (int i = 0; i < 2; i++) { 00447 00448 ROS_INFO("Initializing rectification map (%d)...", i); 00449 00450 initUndistortRectifyMap(cameraMatrices[i], 00451 distCoeffVecs[i], 00452 R_[i], 00453 P_[i], // newCamMat[i] 00454 imSize[i], 00455 CV_32F, // CV_16SC2 00456 map1[i], // map1[i] 00457 map2[i]); // map2[i] 00458 00459 00460 ROS_INFO("Map (%d) initialized.", i); 00461 00462 pt1 = Point(roi[i].x, roi[i].y); 00463 pt2 = Point(roi[i].x + roi[i].width, roi[i].y + roi[i].height); 00464 00465 if ((pt1.x == 0) && (pt1.y == 0) && (pt2.x == 0) && (pt2.y == 0)) { 00466 ROS_WARN("ROI is defined as having zero area..."); 00467 } else { 00468 printf("%s << (und) pt1 = (%d, %d); pt2 = (%d, %d)\n", __FUNCTION__, pt1.x, pt1.y, pt2.x, pt2.y); 00469 00470 rectangleBounds.push_back(Point2f(pt1.x, pt1.y)); 00471 rectangleBounds.push_back(Point2f(pt2.x, pt2.y)); 00472 00473 Rect validROI_x; 00474 //HGH 00475 //rectCamMat[i] = getOptimalNewCameraMatrix(cameraMatrices[i], distCoeffVecs[i], imSize[i], 0.5, imSize[i], &validROI_x); 00476 rectCamMat[i] = getOptimalNewCameraMatrix(cameraMatrices[i], distCoeffVecs[i], imSize[i], configData.alpha, imSize[i], &validROI_x); 00477 00478 00479 00480 00481 /* 00482 undistortPoints(Mat(rectangleBounds), newRecBounds, rectCamMat[i], blankCoeffs, R_[i], P_[i]); 00483 00484 //printf("%s << Original rectangle points: = (%d, %d) & (%d, %d)\n", __FUNCTION__, pt1.x, pt1.y, pt2.x, pt2.y); 00485 00486 pt1 = Point(int(newRecBounds.at(0).x), int(newRecBounds.at(0).y)); 00487 pt2 = Point(int(newRecBounds.at(1).x), int(newRecBounds.at(1).y)); 00488 00489 printf("%s << pt1 = (%d, %d); pt2 = (%d, %d)\n", __FUNCTION__, pt1.x, pt1.y, pt2.x, pt2.y); 00490 00491 if (pt1.y > topValidHeight) 00492 { 00493 topValidHeight = pt1.y; 00494 } 00495 00496 if (pt2.y < botValidHeight) 00497 { 00498 botValidHeight = pt2.y; 00499 } 00500 00501 leftValid[i] = pt1.x; 00502 rightValid[i] = pt2.x; 00503 */ 00504 } 00505 00506 00507 } 00508 00509 printf("%s << topValidHeight = %d; botValidHeight = %d\n", __FUNCTION__, topValidHeight, botValidHeight); 00510 00511 00512 00513 // Prepare epipolar lines etc: 00514 for (int k = 1; k < 32; k++) 00515 { 00516 // should try to center it on the final (thermal) image 00517 leftLinePoints.push_back(Point2f(0, k*(botValidHeight - topValidHeight)/32 - 1)); 00518 rightLinePoints.push_back(Point2f(imSize[0].width, k*(botValidHeight - topValidHeight)/32 - 1)); 00519 } 00520 00521 00522 00523 00524 // Set up timer 00525 timer = ref->createTimer(ros::Duration(avgTime / 1000.0), &calibratorNode::publishRectified, this); 00526 00527 } 00528 00529 void calibratorNode::publishUndistorted(const ros::TimerEvent& event) { 00530 00531 //ROS_INFO("Entered timed loop..."); 00532 00533 Mat dispMat; 00534 00535 if (configData.calibType == "single") { 00536 if (undistortionCount >= frameCount) { 00537 configData.undistortImages = false; 00538 return; 00539 } 00540 00541 // Draw grid 00542 00543 Mat preMat, postMat; 00544 drawGrid(displayImages_1.at(undistortionCount), preMat, 0); 00545 00546 //ROS_WARN("About to publish undistorted frames..."); 00547 remap(preMat, postMat, map1[0], map2[0], INTER_LINEAR, BORDER_TRANSPARENT); 00548 00549 drawGrid(postMat, dispMat, 1); 00550 00551 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_1.data.begin()); 00552 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 00553 //ROS_WARN("Message 1 published..."); 00554 00555 } else { 00556 if (undistortionCount >= validPairs[0].size()) { 00557 configData.undistortImages = false; 00558 return; 00559 } 00560 00561 Mat preMat, postMat; 00562 00563 //ROS_WARN("About to publish undistorted frames..."); 00564 drawGrid(displayImages_1.at(validPairs[0].at(undistortionCount)), preMat, 0); 00565 remap(preMat, postMat, map1[0], map2[0], INTER_LINEAR, BORDER_TRANSPARENT); 00566 drawGrid(postMat, dispMat, 1); 00567 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_1.data.begin()); 00568 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 00569 //ROS_WARN("Message 1 published..."); 00570 00571 if (numCams > 1) { 00572 drawGrid(displayImages_2.at(validPairs[1].at(undistortionCount)), preMat, 0); 00573 remap(preMat, postMat, map1[1], map2[1], INTER_LINEAR, BORDER_TRANSPARENT); 00574 drawGrid(postMat, dispMat, 1); 00575 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_2.data.begin()); 00576 debug_pub_2.publish(msg_debug_2, debug_camera_info_2); 00577 } 00578 } 00579 00580 undistortionCount++; 00581 } 00582 00583 void calibratorNode::publishRectified(const ros::TimerEvent& event) { 00584 00585 //ROS_INFO("Entered timed (rectification) loop..."); 00586 00587 Mat dispMat; 00588 00589 00590 if (rectificationCount >= validPairs[0].size()) { 00591 configData.rectifyImages = false; 00592 return; 00593 } 00594 00595 Mat und1, und2, disp1, disp2; 00596 00597 //ROS_WARN("Publishing rectified images..."); 00598 remap(displayImages_1.at(validPairs[0].at(rectificationCount)), und1, map1[0], map2[0], INTER_LINEAR); 00599 //HGH 00600 //disp1 = displayImages_1.at(validPairs[0].at(rectificationCount)); 00601 //und1 = displayImages_1.at(validPairs[0].at(rectificationCount)); 00602 drawGrid(und1, disp1, 1); 00603 00604 //HGH - draw roi 00605 rectangle(disp1, Point2f(roi[0].x, roi[0].y), Point2f(roi[0].x + roi[0].width , roi[0].y + roi[0].height), CV_RGB(127, 255, 0)); 00606 00607 00608 std::copy(&(disp1.at<Vec3b>(0,0)[0]), &(disp1.at<Vec3b>(0,0)[0])+(disp1.cols*disp1.rows*disp1.channels()), msg_debug_1.data.begin()); 00609 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 00610 00611 remap(displayImages_2.at(validPairs[1].at(rectificationCount)), und2, map1[1], map2[1], INTER_LINEAR); 00612 drawGrid(und2, disp2, 1); 00613 //HGH - draw roi 00614 rectangle(disp2, Point2f(roi[1].x, roi[1].y), Point2f(roi[1].x + roi[1].width , roi[1].y + roi[1].height), CV_RGB(127, 255, 0)); 00615 00616 std::copy(&(disp2.at<Vec3b>(0,0)[0]), &(disp2.at<Vec3b>(0,0)[0])+(disp2.cols*disp2.rows*disp2.channels()), msg_debug_2.data.begin()); 00617 debug_pub_2.publish(msg_debug_2, debug_camera_info_2); 00618 00619 rectificationCount++; 00620 } 00621 00622 void calibratorNode::performExtrinsicCalibration() { 00623 00624 ROS_WARN("preparePatternSubsets..."); 00625 00626 ROS_INFO("Total of (%d) patterns found from (%d) valid frame pairs.", extrinsicsPointSets[0].size(), validPairs[0].size()); 00627 00628 ROS_INFO("Initial intrinsics: "); 00629 00630 cout << "K1 = " << configData.K1 << endl; 00631 00632 cout << "K2 = " << configData.K2 << endl; 00633 00634 cout << "imSize[0] = (" << imSize[0].height << ", " << imSize[0].width << ")" << endl; 00635 00636 cv::vector<cv::vector<Point2f> > emptyPointSetVector; 00637 vector<int> emptyIntVector; 00638 00639 vector<vector<int> > extrinsicTagNames, extrinsicSelectedTags; 00640 cv::vector<cv::vector<cv::vector<Point2f> > > extrinsicsList, extrinsicsCandidates; 00641 00642 //HGH 00643 // vector<string> extractedList; 00644 // cv::vector<cv::vector<Point2f> > cornersList[2]; 00645 00646 cv::vector<Mat> extrinsicsDistributionMap; 00647 extrinsicsDistributionMap.resize(2); 00648 00649 for (unsigned int nnn = 0; nnn < 2; nnn++) { 00650 extrinsicsList.push_back(emptyPointSetVector); 00651 extrinsicsCandidates.push_back(emptyPointSetVector); 00652 extrinsicTagNames.push_back(emptyIntVector); 00653 00654 extrinsicsDistributionMap.at(nnn) = Mat(imSize[nnn], CV_8UC1); 00655 } 00656 00657 00658 for (unsigned int iii = 0; iii < extrinsicsPointSets[0].size(); iii++) { 00659 00660 for (unsigned int nnn = 0; nnn < 2; nnn++) { 00661 extrinsicsList.at(nnn).push_back(extrinsicsPointSets[nnn].at(iii)); 00662 extrinsicsCandidates.at(nnn).push_back(extrinsicsPointSets[nnn].at(iii)); 00663 extrinsicTagNames.at(nnn).push_back(iii); 00664 } 00665 } 00666 00667 vector<Size> extrinsicsSizes; 00668 extrinsicsSizes.push_back(imSize[0]); 00669 extrinsicsSizes.push_back(imSize[1]); 00670 00671 //HGH - use all available patterns 00672 //-> configData.optimizationMethod = allPatterns 00673 optimizeCalibrationSets(extrinsicsSizes, 2, cameraMatrices, distCoeffVecs, extrinsicsDistributionMap, extrinsicsCandidates, extrinsicsList, row, configData.optimizationMethod, configData.setSize, extrinsicTagNames, extrinsicSelectedTags); 00674 00675 00676 ROS_WARN("extrinsicsList.size() = %d", extrinsicsList.at(0).size()); 00677 ROS_WARN("extrinsicsCandidates.size() = %d", extrinsicsCandidates.at(0).size()); 00678 00679 // SO CANDIDATES IS WHERE THE SUBSELECTION ARE KEPT.. 00680 00681 TermCriteria term_crit; 00682 term_crit = TermCriteria(TermCriteria::COUNT+ TermCriteria::EPS, 30, 1e-6); 00683 00684 00685 // Should make R[0] and T[0] the "identity" matrices 00686 R[0] = Mat::eye(3, 3, CV_64FC1); 00687 T[0] = Mat::zeros(3, 1, CV_64FC1); 00688 // HGH - R[0] and T[0] not used but instead R[1] and T[1] 00689 R[1] = Mat::eye(3, 3, CV_64FC1); 00690 T[1] = Mat::zeros(3, 1, CV_64FC1); 00691 00692 cv::vector< cv::vector<Point3f> > objectPoints; 00693 00694 00695 //HGH 00696 // for (int iii = 0; iii < extrinsicsCandidates[0].size(); iii++) 00697 // { 00698 // objectPoints.push_back(row); 00699 // } 00700 //HGH -or version from above can be used... 00701 objectPoints.resize(extrinsicsCandidates[0].size()); 00702 for (int iii = 0; iii < extrinsicsCandidates[0].size(); iii++) 00703 { 00704 for (int j = 0; j < configData.yCount; j++ ){ 00705 for (int i = 0; i < configData.xCount; i++ ){ 00706 objectPoints[iii].push_back(Point3f(j*configData.gridSize, i*configData.gridSize,0)); 00707 } 00708 } 00709 } 00710 00711 00712 stereoError = stereoCalibrate(objectPoints, 00713 extrinsicsCandidates.at(0), extrinsicsCandidates.at(1), 00714 cameraMatrices[0], distCoeffVecs[0], 00715 cameraMatrices[1], distCoeffVecs[1], 00716 extrinsicsSizes[0], // hopefully multiple cameras allow multiple image sizes 00717 R[1], T[1], 00718 E[1], F[1], 00719 term_crit, 00720 CV_CALIB_FIX_INTRINSIC); //CV_CALIB_RATIONAL_MODEL + 00721 00722 00723 cout << "cameraMatrices[0] = " << cameraMatrices[0] << endl; 00724 cout << "cameraMatrices[1] = " << cameraMatrices[1] << endl; 00725 cout << "distCoeffVecs[0] = " << distCoeffVecs[0] << endl; 00726 cout << "distCoeffVecs[1] = " << distCoeffVecs[1] << endl; 00727 cout << "R[1] = " << R[1] << endl; 00728 cout << "T[1] = " << T[1] << endl; 00729 printf("extrinsicsSizes[0] = (%d, %d)\n", extrinsicsSizes[0].width, extrinsicsSizes[0].height); 00730 00731 //alpha = 1.00; 00732 00733 //HGH - use optimal alpha based on left camera if using auto alpha 00734 if (configData.autoAlpha) { 00735 configData.alpha = findBestAlpha(cameraMatrices[0], distCoeffVecs[0], imSize[0]); 00736 ROS_INFO("Optimal alpha = (%f)", configData.alpha); 00737 } 00738 00739 cout << "alpha = " << configData.alpha << endl; 00740 00741 //HGH 00742 stereoRectify(cameraMatrices[0], distCoeffVecs[0], cameraMatrices[1], distCoeffVecs[1], 00743 imSize[0], 00744 R[1], T[1], 00745 R_[0], R_[1], P_[0], P_[1], 00746 Q1, 00747 CALIB_ZERO_DISPARITY, /* or 0 */ 00748 configData.alpha, imSize[0], &roi[0], &roi[1]); 00749 // stereoRectify(cameraMatrices[0], distCoeffVecs[0], cameraMatrices[1], distCoeffVecs[1], 00750 // imSize[0], 00751 // R[1], T[1], 00752 // R_[0], R_[1], P_[0], P_[1], 00753 // Q1, 00754 // CALIB_ZERO_DISPARITY, 00755 // configData.alpha, imSize[0], &roi[0], &roi[1]); 00756 00757 /* HGH - this part was obviously to debug something?!!! 00758 Rect dummy_roi[2]; 00759 stereoRectify(cameraMatrices[1], distCoeffVecs[1], cameraMatrices[0], distCoeffVecs[0], 00760 imSize[1], 00761 R[1].inv(), -T[1], 00762 R_[1], R_[0], P_[1], P_[0], 00763 Q2, 00764 CALIB_ZERO_DISPARITY, 00765 configData.alpha, imSize[1], &dummy_roi[0], &dummy_roi[1]); 00766 //*/ 00767 00768 00769 printf("imsize[0] = (%d, %d)\n", imSize[0].width, imSize[0].height); 00770 printf("imsize[1] = (%d, %d)\n", imSize[1].width, imSize[1].height); 00771 00772 00773 cout << "R_[0] = " << R_[0] << endl; 00774 cout << "R_[1] = " << R_[1] << endl; 00775 cout << "P_[0] = " << P_[0] << endl; 00776 cout << "P_[1] = " << P_[1] << endl; 00777 cout << "Q1 = " << Q1 << endl; 00778 cout << "Q2 = " << Q2 << endl; 00779 00780 printf("roi[0] = (%d, %d, %d, %d)\n", roi[0].x, roi[0].y, roi[0].width, roi[0].height); 00781 printf("roi[1] = (%d, %d, %d, %d)\n", roi[1].x, roi[1].y, roi[1].width, roi[1].height); 00782 00783 extendedExtrinsicReprojectionError = calculateExtrinsicERE(2, objectPoints.at(0), extrinsicsList, cameraMatrices, distCoeffVecs, R, T); 00784 00785 cout << "R = " << R[1] << endl; 00786 cout << "T = " << T[1] << endl; 00787 00788 return; 00789 00790 } 00791 00792 void calibratorNode::performIntrinsicCalibration() { 00793 00794 #pragma parallel for 00795 for (unsigned int xxx = 0; xxx < numCams; xxx++) { 00796 00797 ROS_INFO("Intrinsically calibrating camera (%d) with (%d / %d / %d) patterns...", xxx, candidateSets[xxx].size(), testingSets[xxx].size(), pointSets[xxx].size()); 00798 00799 optimizeCalibrationSet(imSize[xxx], candidateSets[xxx], testingSets[xxx], row, subselectedTags_intrinsics[xxx], configData.optimizationMethod, configData.setSize, true); 00800 00801 ROS_INFO("Set optimized (%d)", subselectedTags_intrinsics[xxx].size()); 00802 00803 vector< vector<Point3f> > objectPoints; 00804 vector< vector<Point2f> > subselectedPatterns; 00805 vector<Mat> rvecs, tvecs; 00806 00807 for (int iii = 0; iii < subselectedTags_intrinsics[xxx].size(); iii++) { 00808 objectPoints.push_back(row); 00809 subselectedPatterns.push_back(candidateSets[xxx].at(iii)); 00810 } 00811 00812 rvecs.resize(subselectedTags_intrinsics[xxx].size()); 00813 tvecs.resize(subselectedTags_intrinsics[xxx].size()); 00814 00815 Mat camMat, distCoeffs; 00816 00817 // Restrictive: CV_CALIB_FIX_K5 + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K3 + CV_CALIB_FIX_K2 + CV_CALIB_FIX_PRINCIPAL_POINT + CV_CALIB_FIX_ASPECT_RATIO + CV_CALIB_ZERO_TANGENT_DIST 00818 // Rational: CV_CALIB_RATIONAL_MODEL 00819 // Conventional: 0 00820 int intrinsicsFlags = 0; 00821 00822 reprojectionError_intrinsics[xxx] = calibrateCamera(objectPoints, subselectedPatterns, imSize[xxx], cameraMatrices[xxx], distCoeffVecs[xxx], rvecs, tvecs, intrinsicsFlags); 00823 00824 ROS_INFO("Reprojection error = %f", reprojectionError_intrinsics[xxx]); 00825 00826 double *errValues; 00827 errValues = new double[subselectedPatterns.size() * subselectedPatterns.at(0).size()]; 00828 00829 extendedReprojectionError_intrinsics[xxx] = calculateERE(imSize[xxx], objectPoints.at(0), subselectedPatterns, cameraMatrices[xxx], distCoeffVecs[xxx], errValues); 00830 00831 ROS_INFO("Extended Reprojection error = %f", extendedReprojectionError_intrinsics[xxx]); 00832 } 00833 00834 00835 00836 } 00837 00838 bool calibratorData::obtainStartingData(ros::NodeHandle& nh) { 00839 00840 nh.param<std::string>("video_stream", video_stream, "video_stream"); 00841 00842 if (video_stream != "video_stream") { 00843 printf("%s << Video stream (%s) selected.\n", __FUNCTION__, video_stream.c_str()); 00844 } else { 00845 printf("%s << ERROR! No video stream specified.\n", __FUNCTION__); 00846 return false; 00847 } 00848 00849 nh.param<std::string>("video_sequence", video_sequence, "video_sequence"); 00850 00851 if (video_sequence != "video_sequence") { 00852 printf("%s << Video sequence (%s) selected.\n", __FUNCTION__, video_sequence.c_str()); 00853 } else { 00854 printf("%s << ERROR! No video sequence specified.\n", __FUNCTION__); 00855 return false; 00856 } 00857 00859 00860 nh.param<bool>("useDefinedTopics", useDefinedTopics, false); 00861 00862 nh.param<std::string>("video_streamLeft", video_streamLeft, "video_streamLeft"); 00863 nh.param<std::string>("video_streamRight", video_streamRight, "video_streamRight"); 00864 00865 nh.param<std::string>("video_sequenceLeft", video_sequenceLeft, "video_sequenceLeft"); 00866 nh.param<std::string>("video_sequenceRight", video_sequenceRight, "video_sequenceRight"); 00867 00868 00869 if (useDefinedTopics){ 00870 00871 if (video_streamLeft != "video_streamLeft") { 00872 printf("%s << Video streamLeft (%s) selected.\n", __FUNCTION__, video_streamLeft.c_str()); 00873 } else { 00874 printf("%s << ERROR! No video stream specified.\n", __FUNCTION__); 00875 return false; 00876 } 00877 00878 if (video_sequenceLeft != "video_sequenceLeft") { 00879 printf("%s << Video sequenceLeft (%s) selected.\n", __FUNCTION__, video_sequenceLeft.c_str()); 00880 } else { 00881 printf("%s << ERROR! No video sequence specified.\n", __FUNCTION__); 00882 return false; 00883 } 00884 00885 00886 if (video_streamRight != "video_streamRight") { 00887 printf("%s << Video streamRight (%s) selected.\n", __FUNCTION__, video_streamRight.c_str()); 00888 } else { 00889 printf("%s << ERROR! No video stream specified.\n", __FUNCTION__); 00890 return false; 00891 } 00892 00893 if (video_sequenceRight != "video_sequenceRight") { 00894 printf("%s << Video sequenceRight (%s) selected.\n", __FUNCTION__, video_sequenceRight.c_str()); 00895 } else { 00896 printf("%s << ERROR! No video sequence specified.\n", __FUNCTION__); 00897 return false; 00898 } 00899 00900 } 00901 //*/ 00902 00903 //HGH 00904 nh.param<double>("flowThreshold", flowThreshold, 1e-4); 00905 nh.param<double>("maxFrac", maxFrac, 0.05); 00906 nh.param<double>("errorThreshold", errorThreshold, 0.0); 00907 00908 nh.param<double>("candidatePatternSampleRate", candidatePatternSampleRate, 1.0); 00909 nh.param<double>("testPatternSampleRate", testPatternSampleRate, 1.0); 00910 00911 ROS_INFO("Candidates selected at (%f) and tested at (%f) probability.", candidatePatternSampleRate, testPatternSampleRate); 00912 00913 nh.param<std::string>("outputFolder", outputFolder, "outputFolder"); 00914 00915 if (outputFolder != "outputFolder") { 00916 ROS_WARN("Output folder (%s) selected.", outputFolder.c_str()); 00917 } else { 00918 outputFolder = read_addr + "/../nodes/calibrator/data"; 00919 ROS_WARN("No output folder supplied. Defaulting to (%s)", outputFolder.c_str()); 00920 } 00921 00922 nh.param<std::string>("calibType", calibType, "calibType"); 00923 00924 if (calibType == "single") { 00925 ROS_INFO("Single-camera calibration selected."); 00926 } else if (calibType == "stereo") { 00927 ROS_INFO("Stereo calibration selected."); 00928 } else if (calibType == "calibType") { 00929 ROS_WARN("No calibration type specified. Single-camera assumed."); 00930 calibType = "single"; 00931 } else { 00932 ROS_ERROR("Invalid calibration type specified. Please choose either 'single' or 'stereo'."); 00933 return false; 00934 } 00935 00936 nh.param<bool>("debug_mode", debugMode, false); 00937 00938 if (debugMode) { 00939 printf("%s << Running in DEBUG mode.\n", __FUNCTION__); 00940 } else { 00941 printf("%s << Running in OPTIMIZED mode.\n", __FUNCTION__); 00942 } 00943 00944 nh.param<std::string>("patternType", patternType, "mask"); 00945 00946 if (patternType == "mask") { 00947 pattType = MASK_FINDER_CODE; 00948 } else if (patternType == "chessboard") { 00949 pattType = CHESSBOARD_FINDER_CODE; 00950 } else if (patternType == "heated_chessboard") { 00951 pattType = HEATED_CHESSBOARD_FINDER_CODE; 00952 } else { 00953 00954 printf("%s::%s << ERROR! patternType incorrectly specified...\n", __PROGRAM__, __FUNCTION__); 00955 return false; 00956 00957 } 00958 00959 printf("%s::%s << selected patternType = (%s) [%d]\n", __PROGRAM__, __FUNCTION__, patternType.c_str(), pattType); 00960 00961 nh.param<int>("maxFrames", maxFrames, DEFAULT_MAX_FRAMES); 00962 nh.param<int>("maxPatterns", maxPatterns, DEFAULT_MAX_PATTERNS); 00963 nh.param<int>("setSize", setSize, DEFAULT_SET_SIZE); 00964 00965 ROS_INFO("maxFrames = %d; maxPatterns = %d; setSize = (%d)", maxFrames, maxPatterns, setSize); 00966 00967 nh.param<double>("gridSize", gridSize, DEFAULT_GRID_SIZE); 00968 00969 nh.param<double>("maxTimeDiff", maxTimeDiff, DEFAULT_MAX_TIME_DIFF); 00970 00971 nh.param<int>("xCount", xCount, DEFAULT_X_COUNT); 00972 nh.param<int>("yCount", yCount, DEFAULT_Y_COUNT); 00973 00974 nh.param<std::string>("optMethod", optMethod, "enhancedMCM"); 00975 00976 if (optMethod == "enhancedMCM") { 00977 optimizationMethod = ENHANCED_MCM_OPTIMIZATION_CODE; 00978 } else if (optMethod == "allPatterns") { 00979 optimizationMethod = ALL_PATTERNS_OPTIMIZATION_CODE; 00980 } else if (optMethod == "randomSet") { 00981 optimizationMethod = RANDOM_SET_OPTIMIZATION_CODE; 00982 } else if (optMethod == "firstN") { 00983 optimizationMethod = FIRST_N_PATTERNS_OPTIMIZATION_CODE; 00984 } else if (optMethod == "randomBest") { 00985 optimizationMethod = BEST_OF_RANDOM_PATTERNS_OPTIMIZATION_CODE; 00986 } else if (optMethod == "exhaustiveSearch") { 00987 optimizationMethod = EXHAUSTIVE_SEARCH_OPTIMIZATION_CODE; 00988 } else if (optMethod == "randomSeed") { 00989 optimizationMethod = RANDOM_SEED_OPTIMIZATION_CODE; 00990 } else if (optMethod == "scoreBased") { 00991 optimizationMethod = SCORE_BASED_OPTIMIZATION_CODE; 00992 } else { 00993 00994 printf("%s::%s << ERROR! optMethod incorrectly specified...\n", __PROGRAM__, __FUNCTION__); 00995 return false; 00996 00997 } 00998 00999 nh.param<bool>("undistortImages", undistortImages, false); 01000 01001 nh.param<bool>("rectifyImages", rectifyImages, false); 01002 01003 nh.param<bool>("wantsIntrinsics", wantsIntrinsics, false); 01004 01006 nh.param<bool>("useIntrinsicsFile", useIntrinsicsFile, false); 01007 nh.param<std::string>("intrinsicsFileLeft", intrinsicsFileLeft, "intrinsicsFileLeft"); 01008 nh.param<std::string>("intrinsicsFileRight", intrinsicsFileRight, "intrinsicsFileRight"); 01009 //*/ 01010 01011 if (calibType == "single") { 01012 01013 if (wantsIntrinsics == false) { 01014 ROS_WARN("(single-cam mode): intrinsics will be calculated regardless of whether this option has been selected."); 01015 wantsIntrinsics = true; 01016 } 01017 01018 } else if (calibType == "stereo") { 01019 01020 if (wantsIntrinsics) { 01021 ROS_INFO("(stereo mode): option to also calculate intrinsics has been selected."); 01022 } 01023 else{ 01024 01025 if (useIntrinsicsFile){ 01026 01027 if (intrinsicsFileLeft =="intrinsicsFileLeft" || intrinsicsFileRight =="intrinsicsFileRight"){ 01028 01029 ROS_WARN("(use intrinsics): intrinsics files not specified correctly. Trying to use intrinsics from message header."); 01030 useIntrinsicsFile = false; 01031 } 01032 } else { 01033 ROS_INFO("(use intrinsics): use intrinsics from message header."); 01034 } 01035 } 01036 //*/ 01037 01038 } 01039 01040 nh.param<double>("alpha", alpha, 0.00); 01041 01042 nh.param<bool>("autoAlpha", autoAlpha, true); 01043 01044 //HGH 01045 nh.param<bool>("stopCapturing", stopCapturing, false); 01046 nh.param<std::string>("patternDetectionMode", patternDetectionMode, "find"); 01047 01048 //HGH 01049 nh.param<double>("contrastLeft", contrastLeft, 1.0); 01050 nh.param<double>("contrastRight", contrastRight, 1.0); 01051 nh.param<double>("brightnessLeft", brightnessLeft, 0.0); 01052 nh.param<double>("brightnessRight", brightnessRight, 0.0); 01053 nh.param<bool>("normLeft", normLeft, false); 01054 nh.param<bool>("normRight", normRight, false); 01055 nh.param<bool>("invertLeft", invertLeft, false); 01056 nh.param<bool>("invertRight", invertRight, false); 01057 01058 //HGH 01059 nh.param<bool>("doOnlineProcessing", doOnlineProcessing, true); 01060 nh.param<bool>("useMutex", useMutex, false); 01061 01062 //HGH 01063 nh.param<bool>("adjustMSERLeft", adjustMSERLeft, false); 01064 nh.param<int>("deltaLeft", deltaLeft, 8); 01065 nh.param<double>("maxVarLeft", maxVarLeft, 0.25); 01066 nh.param<double>("minDivLeft", minDivLeft, 0.2); 01067 nh.param<double>("areaThresholdLeft", areaThresholdLeft, 1.01); 01068 01069 nh.param<bool>("adjustMSERRight", adjustMSERRight, false); 01070 nh.param<int>("deltaRight", deltaRight, 8); 01071 nh.param<double>("maxVarRight", maxVarRight, 0.25); 01072 nh.param<double>("minDivRight", minDivRight, 0.2); 01073 nh.param<double>("areaThresholdRight", areaThresholdRight, 1.01); 01074 01075 01076 return true; 01077 } 01078 01079 void calibratorNode::updateIntrinsicMap(unsigned int idx) { 01080 01081 ROS_INFO("Updating map..."); 01082 01083 if (configData.autoAlpha) { 01084 configData.alpha = findBestAlpha(cameraMatrices[idx], distCoeffVecs[idx], imSize[idx]); 01085 ROS_INFO("Optimal alpha = (%f)", configData.alpha); 01086 } 01087 01088 Rect* validPixROI = 0; 01089 bool centerPrincipalPoint = true; 01090 01091 newCamMat[idx] = getOptimalNewCameraMatrix(cameraMatrices[idx], distCoeffVecs[idx], imSize[idx], configData.alpha, imSize[idx], validPixROI, centerPrincipalPoint); 01092 01093 ROS_WARN("Adjusting undistortion mapping..."); 01094 initUndistortRectifyMap(cameraMatrices[idx], distCoeffVecs[idx], default_R, newCamMat[idx], imSize[idx], CV_32FC1, map1[idx], map2[idx]); 01095 01096 //HGH - debug 01097 cout << "newCamMat: " << newCamMat[idx] << endl; 01098 01099 alphaChanged = false; 01100 01101 } 01102 01103 void calibratorNode::assignDebugCameraInfo() { 01104 01105 // ..? 01106 01107 01108 } 01109 01110 bool calibratorNode::isStillCollecting() { 01111 return stillCollecting; 01112 } 01113 01115 01116 bool calibratorNode::isVerifying() { 01117 return doVerify; 01118 } 01119 01120 01121 bool calibratorNode::findPattern(const Mat& im, vector<Point2f>& dst, Mat& prev, const int useMode = PATTERN_CODE_INVALID, const int cameraNumber = -1) { 01122 01123 //HGH 01124 bool retVal = false; 01125 Mat tmpMat; 01126 01127 01128 if (useMode == PATTERN_CODE_FIND_TRACK){ 01129 //################################### 01130 //find pattern first, then track: 01131 01133 vector<Point2f> dstOrig = dst; 01134 dst.clear(); 01135 01136 //ROS_WARN("Finding Pattern"); 01137 switch (configData.pattType) { 01138 case CHESSBOARD_FINDER_CODE: 01139 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01140 break; 01141 case MASK_FINDER_CODE: 01142 if (configData.adjustMSERLeft && cameraNumber == 0){ 01143 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaLeft, configData.maxVarLeft, configData.minDivLeft); 01144 }else if (configData.adjustMSERRight && cameraNumber == 1){ 01145 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaRight, configData.maxVarRight, configData.minDivRight); 01146 }else{ 01147 retVal = findMaskCorners_1(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 01148 } 01149 break; 01150 case HEATED_CHESSBOARD_FINDER_CODE: 01151 invertMatIntensities(im, tmpMat); 01152 retVal = findChessboardCorners(tmpMat, cvSize(configData.xCount, configData.yCount), dst); 01153 break; 01154 default: 01155 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01156 break; 01157 } 01158 01159 if (retVal){ 01160 ROS_ERROR("Pattern found"); 01161 return true; 01162 01163 }else{ 01164 01165 dst = dstOrig; 01166 01167 if ((configData.trackingMode) && (dst.size() > 0) && (prev.rows > 0) && (prev.cols > 0)) { 01168 // attempt to track, if it doesn't work, attempt re-detect.. 01169 01170 //HGH 01171 double distanceConstraint = (min(im.cols, im.rows) * configData.maxFrac) + ((((int) (max(im.cols, im.rows) * configData.maxFrac)) + 1) % 2); 01172 01173 vector<Point2f> src; 01174 vector<unsigned int> lost; 01175 lost.clear(); 01176 src.insert(src.end(), dst.begin(), dst.end()); 01177 dst.clear(); 01178 01179 ROS_WARN("ATTEMPTING TO TRACK..."); 01180 01181 //ROS_INFO("im data = (%d, %d) : (%d, %d)", prev.rows, prev.cols, im.rows, im.cols); 01182 01183 01184 trackPoints2(prev, im, src, dst, distanceConstraint, configData.flowThreshold, lost, cvSize(configData.xCount, configData.yCount), configData.errorThreshold); 01185 01186 // Then check if it's tracked effectively... 01187 01188 if (lost.size() > 0) { 01189 ROS_ERROR("TRACKING FAILED"); 01190 dst.clear(); 01191 retVal = false; 01192 } else { 01193 ROS_WARN("TRACKING SUCCESSFUL"); 01194 //HGH 01195 retVal = true; 01196 } 01197 01198 } else { 01199 ROS_ERROR("Tracking not even possible"); 01200 //ROS_ERROR("NOT EVEN TRYING TO TRACK: trackingMode=%d, dst.size()=%d", configData.trackingMode ? 1 : 0, dst.size()); 01201 dst.clear(); 01202 01203 } 01204 01205 } //*/ 01206 01207 01208 }else if (useMode == PATTERN_CODE_TRACK_FIND){ 01209 //################################### 01210 //track first then find pattern: 01211 01212 01214 if ((configData.trackingMode) && (dst.size() > 0) && (prev.rows > 0) && (prev.cols > 0)) { 01215 // attempt to track, if it doesn't work, attempt re-detect.. 01216 01217 //HGH 01218 double distanceConstraint = (min(im.cols, im.rows) * configData.maxFrac) + ((((int) (max(im.cols, im.rows) * configData.maxFrac)) + 1) % 2); 01219 01220 vector<Point2f> src; 01221 vector<unsigned int> lost; 01222 lost.clear(); 01223 src.insert(src.end(), dst.begin(), dst.end()); 01224 dst.clear(); 01225 01226 ROS_WARN("ATTEMPTING TO TRACK..."); 01227 01228 //ROS_INFO("im data = (%d, %d) : (%d, %d)", prev.rows, prev.cols, im.rows, im.cols); 01229 01230 01231 trackPoints2(prev, im, src, dst, distanceConstraint, configData.flowThreshold, lost, cvSize(configData.xCount, configData.yCount), configData.errorThreshold); 01232 01233 // Then check if it's tracked effectively... 01234 01235 if (lost.size() > 0) { 01236 ROS_ERROR("TRACKING FAILED"); 01237 dst.clear(); 01238 retVal = false; 01239 } else { 01240 ROS_WARN("TRACKING SUCCESSFUL"); 01241 //HGH 01242 retVal = true; 01243 } 01244 01245 } else { 01246 ROS_ERROR("NOT EVEN TRYING TO TRACK: trackingMode=%d, dst.size()=%d", configData.trackingMode ? 1 : 0, dst.size()); 01247 dst.clear(); 01248 01249 } 01250 01251 if (dst.size() == 0) { 01252 01253 //ROS_WARN("Finding Pattern"); 01254 switch (configData.pattType) { 01255 case CHESSBOARD_FINDER_CODE: 01256 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01257 break; 01258 case MASK_FINDER_CODE: 01259 if (configData.adjustMSERLeft && cameraNumber == 0){ 01260 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaLeft, configData.maxVarLeft, configData.minDivLeft); 01261 }else if (configData.adjustMSERRight && cameraNumber == 1){ 01262 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaRight, configData.maxVarRight, configData.minDivRight); 01263 }else{ 01264 retVal = findMaskCorners_1(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 01265 } 01266 break; 01267 case HEATED_CHESSBOARD_FINDER_CODE: 01268 invertMatIntensities(im, tmpMat); 01269 retVal = findChessboardCorners(tmpMat, cvSize(configData.xCount, configData.yCount), dst); 01270 break; 01271 default: 01272 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01273 break; 01274 } 01275 01276 } 01277 //*/ 01278 01279 }else if (useMode == PATTERN_CODE_FIND){ 01280 01281 //################################### 01282 //only find pattern, no tracking: 01283 01284 // /* 01285 //ROS_WARN("Finding Pattern"); 01286 switch (configData.pattType) { 01287 case CHESSBOARD_FINDER_CODE: 01288 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01289 break; 01290 case MASK_FINDER_CODE: 01291 if (configData.adjustMSERLeft && cameraNumber == 0){ 01292 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaLeft, configData.maxVarLeft, configData.minDivLeft); 01293 }else if (configData.adjustMSERRight && cameraNumber == 1){ 01294 retVal = findMaskCorners_2(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG, configData.deltaRight, configData.maxVarRight, configData.minDivRight); 01295 }else{ 01296 retVal = findMaskCorners_1(im, cvSize(configData.xCount, configData.yCount), dst, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 01297 } 01298 break; 01299 case HEATED_CHESSBOARD_FINDER_CODE: 01300 invertMatIntensities(im, tmpMat); 01301 retVal = findChessboardCorners(tmpMat, cvSize(configData.xCount, configData.yCount), dst); 01302 break; 01303 default: 01304 retVal = findChessboardCorners(im, cvSize(configData.xCount, configData.yCount), dst); 01305 break; 01306 } 01307 01308 if (retVal){ 01309 ROS_INFO("PATTERNFINDING SUCCESFUL"); 01310 }else{ 01311 ROS_WARN("PATTERNFINDING FAILED"); 01312 } 01313 01315 01316 } else{ 01317 ROS_ERROR("PATTERN FIND MODE IS INVALID!"); 01318 } 01319 01320 01321 return retVal; 01322 01323 } 01324 01325 01326 01327 void calibratorNode::trackPattern(int cameraNumber, const Mat& currentImg, const int currentFrame){ 01328 01329 bool patternFound = false; 01330 01331 Mat grayImg; 01332 01333 if (currentImg.type() == CV_8UC3){ 01334 cvtColor(currentImg, grayImg, CV_RGB2GRAY); 01335 }else{ 01336 grayImg = Mat(currentImg); 01337 } 01338 01339 patternFound = findPattern(grayImg, cornerSets[cameraNumber], lastMat[cameraNumber],configData.usePatternDetectionMode, cameraNumber); 01340 01341 if (configData.debugMode) { 01342 01343 Mat dispMat; 01344 01345 if (currentImg.type() == CV_8UC3) { 01346 currentImg.copyTo(dispMat); 01347 } else { 01348 cvtColor(currentImg, dispMat, CV_GRAY2RGB); 01349 } 01350 01351 01352 drawChessboardCorners(dispMat, cvSize(configData.xCount, configData.yCount), Mat(cornerSets[cameraNumber]), patternFound); 01353 01354 01355 if (cameraNumber == 0){ 01356 01357 if (msg_debug_1.width > 0) { 01358 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_1.data.begin()); 01359 } 01360 01361 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 01362 01363 } else if (cameraNumber == 1){ 01364 01365 if (msg_debug_2.width > 0) { 01366 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_2.data.begin()); 01367 } 01368 01369 debug_pub_2.publish(msg_debug_2, debug_camera_info_2); 01370 01371 } 01372 } 01373 01374 if (patternFound) { 01375 pointSets[cameraNumber].push_back(cornerSets[cameraNumber]); 01376 frameCounts[cameraNumber].push_back(currentFrame); // contains all frames where pattern was found 01377 grayImg.copyTo(lastMat[cameraNumber]); 01378 ROS_INFO("For cam (%d), (%d) patterns found.",cameraNumber, pointSets[cameraNumber].size()); 01379 // }else{ 01380 // cornerSets[cameraNumber].clear(); 01381 // lastMat[cameraNumber] = Mat(); 01382 } 01383 } 01384 01385 01386 void calibratorNode::determineValidPairs() { 01387 01388 ROS_INFO("Determine valid frame pairs..."); 01389 01390 int maxCam1 = std::min(((int) times_1.size()), frameCount_1); 01391 int maxCam2 = std::min(((int) times_2.size()), frameCount_2); 01392 01393 01394 //Mat dispMat1, dispMat2; 01395 //ROS_WARN("HERE BEGIN---"); 01396 while (checkIndex_1 < maxCam1) { 01397 01398 if (checkIndex_1 >= duplicateFlags_1.size()) { 01399 break; 01400 } 01401 01402 //ROS_WARN("checkIndex_1 %d-",checkIndex_1); 01403 01404 if (duplicateFlags_1.at(checkIndex_1) == 1) { 01405 checkIndex_1++; 01406 continue; 01407 } 01408 01409 //ROS_WARN("- checkIndex_1 %d-",checkIndex_1); 01410 //ROS_WARN("times_1.size() %d-",times_1.size()); 01411 //cout << times_1.at(checkIndex_1) << endl; 01412 01413 01414 double leastDiff = 9e99; 01415 int bestMatch = -1; 01416 01417 bool candidatesExhausted = false; 01418 01419 //ROS_WARN("checkIndex_2 %d-",checkIndex_2); 01420 //ROS_WARN("times_2.size() %d-",times_2.size()); 01421 //cout << times_2.at(checkIndex_2) << endl; 01422 01423 //cout << "m(timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) < configData.maxTimeDiff) " << (timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) < configData.maxTimeDiff) << endl; 01424 //ROS_WARN("diffdone"); 01425 01426 while ((timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) < configData.maxTimeDiff)) { 01427 01428 //ROS_WARN("maxCam2-1= %d-",maxCam2-1); 01429 //ROS_WARN("checkIndex_2 %d-",checkIndex_2); 01430 if (checkIndex_2 >= (maxCam2-1)) { 01431 ROS_WARN("..."); 01432 break; 01433 01434 } 01435 01436 if (checkIndex_2 >= duplicateFlags_2.size()) { 01437 break; 01438 } 01439 01440 //ROS_WARN("DEUBG %s", 3); 01441 if (duplicateFlags_2.at(checkIndex_2) == 1) { 01442 checkIndex_2++; 01443 continue; 01444 } 01445 //ROS_WARN("DEUBG %s", 4); 01446 double diff = abs(timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1))); 01447 01448 01449 // ROS_WARN("DEUBG %s", 5); 01450 if (diff < leastDiff) { 01451 leastDiff = diff; 01452 bestMatch = checkIndex_2; 01453 } 01454 01455 checkIndex_2++; 01456 } 01457 01458 //ROS_WARN("DEUBG %s", 10); 01459 01460 if ((timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) >= configData.maxTimeDiff)) { 01461 candidatesExhausted = true; 01462 } 01463 01464 //checkIndex_2 = bestMatch; 01465 01466 if ((leastDiff < configData.maxTimeDiff) && (bestMatch >= 0)) { 01467 01468 //ROS_WARN("Pushing back match (%f) (%d) [%02d.%04d] and (%d) [%02d.%04d]...", leastDiff, checkIndex_1, times_1.at(checkIndex_1).sec, times_1.at(checkIndex_1).nsec, bestMatch, times_2.at(bestMatch).sec, times_2.at(bestMatch).nsec); 01469 01470 validPairs[0].push_back(checkIndex_1); 01471 checkIndex_1++; 01472 validPairs[1].push_back(bestMatch); 01473 01474 01475 } else if (candidatesExhausted) { // (checkIndex_2 < (maxCam2-1)) { 01476 checkIndex_1++; 01477 } else { 01478 break; 01479 } 01480 01481 } 01482 01483 } 01484 01485 01486 void calibratorNode::evaluateFrames() { 01487 01488 ROS_WARN("evaluateFrames..."); 01489 01490 if (!configData.doOnlineProcessing){ 01491 01492 ROS_INFO("Track pattern offline..."); 01493 01494 pointSets[0].clear(); 01495 pointSets[1].clear(); 01496 frameCounts[0].clear(); 01497 frameCounts[1].clear(); 01498 01499 Mat dispMat; 01500 01501 //cam1 01502 for (int i=0; i < displayImages_1.size() ; i++){ 01503 01504 dispMat = displayImages_1.at(i); 01505 01506 trackPattern(0, dispMat, i); //cam1 01507 } 01508 //cam2 01509 for (int i=0; i < displayImages_2.size() ; i++){ 01510 01511 dispMat = displayImages_2.at(i); 01512 01513 trackPattern(1, dispMat, i); //cam2 01514 } 01515 01516 } 01517 01518 vector<validPattern> validPatternData[2]; 01519 01520 01521 // check if pattern was found in valid frame: 01522 01523 for (int camNumber = 0; camNumber <= 2; camNumber++ ){ 01524 01525 for (int i = 0; i < validPairs[camNumber].size(); i++){ 01526 01527 for (int j = 0; j < frameCounts[camNumber].size(); j++){ 01528 01529 validPattern tmpData; 01530 tmpData.validFrameID = validPairs[camNumber].at(i); 01531 tmpData.patternID = j; 01532 01533 01534 if(validPairs[camNumber].at(i)==frameCounts[camNumber].at(j)){ 01535 01536 tmpData.patternFound = true; 01537 tmpData.isValidFrame = true; 01538 01539 validPatternData[camNumber].push_back(tmpData); 01540 break; 01541 01542 01543 ROS_INFO("Valid pattern found for cam (%d) in frame %d", camNumber, frameCounts[camNumber].at(j)); 01544 01545 } else if(j==frameCounts[camNumber].size()-1){ 01546 01547 //no valid pattern found for valid pair ///stimmt loop? 01548 01549 tmpData.patternFound = false; 01550 tmpData.isValidFrame = true; 01551 01552 validPatternData[camNumber].push_back(tmpData); 01553 01554 } 01555 } 01556 } 01557 } 01558 01559 01560 Mat dispMat1, dispMat2; 01561 01562 01563 01564 int totalValidPatterns = 0; 01565 01566 for(int i=0; i < validPatternData[0].size(); i++){ 01567 01568 if ( validPatternData[0].at(i).patternFound && validPatternData[1].at(i).patternFound){ 01569 01570 if ( !configData.debugMode) { 01571 extrinsicsPointSets[0].push_back(pointSets[0].at(validPatternData[0].at(i).patternID)); 01572 extrinsicsPointSets[1].push_back(pointSets[1].at(validPatternData[1].at(i).patternID)); 01573 } 01574 totalValidPatterns++; 01575 01576 } 01577 01578 } 01579 01580 cout << "synced frames: " << validPairs[0].size() << endl; 01581 cout << "cam1 patterns found: " << frameCounts[0].size() << endl; 01582 cout << "cam2 patterns found: " << frameCounts[1].size() << endl; 01583 01584 cout << "valid pairs: " << validPatternData[0].size() << endl; 01585 cout << "total valid patterns: " << totalValidPatterns << endl; 01586 01587 01588 01589 if ( configData.debugMode) { 01590 01591 doVerify = true; 01592 01593 int currentValidPattern = 0; 01594 01595 for(int i=0; i < validPatternData[0].size(); i++){ 01596 01597 if ( validPatternData[0].at(i).patternFound && validPatternData[1].at(i).patternFound){ 01598 01599 ROS_INFO("\nValid pattern pair %d out of %d : frame cam1: %d, frame cam2 %d ", currentValidPattern + 1, totalValidPatterns, validPatternData[0].at(i).patternID , validPatternData[1].at(i).patternID ); 01600 01601 01602 01603 int dispFrame1 = validPatternData[0].at(i).validFrameID; 01604 int dispFrame2 = validPatternData[1].at(i).validFrameID; 01605 01606 int dispPattern1 = validPatternData[0].at(i).patternID; 01607 int dispPattern2 = validPatternData[1].at(i).patternID; 01608 01609 if (displayImages_1.at(dispFrame1).type() == CV_8UC3) { 01610 displayImages_1.at(dispFrame1).copyTo(dispMat1); 01611 } else { 01612 cvtColor(displayImages_1.at(dispFrame1), dispMat1, CV_GRAY2RGB); 01613 } 01614 01615 01616 drawChessboardCorners(dispMat1, cvSize(configData.xCount, configData.yCount), Mat(pointSets[0].at(dispPattern1)), true); 01617 01618 01619 if (displayImages_2.at(dispFrame2).type() == CV_8UC3) { 01620 displayImages_2.at(dispFrame2).copyTo(dispMat2); 01621 } else { 01622 cvtColor(displayImages_2.at(dispFrame2), dispMat2, CV_GRAY2RGB); 01623 } 01624 01625 drawChessboardCorners(dispMat2, cvSize(configData.xCount, configData.yCount), Mat(pointSets[1].at(dispPattern2)), true); 01626 01627 01628 if(currentValidPattern < totalValidPatterns - 1){ 01629 01630 imshow("pattern1", dispMat1); 01631 imshow("pattern2", dispMat2); 01632 01633 ROS_INFO("%d << Press 'c' to use this keyframes or any other key to discard...", i); 01634 01635 01636 char key = waitKey(); 01637 if (key == 'c'){ 01638 extrinsicsPointSets[0].push_back(pointSets[0].at(validPatternData[0].at(i).patternID)); 01639 extrinsicsPointSets[1].push_back(pointSets[1].at(validPatternData[1].at(i).patternID)); 01640 ROS_INFO("Added patterns for valid pair %d...", currentValidPattern); 01641 } 01642 01643 currentValidPattern++; 01644 01645 } else { 01646 destroyWindow("pattern1"); 01647 destroyWindow("pattern2"); 01648 doVerify = false; 01649 } 01650 01651 } 01652 01653 } 01654 01655 } 01656 01657 } 01658 01659 //preprocess images 01660 void calibratorNode::preprocessImage(Mat src, Mat &dst, double a = 1.0, double b = 0.0, bool normalize = false, bool negative = false){ 01661 \ 01662 01663 Mat newImage = Mat::zeros(src.size(), src.type()); 01664 01665 if (src.type() == CV_8UC1){ 01666 01667 for (int j = 0; j < src.rows; j++){ 01668 for (int i = 0; i < src.cols; i++){ 01669 newImage.at<uchar>(j,i) = saturate_cast<uchar> (a * (src.at<uchar>(j,i))+ b); 01670 } 01671 } 01672 01673 }else{ 01674 01675 for (int j = 0; j < src.rows; j++){ 01676 for (int i = 0; i < src.cols; i++){ 01677 for (int c = 0; c< 3; c++){ 01678 newImage.at<Vec3b>(j,i)[c] = saturate_cast<uchar> (a * (src.at<Vec3b>(j,i)[c])+ b); 01679 } 01680 } 01681 } 01682 01683 } 01684 01685 01686 //normalize 01687 if (normalize){ 01688 cvtColor(newImage, src, CV_RGB2GRAY); 01689 equalizeHist(src,newImage); 01690 } 01691 01692 01693 //invert 01694 01695 if (negative){ 01696 01697 if (src.type() == CV_8UC1){ 01698 01699 for (int j = 0; j < newImage.rows; j++){ 01700 for (int i = 0; i < newImage.cols; i++){ 01701 newImage.at<uchar>(j,i) = 255 - saturate_cast<uchar> (newImage.at<uchar>(j,i)); 01702 } 01703 } 01704 01705 }else{ 01706 01707 for (int j = 0; j < newImage.rows; j++){ 01708 for (int i = 0; i < newImage.cols; i++){ 01709 for (int c = 0; c< 3; c++){ 01710 newImage.at<Vec3b>(j,i)[c] = 255 - saturate_cast<uchar> ( newImage.at<Vec3b>(j,i)[c]); 01711 } 01712 } 01713 } 01714 01715 } 01716 01717 } 01718 01719 01720 01721 01722 dst = Mat(newImage); 01723 01724 } 01725 01726 01727 void calibratorNode::updatePairs() { 01728 01729 01730 //HGH 01731 determineValidPairs(); 01732 Mat dispMat1, dispMat2; 01733 /* HGH 01734 01735 int maxCam1 = std::min(((int) times_1.size()), frameCount_1); 01736 int maxCam2 = std::min(((int) times_2.size()), frameCount_2); 01737 01738 Mat dispMat1, dispMat2; 01739 01740 while (checkIndex_1 < maxCam1) { 01741 01742 if (checkIndex_1 >= duplicateFlags_1.size()) { 01743 break; 01744 } 01745 01746 if (duplicateFlags_1.at(checkIndex_1) == 1) { 01747 checkIndex_1++; 01748 continue; 01749 } 01750 01751 double leastDiff = 9e99; 01752 int bestMatch = -1; 01753 01754 bool candidatesExhausted = false; 01755 01756 01757 while ((timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) < configData.maxTimeDiff)) { 01758 01759 if (checkIndex_2 >= (maxCam2-1)) { 01760 break; 01761 01762 } 01763 01764 if (checkIndex_2 >= duplicateFlags_2.size()) { 01765 break; 01766 } 01767 01768 if (duplicateFlags_2.at(checkIndex_2) == 1) { 01769 checkIndex_2++; 01770 continue; 01771 } 01772 01773 double diff = abs(timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1))); 01774 01775 01776 01777 if (diff < leastDiff) { 01778 leastDiff = diff; 01779 bestMatch = checkIndex_2; 01780 } 01781 01782 checkIndex_2++; 01783 } 01784 01785 if ((timeDiff(times_2.at(checkIndex_2), times_1.at(checkIndex_1)) >= configData.maxTimeDiff)) { 01786 candidatesExhausted = true; 01787 } 01788 01789 //checkIndex_2 = bestMatch; 01790 01791 if ((leastDiff < configData.maxTimeDiff) && (bestMatch >= 0)) { 01792 01793 //ROS_WARN("Pushing back match (%f) (%d) [%02d.%04d] and (%d) [%02d.%04d]...", leastDiff, checkIndex_1, times_1.at(checkIndex_1).sec, times_1.at(checkIndex_1).nsec, bestMatch, times_2.at(bestMatch).sec, times_2.at(bestMatch).nsec); 01794 01795 validPairs[0].push_back(checkIndex_1); 01796 checkIndex_1++; 01797 validPairs[1].push_back(bestMatch); 01798 } else if (candidatesExhausted) { // (checkIndex_2 < (maxCam2-1)) { 01799 checkIndex_1++; 01800 } else { 01801 break; 01802 } 01803 01804 } 01805 01806 //*/ 01807 01808 if (validPairs[0].size() > publishCount) { 01809 01810 int currentPair = validPairs[0].size()-1; 01811 01812 if (currentPair == -1) { 01813 return; 01814 } 01815 01816 01817 01818 // This is probably where it's worth attempting to find the patterns 01819 01820 bool patternFound_1 = false, patternFound_2 = false; 01821 01822 Mat tmpMat1, tmpMat2; 01823 01824 vector<Point2f> cornerSet_1, cornerSet_2; 01825 01826 01827 if ((validPairs[0].at(currentPair) >= displayImages_1.size()) || (validPairs[1].at(currentPair) >= displayImages_2.size())) { 01828 ROS_WARN("Skipping detection because there appear to be insufficient buffered frames [(%d)(%d) : (%d)(%d)", validPairs[0].at(currentPair), displayImages_1.size(), validPairs[1].at(currentPair), displayImages_2.size()); 01829 return; 01830 } 01831 01832 //ROS_WARN("Processing pair (%d) (%d, %d)[sync'ed: %f]", currentPair, validPairs[0].at(currentPair), validPairs[1].at(currentPair), timeDiff(times_2.at(validPairs[1].at(currentPair)), times_1.at(validPairs[0].at(currentPair)))); 01833 01834 Mat grayMat1, grayMat2; 01835 01836 if (displayImages_1.at(validPairs[0].at(currentPair)).type() == CV_8UC3) { 01837 cvtColor(displayImages_1.at(validPairs[0].at(currentPair)), grayMat1, CV_RGB2GRAY); 01838 } else { 01839 grayMat1 = Mat(displayImages_1.at(validPairs[0].at(currentPair))); 01840 } 01841 01842 //ROS_WARN("First image retrieved.."); 01843 01844 if (displayImages_2.at(validPairs[1].at(currentPair)).type() == CV_8UC3) { 01845 cvtColor(displayImages_2.at(validPairs[1].at(currentPair)), grayMat2, CV_RGB2GRAY); 01846 } else { 01847 grayMat2 = Mat(displayImages_2.at(validPairs[1].at(currentPair))); 01848 } 01849 01850 01851 switch (configData.pattType) { 01852 case CHESSBOARD_FINDER_CODE: 01853 patternFound_1 = findChessboardCorners(grayMat1, cvSize(configData.xCount, configData.yCount), cornerSet_1); 01854 patternFound_2 = findChessboardCorners(grayMat2, cvSize(configData.xCount, configData.yCount), cornerSet_2); 01855 break; 01856 case MASK_FINDER_CODE: 01857 patternFound_1 = findMaskCorners_1(grayMat1, cvSize(configData.xCount, configData.yCount), cornerSet_1, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 01858 patternFound_2 = findMaskCorners_1(grayMat2, cvSize(configData.xCount, configData.yCount), cornerSet_2, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 01859 break; 01860 case HEATED_CHESSBOARD_FINDER_CODE: 01861 invertMatIntensities(grayMat1, tmpMat1); 01862 patternFound_1 = findChessboardCorners(tmpMat1, cvSize(configData.xCount, configData.yCount), cornerSet_1); 01863 01864 invertMatIntensities(grayMat2, tmpMat2); 01865 patternFound_2 = findChessboardCorners(tmpMat2, cvSize(configData.xCount, configData.yCount), cornerSet_2); 01866 01867 break; 01868 default: 01869 patternFound_1 = findChessboardCorners(grayMat1, cvSize(configData.xCount, configData.yCount), cornerSet_1); 01870 patternFound_2 = findChessboardCorners(grayMat2, cvSize(configData.xCount, configData.yCount), cornerSet_2); 01871 break; 01872 } 01873 01874 if (patternFound_1 && patternFound_2) { 01875 01876 extrinsicsPointSets[0].push_back(cornerSet_1); 01877 extrinsicsPointSets[1].push_back(cornerSet_2); 01878 ROS_INFO("(%d) patterns found from (%d) valid frame pairs...", extrinsicsPointSets[0].size(), validPairs[0].size()); 01879 pointSets[0].push_back(cornerSet_1); 01880 pointSets[1].push_back(cornerSet_2); 01881 //ROS_INFO("For cam (0), (%d) patterns found.", pointSets[0].size()); 01882 //ROS_INFO("For cam (1), (%d) patterns found.", pointSets[1].size()); 01883 } else if (patternFound_1) { 01884 pointSets[0].push_back(cornerSet_1); 01885 //ROS_INFO("For cam (0), (%d) patterns found.", pointSets[0].size()); 01886 } else if (patternFound_2) { 01887 pointSets[1].push_back(cornerSet_2); 01888 //ROS_INFO("For cam (1), (%d) patterns found.", pointSets[1].size()); 01889 } 01890 01891 if (configData.debugMode) { 01892 01893 if (displayImages_1.at(validPairs[0].at(currentPair)).type() == CV_8UC3) { 01894 displayImages_1.at(validPairs[0].at(currentPair)).copyTo(dispMat1); 01895 } else { 01896 cvtColor(displayImages_1.at(validPairs[0].at(currentPair)), dispMat1, CV_GRAY2RGB); 01897 } 01898 01899 01900 drawChessboardCorners(dispMat1, cvSize(configData.xCount, configData.yCount), Mat(cornerSet_1), patternFound_1); 01901 01902 if (msg_debug_1.width > 0) { 01903 std::copy(&(dispMat1.at<Vec3b>(0,0)[0]), &(dispMat1.at<Vec3b>(0,0)[0])+(dispMat1.cols*dispMat1.rows*dispMat1.channels()), msg_debug_1.data.begin()); 01904 } 01905 01906 if (displayImages_2.at(validPairs[1].at(currentPair)).type() == CV_8UC3) { 01907 displayImages_2.at(validPairs[1].at(currentPair)).copyTo(dispMat2); 01908 } else { 01909 cvtColor(displayImages_2.at(validPairs[1].at(currentPair)), dispMat2, CV_GRAY2RGB); 01910 } 01911 01912 drawChessboardCorners(dispMat2, cvSize(configData.xCount, configData.yCount), Mat(cornerSet_2), patternFound_2); 01913 01914 if (msg_debug_2.width > 0) { 01915 std::copy(&(dispMat2.at<Vec3b>(0,0)[0]), &(dispMat2.at<Vec3b>(0,0)[0])+(dispMat2.cols*dispMat2.rows*dispMat2.channels()), msg_debug_2.data.begin()); 01916 } 01917 01918 //ROS_ERROR("Publishing frame pair..."); 01919 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 01920 debug_pub_2.publish(msg_debug_2, debug_camera_info_2); 01921 01922 } 01923 01924 publishCount = validPairs[0].size(); 01925 //publishCount++; 01926 } 01927 01928 01929 } 01930 01931 01932 01933 void calibratorNode::handle_image_1(const sensor_msgs::ImageConstPtr& msg_ptr, const sensor_msgs::CameraInfoConstPtr& info_msg) { 01934 //ROS_WARN("Handling image 1..."); 01935 01936 //HGH 01937 01938 if(configData.stopCapturing){ 01939 stillCollectingSet[0]=false; 01940 stillCollectingSet[1]=false; 01941 stillCollecting = false; 01942 return; 01943 } 01944 01945 01946 if ((frameCount_1 > configData.maxFrames)) { 01947 //if ((pointSets[0].size() >= configData.maxPatterns) || (frameCount_1 >= configData.maxFrames)) { 01948 01949 stillCollectingSet[0] = false; 01950 01951 //HGH 01952 if (!stillCollectingSet[1]){ 01953 //ROS_ERROR("Max frames/patterns received..."); 01954 stillCollectingSet[1] = false; 01955 stillCollecting = false; 01956 return; 01957 } 01958 01959 return; 01960 } 01961 01962 while (!infoProcessed_1) { 01963 01964 if (configData.wantsIntrinsics) { 01965 infoProcessed_1 = true; 01966 } else { 01967 01969 //use provided intrinsics file 01970 if (configData.useIntrinsicsFile){ 01971 01972 ROS_WARN("(use intrinsics): intrinsicsFileLeft: %s", configData.intrinsicsFileLeft.c_str()); 01973 01974 if (configData.intrinsicsFileLeft[0] != '/') { 01975 configData.intrinsicsFileLeft = configData.read_addr + configData.intrinsicsFileLeft; 01976 } 01977 01978 // http://www.mathpirate.net/log/2009/11/26/when-in-doubt-link-debug/ 01979 Mat dummyImage(300, 300, CV_8UC1); 01980 GaussianBlur(dummyImage, dummyImage, Size(5, 5), 1.5); 01981 01982 try { 01983 01984 FileStorage fs(configData.intrinsicsFileLeft, FileStorage::READ); 01985 fs["cameraMatrix"] >> configData.K1; 01986 fs["distCoeffs"] >> configData.distCoeffs1; 01987 fs.release(); 01988 01989 //ros::Duration(0.5).sleep(); 01990 01991 ROS_INFO("Calibration data read."); 01992 01993 if (configData.K1.empty()){ 01994 ROS_ERROR("Intrinsics file %s invalid! Please check path and filecontent...\n", configData.intrinsicsFileLeft.c_str()); 01995 } 01996 01997 infoProcessed_1 = true; 01998 01999 }catch(int e){ 02000 ROS_ERROR("Some failure in reading in the camera parameters..."); 02001 } 02002 02003 } else { 02004 //extract intrinsics from msg header 02005 //*///HGH end 02006 02007 02008 try { 02009 02010 configData.K1 = Mat::eye(3, 3, CV_64FC1); 02011 02012 for (unsigned int mmm = 0; mmm < 3; mmm++) { 02013 for (unsigned int nnn = 0; nnn < 3; nnn++) { 02014 configData.K1.at<double>(mmm, nnn) = info_msg->K[3*mmm + nnn]; 02015 } 02016 } 02017 02018 unsigned int maxDistortionIndex; 02019 if (info_msg->distortion_model == "plumb_bob") { 02020 maxDistortionIndex = 5; 02021 } else if (info_msg->distortion_model == "rational_polynomial") { 02022 maxDistortionIndex = 8; 02023 } 02024 02025 configData.distCoeffs1 = Mat::zeros(1, maxDistortionIndex, CV_64FC1); 02026 02027 for (unsigned int iii = 0; iii < maxDistortionIndex; iii++) { 02028 configData.distCoeffs1.at<double>(0, iii) = info_msg->D[iii]; 02029 } 02030 02031 ROS_INFO("Camera 1 intrinsics:"); 02032 cout << configData.K1 << endl; 02033 cout << configData.distCoeffs1 << endl; 02034 infoProcessed_1 = true; 02035 } catch (sensor_msgs::CvBridgeException& e) { 02036 ROS_ERROR("Some failure in reading in the camera parameters..."); 02037 } 02038 02039 }//HGH 02040 } 02041 02042 } 02043 02044 if (infoProcessed_1) { 02045 02046 elapsedTime = timeElapsedMS(cycle_timer); 02047 02048 if (frameCount_1 > 0) { 02049 avgTime += elapsedTime; 02050 } 02051 02052 times_1.push_back(info_msg->header.stamp); 02053 02054 cv_ptr_1 = cv_bridge::toCvCopy(msg_ptr, enc::BGR8); 02055 02056 Mat newImage(cv_ptr_1->image); 02057 Mat currImage, gray16, dispMat; 02058 02059 if (newImage.type() == CV_16UC1) { 02060 //ROS_WARN("type = CV_16UC1"); 02061 adaptiveDownsample(newImage, currImage, 0); 02062 newImage = Mat(currImage); 02063 } else if (newImage.type() == CV_16UC3) { 02064 //ROS_WARN("type = CV_16UC3"); 02065 cvtColor(newImage, gray16, CV_RGB2GRAY); 02066 adaptiveDownsample(gray16, currImage, 0); 02067 newImage = Mat(currImage); 02068 } 02069 02070 02071 if (newImage.type() == CV_8UC1) { 02072 cvtColor(newImage, dispMat, CV_GRAY2RGB); 02073 02074 } else { 02075 dispMat = Mat(newImage); 02076 } 02077 02078 //HGH 02079 preprocessImage(dispMat, dispMat, configData.contrastLeft, configData.brightnessLeft, configData.normLeft, configData.invertLeft); 02080 02081 02082 // Debug Publication 02083 02084 if (displayImages_1.size() > 0) { 02085 if (matricesAreEqual(displayImages_1.at(displayImages_1.size()-1), dispMat)) { 02086 duplicateFlags_1.push_back(1); 02087 // ROS_WARN("Received duplicate frame at cam 1 (%d)", frameCount_1); 02088 } else { 02089 duplicateFlags_1.push_back(0); 02090 } 02091 } else { 02092 duplicateFlags_1.push_back(0); 02093 imSize[0] = newImage.size(); 02094 } 02095 02096 displayImages_1.push_back(dispMat); 02097 02098 if (configData.debugMode) { 02099 02100 if (msg_debug_1.width == 0) { 02101 msg_debug_1.width = dispMat.cols; 02102 msg_debug_1.height = dispMat.rows; 02103 msg_debug_1.encoding = "bgr8"; 02104 msg_debug_1.is_bigendian = false; 02105 msg_debug_1.step = dispMat.cols*3; 02106 msg_debug_1.data.resize(dispMat.cols*dispMat.rows*dispMat.channels()); 02107 } 02108 } 02109 02110 // Check for sync'ed frames here (only with camera 1) 02111 02112 //ROS_WARN("DEBUG checking frames img1.."); 02113 //HGH 02114 if(configData.useMutex){ 02115 if (_access.try_lock()) { 02116 updatePairs(); 02117 _access.unlock(); 02118 } 02119 }else{ 02120 02121 //HGH 02122 if (configData.doOnlineProcessing){ 02123 trackPattern(0, dispMat, frameCount_1); //cam1 02124 }else{ 02125 ROS_INFO("Cam 1: current frame %d", frameCount_1); 02126 if (frameCount_1%20==0){ 02127 trackPattern(0, dispMat, frameCount_1); 02128 } 02129 } 02130 } 02131 02132 frameCount_1++; 02133 02134 } 02135 } 02136 02137 02138 02139 void calibratorNode::handle_image_2(const sensor_msgs::ImageConstPtr& msg_ptr, const sensor_msgs::CameraInfoConstPtr& info_msg) { 02140 //ROS_WARN("Handling image 2..."); 02141 02142 if (!stillCollecting){ 02143 return; 02144 } 02145 02146 02147 //HGH 02148 if(configData.stopCapturing){ 02149 stillCollectingSet[0]=false; 02150 stillCollectingSet[1]=false; 02151 stillCollecting = false; 02152 return; 02153 } 02154 02155 if ((frameCount_2 >= configData.maxFrames)) { 02156 //if ((pointSets[1].size() >= configData.maxPatterns) || (frameCount_2 >= configData.maxFrames)) { 02157 02158 stillCollectingSet[1] = false; 02159 02160 //HGH 02161 if ( !stillCollectingSet[0]){ 02162 //ROS_ERROR("Max frames/patterns received..."); 02163 stillCollectingSet[0] = false; 02164 stillCollecting = false; 02165 return; 02166 } 02167 02168 return; 02169 } 02170 02171 02172 02173 while (!infoProcessed_2) { 02174 02175 if (configData.wantsIntrinsics) { 02176 infoProcessed_2 = true; 02177 } else { 02178 02180 //use provided intrinsics file 02181 if (configData.useIntrinsicsFile){ 02182 02183 ROS_WARN("(use intrinsics): intrinsicsFileRight: %s", configData.intrinsicsFileRight.c_str()); 02184 02185 if (configData.intrinsicsFileRight[0] != '/') { 02186 configData.intrinsicsFileRight = configData.read_addr + configData.intrinsicsFileRight; 02187 } 02188 02189 02190 // http://www.mathpirate.net/log/2009/11/26/when-in-doubt-link-debug/ 02191 Mat dummyImage(300, 300, CV_8UC1); 02192 GaussianBlur(dummyImage, dummyImage, Size(5, 5), 1.5); 02193 02194 try { 02195 02196 FileStorage fs(configData.intrinsicsFileRight, FileStorage::READ); 02197 fs["cameraMatrix"] >> configData.K2; 02198 fs["distCoeffs"] >> configData.distCoeffs2; 02199 fs.release(); 02200 02201 //ros::Duration(0.5).sleep(); 02202 02203 ROS_INFO("Calibration data read."); 02204 02205 if (configData.K2.empty()){ 02206 ROS_ERROR("Intrinsics file %s invalid! Please check path and filecontent...\n", configData.intrinsicsFileRight.c_str()); 02207 } 02208 02209 infoProcessed_2 = true; 02210 02211 }catch(int e){ 02212 ROS_ERROR("Some failure in reading in the camera parameters..."); 02213 } 02214 02215 } else { 02216 //extract intrinsics from msg header 02217 //*///HGH end 02218 02219 02220 try { 02221 02222 configData.K2 = Mat::eye(3, 3, CV_64FC1); 02223 02224 for (unsigned int mmm = 0; mmm < 3; mmm++) { 02225 for (unsigned int nnn = 0; nnn < 3; nnn++) { 02226 configData.K2.at<double>(mmm, nnn) = info_msg->K[3*mmm + nnn]; 02227 } 02228 } 02229 02230 unsigned int maxDistortionIndex; 02231 if (info_msg->distortion_model == "plumb_bob") { 02232 maxDistortionIndex = 5; 02233 } else if (info_msg->distortion_model == "rational_polynomial") { 02234 maxDistortionIndex = 8; 02235 } 02236 02237 configData.distCoeffs2 = Mat::zeros(1, maxDistortionIndex, CV_64FC1); 02238 02239 for (unsigned int iii = 0; iii < maxDistortionIndex; iii++) { 02240 configData.distCoeffs2.at<double>(0, iii) = info_msg->D[iii]; 02241 } 02242 02243 ROS_INFO("Camera 2 intrinsics:"); 02244 cout << configData.K2 << endl; 02245 cout << configData.distCoeffs2 << endl; 02246 infoProcessed_2 = true; 02247 02248 02249 } catch (sensor_msgs::CvBridgeException& e) { 02250 ROS_ERROR("Some failure in reading in the camera parameters..."); 02251 } 02252 02253 }//HGH 02254 02255 } 02256 02257 } 02258 02259 if (infoProcessed_2) { 02260 02261 times_2.push_back(info_msg->header.stamp); 02262 02263 cv_ptr_2 = cv_bridge::toCvCopy(msg_ptr, enc::BGR8); 02264 02265 Mat newImage(cv_ptr_2->image); 02266 Mat currImage, gray16, dispMat; 02267 02268 if (newImage.type() == CV_16UC1) { 02269 //ROS_WARN("type = CV_16UC1"); 02270 adaptiveDownsample(newImage, currImage, 0); 02271 newImage = Mat(currImage); 02272 } else if (newImage.type() == CV_16UC3) { 02273 //ROS_WARN("type = CV_16UC3"); 02274 cvtColor(newImage, gray16, CV_RGB2GRAY); 02275 adaptiveDownsample(gray16, currImage, 0); 02276 newImage = Mat(currImage); 02277 } 02278 02279 if (newImage.type() == CV_8UC1) { 02280 cvtColor(newImage, dispMat, CV_GRAY2RGB); //orig 02281 } else { 02282 dispMat = Mat(newImage); //orig 02283 } 02284 02285 //HGH 02286 preprocessImage(dispMat, dispMat, configData.contrastRight, configData.brightnessRight, configData.normRight, configData.invertRight); 02287 02288 02289 // Debug Publication 02290 02291 if (displayImages_2.size() > 0) { 02292 if (matricesAreEqual(displayImages_2.at(displayImages_2.size()-1), dispMat)) { 02293 duplicateFlags_2.push_back(1); 02294 //ROS_WARN("Received duplicate frame at cam 2 (%d)", frameCount_2); 02295 } else { 02296 duplicateFlags_2.push_back(0); 02297 } 02298 } else { 02299 duplicateFlags_2.push_back(0); 02300 imSize[1] = newImage.size(); 02301 } 02302 02303 displayImages_2.push_back(dispMat); 02304 02305 02306 if (configData.debugMode) { 02307 02308 if (msg_debug_2.width == 0) { 02309 msg_debug_2.width = dispMat.cols; 02310 msg_debug_2.height = dispMat.rows; 02311 msg_debug_2.encoding = "bgr8"; 02312 msg_debug_2.is_bigendian = false; 02313 msg_debug_2.step = dispMat.cols*3; 02314 msg_debug_2.data.resize(dispMat.cols*dispMat.rows*dispMat.channels()); 02315 } 02316 } 02317 02318 //ROS_WARN("DEBUG checking frames img2..");\ 02319 //HGH 02320 if(configData.useMutex){ 02321 if (_access.try_lock()) { 02322 updatePairs(); 02323 _access.unlock(); 02324 } 02325 }else{ 02326 //HGH 02327 if (configData.doOnlineProcessing){ 02328 trackPattern(1,dispMat, frameCount_2); //cam2 02329 }else{ 02330 ROS_INFO("Cam 2: current frame %d", frameCount_2); 02331 if (frameCount_2%20==0){ 02332 trackPattern(1,dispMat, frameCount_2); 02333 } 02334 } 02335 } 02336 02337 frameCount_2++; 02338 02339 } 02340 } 02341 02342 void calibratorNode::handle_image(const sensor_msgs::ImageConstPtr& msg_ptr, const sensor_msgs::CameraInfoConstPtr& info_msg) { 02343 02344 if ((pointSets[0].size() >= configData.maxPatterns) || (frameCount >= configData.maxFrames)) { 02345 ROS_INFO("Max frames/patterns received."); 02346 stillCollecting = false; 02347 return; 02348 } 02349 02350 // Currently not doing any camera info processing... 02351 infoProcessed = true; 02352 02353 if (infoProcessed) { 02354 02355 elapsedTime = timeElapsedMS(cycle_timer); 02356 02357 if (frameCount > 0) { 02358 avgTime += elapsedTime; 02359 } 02360 02361 cv_ptr = cv_bridge::toCvCopy(msg_ptr, enc::BGR8); // For some reason it reads as BGR, not gray 02362 02363 Mat newImage(cv_ptr->image); 02364 02365 if (imSize[0].width == 0) { 02366 if (newImage.rows != 0) { 02367 imSize[0] = newImage.size(); 02368 } 02369 } 02370 02371 02372 02373 if (configData.debugMode) { 02374 if (newImage.rows > 0) { 02375 02376 Mat tmpCpy, grayMat, tmpMat, dispMat; 02377 02378 if (newImage.type() == CV_8UC3) { 02379 tmpCpy = Mat(newImage); 02380 cvtColor(newImage, grayMat, CV_RGB2GRAY); 02381 } else { 02382 grayMat = Mat(newImage); 02383 cvtColor(newImage, tmpCpy, CV_GRAY2RGB); 02384 02385 } 02386 02387 displayImages_1.push_back(tmpCpy); 02388 02389 02390 if (frameCount == 0) { 02391 msg_debug_1.width = tmpCpy.cols; 02392 msg_debug_1.height = tmpCpy.rows; 02393 msg_debug_1.encoding = "bgr8"; 02394 msg_debug_1.is_bigendian = false; 02395 msg_debug_1.step = tmpCpy.cols*3; 02396 msg_debug_1.data.resize(tmpCpy.cols*tmpCpy.rows*tmpCpy.channels()); 02397 } 02398 02399 bool patternFound; 02400 02401 //HGH 02402 //vector<Point2f> cornerSet; 02403 02404 //ROS_WARN("About to attempt pattern-finding..."); 02405 02406 //HGH 02407 patternFound = findPattern(tmpCpy, cornerSet, prevMat, configData.usePatternDetectionMode); 02408 02409 //HGH 02410 // switch (configData.pattType) { 02411 // case CHESSBOARD_FINDER_CODE: 02412 // patternFound = findChessboardCorners(tmpCpy, cvSize(configData.xCount, configData.yCount), cornerSet); 02413 // break; 02414 // case MASK_FINDER_CODE: 02415 // //printf("%s << here (%d, %d)\n", __FUNCTION__, configData.xCount, configData.yCount); 02416 // patternFound = findMaskCorners_1(tmpCpy, cvSize(configData.xCount, configData.yCount), cornerSet, PATTERN_FINDER_CV_CORNER_SUBPIX_FLAG); 02417 // break; 02418 // case HEATED_CHESSBOARD_FINDER_CODE: 02419 // invertMatIntensities(grayMat, tmpMat); 02420 // tmpMat.copyTo(grayMat); 02421 // patternFound = findChessboardCorners(tmpCpy, cvSize(configData.xCount, configData.yCount), cornerSet); 02422 // break; 02423 // default: 02424 // patternFound = findChessboardCorners(tmpCpy, cvSize(configData.xCount, configData.yCount), cornerSet); 02425 // break; 02426 // } 02427 02428 //printf("%s << Pattern found? %d\n", __FUNCTION__, patternFound); 02429 02430 tmpCpy.copyTo(dispMat); 02431 02432 02433 drawChessboardCorners(dispMat, cvSize(configData.xCount, configData.yCount), Mat(cornerSet), patternFound); 02434 02435 if (patternFound) { 02436 //HGH 02437 tmpCpy.copyTo(prevMat); 02438 02439 //ROS_WARN("Pattern found!"); 02440 pointSets[0].push_back(cornerSet); 02441 } 02442 02443 std::copy(&(dispMat.at<Vec3b>(0,0)[0]), &(dispMat.at<Vec3b>(0,0)[0])+(dispMat.cols*dispMat.rows*dispMat.channels()), msg_debug_1.data.begin()); 02444 02445 //printf("%s::%s << Debug copied.\n", __PROGRAM__, __FUNCTION__); 02446 02447 debug_pub_1.publish(msg_debug_1, debug_camera_info_1); 02448 } 02449 } 02450 02451 } 02452 02453 frameCount++; 02454 02455 } 02456 02457 calibratorNode::calibratorNode(ros::NodeHandle& nh, calibratorData startupData) { 02458 02459 //alpha = 0.00; 02460 02461 alphaChanged = true; 02462 02463 publishCount = 0; 02464 02465 readyForOutput = false; 02466 02467 topValidHeight = 0; 02468 botValidHeight = 65535; 02469 02470 checkIndex_1 = 0; 02471 checkIndex_2 = 0; 02472 02473 ref = &nh; 02474 02475 stillCollecting = true; 02476 02477 //HGH 02478 stillCollectingSet[0] = true; 02479 stillCollectingSet[1] = true; 02480 doVerify = false; 02481 02482 default_R = Mat::eye(3,3,CV_64FC1); 02483 02484 avgTime = 0.0; 02485 02486 numCams = 1; 02487 02488 frameCount = 0; 02489 frameCount_1 = 0; 02490 frameCount_2 = 0; 02491 //HGH 02492 totalFrameCount_1 = 0; 02493 totalFrameCount_2 = 0; 02494 02495 undistortionCount = 0; 02496 rectificationCount = 0; 02497 02498 infoProcessed = false; 02499 infoProcessed_1 = false; 02500 infoProcessed_2 = false; 02501 02502 sprintf(nodeName, "%s", ros::this_node::getName().c_str()); 02503 02504 configData = startupData; 02505 02506 //HGH 02507 if (configData.patternDetectionMode=="findThenTrack"){ 02508 configData.usePatternDetectionMode = PATTERN_CODE_FIND_TRACK; 02509 ROS_INFO("Using pattern detection mode: find then track..."); 02510 }else if(configData.patternDetectionMode=="trackThenFind"){ 02511 configData.usePatternDetectionMode = PATTERN_CODE_TRACK_FIND; 02512 ROS_INFO("Using pattern detection mode: track then find..."); 02513 }else if (configData.patternDetectionMode=="find"){ 02514 configData.usePatternDetectionMode = PATTERN_CODE_FIND; 02515 ROS_INFO("Using pattern detection mode: find only, no tracking..."); 02516 }else{ 02517 configData.usePatternDetectionMode = PATTERN_CODE_FIND; 02518 ROS_WARN("patternDetectionMode set to default: find only, no tracking"); 02519 } 02520 02521 02522 if (configData.calibType == "single") { 02523 02524 sprintf(debug_pub_name, "thermalvis%s/image_col", nodeName); 02525 02526 topic = nh.resolveName(configData.video_stream + configData.video_sequence); 02527 topic_info = nh.resolveName(configData.video_stream + "camera_info"); 02528 02529 ROS_INFO("Subscribing to topic (%s) with info (%s).", topic.c_str(), topic_info.c_str()); 02530 02531 image_transport::ImageTransport it(nh); 02532 02533 camera_sub = it.subscribeCamera(topic, 1, &calibratorNode::handle_image, this); 02534 02535 /* 02536 info_sub = nh.subscribe<sensor_msgs::CameraInfo>(topic_info, 1, &calibratorNode::handle_info, this); 02537 image_sub = it.subscribe(topic, 1, &calibratorNode::handle_image, this); 02538 */ 02539 if (configData.debugMode) { 02540 debug_pub_1 = it.advertiseCamera(debug_pub_name, 1); 02541 ROS_INFO("Advertising tracker debugging video (%s)", debug_pub_name); 02542 } 02543 02544 numCams = 1; 02545 02546 } else if (configData.calibType == "stereo") { 02547 02548 sprintf(debug_pub_name_1, "thermalvis/calib_left/image_col"); 02549 sprintf(debug_pub_name_2, "thermalvis/calib_right/image_col"); 02550 02552 if (configData.useDefinedTopics){ 02553 02554 topic_1 = nh.resolveName(configData.video_streamLeft + configData.video_sequenceLeft); 02555 topic_2 = nh.resolveName(configData.video_streamRight + configData.video_sequenceRight); 02556 02557 }else{ 02558 //*/ 02559 topic_1 = nh.resolveName(configData.video_stream + "left" + "/" + configData.video_sequence); 02560 topic_2 = nh.resolveName(configData.video_stream + "right" + "/" + configData.video_sequence); 02561 02562 02563 }//HGH 02564 02565 ROS_INFO("(cam 1): Subscribing to topic (%s)...", topic_1.c_str()); 02566 ROS_INFO("(cam 2): Subscribing to topic (%s)...", topic_2.c_str()); 02567 02568 image_transport::ImageTransport it(nh); 02569 02570 camera_sub_1 = it.subscribeCamera(topic_1, 1, &calibratorNode::handle_image_1, this); 02571 camera_sub_2 = it.subscribeCamera(topic_2, 1, &calibratorNode::handle_image_2, this); 02572 02573 /* 02574 info_sub_1 = nh.subscribe<sensor_msgs::CameraInfo>(topic_info_1, 1, &calibratorNode::handle_info_1, this); 02575 info_sub_2 = nh.subscribe<sensor_msgs::CameraInfo>(topic_info_2, 1, &calibratorNode::handle_info_2, this); 02576 image_sub_1 = it.subscribe(topic_1, 1, &calibratorNode::handle_image_1, this); 02577 image_sub_2 = it.subscribe(topic_2, 1, &calibratorNode::handle_image_2, this); 02578 */ 02579 02580 ROS_INFO("Subscribed to topics..."); 02581 02582 if (configData.debugMode) { 02583 debug_pub_1 = it.advertiseCamera(debug_pub_name_1, 1); 02584 debug_pub_2 = it.advertiseCamera(debug_pub_name_2, 1); 02585 ROS_INFO("%s << Publishing debug topics at (%s) & (%s)\n", __FUNCTION__, debug_pub_name_1, debug_pub_name_2); 02586 } 02587 02588 numCams = 2; 02589 02590 } 02591 02592 02593 02594 // Pattern Corner Co-ordinates 02595 for (unsigned int iii = 0; iii < configData.yCount; iii++) { 02596 for (unsigned int jjj = 0; jjj < configData.xCount; jjj++) { 02597 row.push_back(Point3f(((float)iii)*configData.gridSize, ((float)jjj)*configData.gridSize, 0.0)); 02598 } 02599 } 02600 02601 ROS_INFO("Establishing server callback..."); 02602 f = boost::bind (&calibratorNode::serverCallback, this, _1, _2); 02603 server.setCallback (f); 02604 02605 } 02606 02607 02608 void calibratorNode::parameterCallback(const sensor_msgs::CameraInfo& msg) 02609 { 02610 /* 02611 try { 02612 02613 configData.cameraData.K = Mat::eye(3, 3, CV_64FC1); 02614 configData.cameraData.K.at<double>(0,0) = msg.fx(); 02615 configData.cameraData.K.at<double>(1,1) = msg.fy(); 02616 configData.cameraData.K.at<double>(0,2) = msg.cx(); 02617 configData.cameraData.K.at<double>(1,2) = msg.cy(); 02618 02619 } catch (sensor_msgs::CvBridgeException& e) { 02620 ROS_ERROR("Some failure in reading in the camera parameters..."); 02621 } 02622 */ 02623 } 02624 02625 void calibratorNode::serverCallback(thermalvis::calibratorConfig &config, uint32_t level) { 02626 02627 ROS_INFO("Reconfigure Request: (%1.2f, %d)", 02628 02629 config.alpha, 02630 config.autoAlpha?1:0); 02631 02632 if ((config.autoAlpha != configData.autoAlpha) || ((!config.autoAlpha) && (config.alpha != configData.alpha))) { 02633 02634 configData.autoAlpha = config.autoAlpha; 02635 configData.alpha = config.alpha; 02636 02637 alphaChanged = true; 02638 02639 ROS_WARN("About to try and update maps..."); 02640 if (readyForOutput) { 02641 ROS_WARN("Updating maps..."); 02642 02643 for (unsigned int iii = 0; iii < numCams; iii++) { 02644 updateIntrinsicMap(iii); 02645 } 02646 02647 } 02648 02649 } else { 02650 configData.alpha = config.alpha; 02651 } 02652 02653 configData.trackingMode = config.trackingMode; 02654 02655 ROS_WARN("Tracking mode has been set as (%d)", configData.trackingMode ? 1 : 0); 02656 02657 configData.flowThreshold = config.flowThreshold; 02658 02659 configData.maxFrac = config.maxFrac; 02660 02661 //HGH 02662 configData.errorThreshold = config.errorThreshold; 02663 02664 configData.stopCapturing = config.stopCapturing; 02665 02666 configData.contrastLeft = config.contrastLeft; 02667 configData.brightnessLeft = config.brightnessLeft; 02668 configData.normLeft = config.normLeft; 02669 configData.invertLeft = config.invertLeft; 02670 02671 configData.contrastRight = config.contrastRight; 02672 configData.brightnessRight = config.brightnessRight; 02673 configData.normRight = config.normRight; 02674 configData.invertRight = config.invertRight; 02675 02676 configData.adjustMSERLeft = config.adjustMSERLeft; 02677 configData.adjustMSERRight = config.adjustMSERRight; 02678 configData.deltaLeft = config.deltaLeft; 02679 configData.deltaRight = config.deltaRight; 02680 configData.deltaLeft = config.deltaLeft; 02681 configData.maxVarLeft = config.maxVarLeft; 02682 configData.maxVarRight = config.maxVarRight; 02683 configData.minDivLeft = config.minDivLeft; 02684 configData.minDivRight = config.minDivRight; 02685 configData.areaThresholdLeft = config.areaThresholdLeft; 02686 configData.areaThresholdRight = config.areaThresholdRight; 02687 02688 02689 } 02690 02691 void calibratorNode::set_ready_for_output() { 02692 readyForOutput = true; 02693 }