bool MFReconstruct::runReconstruction() { bool runSucess = false; ///加载相机标定参数及所采集图像 for(int i = 0; i < 2; i++){ camsPixels[i] = new cv::vector<double>[cameraHeight * cameraWidth];//将每个相机图像中的每个像素在投影区域中的横坐标记录 runSucess = loadCamImgs(scanFolder[i], imgPrefix[i], imgSuffix); ///对指针存储器camsPixels赋值,camsPixels[i]的地址就是camPixel的地址 camPixels = camsPixels[i]; ///截至这一步,实例camera的position、width、height属性已被赋值,camera对应cameras[i] if(!runSucess)//如果加载图片失败,中断 break; else{ computeShadows(); decodePatterns(); unloadCamImgs(); } } if(runSucess){ points3DProjView = new PointCloudImage(cameraWidth, cameraHeight, haveColor); //最后一个bool值代表是否上色,这里改为false triangulation(camsPixels[0],camsPixels[1]); } return runSucess; }
QcPolygonTriangulation::QcPolygonTriangulation(const QcPathDouble & path) : m_path(path) { int number_of_vertexes = path.number_of_vertexes(); int number_of_segments = number_of_vertexes -2; // Fixme: true ? double vertexes[number_of_vertexes][2]; int i = 0; for (const auto & vertex : path.vertexes()) { qInfo() << vertex; vertexes[i][0] = vertex.x(); vertexes[i][1] = vertex.y(); i++; } int triangles[number_of_segments][3]; for (int i = 0; i < number_of_segments; i++) { for (int j = 0; j < 3; j++) triangles[i][j] = 0; } QcSeidlerPolygonTriangulation triangulation(number_of_vertexes, vertexes, triangles); for (int i = 0; i < number_of_segments; i++) { qInfo() << triangles[i][0] << triangles[i][1] << triangles[i][2]; m_triangles << QcTriangleIndex(triangles[i][0] -1, triangles[i][1] -1, triangles[i][2] -1); } }
std::vector<int> collectInnerPointsIDs(std::vector<Point_3> points) { DEBUG_START; Delaunay::Lock_data_structure locking_ds( CGAL::Bbox_3(-1000., -1000., -1000., 1000., 1000., 1000.), 50); Delaunay triangulation(points.begin(), points.end(), &locking_ds); auto infinity = triangulation.infinite_vertex(); std::vector<int> outerPlanesIDs; int numPlanes = points.size(); for (int i = 0; i < numPlanes; ++i) { Point_3 point = points[i]; Delaunay::Locate_type lt; int li, lj; Delaunay::Cell_handle c = triangulation.locate(point, lt, li, lj); auto vertex = c->vertex(li); ASSERT(lt == Delaunay::VERTEX && vertex->point() == point); if (!triangulation.is_edge(vertex, infinity, c, li, lj)) { outerPlanesIDs.push_back(i); } } DEBUG_END; return outerPlanesIDs; }
tree<T,P,M,N,impl_type> & operator=(const graph<T,P,M,N, impl_type> &g) { typedef graph<T,P,M,N,impl_type> super; // we make first a copy of the graph where we subsequently apply "moralization" and "triangulation" super::operator=(g); moralization(); triangulation(); return *this; }
// This test case is based on the example presented on page 725 of the // paper: "Three dimensional triganulations from local transformations" // by Barry Joe (Siam J. Sci. Stat. Comput. Vol 10, No 4, 1989). void DelaunayTriangulationTest::joe89() { std::vector<chemkit::Point3> points; points.push_back(chemkit::Point3(0.054f, 0.099f, 0.993f)); points.push_back(chemkit::Point3(0.066f, 0.756f, 0.910f)); points.push_back(chemkit::Point3(0.076f, 0.578f, 0.408f)); points.push_back(chemkit::Point3(0.081f, 0.036f, 0.954f)); points.push_back(chemkit::Point3(0.082f, 0.600f, 0.726f)); points.push_back(chemkit::Point3(0.085f, 0.327f, 0.731f)); points.push_back(chemkit::Point3(0.123f, 0.666f, 0.842f)); points.push_back(chemkit::Point3(0.161f, 0.303f, 0.975f)); chemkit::DelaunayTriangulation triangulation(points); QCOMPARE(triangulation.vertexCount(), 8); QCOMPARE(triangulation.tetrahedronCount(), 13); QList<QVector<int> > expectedTetrahedra; expectedTetrahedra.append(QVector<int>() << 0 << 1 << 2 << 4); expectedTetrahedra.append(QVector<int>() << 0 << 1 << 4 << 5); expectedTetrahedra.append(QVector<int>() << 0 << 1 << 5 << 7); expectedTetrahedra.append(QVector<int>() << 0 << 2 << 3 << 5); expectedTetrahedra.append(QVector<int>() << 0 << 2 << 4 << 5); expectedTetrahedra.append(QVector<int>() << 0 << 3 << 5 << 7); expectedTetrahedra.append(QVector<int>() << 1 << 2 << 4 << 6); expectedTetrahedra.append(QVector<int>() << 1 << 4 << 5 << 7); expectedTetrahedra.append(QVector<int>() << 1 << 4 << 6 << 7); expectedTetrahedra.append(QVector<int>() << 2 << 3 << 5 << 7); expectedTetrahedra.append(QVector<int>() << 2 << 4 << 5 << 6); expectedTetrahedra.append(QVector<int>() << 2 << 5 << 6 << 7); expectedTetrahedra.append(QVector<int>() << 4 << 5 << 6 << 7); std::vector<std::vector<int> > tetrahedra = triangulation.tetrahedra(); QCOMPARE(tetrahedra.size(), size_t(expectedTetrahedra.size())); for(unsigned int i = 0; i < tetrahedra.size(); i++){ std::vector<int> tetrahedron = tetrahedra[i]; std::sort(tetrahedron.begin(), tetrahedron.end()); int foundCount = 0; for(int j = 0; j < expectedTetrahedra.size(); j++){ QVector<int> expectedTetrahedron = expectedTetrahedra[j]; if(tetrahedron == expectedTetrahedron.toStdVector()){ foundCount++; } } if(foundCount != 1){ qDebug() << "tetrahedron (index " << i << ") was not found. verticies: " << QVector<int>::fromStdVector(tetrahedron); } QCOMPARE(foundCount, 1); } }
void DelaunayTriangulationTest::serine() { // coordinates of the atoms std::vector<chemkit::Point3> points; points.push_back(chemkit::Point3(-0.1664, -1.0370, 0.4066)); points.push_back(chemkit::Point3(1.2077, -0.5767, -0.0716)); points.push_back(chemkit::Point3(-0.6079, -1.5894, -0.3173)); points.push_back(chemkit::Point3(1.1440, -0.3456, -1.0571)); points.push_back(chemkit::Point3(2.2495, -1.7077, 0.1008)); points.push_back(chemkit::Point3(1.6659, 0.7153, 0.7175)); points.push_back(chemkit::Point3(1.7844, 0.4727, 1.7759)); points.push_back(chemkit::Point3(0.8959, 1.5129, 0.6034)); points.push_back(chemkit::Point3(2.8918, 1.1700, 0.2007)); points.push_back(chemkit::Point3(3.1444, 1.9558, 0.6711)); points.push_back(chemkit::Point3(1.8101, -2.8570, 0.2804)); points.push_back(chemkit::Point3(3.4579, -1.3878, 0.0035)); points.push_back(chemkit::Point3(-0.0600, -1.6097, 1.2601)); points.push_back(chemkit::Point3(-0.7527, -0.2118, 0.6162)); // calculate delaunay triangulation chemkit::DelaunayTriangulation triangulation(points); QCOMPARE(triangulation.vertexCount(), 14); QCOMPARE(triangulation.edgeCount(), 60); QCOMPARE(triangulation.triangleCount(), 140); QCOMPARE(triangulation.tetrahedronCount(), 39); // weights (squared van der waals radii) std::vector<chemkit::Real> weights; weights.push_back(2.4025); weights.push_back(2.90); weights.push_back(1.44); weights.push_back(1.44); weights.push_back(2.90); weights.push_back(2.90); weights.push_back(1.44); weights.push_back(1.44); weights.push_back(2.3104); weights.push_back(1.44); weights.push_back(2.3104); weights.push_back(2.3104); weights.push_back(1.44); weights.push_back(1.44); // calculate weighted delaunay triangulation chemkit::DelaunayTriangulation weightedTriangulation(points, weights); QCOMPARE(weightedTriangulation.vertexCount(), 14); QCOMPARE(weightedTriangulation.edgeCount(), 60); QCOMPARE(weightedTriangulation.triangleCount(), 140); QCOMPARE(weightedTriangulation.tetrahedronCount(), 39); }
void StereoReconstructor::RestructPointCloud(bool objSpace, bool undistort, std::string pcfilename) { //载入2个虚拟摄像机 VirtualCamera vc1; VirtualCamera vc2; //载入内参 vc1.loadCameraMatrix("reconstruct\\LeftMatrix.txt"); vc1.loadDistortion("reconstruct\\LeftDistortion.txt"); vc1.rotationMatrix = cv::Mat::eye(3, 3, CV_32FC1); vc1.translationVector = cv::Mat::zeros(3, 1, CV_32FC1); vc2.loadCameraMatrix("reconstruct\\RightMatrix.txt"); vc2.loadDistortion("reconstruct\\RightDistortion.txt"); vc2.loadRotationMatrix("reconstruct\\R.txt"); vc2.loadTranslationVector("reconstruct\\T.txt"); vc1.loadKeyPoints("left.txt"); //载入角点 vc2.loadKeyPoints("right.txt"); //重建3d点 std::vector<RestructPoint> ret; ret = triangulation(vc1, vc2, undistort); //true进行畸变矫正,false表示不进行 //保存结果 std::vector<StereoReconstructor::RestructPoint> ans; for (size_t i = 0; i != ret.size(); ++i) ans.push_back(StereoReconstructor::RestructPoint(ret[i].point, ret[i].distance)); plyFileGenerate(ans, pcfilename, //ply文件 "_calPointsDis.txt", //3d点+相交距离 "_calPoints.txt"); //3d点 //转换到物体坐标系 if (objSpace) { translateCoordinate( "Coordinate.txt", //棋盘格坐标系 "_calPoints.txt", //要转换的3D点 "Points_obj.txt"); //在棋盘格坐标系下的坐标calPoints_ObjSpace.txt //生成物体坐标系下的ply文件 std::vector<cv::Point3f> pointcloud = Utilities::load3dPoints("Points_obj.txt"); Utilities::savePly(pointcloud, "PointsObj.ply"); } }
bool NNormalSurfaceList::saveCSVEdgeWeight(const char* filename, int additionalFields) { std::ofstream out(filename); if (! out) return false; unsigned long n = triangulation()->countEdges(); unsigned long i, j; // Write the CSV header. writePropHeader(out, additionalFields); for (i = 0; i < n; ++i) { out << 'E' << i; if (i < n - 1) out << ','; } out << std::endl; // Write the data for individual surfaces. unsigned long tot = size(); const NNormalSurface* s; for (i = 0; i < tot; ++i) { s = surface(i); writePropData(out, s, additionalFields); for (j = 0; j < n; ++j) { out << s->edgeWeight(j); if (j < n - 1) out << ','; } out << std::endl; } // All done! return true; }
void Reconstructor::runReconstruction() { for(int i=0; i< numOfCams; i++) { if(cameras[i].distortion.empty()) { std::cout<<"Camera "<<i<< "is not set.\n"; exit(-1); } if(pathSet[i] == false) { std::cout<<"Image path for camera "<< i <<" is not set."; exit(-1); } } GrayCodes grays(proj_w,proj_h); numOfColBits = grays.getNumOfColBits(); numOfRowBits = grays.getNumOfRowBits(); numberOfImgs = grays.getNumOfImgs(); for(int i=0; i < numOfCams; i++) { //findProjectorCenter(); cameras[i].position = cv::Point3f(0,0,0); cam2WorldSpace(cameras[i],cameras[i].position); camera = &cameras[i]; camsPixels[i] = new cv::vector<cv::Point>[proj_h*proj_w]; camPixels = camsPixels[i]; loadCamImgs(camFolder[i],imgPrefix[i],imgSuffix[i]); colorImgs.push_back(cv::Mat()); colorImgs[i] = color; computeShadows(); if(saveShadowMask_) { std::stringstream path; path<<"cam"<<i+1<<"Mask.png"; saveShadowImg(path.str().c_str()); } decodePaterns(); unloadCamImgs(); } //reconstruct points3DProjView = new PointCloudImage( proj_w, proj_h , true ); for(int i = 0; i < numOfCams; i++) { for(int j=i+1; j< numOfCams; j++) triangulation(camsPixels[i],cameras[i],camsPixels[j],cameras[j],i,j); } }
/** * Function for reading the input from a OFF file. * @param *infile FILE, the file to be read. * @param NVertices int, the number of vertices. * @param NFaces int, the total amount of faces. * @param NEdges int, the total amount of edges. * @param *allVectors, one pointer to one array of struct type myVector. * @return a pointer to a triangledFaces struct. */ triangledFaces *readFromFile(FILE *inFile, int NVertices, int NFaces, int NEdges, myVector *allVectors, objectData *allData){ setlocale(LC_ALL,"C"); char readLine[256], *temp; int i,j, colorCounter, totNrOfTriangles = 0; faces *(allFaces[NFaces]); /*reading and storing all the vertices.*/ for(i=0;i<NVertices;i++){ fgets(readLine,256,inFile); /*dont read lines that doesn't contain anything.*/ if(strlen(readLine)>2){ //putting in the vector values in a struct. sscanf(readLine,"%f%f%f",&allVectors[i].x,&allVectors[i].y, &allVectors[i].z); /*saving the smallest/biggest values for calculating the origo.*/ if(allVectors[i].x > allData->biggestX){ allData->biggestX = allVectors[i].x; } if(allVectors[i].x < allData->smallestX){ allData->smallestX = allVectors[i].x; } if(allVectors[i].y > allData->biggestY){ allData->biggestY = allVectors[i].y; } if(allVectors[i].y < allData->smallestY){ allData->smallestY = allVectors[i].y; } if(allVectors[i].z > allData->biggestZ){ allData->biggestZ = allVectors[i].z; } if(allVectors[i].z < allData->smallestZ){ allData->smallestZ = allVectors[i].z; } }else{ i--; } } /*allocating and calculating the origo for the object (a + ((b-a)/2) ).*/ allData->origoForObject = (myVector*) malloc(sizeof(myVector)); allData->origoForObject->x = (allData->smallestX + ((allData->biggestX-allData->smallestX)/2)); allData->origoForObject->y = (allData->smallestY + ((allData->biggestY-allData->smallestY)/2)); allData->origoForObject->z = (allData->smallestZ + ((allData->biggestZ-allData->smallestZ)/2)); /*getting all the edges*/ for (i=0;i<NFaces;i++){ fgets(readLine,256,inFile); faces *oneFace = (faces*) malloc(sizeof(faces)); //putting all the edge values in a struct. observe token=space and tab. temp = strtok(readLine," \t"); oneFace-> nrOfvertices = atoi(temp); totNrOfTriangles = totNrOfTriangles + (atoi(temp) -2); //make sure that the polygon values fits in array vertices[]. if(oneFace->nrOfvertices < 128){ for(j=0;j<(oneFace->nrOfvertices);j++){ temp = strtok(NULL," \t"); oneFace->vertices[j] = &allVectors[atoi(temp)]; oneFace->vertexIndeces[j] = atoi(temp); } colorCounter = 0; //reading in color (if any). while((temp = strtok(NULL," ")) != NULL){ oneFace->colours[colorCounter] = atof(temp); colorCounter++; } allFaces[i] = oneFace; }else{ printf("ERROR! one polygon has too many vertices "); printf("to fit in the program.\n"); printf("closing program.\n"); return NULL; } } triangledFaces *triangles = (triangledFaces*) calloc(totNrOfTriangles, sizeof (triangledFaces)); //call function for triangulation. triangulation(allFaces, NFaces, triangles); nrOfTrianglePolygons = totNrOfTriangles; return triangles; }
bool NNormalSurfaceList::saveCSVStandard(const char* filename, int additionalFields) { std::ofstream out(filename); if (! out) return false; unsigned long n = triangulation()->size(); unsigned long i, j; // Write the CSV header. writePropHeader(out, additionalFields); for (i = 0; i < n; ++i) { out << 'T' << i << ":0,"; out << 'T' << i << ":1,"; out << 'T' << i << ":2,"; out << 'T' << i << ":3,"; out << 'Q' << i << ":01/23,"; out << 'Q' << i << ":02/13,"; out << 'Q' << i << ":03/12"; if (! allowsAlmostNormal()) { if (i < n - 1) out << ','; continue; } out << ','; out << 'K' << i << ":01/23,"; out << 'K' << i << ":02/13,"; out << 'K' << i << ":03/12"; if (i < n - 1) out << ','; } out << std::endl; // Write the data for individual surfaces. unsigned long tot = size(); const NNormalSurface* s; for (i = 0; i < tot; ++i) { s = surface(i); writePropData(out, s, additionalFields); for (j = 0; j < n; ++j) { out << s->triangles(j, 0) << ','; out << s->triangles(j, 1) << ','; out << s->triangles(j, 2) << ','; out << s->triangles(j, 3) << ','; out << s->quads(j, 0) << ','; out << s->quads(j, 1) << ','; out << s->quads(j, 2); if (! allowsAlmostNormal()) { if (j < n - 1) out << ','; continue; } out << ','; out << s->octs(j, 0) << ','; out << s->octs(j, 1) << ','; out << s->octs(j, 2); if (j < n - 1) out << ','; } out << std::endl; } // All done! return true; }
void StereoReconstructor::RestructCalibrationPointsFromImage(std::string leftFilename, std::string rightFilename, int x, int y, int squareLength) { //计算角点 bool f1, f2; CameraCalibration::findCorners(leftFilename, f1, x, y); CameraCalibration::findCorners(rightFilename, f2, x, y); if (!f1 || !f2) { std::cout << "角点没找到" << std::endl; return; } //载入2个虚拟摄像机 VirtualCamera vc1; VirtualCamera vc2; //载入内参 vc1.loadCameraMatrix("reconstruct\\LeftMatrix.txt"); vc1.loadDistortion("reconstruct\\LeftDistortion.txt"); vc1.rotationMatrix = cv::Mat::eye(3, 3, CV_32FC1); vc1.translationVector = cv::Mat::zeros(3, 1, CV_32FC1); vc2.loadCameraMatrix("reconstruct\\RightMatrix.txt"); vc2.loadDistortion("reconstruct\\RightDistortion.txt"); vc2.loadRotationMatrix("reconstruct\\R.txt"); vc2.loadTranslationVector("reconstruct\\T.txt"); //载入角点 vc1.loadKeyPoints(leftFilename + "_imgCorners.txt"); vc2.loadKeyPoints(rightFilename + "_imgCorners.txt"); //重建3d点 std::vector<RestructPoint> ret; ret = triangulation(vc1, vc2, true); //进行畸变矫正,false表示不进行 //保存结果 //生成点云文件 plyFileGenerate(ret, leftFilename + ".ply", //ply文件 "_calPointsDis.txt", //3d点+相交距离 "_calPoints.txt"); //3d点 //评估长度误差 resultEvaluate(ret, "_calLineLength.txt", //157条线段的误差calLineLength.txt "_calLineLengthDist.txt", //线段的长度的概率分布 x, y, squareLength); //计算棋盘格坐标系 computeCoordinate( "_calPoints.txt", //读取棋盘格坐标 "_coordinate.txt", //计算坐标系,保存到Coordinate.txt x, y); //水平方向和垂直方向的角点个数 //转换到棋盘格坐标系 translateCoordinate( "_coordinate.txt", //棋盘格坐标系 "_calPoints.txt", //要转换的3D点 "_calPoints_ObjSpace.txt"); //在棋盘格坐标系下的坐标calPoints_ObjSpace.txt //生成物体坐标系下的ply文件 std::vector<cv::Point3f> pointcloud = Utilities::load3dPoints("_calPoints_ObjSpace.txt"); Utilities::savePly(pointcloud, "ObjSpace" + leftFilename + ".ply"); //生成棋盘格物体空间坐标,并载入 Utilities::generateObjCorners("_chessbordCorner.txt", x, y, squareLength); std::vector<cv::Point3f> ideaPts = Utilities::load3dPoints("_chessbordCorner.txt"); std::vector<cv::Point3f> realPts = Utilities::load3dPoints("_calPoints_ObjSpace.txt"); //计算到角点的绝对距离,并保存 std::ofstream absDis("_absCornerDistance.txt"); for (int i = 0; i < ideaPts.size(); i++) { cv::Point3f idea = ideaPts[i]; cv::Point3f real = realPts[i]; float dis = cv::norm((idea - real)); absDis << dis << std::endl; } absDis.close(); }
void mousePtPlot(GLint button, GLint action, GLint xMouse, GLint yMouse){ EDGE *ptr; int j=0; PLG *PLGptr; if(flag == 9) return; //按下左鍵 if(button == GLUT_LEFT_BUTTON && action == GLUT_DOWN){ //第二個點 if(flag == 1){ //存入邊 listhead = listLink(listhead, ¤t, previousX, previousY, xMouse, winHeight - yMouse, 1); counti++; //畫出外框 glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINES); glVertex2i(previousX, previousY); glVertex2i(xMouse, winHeight - yMouse); glEnd(); } //第一個點 if(flag == 0){ //紀錄起始點 startX = xMouse; startY = winHeight - yMouse; flag = 1; } //紀錄上一個點 else if(flag == 4){ printf("triangle start\n"); PLGptr = polygonlist; for(j=1;;j++){ triangulation(PLGptr->list, trianglehead); PLGptr = PLGptr->next; if(PLGptr == NULL) break; } PrintTRG(trianglehead); glFlush(); printf("triangle finish\n"); flag = 5; } else if(flag == 5){ printf("drawing start\n"); fillcollor(trianglehead); printf("drawing finish\n"); flag = 9; } if(flag != 5 || flag != 9){ previousX = xMouse; previousY = winHeight - yMouse; plotPoint(xMouse, winHeight - yMouse); } if(flag == 3) flag = 4; } //按下右鍵 if(button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN && doneflag == 0){ //把最後一個點和起始點連接 listhead = listLink(listhead, ¤t, previousX, previousY,startX, startY, 1); polygonlist = polygon_link(polygonlist, listhead, &PLGcurrent); glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINES); glVertex2i(previousX, previousY); glVertex2i(startX, startY); glEnd(); flag = 4; //畫出外框 glFlush(); printf("draw contour finish\n"); doneflag = 1; } glFlush(); }
/* Function: main * * Description: Main function to extract frames from 2 video files and runs the * rest of the program using them. Takes at least 10 commandline arguments, * in the order: * <number of camera pairs> * <pair 1 camera 1 filename> * <pair 1 camera 1 frame number> * <pair 1 camera 2 filename> * <pair 1 camera 2 frame number> * <pair 1 view name> * <pair 1 camera coefficients filename> * ... * <TPS smoothing parameter> * <feature detector> * <output directory> * * Parameters: * argc: number of commandline arguments * argv: string array of commandline arguments * * Returns: 0 on success, 1 on error. */ int main (int argc, char *argv[]) { // check for minimum number of commandline arguments if (argc < 11) { printf("Usage:\nvideos\n\t<number of camera pairs>\n\t<pair 1 camera 1 filename>\n\t<pair 1 camera 1 frame number>\n\t<pair 1 camera 2 filename>\n\t<pair 1 camera 2 frame number>\n\t<pair 1 view name>\n\t<pair 1 camera coefficients filename>\n\t...\n\t<TPS smoothing parameter>\n\t<feature detector>\n\t<output directory>\n"); exit(1); } // get the number of camera pairs int numCameraPairs = atoi(argv[1]); if (numCameraPairs <= 0) { printf("Invalid number of camera pairs.\n"); exit(1); } // number of commandline arguments should be numCameraPairs*6 + 5 if (argc != numCameraPairs*6 + 5) { printf("Usage:\nvideos\n\t<number of camera pairs>\n\t<pair 1 camera 1 filename>\n\t<pair 1 camera 1 frame number>\n\t<pair 1 camera 2 filename>\n\t<pair 1 camera 2 frame number>\n\t<pair 1 view name>\n\t<pair 1 camera coefficients filename>\n\t...\n\t<TPS smoothing parameter>\n\t<feature detector>\n\t<output directory>\n"); exit(1); } // allocate memory to store information for camera pairs char **camera1Filenames = (char **)malloc(numCameraPairs * sizeof(char *)); int *camera1Frames = (int *)malloc(numCameraPairs * sizeof(int)); if (camera1Filenames == NULL || camera1Frames == NULL) { printf("Out of memory error.\n"); exit(1); } char **camera2Filenames = (char **)malloc(numCameraPairs * sizeof(char *)); int *camera2Frames = (int *)malloc(numCameraPairs * sizeof(int)); if (camera2Filenames == NULL || camera2Frames == NULL) { printf("Out of memory error.\n"); exit(1); } char **cameraNames = (char **)malloc(numCameraPairs * sizeof(char *)); if (cameraNames == NULL) { printf("Out of memory error.\n"); exit(1); } char **cameraCoefficientsFilenames = (char **)malloc(numCameraPairs * sizeof(char *)); if (cameraCoefficientsFilenames == NULL) { printf("Out of memory error.\n"); exit(1); } int argIndex = 2; for (int i = 0; i < numCameraPairs; i++) { camera1Filenames[i] = argv[argIndex]; camera1Frames[i] = atoi(argv[argIndex+1]); camera2Filenames[i] = argv[argIndex+2]; camera2Frames[i] = atoi(argv[argIndex+3]); cameraNames[i] = argv[argIndex+4]; cameraCoefficientsFilenames[i] = argv[argIndex+5]; // make sure input video frames are valid if (camera1Frames[i] <= 0) { printf("Invalid frame number for pair %d camera 1.\n", i+1); exit(1); } if (camera2Frames[i] <= 0) { printf("Invalid frame number for pair %d camera 1.\n", i+1); exit(1); } // make sure input filenames are valid if (!fileExists(camera1Filenames[i])) { printf("Could not open pair %d camera 1 video file.\n", i+1); exit(1); } if (!fileExists(camera2Filenames[i])) { printf("Could not open pair %d camera 2 video file.\n", i+1); exit(1); } if (!fileExists(cameraCoefficientsFilenames[i])) { printf("Could not open pair %d camera coefficients file.\n", i+1); exit(1); } argIndex += 6; } double regularization = atof(argv[argIndex]); char *featureDetector = argv[argIndex+1]; char *outputDirectory = argv[argIndex+2]; // make sure input feature dectector is recognized if (strcasecmp(featureDetector, FAST_FEATURE_DETECTOR) && strcasecmp(featureDetector, GFTT_FEATURE_DETECTOR) && strcasecmp(featureDetector, SURF_FEATURE_DETECTOR) && strcasecmp(featureDetector, SIFT_FEATURE_DETECTOR) && strcasecmp(featureDetector, SPEEDSIFT_FEATURE_DETECTOR)) { printf("Feature Detector not recognized. Please select from the following:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", FAST_FEATURE_DETECTOR, GFTT_FEATURE_DETECTOR, SURF_FEATURE_DETECTOR, SIFT_FEATURE_DETECTOR, SPEEDSIFT_FEATURE_DETECTOR); exit(1); } // make sure regularization parameter for TPS is valid if (regularization <= 0.0 || regularization == HUGE_VAL) { printf("Invalid smoothing parameter value.\n"); exit(1); } // if output directory doesn't end with '/' char, append '/' to the string. // this is so we can later append a filename to the directory when we want // to write the file to that directory if (outputDirectory[strlen(outputDirectory)-1] != '/') { strcat(outputDirectory, "/"); } DIR *dir = opendir(outputDirectory); // if output directory does not exist, create it with correct permissions if (dir == NULL) { printf("Output directory does not exist.\n"); if (mkdir(outputDirectory, S_IRWXO | S_IRWXG | S_IRWXU)) { printf("Could not create output directory.\n"); exit(1); } else { printf("Created output directory.\n"); } } else { closedir(dir); } // string for the MATLAB commands char command[500]; Engine *matlabEngine; // open MATLAB engine if (!(matlabEngine = engOpen("\0"))) { printf("Can't start MATLAB engine\n"); exit(1); } // create MATLAB arrays to retrieve values from MATLAB workspace mxArray **c1ImageData = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); mxArray **c1ImageDimensions = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); mxArray **c1ImagePaddedWidths = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); if (c1ImageData == NULL || c1ImageDimensions == NULL || c1ImagePaddedWidths == NULL) { printf("Out of memory error.\n"); exit(1); } mxArray **c2ImageData = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); mxArray **c2ImageDimensions = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); mxArray **c2ImagePaddedWidths = (mxArray **)malloc(numCameraPairs * sizeof(mxArray *)); if (c2ImageData == NULL || c2ImageDimensions == NULL || c2ImagePaddedWidths == NULL) { printf("Out of memory error.\n"); exit(1); } // create IplImage arrays for camera 1 and 2 images for all camera pairs IplImage **c1Images = (IplImage **)malloc(numCameraPairs * sizeof(IplImage *)); IplImage **c2Images = (IplImage **)malloc(numCameraPairs * sizeof(IplImage *)); if (c1Images == NULL || c2Images == NULL) { printf("Out of memory error.\n"); exit(1); } // for each camera pair, get the specified frames from cameras 1 and 2, using // MATLAB functions for (int i = 0; i < numCameraPairs; i++) { char video1Extension[6]; // get the video file extension for the first video file if (getVideoFileExtension(camera1Filenames[i], video1Extension) == INVALID_VIDEO_FILE_EXTENSION_ERROR) { printf("Video files must be of extension .mrf or .cine.\n"); exit(1); } // call appropriate MATLAB function depending on whether video file is .cine // or .mrf to extract the frame as a MATLAB image. If neither, error. if ((strcasecmp(video1Extension, ".cine") == 0) || (strcasecmp(video1Extension, ".cin") == 0)) { sprintf(command, "c1 = cineRead('%s', %d);", camera1Filenames[i], camera1Frames[i]); engEvalString(matlabEngine, command); } else if (strcasecmp(video1Extension, ".mrf") == 0) { sprintf(command, "c1 = mrfRead('%s', %d);", camera1Filenames[i], camera1Frames[i]); engEvalString(matlabEngine, command); } else { printf("Videos must be of extension .mrf or .cine.\n"); exit(1); } char video2Extension[6]; // get the video file extension for the second video file if (getVideoFileExtension(camera2Filenames[i], video2Extension) == INVALID_VIDEO_FILE_EXTENSION_ERROR) { printf("Video files must be of extension .mrf or .cine.\n"); exit(1); } // call appropriate MATLAB function depending on whether video file is .cine // or .mrf to extract the frame as a MATLAB image. If neither, error. if ((strcasecmp(video2Extension, ".cine") == 0) || (strcasecmp(video2Extension, ".cin") == 0)) { sprintf(command, "c2 = cineRead('%s', %d);", camera2Filenames[i], camera2Frames[i]); engEvalString(matlabEngine, command); } else if (strcasecmp(video2Extension, ".mrf") == 0) { sprintf(command, "c2 = mrfRead('%s', %d);", camera2Filenames[i], camera2Frames[i]); engEvalString(matlabEngine, command); } else { printf("Videos must be of extension .mrf or .cine.\n"); exit(1); } // call MATLAB function convert_image_matlab2cv_gs on MATLAB images to convert // them into a format that will be compatible with the IplImages of OpenCV sprintf(command, "[c1_img c1_dim c1_padded_width] = convert_image_matlab2cv_gs(c1);"); engEvalString(matlabEngine, command); sprintf(command, "[c2_img c2_dim c2_padded_width] = convert_image_matlab2cv_gs(c2);"); engEvalString(matlabEngine, command); // retrieve the image data, image dimensions, and image padded width variables // from MATLAB for both camera images c1ImageData[i] = engGetVariable(matlabEngine, "c1_img"); c1ImageDimensions[i] = engGetVariable(matlabEngine, "c1_dim"); c1ImagePaddedWidths[i] = engGetVariable(matlabEngine, "c1_padded_width"); c2ImageData[i] = engGetVariable(matlabEngine, "c2_img"); c2ImageDimensions[i] = engGetVariable(matlabEngine, "c2_dim"); c2ImagePaddedWidths[i] = engGetVariable(matlabEngine, "c2_padded_width"); if (c1ImageData[i] == NULL || c1ImageDimensions[i] == NULL || c1ImagePaddedWidths[i] == NULL) { printf("Could not retrieve all necessary information for pair %d camera 1 frame %d from MATLAB.\n", i+1, camera1Frames[i]); exit(1); } if (c2ImageData[i] == NULL || c2ImageDimensions[i] == NULL || c2ImagePaddedWidths[i] == NULL) { printf("Could not retrieve all necessary information for pair %d camera 2 frame %d from MATLAB.\n", i+1, camera2Frames[i]); exit(1); } int c1Status, c2Status; ImageInfo c1ImageInfo, c2ImageInfo; // extract the image information from the MATLAB variables in the form of // mxArrays, and store in ImageInfo structs c1Status = getInputImageInfo(&c1ImageInfo, c1ImageData[i], c1ImageDimensions[i], c1ImagePaddedWidths[i]); c2Status = getInputImageInfo(&c2ImageInfo, c2ImageData[i], c2ImageDimensions[i], c2ImagePaddedWidths[i]); if (c1Status == IMAGE_INFO_DATA_ERROR) { printf("Pair %d camera 1: Images must have two dimensions.\n", i+1); exit(1); } if (c2Status == IMAGE_INFO_DATA_ERROR) { printf("Pair %d camera 2: Images must have two dimensions.\n", i+1); exit(1); } if (c1Status == IMAGE_INFO_DIMENSIONS_ERROR) { printf("Pair %d camera 1: Image dimension vectors must contain two elements: [width, height].\n", i+1); exit(1); } if (c2Status == IMAGE_INFO_DIMENSIONS_ERROR) { printf("Pair %d camera 2: Image dimension vectors must contain two elements: [width, height].\n", i+1); exit(1); } if (c1Status == IMAGE_INFO_PADDED_WIDTH_ERROR) { printf("Pair %d camera 1: Padded image widths must be scalars.\n", i+1); exit(1); } if (c2Status == IMAGE_INFO_PADDED_WIDTH_ERROR) { printf("Pair %d camera 2: Padded image widths must be scalars.\n", i+1); exit(1); } if (c1Status == IMAGE_DEPTH_ERROR) { printf("Pair %d camera 1: Images must be represented by 8 or 16-bit integers.\n", i+1); exit(1); } if (c2Status == IMAGE_DEPTH_ERROR) { printf("Pair %d camera 2: Images must be represented by 8 or 16-bit integers.\n", i+1); exit(1); } // create IplImages using values in ImageInfo structs c1Status = createIplImageFromImageInfo(&(c1Images[i]), c1ImageInfo); c2Status = createIplImageFromImageInfo(&(c2Images[i]), c2ImageInfo); if (c1Status == OUT_OF_MEMORY_ERROR || c2Status == OUT_OF_MEMORY_ERROR) { printf("Out of memory error.\n"); exit(1); } // flip the images over the y-axis to compensate for the differences in axial // labels between MATLAB and OpenCV (camera coefficients would not correctly // correspond to image otherwise) cvFlip(c1Images[i], NULL, 1); cvFlip(c2Images[i], NULL, 1); } char errorMessage[500]; int numContours; char **contourNames; CvPoint3D32f **features3D; char **validFeatureIndicator; int *numFeaturesInContours; char contoursFilename[MAX_FILENAME_LENGTH]; // for each camera pair, run features and triangulation for (int i = 0; i < numCameraPairs; i++) { // create the output 2D features filename as "frame<frame number>_features2D_<camera name>.txt" char features2DFilename[MAX_FILENAME_LENGTH]; sprintf(features2DFilename, "%sframe%d_features2D_%s.txt", outputDirectory, camera1Frames[i], cameraNames[i]); // create the output contours filename as "frame<frame number>_contours_<camera name>.txt" char tempContoursFilename[MAX_FILENAME_LENGTH]; sprintf(tempContoursFilename, "%sframe%d_contours_%s.txt", outputDirectory, camera1Frames[i], cameraNames[i]); printf("Camera pair for %s view:\n", cameraNames[i]); // run the features program to extract matching 2D features from the 2 // images within user defined contour if (features(c1Images[i], c2Images[i], features2DFilename, tempContoursFilename, featureDetector, errorMessage)) { printf("Features: %s\n", errorMessage); exit(1); } // we only need to save the contour(s) for the first camera pair, as that // is the one we will use to create the meshes, and we only use the contours // with the same name(s) in subsequent camera pairs if (i == 0) { strcpy(contoursFilename, tempContoursFilename); // get the contour names of the contours selected in features function for // output file naming and contour matching in other camera pairs int status = readContourNamesFromInputFile(&numContours, &contourNames, contoursFilename); if (status == INPUT_FILE_OPEN_ERROR) { printf("Could not open contour vertices file.\n"); exit(1); } if (status == INCORRECT_INPUT_FILE_FORMAT_ERROR) { printf("Contour vertices file has incorrect format.\n"); exit(1); } if (status == OUT_OF_MEMORY_ERROR) { printf("Out of memory error.\n"); exit(1); } // allocate memory for 3D features features3D = (CvPoint3D32f **)malloc(numContours * sizeof(CvPoint3D32f *)); validFeatureIndicator = (char **)malloc(numContours * sizeof(char *)); numFeaturesInContours = (int *)malloc(numContours * sizeof(int)); if (features3D == NULL || numFeaturesInContours == NULL || validFeatureIndicator == NULL) { printf("Out of memory error.\n"); exit(1); } for (int j = 0; j < numContours; j++) { features3D[j] = (CvPoint3D32f *)malloc(MAX_FEATURES_IN_CONTOUR * sizeof(CvPoint3D32f)); validFeatureIndicator[j] = (char *)malloc(MAX_FEATURES_IN_CONTOUR * sizeof(char)); if (features3D[j] == NULL || validFeatureIndicator[j] == NULL) { printf("Out of memory error.\n"); exit(1); } numFeaturesInContours[j] = 0; } } // create the output 3D features filename as "frame<frame number>_features3D_<camera name>.txt" char features3DFilename[MAX_FILENAME_LENGTH]; sprintf(features3DFilename, "%sframe%d_features3D_%s.txt", outputDirectory, camera1Frames[i], cameraNames[i]); // triangulate the matching 2D features between cameras to find the 3D coordinates // of the features, and remove invalid features if (triangulation(cameraCoefficientsFilenames[i], features2DFilename, features3DFilename, c1Images[i], errorMessage)) { printf("Triangulation: %s\n", errorMessage); exit(1); } // if features from triangulation lie within contours that have the same // names as those defined for the first camera pair, add them to the // 3D features array for mesh creation int status = read3DFeaturesFromFileForMatchingContours(features3DFilename, features3D, numFeaturesInContours, numContours, contourNames); if (status == INPUT_FILE_OPEN_ERROR) { printf("Could not open 3D features file.\n"); exit(1); } if (status == INVALID_NUM_CONTOURS_ERROR) { printf("At least 1 contour region required.\n"); exit(1); } if (status == INCORRECT_INPUT_FILE_FORMAT_ERROR) { printf("3D features file has incorrect format.\n"); exit(1); } } // for each contour (defined for the first camera pair), perform RANSAC on // the cumulative 3D features from all camera pairs that lie within the contour for (int i = 0; i < numContours; i++) { memset(validFeatureIndicator[i], 1, numFeaturesInContours[i] * sizeof(char)); // perform RANSAC to remove points that lie too far off a best-fit surface if (ransac(features3D[i], validFeatureIndicator[i], numFeaturesInContours[i], errorMessage)) { printf("RANSAC: %s\n", errorMessage); exit(1); } int numValidFeatures = 0; for (int j = 0; j < numFeaturesInContours[i]; j++) { if (validFeatureIndicator[i][j]) { numValidFeatures++; } } printf("Total valid features after RANSAC for contour %s: %d\n", contourNames[i], numValidFeatures); } // create the output 3D features filename for all camera pairs as // "frame<frame number>_features3D.txt", and write the result of RANSAC to // the file char features3DFilename[MAX_FILENAME_LENGTH]; sprintf(features3DFilename, "%sframe%d_features3D.txt", outputDirectory, camera1Frames[0]); int status = write3DFeaturesToFile(features3D, validFeatureIndicator, numFeaturesInContours, contourNames, numContours, features3DFilename); if (status == OUTPUT_FILE_OPEN_ERROR) { sprintf(errorMessage, "Could not open output file."); return 1; } char **meshFilenames = (char **)malloc(numContours * sizeof(char *)); if (meshFilenames == NULL) { printf("Out of memory error.\n"); exit(1); } // for each contour, create a different mesh output file for (int i = 0; i < numContours; i++) { meshFilenames[i] = (char *)malloc(MAX_FILENAME_LENGTH * sizeof(char)); if (meshFilenames[i] == NULL) { printf("Out of memory error.\n"); exit(1); } // create the output mesh filename as "frame<frame number>_mesh_<contour name>_<camera name>.txt" sprintf(meshFilenames[i], "%sframe%d_mesh_%s.txt", outputDirectory, camera1Frames[0], contourNames[i]); } // create the wing meshes from the triangulated 3D points and the user-selected // contours, and write each mesh to a different file for each contour if (mesh(features3DFilename, contoursFilename, cameraCoefficientsFilenames[0], meshFilenames, numContours, regularization, errorMessage)) { printf("Mesh: %s\n", errorMessage); exit(1); } // we only calculate the flow of a wing mesh if there is a mesh file with the // same contour name in the output directory for the previous video frame char **flowFilenames = (char **)malloc(numContours * sizeof(char *)); if (flowFilenames == NULL) { printf("Out of memory error.\n"); exit(1); } for (int i = 0; i < numContours; i++) { flowFilenames[i] = NULL; } int numFilesInDirectory; char **filenamesInDirectory = (char **)malloc(MAX_FILES_IN_DIRECTORY * sizeof(char *)); if (filenamesInDirectory == NULL) { printf("Out of memory error.\n"); exit(1); } for (int i = 0; i < MAX_FILES_IN_DIRECTORY; i++) { filenamesInDirectory[i] = (char *)malloc(MAX_FILENAME_LENGTH * sizeof(char)); if (filenamesInDirectory[i] == NULL) { printf("Out of memory error.\n"); exit(1); } } // get all files in the output directory getAllFilenamesInDirectory(outputDirectory, &numFilesInDirectory, filenamesInDirectory); // for each contour check if previous frame mesh file for same contour exists // in output directory for (int i = 0; i < numContours; i++) { // set substring indicating match to be "frame<previous frame number>_mesh_<contour name>.txt" char filenameToMatch[MAX_FILENAME_LENGTH]; sprintf(filenameToMatch, "frame%d_mesh_%s.txt", camera1Frames[0]-1, contourNames[i]); // try to find a filename from the output directory that contains the // substring indicating a match for a previous frame mesh for the same // contour int fileExists = getIndexOfMatchingString(filenamesInDirectory, numFilesInDirectory, filenameToMatch); // if filename was found, create a flow output file for current contour // and call flow to calculate the flow between previous contour mesh and // current contour mesh if (fileExists != -1) { flowFilenames[i] = (char *)malloc(MAX_FILENAME_LENGTH * sizeof(char)); if (flowFilenames[i] == NULL) { printf("Out of memory error.\n"); exit(1); } // create the output flow filename as "frame<frame number>_flow_<contour name>_<camera name>.txt" sprintf(flowFilenames[i], "%sframe%d_flow_%s.txt", outputDirectory, camera1Frames[0], contourNames[i]); // add the output directory name to the beginning of the previous mesh // filename char prevFrameMeshFile[MAX_FILENAME_LENGTH]; sprintf(prevFrameMeshFile, "%s%s", outputDirectory, filenameToMatch); // call flow to find the flow between the previous mesh file and the // current mesh file for each mesh point current contour if (flow(prevFrameMeshFile, meshFilenames[i], flowFilenames[i], errorMessage)) { printf("Flow: %s\n", errorMessage); exit(1); } } else { printf("Mesh points file for previous frame not found for contour %s. Unable to calculate flow.\n", contourNames[i]); } } sprintf(command, "hold on;"); engEvalString(matlabEngine, command); // for each contour, display MATLAB 3D plot of the mesh, as well as the flow // for the mesh, if applicable for (int i = 0; i < numContours; i++) { if (flowFilenames[i] != NULL) { sprintf(command, "flows = load('%s');", flowFilenames[i]); engEvalString(matlabEngine, command); // plot the flows of the mesh points sprintf(command, "quiver3(flows(:,1), flows(:,2), flows(:,3), flows(:,4), flows(:,5), flows(:,6), 4, 'r-');"); engEvalString(matlabEngine, command); } sprintf(command, "mesh = importdata('%s', ' ', 1);", meshFilenames[i]); engEvalString(matlabEngine, command); // plot the mesh points sprintf(command, "plot3(mesh.data(:,1), mesh.data(:,2), mesh.data(:,3), 'b.');"); engEvalString(matlabEngine, command); } // reverse the z and y coordinates in the display sprintf(command, "set(gca,'zdir','reverse','ydir','reverse');"); engEvalString(matlabEngine, command); // scale the axes to be equal sprintf(command, "axis equal"); engEvalString(matlabEngine, command); // wait for the user to hit enter printf("Hit return to continue.\n"); fgetc(stdin); // close MATLAB engine engClose(matlabEngine); // cleanup free(camera1Filenames); free(camera1Frames); free(camera2Filenames); free(camera2Frames); free(cameraNames); free(cameraCoefficientsFilenames); for (int i = 0; i < numCameraPairs; i++) { mxDestroyArray(c1ImageData[i]); mxDestroyArray(c1ImageDimensions[i]); mxDestroyArray(c1ImagePaddedWidths[i]); mxDestroyArray(c2ImageData[i]); mxDestroyArray(c2ImageDimensions[i]); mxDestroyArray(c2ImagePaddedWidths[i]); free(c1Images[i]->imageData); cvReleaseImageHeader(&c1Images[i]); free(c2Images[i]->imageData); cvReleaseImageHeader(&c2Images[i]); } free(c1ImageData); free(c1ImageDimensions); free(c1ImagePaddedWidths); free(c2ImageData); free(c2ImageDimensions); free(c2ImagePaddedWidths); free(c1Images); free(c2Images); for (int i = 0; i < MAX_FILES_IN_DIRECTORY; i++) { free(filenamesInDirectory[i]); } free(filenamesInDirectory); for (int i = 0; i < numContours; i++) { free(contourNames[i]); free(features3D[i]); free(validFeatureIndicator[i]); free(meshFilenames[i]); if (flowFilenames[i] != NULL) { free(flowFilenames[i]); } } free(contourNames); free(features3D); free(validFeatureIndicator); free(numFeaturesInContours); free(meshFilenames); free(flowFilenames); exit(0); }
// To assign a graph to a tree requires pruning all edges which makes it not // a tree. We perform here the junction tree algorithm. tree(const graph<T,P,M,N,impl_type> &g) { typedef graph<T,P,M,N,impl_type> super; super::operator=(g); moralization(); triangulation(); }