/* * pose implementation * * Copyright (C) Stanislav Serebryakov * * Released under the GPL version 3. * */ #include #include #include #include #include // OpenCV #if (defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) || (defined(__APPLE__) & defined(__MACH__))) #include #include #elif (CV_MAJOR_VERSION == 2) && (CV_MINOR_VERSION < 2) #include #else #include #endif // GL: GLFW (window etc, ala glut) and FTGL (text rendering) #include #include // PMD-related stuff #include "pmdsdk2.h" #include "cvpmd.h" #include "pmdWrap.h" #include "history.h" // SLAM6D #include "slam6d/point.h" #include "slam6d/ptpair.h" #include FTGLPixmapFont *font; // opengl text rendring void usage(char* progName) { printf("usage: %s [options]\n", progName); printf("options:\n \ \t--ui 0|1\t disable|enable ui (default: 1)\n\ \t--gl 0|1\t disable|enable 3d rendering (default: 1)\n\ \t--cfg file\t parse configuration from file (default: pmdc.conf)\n\ \t--help\t\t display this help.\n"); } void render( History *history, CvPoint3D32f *camPts, int trPtsCnt , CvMat *rot, CvMat *trn , CvPoint3D32f **camPts3D, char **pts3DStatus , int reprojected, bool poseEstimated); /* reprojects PMD-aquired 3D points on the web cam image */ //FIXME this function should be dispached >_> int projectImageToPMD( CvMat *rot, CvMat *trn, CvMat *intrinsic , CvPoint3D32f **pmdPts, CvSize pmdSz , CvSize camSz, CvPoint **pmd2imgIdxs , CvPoint2D32f *trackedPts , int *trPtsCnt, CvPoint3D32f *trackedPts3D, char *pts3DStatus , CvPoint *tr2pmdIdxs) { /* TODO: assert null image, not clean image, bad image depth */ // pmd point's matrix CvMat *pt = cvCreateMat(3, 1, CV_32FC1); // point in cam coorinate system CvMat *reprojPt = cvCreateMat(3, 1, CV_32FC1); // points on cam screen CvMat *camPt3 = cvCreateMat(3, 1, CV_32FC1); CvMat *camPt = cvCreateMat(2, 1, CV_32FC1); // rotation matrix CvMat *rotMat = cvCreateMat(3, 3, CV_32FC1); cvRodrigues2(rot, rotMat, NULL); // clear previous found tracked pts for(int k = 0; k < *trPtsCnt; k++) pts3DStatus[k] = 0; //int l = 0; // count corresponding points int reprojected = 0; for(int j = 0; j < pmdSz.width; j++) for(int i = 0; i < pmdSz.height; i++) { if( fabs(pmdPts[i][j].x) > 20.0 || fabs(pmdPts[i][j].y) > 20.0 || fabs(pmdPts[i][j].z) > 20.0) continue; //FIXME: more realistic limit, status = false // convert to mat CV_MAT_ELEM(*pt, float, 0, 0) = (float)pmdPts[i][j].x; CV_MAT_ELEM(*pt, float, 1, 0) = (float)pmdPts[i][j].y; CV_MAT_ELEM(*pt, float, 2, 0) = (float)pmdPts[i][j].z; // reproject to the camera coordinate system cvMatMulAdd(rotMat, pt, trn, reprojPt); // project to the image cvMatMul(intrinsic, reprojPt, camPt3); // cvConvertPointsHomogenious(camPt3, camPt); /* cvProjectPoints2(pt, rot, trn, intrinsic, NULL, camPt , NULL, NULL, NULL, NULL, NULL);*/ float scale = (float)CV_MAT_ELEM(*camPt3, float, 2, 0); float xf = CV_MAT_ELEM(*camPt3, float, 0, 0) / scale; float yf = CV_MAT_ELEM(*camPt3, float, 1, 0) / scale; int x = (int)xf; int y = camSz.height - (int)yf; //FIXME revise coordinates if((x < 0) || (x > camSz.width) || (y < 0) || (y > camSz.height)) { pmd2imgIdxs[i][j].x = -1; pmd2imgIdxs[i][j].y = -1; continue; } else { // point is projected to cam // contains which PMD point is seen from this pixel pmd2imgIdxs[i][j].x = x; pmd2imgIdxs[i][j].y = y; } //find tracked 3d points (fused here, can be dispached) for(int k = 0; k < *trPtsCnt; k++) if(pts3DStatus[k]) continue; // kill to accumulate (*) else if( (abs((trackedPts[k].x - (float)x)) < 3) //TODO: distance SHOULD be chousen depending on depth!!! && (abs((trackedPts[k].y - (float)y)) < 3)) { //FIXME: hardcoded distance //TODO: we can accumulate points here to get more presise results (*) trackedPts3D[k].x = pmdPts[i][j].x; trackedPts3D[k].y = pmdPts[i][j].y; trackedPts3D[k].z = pmdPts[i][j].z; pts3DStatus[k] = 1; tr2pmdIdxs[k].x = i; //FIXME: cvPoint(i,j)? tr2pmdIdxs[k].y = j; reprojected++; break; // kill to accumulate (*) } } cvReleaseMat(&pt); cvReleaseMat(&reprojPt); cvReleaseMat(&camPt); cvReleaseMat(&rotMat); return reprojected; } static inline float cvPoint3D32fNorm(CvPoint3D32f pt) { return sqrt( (pt.x - pt.x)*(pt.x - pt.x) +(pt.y - pt.y)*(pt.y - pt.y) +(pt.z - pt.z)*(pt.z - pt.z)); } float dpthS( IplImage *img , CvPoint ptI, CvPoint dp , CvPoint3D32f **pts , CvPoint ptD, CvSize pmdSz , float sD, float sC) { CvSize imgSz = cvGetSize(img); if( ptD.x + dp.x > pmdSz.width - 1 || ptD.x + dp.x < 0 || ptD.y + dp.y > pmdSz.height - 1 || ptD.y + dp.y < 0 || ptI.x + dp.x > imgSz.width - 1 || ptI.x + dp.x < 0 || ptI.y + dp.y > imgSz.height - 1 || ptI.y + dp.y < 0) return 0.0; uchar *pI = &((uchar*) (img->imageData + img->widthStep * ptI.y))[ptI.x*3]; uchar *pJ = &((uchar*) (img->imageData + img->widthStep * (ptI.y+dp.y)))[(ptI.x+dp.x)*3]; float dr = (float)pI[2] - (float)pJ[2]; float dg = (float)pI[1] - (float)pJ[1]; float db = (float)pI[0] - (float)pJ[0]; float wij = exp(-(sqrt(dr*dr + dg*dg + db*db))/sC); float dpI = cvPoint3D32fNorm(pts[ptD.x][ptD.y]); float dpJ = cvPoint3D32fNorm(pts[ptD.x + dp.x][ptD.y + dp.y]); float s = exp(-wij*(dpI - dpJ)*(dpI - dpJ)/sD); return s; } #define DPTHS(dx, dy) (dpthS( img, idx, cvPoint((dx),(dy)) \ , pmdPts \ , pmdIdx, pmdSz \ , sigmaDepth, sigmaColor)) void outliersDepthAndColor( CvPoint3D32f **pmdPts, IplImage *img, CvSize pmdSz , CvPoint2D32f *trackedPts, int trPtsCnt, CvPoint* tr2pmdIdxs , char *pts3DStatus // this actually return parameter , float sigmaDepth, float threshold, float sigmaColor ) { if(threshold < 0.0) return; // depth score outliers removal, see pmdc.conf comments for(int k = 0; k < trPtsCnt; k++) { //FIXME: check array bounds CvPoint pmdIdx = tr2pmdIdxs[k]; CvPoint idx = cvPointFrom32f(trackedPts[k]); float s00, s01, s02; s00 = DPTHS(-1, -1); s01 = DPTHS( 0, -1); s02 = DPTHS( 1, -1); float s10 = DPTHS(-1, 0); float s12 = DPTHS( 1, 0); float s20 = DPTHS(-1, 1); float s21 = DPTHS( 0, 1); float s22 = DPTHS( 1, 1); float score = s00 + s01 + s02 + s10 + 0.0 + s12 + s20 + s21 + s22; printf("score = %f\n", score); if(score < threshold) pts3DStatus[k] = 0; } } int motionMeanAndVariance(CvPoint3D32f **camPts3D, char **pts3DStatus, int trPtsCnt, float *mean, float *var) { // float *mean = meanAndVariance; // float *var = &(meanAndVariance[3]); // float motion[3]; float dx, dy, dz; float magSq; float motionSum = 0; //[3] = {0.0, 0.0, 0.0}; float motionSqrSum = 0; //[3] = {0.0, 0.0, 0.0}; int sz = 0; // pairs count for(int i = 0; i < trPtsCnt; i++) if(pts3DStatus[1][i] && pts3DStatus[0][i]) { sz++; dx = camPts3D[1][i].x - camPts3D[0][i].x; dy = camPts3D[1][i].y - camPts3D[0][i].y; dz = camPts3D[1][i].z - camPts3D[0][i].z; magSq = dx*dx + dy*dy + dz*dz; motionSum += sqrt(magSq); //FIXME: optimisation, we can use it without sqrt motionSqrSum += magSq; //thus, it would be sqr here /* motionSum[0] += motion[0]; motionSum[1] += motion[1]; motionSum[2] += motion[2]; motionSqrSum[0] += motion[0]*motion[0]; motionSqrSum[1] += motion[1]*motion[1]; motionSqrSum[2] += motion[2]*motion[2];*/ } if(0 == sz) return 0; // mean *mean = motionSum / sz; /* mean[0] = motionSum[0] / (float)sz; mean[1] = motionSum[1] / (float)sz; mean[2] = motionSum[2] / (float)sz;*/ // variance for(int i = 0; i < trPtsCnt; i++) if(pts3DStatus[1][i] && pts3DStatus[0][i]) { dx = camPts3D[1][i].x - camPts3D[0][i].x; dy = camPts3D[1][i].y - camPts3D[0][i].y; dz = camPts3D[1][i].z - camPts3D[0][i].z; magSq = dx*dx + dy*dy + dz*dz; *var += (magSq - *mean)*(magSq - *mean); } *var /= sz; // = motionSqrSum / sz - (*mean)*(*mean); /* var[0] = motionSqrSum[0] / (float)sz - mean[0]*mean[0]; var[1] = motionSqrSum[1] / (float)sz - mean[1]*mean[1]; var[2] = motionSqrSum[2] / (float)sz - mean[2]*mean[2];*/ return 1; } void outliersSpeedSigma(CvPoint3D32f **camPts3D, char **pts3DStatus, int trPtsCnt, float mean, float var) { float dx, dy, dz; float mag; float sigma = sqrt(var); for(int i = 0; i < trPtsCnt; i++) if(pts3DStatus[1][i] && pts3DStatus[0][i]) { dx = camPts3D[1][i].x - camPts3D[0][i].x; dy = camPts3D[1][i].y - camPts3D[0][i].y; dz = camPts3D[1][i].z - camPts3D[0][i].z; mag = sqrt(dx*dx + dy*dy + dz*dz); if(fabs(mag - mean) > sigma) { pts3DStatus[0][i] = 0; } } } int main(int argc, char **argv) { // settings bool ui = true; bool gl = true; bool fps = false; const char *config = "./pmdc.conf"; // args parsing for(int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--ui")) ui = (bool) atoi(argv[++i]); else if (!strcmp(argv[i], "--gl")) gl = (bool) atoi(argv[++i]); else if (!strcmp(argv[i], "--fps")) fps = true; else if (!strcmp(argv[i], "--cfg")) config = argv[++i]; //TODO: config else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { usage(argv[0]); return 1; } else { fprintf(stderr, "ERROR: unknown flag: %s\n", argv[i]); return 1; } } // pose guess CvMat *rotMatGuess = cvCreateMat(3,3, CV_32FC1); CvMat *rotGuess = cvCreateMat(3, 1, CV_32FC1); CvMat *trnGuess = cvCreateMat(3, 1, CV_32FC1); /***** init device and allocate images *****/ PMDCam *pmdc = initPMDCam(config); CvSize pmdSz = cvGetSize(pmdc->iPMDI); CvSize camSz = cvGetSize(pmdc->iCam); printf("pose: pmd init done\n"); /***** essential matrix *****/ CvMat *rot = (CvMat*)cvLoad("../essential-rot.xml"); //FIXME: load path from cfg CvMat *trn = (CvMat*)cvLoad("../essential-trn.xml"); /***** LK-tracking *****/ IplImage *swapTemp; int featuresMax = pmdc->_track.maxFeatures; int trPtsCnt = 0; // counts found points // eigenvalues for GFTT IplImage* eig = cvCreateImage(camSz, 32, 1); IplImage* tmp = cvCreateImage(camSz, 32, 1); IplImage* mask = cvCreateImage(camSz, IPL_DEPTH_8U, 1); // previous image and pyramides IplImage *imgCamPrv = cvCreateImage(camSz, 8, 1); IplImage *imgCamPyr = cvCreateImage(camSz, 8, 1); IplImage *imgCamPyrPrv = cvCreateImage(camSz, 8, 1); // prev and curr tracked points CvPoint2D32f *camPts[2]; camPts[0] = (CvPoint2D32f*) cvAlloc(featuresMax * sizeof(CvPoint2D32f)); camPts[1] = (CvPoint2D32f*) cvAlloc(featuresMax * sizeof(CvPoint2D32f)); CvPoint3D32f *camPts3D[2]; camPts3D[0] = (CvPoint3D32f*) cvAlloc(featuresMax * sizeof(CvPoint3D32f)); camPts3D[1] = (CvPoint3D32f*) cvAlloc(featuresMax * sizeof(CvPoint3D32f)); CvPoint2D32f *swapPts; CvPoint3D32f *swapPts3; // i guess i can use void* d:D char *swapStatus; char *camPtsStatus = (char*)cvAlloc(featuresMax); char *pts3DStatus[2]; pts3DStatus[0] = (char*) cvAlloc(featuresMax * sizeof(char)); pts3DStatus[1] = (char*) cvAlloc(featuresMax * sizeof(char)); CvPoint *tr2pmdIdxs = (CvPoint*) cvAlloc(featuresMax * sizeof(CvPoint)); // 3d rays where points points :P CvPoint3D32f *trackedPts = (CvPoint3D32f*) cvAlloc(featuresMax * sizeof(CvPoint3D32f)); // contains (row,col) of pmd 3D pts CvPoint **pmd2imgIdxs = (CvPoint**) cvAlloc(pmdSz.height * sizeof(CvPoint*)); for(int i = 0; i < pmdSz.height; i++) pmd2imgIdxs[i] = (CvPoint*) cvAlloc(pmdSz.width * sizeof(CvPoint)); // pmd history History *history = createHistory(); /***** ui and gl stuff *****/ if(ui) { cvNamedWindow("PMD", 0); cvNamedWindow("Cam", 0); } if(gl) { glfwInit(); if(!glfwOpenWindow(640, 480, 8, 8, 8, 8, 24, 0, GLFW_WINDOW)) { glfwTerminate(); fprintf(stderr, "ERROR: can't init glfw window!\n"); return 1; } } //FIXME: put this in if(gl) font = new FTGLPixmapFont("./djvm.ttf"); if(font->Error()) { fprintf(stderr, "ERROR: can't load font ./djvm.ttf"); return 1; } font->FaceSize(20); // fps counting time_t tic=time(0); time_t tac; int fpsCnt = 0; //icp pairs vector pairs; vector motion; float mean, var; /***** main loop *****/ /*********************/ int frames = 0; int goodFrames = 0; while(1) { /***** fps counting *****/ if(fps) { tac = time(0); if(tac - tic >= 1) { printf("%i FPS\n", fpsCnt); fflush(stdout); fpsCnt = 0; tic=tac; } fpsCnt++; } if(grabData(pmdc)) break; // end of seq? /***** tracking *****/ //if(trPtsCnt) cvCalcOpticalFlowPyrLK( imgCamPrv, pmdc->iCam, imgCamPyrPrv, imgCamPyr , camPts[0], camPts[1], trPtsCnt , cvSize(pmdc->_track.winSz, pmdc->_track.winSz), 3, camPtsStatus, 0 , cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03) , pmdc->_track.trackingFlags); pmdc->_track.trackingFlags |= CV_LKFLOW_PYR_A_READY; // filter out not tracked points int k = 0; for(int i = 0; i < trPtsCnt; i++) if(camPtsStatus[i]) { camPts3D[0][k] = camPts3D[0][i]; pts3DStatus[0][k] = pts3DStatus[0][i]; camPts[1][k++] = camPts[1][i]; } trPtsCnt = k; /***** 3d (re)projection *****/ cvProjectArrayToCartesian(pmdc->intrinsicCam, camPts[1], trPtsCnt, trackedPts); int reprojected = projectImageToPMD( rot, trn, pmdc->intrinsicCam, pmdc->pts, pmdSz, camSz, pmd2imgIdxs , camPts[1], &trPtsCnt, camPts3D[1], pts3DStatus[1], tr2pmdIdxs); double alignError = 0.0; bool poseEstimated = false; if(reprojected >= pmdc->minPts4Pose) { // we need at least minPts4Pose points if(motionMeanAndVariance(camPts3D, pts3DStatus, trPtsCnt, &mean, &var)) // TODO: can be fused with centroid computation outliersSpeedSigma(camPts3D, pts3DStatus, trPtsCnt, mean, var); outliersDepthAndColor( pmdc->pts, pmdc->iCamColor, pmdSz, camPts[1], trPtsCnt , tr2pmdIdxs, pts3DStatus[1], pmdc->sigmaDepth , pmdc->dpThreshold, pmdc->sigmaColor); pairs.clear(); double centroidM[3] = {0.0, 0.0, 0.0}; double centroidD[3] = {0.0, 0.0, 0.0}; double pt1[3]; double pt2[3]; for(int i = 0; i < trPtsCnt; i++) if(pts3DStatus[1][i] && pts3DStatus[0][i]) { pt1[0] = camPts3D[0][i].x; pt1[1] = camPts3D[0][i].y; pt1[2] = camPts3D[0][i].z; pt2[0] = camPts3D[1][i].x; pt2[1] = camPts3D[1][i].y; pt2[2] = camPts3D[1][i].z; //TODO can be fused -- (+=) :: a -> a -> a centroidM[0] += camPts3D[0][i].x; centroidM[1] += camPts3D[0][i].y; centroidM[2] += camPts3D[0][i].z; centroidD[0] += camPts3D[1][i].x; centroidD[1] += camPts3D[1][i].y; centroidD[2] += camPts3D[1][i].z; PtPair currentPair(pt1, pt2); pairs.push_back(currentPair); } reprojected = pairs.size(); if(reprojected >= pmdc->minPts4Pose) { // enough corresponding points centroidM[0] /= reprojected; centroidM[1] /= reprojected; centroidM[2] /= reprojected; centroidD[0] /= reprojected; centroidD[1] /= reprojected; centroidD[2] /= reprojected; double transformMat[16]; try { alignError = pmdc->icp->Point_Point_Align(pairs, transformMat, centroidM, centroidD); } catch(...) { fprintf(stderr, "ERROR: matrix is singular!\n"); } if(!gl) printf( "%i: align error: %f, 3d pts count: %i, 2d pts count: %i\n" , frames, alignError, reprojected, trPtsCnt); for(int i = 1; i < 16; i++) if (i%4 > 2) continue; // bottom row else if(i/4 > 2) CV_MAT_ELEM(*trnGuess, float, i%4, 0) = transformMat[i]; else CV_MAT_ELEM(*rotMatGuess, float, i/4, i%4) = transformMat[i]; // right col cvRodrigues2(rotMatGuess, rotGuess, NULL); if(alignError < pmdc->maxError) poseEstimated = true; } } /**** Print pose to file ****/ //TODO: config option if(pmdc->savePoses) { char filename[] = "./dat/scan0000.pose"; sprintf(filename, "./dat/scan%04d.pose", frames); FILE *pose = fopen(filename, "wb"); if(!pose) fprintf(stderr, "cant create file %s!\n", filename); if(poseEstimated) { fprintf(pose, "%f %f %f\n%f %f %f\n" , 100.0*CV_MAT_ELEM(*rotGuess, float, 0, 0) , 100.0*CV_MAT_ELEM(*rotGuess, float, 0, 0) , 100.0*CV_MAT_ELEM(*rotGuess, float, 0, 0) , 100.0*CV_MAT_ELEM(*trnGuess, float, 0, 0) , 100.0*CV_MAT_ELEM(*trnGuess, float, 1, 0) , 100.0*CV_MAT_ELEM(*trnGuess, float, 2, 0)); goodFrames++; } else { fprintf( stderr, "ERROR: %i points found, align error: %f\n" , reprojected, alignError); fprintf(pose, "%f %f %f\n%f %f %f\n", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } fflush(pose); fclose(pose); } frames++; /***** find features *****/ if(trPtsCnt < pmdc->_track.minFeatures) { int trPtsCntFound = featuresMax - trPtsCnt; cvSet(mask, cvScalarAll(255)); for(int i = 0; i < trPtsCnt; i++) cvCircle(mask, cvPointFrom32f(camPts[1][i]), 20, CV_RGB(0,0,0), -1, 8, 0); cvGoodFeaturesToTrack( pmdc->iCam, eig, tmp, camPts[1] + trPtsCnt, &trPtsCntFound , pmdc->_track.quality, pmdc->_track.minDist, mask, 3, 0, 0.04); cvFindCornerSubPix( pmdc->iCam, camPts[1] + trPtsCnt, trPtsCntFound , cvSize(pmdc->_track.winSz,pmdc->_track.winSz), cvSize(-1,-1) , cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03)); trPtsCnt += trPtsCntFound; } Frame *f = allocFrame3DData(pmdSz); fillFrame(f, pmdc->iCamColor, pmdSz, pmdc->pts, pmd2imgIdxs, rotGuess, trnGuess, alignError); history = addFrame(history, f); checkHistoryLen(history, pmdc->historyLen); bool pause = false; do { /***** ui and rendring *****/ if(gl) render( history, trackedPts, trPtsCnt , rot, trn, camPts3D, pts3DStatus , reprojected, poseEstimated); if(ui) { for(int i = 0; i < trPtsCnt; i++) cvCircle( pmdc->iCamColor, cvPointFrom32f(camPts[1][i]) , 3, CV_RGB(255,0,255), -1, 8, 0); cvShowImage("PMD", pmdc->iPMDI); cvShowImage("Cam", pmdc->iCamColor); } int key = cvWaitKey(5); if(27 == key) return 0; // ESC pressed FIXME: release stuff if((int)' ' == key) pause = !pause; if(gl) if(glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) return 0; //in OpenGL window ;) } while(pause); CV_SWAP(imgCamPrv, pmdc->iCam, swapTemp); CV_SWAP(imgCamPyrPrv, imgCamPyr, swapTemp); CV_SWAP(camPts[0], camPts[1], swapPts); CV_SWAP(camPts3D[0], camPts3D[1], swapPts3); CV_SWAP(pts3DStatus[0], pts3DStatus[1], swapStatus); } // while(1) // let OS clean all images and matrices // TODO: releasePMD(&pmd); if(gl) { glfwTerminate(); } printf("%i good frames, %i frames total.\n", goodFrames, frames); return 0; } // Global rendering settings float rotx = 0; float roty = 0; float rotz = 0; float scale = 0.7; int renderCoords = 1; int renderCams = 1; int renderColorPts = 1; int renderLines = 0; int renderTracked = 1; int renderHistory = 1; int centerCloud = 0; void renderFrame(Frame *f) { assert(f->img->imageData); glBegin(GL_POINTS); if(!renderColorPts) { //FIXME: mess with the indices (i,j) for(int j = 0; j < f->sz.width; j++) for(int i = 0; i < f->sz.height; i++) glVertex3f(f->pts[i][j].x, f->pts[i][j].y, f->pts[i][j].z); glEnd(); } else { uchar *imgCamPix = 0; for(int j = 0; j < f->sz.width; j++) for(int i = 0; i < f->sz.height; i++) { int x = f->status[i][j].x; int y = f->status[i][j].y; if(x > 0) { imgCamPix = &((uchar*) (f->img->imageData + f->img->widthStep * y))[x*3]; glColor3f( ((float)imgCamPix[2])/255.0 , ((float)imgCamPix[1])/255.0 , ((float)imgCamPix[0])/255.0); //BGR } else glColor3f(1.0, 0.0, 0.0); glVertex3f(f->pts[i][j].x, f->pts[i][j].y, f->pts[i][j].z); } } // if renderColorPts else } void render( History *history, CvPoint3D32f *camPts, int trPtsCnt , CvMat *rot, CvMat *trn , CvPoint3D32f **camPts3D, char **pts3DStatus , int reprojected, bool poseEstimated) { if(glfwGetKey((int)'W') == GLFW_PRESS) roty += 10.0; if(glfwGetKey((int)'S') == GLFW_PRESS) roty -= 10.0; if(glfwGetKey((int)'A') == GLFW_PRESS) rotx -= 10.0; if(glfwGetKey((int)'D') == GLFW_PRESS) rotx += 10.0; if(glfwGetKey((int)'Q') == GLFW_PRESS) rotz -= 10.0; if(glfwGetKey((int)'E') == GLFW_PRESS) rotz += 10.0; if(glfwGetKey((int)'R') == GLFW_PRESS) scale -= 0.1; if(glfwGetKey((int)'F') == GLFW_PRESS) scale += 0.1; if(glfwGetKey((int)'1') == GLFW_PRESS) renderCoords = !renderCoords; if(glfwGetKey((int)'2') == GLFW_PRESS) renderCams = !renderCams; if(glfwGetKey((int)'3') == GLFW_PRESS) renderColorPts = !renderColorPts; if(glfwGetKey((int)'4') == GLFW_PRESS) renderLines = !renderLines; if(glfwGetKey((int)'5') == GLFW_PRESS) renderTracked = !renderTracked; if(glfwGetKey((int)'6') == GLFW_PRESS) renderHistory = !renderHistory; if(glfwGetKey((int)'C') == GLFW_PRESS) centerCloud = !centerCloud; int width, height; GLUquadric *quadric; glfwGetWindowSize(&width, &height); height = height < 1 ? 1 : height; glViewport(0, 0, width, height); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70, (double)width/(double)height, 0.01, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); int cj = history->frame->sz.width / 2; int ci = history->frame->sz.height / 2; CvPoint3D32f **pts = history->frame->pts; // gluLookAt(scale, scale, scale, // pts[ci][cj].x, pts[ci][cj].y, -pts[ci][cj].z, 0.0, 1.0, 0.0); gluLookAt(scale, scale, scale, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glScalef(1.0, 1.0, -1.0); // convert opengl coord system to left handed glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); /* text rendering */ char info[30]; FTPoint pt(5.0, 5.0); sprintf(info, "2D pts: %i", trPtsCnt); font->Render(info, -1, pt); pt.Y(35.0); sprintf(info, "3D pts: %i", reprojected); font->Render(info, -1, pt); pt.Y(65.0); sprintf(info, "Align error: %f", history->frame->alignError); font->Render(info, -1, pt); glRotatef(rotz, 0.0, 0.0, 1.0); glRotatef(roty, 0.0, 1.0, 0.0); glRotatef(rotx, 1.0, 0.0, 0.0); if(centerCloud) glTranslatef(-pts[ci][cj].x, -pts[ci][cj].y, -pts[ci][cj].z); /***** xyz axes *****/ if(renderCoords) { glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(1.0, 0.0, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(0.0, 1.0, 0.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 1.0); glEnd(); } /***** render PMD-points PMD-cam in the O *****/ fflush(stdout); renderFrame(history->frame); fflush(stdout); if(renderHistory) { fflush(stdout); History *histI = history; glPushMatrix(); //for(int i = 0; histI->prev; i++) { while(histI->prev) { glColor3f(1.0, 0.0, 0.0);//, (100.0-i)/100); assert(histI); //if(histI->frame->alignError < 0.03) { //FIXME_ hardcoded thrs glRotatef(-CV_MAT_ELEM(*histI->frame->rot, float, 0, 0), 1.0f, 0.0f, 0.0f); glRotatef(-CV_MAT_ELEM(*histI->frame->rot, float, 1, 0), 0.0f, 1.0f, 0.0f); glRotatef(-CV_MAT_ELEM(*histI->frame->rot, float, 2, 0), 0.0f, 0.0f, 1.0f); glTranslatef( -CV_MAT_ELEM(*histI->frame->trn, float, 0, 0) , -CV_MAT_ELEM(*histI->frame->trn, float, 1, 0) , -CV_MAT_ELEM(*histI->frame->trn, float, 2, 0)); //} histI = histI->prev; renderFrame(histI->frame); } glPopMatrix(); } quadric = gluNewQuadric(); if(renderCams) { glColor3f(0.5, 0.5, 0.0); glPushMatrix(); glScalef(1.0, 1.0, -1.0); // rotated cylinder gluCylinder(quadric, 0.05, 0.0, 0.05, 10, 10); glPopMatrix(); } /***** render Cam and features according to essential matrix [R|t] *****/ if(renderTracked) { glBegin(GL_LINES); for(int i = 0; i < trPtsCnt; i++) { if(pts3DStatus[1][i] && pts3DStatus[0][i]) { glColor3f(1.0, 0.0, 0.0); glVertex3f(camPts3D[0][i].x, camPts3D[0][i].y, camPts3D[0][i].z); glVertex3f(camPts3D[1][i].x, camPts3D[1][i].y, camPts3D[1][i].z); glColor3f(0.0, 0.0, 0.5); glPushMatrix(); glTranslatef(camPts3D[0][i].x, camPts3D[0][i].y, camPts3D[0][i].z); gluSphere(quadric, 0.005f, 10, 10); glPopMatrix(); glColor3f(0.5, 0.0, 1.0); glPushMatrix(); glTranslatef(camPts3D[1][i].x, camPts3D[1][i].y, camPts3D[1][i].z); gluSphere(quadric, 0.01f, 10, 10); glPopMatrix(); } } glEnd(); } glBegin(GL_LINES); for(int i = 0; i < trPtsCnt; i++) if(pts3DStatus[1][i] && pts3DStatus[0][i]) { glColor3f(1.0, 0.0, 0.0); glVertex3f(camPts3D[0][i].x, camPts3D[0][i].y, camPts3D[0][i].z); glVertex3f(camPts3D[1][i].x, camPts3D[1][i].y, camPts3D[1][i].z); } glEnd(); glPushMatrix(); glTranslatef( -CV_MAT_ELEM(*trn, float, 0, 0) , -CV_MAT_ELEM(*trn, float, 1, 0) , -CV_MAT_ELEM(*trn, float, 2, 0)); glRotatef(-CV_MAT_ELEM(*rot, float, 0, 0), 1.0f, 0.0f, 0.0f); glRotatef(-CV_MAT_ELEM(*rot, float, 1, 0), 0.0f, 1.0f, 0.0f); glRotatef(-CV_MAT_ELEM(*rot, float, 2, 0), 0.0f, 0.0f, 1.0f); if(renderCams) { glColor3f(0.0, 0.5, 0.5); glPushMatrix(); glScalef(1.0, 1.0, -1.0); gluCylinder(quadric, 0.05, 0.0, 0.05, 10, 10); glPopMatrix(); } if(renderLines) { glColor3f(1.0, 0.0, 1.0); glBegin(GL_LINES); for(int i = 0; i < trPtsCnt; i++) { glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(-camPts[i].x, camPts[i].y, camPts[i].z); //FIXME: revise coordinates! why -camPts?! } glEnd(); } glPopMatrix(); glPushMatrix(); glRotatef(CV_MAT_ELEM(*history->frame->rot, float, 2, 0), 0.0f, 0.0f, 1.0f); glRotatef(CV_MAT_ELEM(*history->frame->rot, float, 1, 0), 0.0f, 1.0f, 0.0f); glRotatef(CV_MAT_ELEM(*history->frame->rot, float, 0, 0), 1.0f, 0.0f, 0.0f); glTranslatef( CV_MAT_ELEM(*history->frame->trn, float, 0, 0) , CV_MAT_ELEM(*history->frame->trn, float, 1, 0) , CV_MAT_ELEM(*history->frame->trn, float, 2, 0)); if(poseEstimated) glColor3f(0.0, 0.0, 1.0); else glColor3f(0.0, 0.0, 0.3); //render pose and pmd cam glScalef(1.0, 1.0, -1.0); gluCylinder(quadric, 0.05, 0.0, 0.05, 10, 10); glColor4f(1.0, 0.0, 0.0, 0.5); gluSphere(quadric, history->frame->alignError, 20, 20); glPopMatrix(); gluDeleteQuadric(quadric); glfwSwapBuffers(); }