/** * \fn Dessin::Dessin () * \brief Constructeur de la classe Dessin * \return Rien */ Dessin::Dessin () { lecture_coordonnees_points(); /* Ajout d'évènements non gérés par défaut par DrawingArea */ this->add_events(Gdk::BUTTON_PRESS_MASK); this->add_events(Gdk::BUTTON1_MOTION_MASK); this->add_events(Gdk::BUTTON2_MOTION_MASK); this->add_events(Gdk::BUTTON3_MOTION_MASK); this->add_events(Gdk::BUTTON_RELEASE_MASK); this->signal_event().connect(sigc::mem_fun(*this, &Dessin::on_event_happend)); /* Initialisation des valeurs de la taille de la carte avec des valeurs par défaut */ zoom_actif = 0; hauteur_zoom = H_MAP; largeur_zoom = H_MAP; decalage_x_zoom = 0; decalage_y_zoom = 0; matrice = Matrice(194, 196); matrice = Matrice::Zero(194, 196); valeur_min = 0; valeur_max = 0; actif = 0; initialisation = 0; }
int main(int argc, char *argv[]) { /* % MINIMALPATH Recherche du chemin minimum de Haut vers le bas et de % bas vers le haut tel que dÈcrit par Luc Vincent 1998 % [sR,sC,S] = MinimalPath(I,factx) % % I : Image d'entrÔøΩe dans laquelle on doit trouver le % chemin minimal % factx : Poids de linearite [1 10] % % Programme par : Ramnada Chav % ModifiÈ le 16 novembre 2007 */ typedef itk::ImageDuplicator< ImageType > DuplicatorType3D; typedef itk::InvertIntensityImageFilter <ImageType> InvertIntensityImageFilterType; typedef itk::StatisticsImageFilter<ImageType> StatisticsImageFilterType; ImageType::Pointer inverted_image = image; // if (invert) // { // StatisticsImageFilterType::Pointer statisticsImageFilterInput = StatisticsImageFilterType::New(); // statisticsImageFilterInput->SetInput(image); // statisticsImageFilterInput->Update(); // double maxIm = statisticsImageFilterInput->GetMaximum(); // InvertIntensityImageFilterType::Pointer invertIntensityFilter = InvertIntensityImageFilterType::New(); // invertIntensityFilter->SetInput(image); // invertIntensityFilter->SetMaximum(maxIm); // invertIntensityFilter->Update(); // inverted_image = invertIntensityFilter->GetOutput(); // } ImageType::SizeType sizeImage = image->GetLargestPossibleRegion().GetSize(); int m = sizeImage[0]; // x to change because we are in AIL int n = sizeImage[2]; // y int p = sizeImage[1]; // z // create image with high values J1 DuplicatorType3D::Pointer duplicator = DuplicatorType3D::New(); duplicator->SetInputImage(inverted_image); duplicator->Update(); ImageType::Pointer J1 = duplicator->GetOutput(); typedef itk::ImageRegionIterator<ImageType> ImageIterator3D; ImageIterator3D vItJ1( J1, J1->GetBufferedRegion() ); vItJ1.GoToBegin(); while ( !vItJ1.IsAtEnd() ) { vItJ1.Set(100000000); ++vItJ1; } // create image with high values J2 DuplicatorType3D::Pointer duplicatorJ2 = DuplicatorType3D::New(); duplicatorJ2->SetInputImage(inverted_image); duplicatorJ2->Update(); ImageType::Pointer J2 = duplicatorJ2->GetOutput(); ImageIterator3D vItJ2( J2, J2->GetBufferedRegion() ); vItJ2.GoToBegin(); while ( !vItJ2.IsAtEnd() ) { vItJ2.Set(100000000); ++vItJ2; } DuplicatorType3D::Pointer duplicatorCPixel = DuplicatorType3D::New(); duplicatorCPixel->SetInputImage(inverted_image); duplicatorCPixel->Update(); ImageType::Pointer cPixel = duplicatorCPixel->GetOutput(); ImageType::IndexType index; // iterate on slice from slice 1 (start=0) to slice p-2. Basically, we avoid first and last slices. // IMPORTANT: first slice of J1 and last slice of J2 must be set to 0... for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = 0; index[2] = y; J1->SetPixel(index, 0.0); } } for (int slice=1; slice<p; slice++) { // 1. extract pJ = the (slice-1)th slice of the image J1 Matrice pJ = Matrice(m,n); for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice-1; index[2] = y; pJ(x,y) = J1->GetPixel(index); } } // 2. extract cP = the (slice)th slice of the image cPixel Matrice cP = Matrice(m,n); for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice; index[2] = y; cP(x,y) = cPixel->GetPixel(index); } } // 2' Matrice cPm = Matrice(m,n); if (homoInt) { for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice-1; index[2] = y; cP(x,y) = cPixel->GetPixel(index); } } } // 3. Create a matrix VI with 5 slices, that are exactly a repetition of cP without borders // multiply all elements of all slices of VI except the middle one by factx Matrice VI[5]; for (int i=0; i<5; i++) { // Create VI Matrice cP_in = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { cP_in(x,y) = cP(x+1,y+1); if (i!=2) cP_in(x,y) *= factx; } } VI[i] = cP_in; } // 3'. Matrice VIm[5]; if (homoInt) { for (int i=0; i<5; i++) { // Create VIm Matrice cPm_in = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { cPm_in(x,y) = cPm(x+1,y+1); if (i!=2) cPm_in(x,y) *= factx; } } VIm[i] = cPm_in; } } // 4. create a matrix of 5 slices, containing pJ(vectx-1,vecty),pJ(vectx,vecty-1),pJ(vectx,vecty),pJ(vectx,vecty+1),pJ(vectx+1,vecty) where vectx=2:m-1; and vecty=2:n-1; Matrice Jq[5]; int s = 0; Matrice pJ_temp = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { pJ_temp(x,y) = pJ(x+1,y+1); } } Jq[2] = pJ_temp; for (int k=-1; k<=1; k+=2) { for (int l=-1; l<=1; l+=2) { Matrice pJ_temp = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { pJ_temp(x,y) = pJ(x+k+1,y+l+1); } } Jq[s] = pJ_temp; s++; if (s==2) s++; // we deal with middle slice before } } // 4'. An alternative is to minimize the difference in intensity between slices. if (homoInt) { Matrice VI_temp[5]; // compute the difference between VI and VIm for (int i=0; i<5; i++) VI_temp[i] = VI[i] - VIm[i]; // compute the minimum value for each element of the matrices for (int i=0; i<5; i++) { for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { if (VI_temp[i](x,y) > 0) VI[i](x,y) = abs(VI_temp[i](x,y));///VIm[i](x,y); else VI[i](x,y) = abs(VI_temp[i](x,y));///VI[i](x,y); } } } } // 5. sum Jq and Vi voxel by voxel to produce JV Matrice JV[5]; for (int i=0; i<5; i++) JV[i] = VI[i] + Jq[i]; // 6. replace each pixel of the (slice)th slice of J1 with the minimum value of the corresponding column in JV for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { double min_value = 1000000; for (int i=0; i<5; i++) { if (JV[i](x,y) < min_value) min_value = JV[i](x,y); } index[0] = x+1; index[1] = slice; index[2] = y+1; J1->SetPixel(index, min_value); } } } // iterate on slice from slice n-1 to slice 1. Basically, we avoid first and last slices. // IMPORTANT: first slice of J1 and last slice of J2 must be set to 0... for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = p-1; index[2] = y; J2->SetPixel(index, 0.0); } } for (int slice=p-2; slice>=0; slice--) { // 1. extract pJ = the (slice-1)th slice of the image J1 Matrice pJ = Matrice(m,n); for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice+1; index[2] = y; pJ(x,y) = J2->GetPixel(index); } } // 2. extract cP = the (slice)th slice of the image cPixel Matrice cP = Matrice(m,n); for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice; index[2] = y; cP(x,y) = cPixel->GetPixel(index); } } // 2' Matrice cPm = Matrice(m,n); if (homoInt) { for (int x=0; x<m; x++) { for (int y=0; y<n; y++) { index[0] = x; index[1] = slice+1; index[2] = y; cPm(x,y) = cPixel->GetPixel(index); } } } // 3. Create a matrix VI with 5 slices, that are exactly a repetition of cP without borders // multiply all elements of all slices of VI except the middle one by factx Matrice VI[5]; for (int i=0; i<5; i++) { // Create VI Matrice cP_in = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { cP_in(x,y) = cP(x+1,y+1); if (i!=2) cP_in(x,y) *= factx; } } VI[i] = cP_in; } // 3'. Matrice VIm[5]; if (homoInt) { for (int i=0; i<5; i++) { // Create VI Matrice cPm_in = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { cPm_in(x,y) = cPm(x+1,y+1); if (i!=2) cPm_in(x,y) *= factx; } } VIm[i] = cPm_in; } } // 4. create a matrix of 5 slices, containing pJ(vectx-1,vecty),pJ(vectx,vecty-1),pJ(vectx,vecty),pJ(vectx,vecty+1),pJ(vectx+1,vecty) where vectx=2:m-1; and vecty=2:n-1; Matrice Jq[5]; int s = 0; Matrice pJ_temp = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { pJ_temp(x,y) = pJ(x+1,y+1); } } Jq[2] = pJ_temp; for (int k=-1; k<=1; k+=2) { for (int l=-1; l<=1; l+=2) { Matrice pJ_temp = Matrice(m-1, n-1); for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { pJ_temp(x,y) = pJ(x+k+1,y+l+1); } } Jq[s] = pJ_temp; s++; if (s==2) s++; // we deal with middle slice before } } // 4'. An alternative is to minimize the difference in intensity between slices. if (homoInt) { Matrice VI_temp[5]; // compute the difference between VI and VIm for (int i=0; i<5; i++) VI_temp[i] = VI[i] - VIm[i]; // compute the minimum value for each element of the matrices for (int i=0; i<5; i++) { for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { if (VI_temp[i](x,y) > 0) VI[i](x,y) = abs(VI_temp[i](x,y));///VIm[i](x,y); else VI[i](x,y) = abs(VI_temp[i](x,y));///VI[i](x,y); } } } } // 5. sum Jq and Vi voxel by voxel to produce JV Matrice JV[5]; for (int i=0; i<5; i++) JV[i] = VI[i] + Jq[i]; // 6. replace each pixel of the (slice)th slice of J1 with the minimum value of the corresponding column in JV for (int x=0; x<m-2; x++) { for (int y=0; y<n-2; y++) { double min_value = 10000000; for (int i=0; i<5; i++) { if (JV[i](x,y) < min_value) min_value = JV[i](x,y); } index[0] = x+1; index[1] = slice; index[2] = y+1; J2->SetPixel(index, min_value); } } } // add J1 and J2 to produce "S" which is actually J1 here. ImageIterator3D vItS( J1, J1->GetBufferedRegion() ); ImageIterator3D vItJ2b( J2, J2->GetBufferedRegion() ); vItS.GoToBegin(); vItJ2b.GoToBegin(); while ( !vItS.IsAtEnd() ) { vItS.Set(vItS.Get()+vItJ2b.Get()); ++vItS; ++vItJ2b; } // Find the minimal value of S for each slice and create a binary image with all the coordinates // TO DO: the minimal path shouldn't be a pixelar path. It should be a continuous spline that is minimum. double val_temp; vector<CVector3> list_index; for (int slice=1; slice<p-1; slice++) { double min_value_S = 10000000; ImageType::IndexType index_min; for (int x=1; x<m-1; x++) { for (int y=1; y<n-1; y++) { index[0] = x; index[1] = slice; index[2] = y; val_temp = J1->GetPixel(index); if (val_temp < min_value_S) { min_value_S = val_temp; index_min = index; } } } list_index.push_back(CVector3(index_min[0], index_min[1], index_min[2])); } //BSplineApproximation centerline_approximator = BSplineApproximation(&list_index); //list_index = centerline_approximator.EvaluateBSplinePoints(list_index.size()); /*// create image with high values J1 ImageType::Pointer result_bin = J2; ImageIterator3D vItresult( result_bin, result_bin->GetBufferedRegion() ); vItresult.GoToBegin(); while ( !vItresult.IsAtEnd() ) { vItresult.Set(0.0); ++vItresult; } for (int i=0; i<list_index.size(); i++) { index[0] = list_index[i][0]; index[1] = list_index[i][1]; index[2] = list_index[i][2]; result_bin->SetPixel(index,1.0); } typedef itk::ImageFileWriter< ImageType > WriterTypeM; WriterTypeM::Pointer writerMin = WriterTypeM::New(); itk::NiftiImageIO::Pointer ioV = itk::NiftiImageIO::New(); writerMin->SetImageIO(ioV); writerMin->SetInput( J1 ); // result_bin writerMin->SetFileName("minimalPath.nii.gz"); try { writerMin->Update(); } catch( itk::ExceptionObject & e ) { cout << "Exception thrown ! " << endl; cout << "An error ocurred during Writing Min" << endl; cout << "Location = " << e.GetLocation() << endl; cout << "Description = " << e.GetDescription() << endl; }*/ centerline = list_index; return J1; // return image with minimal path }
void pose_estimation_from_line_correspondence(Eigen::MatrixXf start_points, Eigen::MatrixXf end_points, Eigen::MatrixXf directions, Eigen::MatrixXf points, Eigen::MatrixXf &rot_cw, Eigen::VectorXf &pos_cw) { int n = start_points.cols(); if(n != directions.cols()) { return; } if(n<4) { return; } float condition_err_threshold = 1e-3; Eigen::VectorXf cosAngleThreshold(3); cosAngleThreshold << 1.1, 0.9659, 0.8660; Eigen::MatrixXf optimumrot_cw(3,3); Eigen::VectorXf optimumpos_cw(3); std::vector<float> lineLenVec(n,1); vfloat3 l1; vfloat3 l2; vfloat3 nc1; vfloat3 Vw1; vfloat3 Xm; vfloat3 Ym; vfloat3 Zm; Eigen::MatrixXf Rot(3,3); std::vector<vfloat3> nc_bar(n,vfloat3(0,0,0)); std::vector<vfloat3> Vw_bar(n,vfloat3(0,0,0)); std::vector<vfloat3> n_c(n,vfloat3(0,0,0)); Eigen::MatrixXf Rx(3,3); int line_id; for(int HowToChooseFixedTwoLines = 1 ; HowToChooseFixedTwoLines <=3 ; HowToChooseFixedTwoLines++) { if(HowToChooseFixedTwoLines==1) { #pragma omp parallel for for(int i = 0; i < n ; i++ ) { // to correct float lineLen = 10; lineLenVec[i] = lineLen; } std::vector<float>::iterator result; result = std::max_element(lineLenVec.begin(), lineLenVec.end()); line_id = std::distance(lineLenVec.begin(), result); vfloat3 temp; temp = start_points.col(0); start_points.col(0) = start_points.col(line_id); start_points.col(line_id) = temp; temp = end_points.col(0); end_points.col(0) = end_points.col(line_id); end_points.col(line_id) = temp; temp = directions.col(line_id); directions.col(0) = directions.col(line_id); directions.col(line_id) = temp; temp = points.col(0); points.col(0) = points.col(line_id); points.col(line_id) = temp; lineLenVec[line_id] = lineLenVec[1]; lineLenVec[1] = 0; l1 = start_points.col(0) - end_points.col(0); l1 = l1/l1.norm(); } for(int i = 1; i < n; i++) { std::vector<float>::iterator result; result = std::max_element(lineLenVec.begin(), lineLenVec.end()); line_id = std::distance(lineLenVec.begin(), result); l2 = start_points.col(line_id) - end_points.col(line_id); l2 = l2/l2.norm(); lineLenVec[line_id] = 0; MatrixXf cosAngle(3,3); cosAngle = (l1.transpose()*l2).cwiseAbs(); if(cosAngle.maxCoeff() < cosAngleThreshold[HowToChooseFixedTwoLines]) { break; } } vfloat3 temp; temp = start_points.col(1); start_points.col(1) = start_points.col(line_id); start_points.col(line_id) = temp; temp = end_points.col(1); end_points.col(1) = end_points.col(line_id); end_points.col(line_id) = temp; temp = directions.col(1); directions.col(1) = directions.col(line_id); directions.col(line_id) = temp; temp = points.col(1); points.col(1) = points.col(line_id); points.col(line_id) = temp; lineLenVec[line_id] = lineLenVec[1]; lineLenVec[1] = 0; // The rotation matrix R_wc is decomposed in way which is slightly different from the description in the paper, // but the framework is the same. // R_wc = (Rot') * R * Rot = (Rot') * (Ry(theta) * Rz(phi) * Rx(psi)) * Rot nc1 = x_cross(start_points.col(1),end_points.col(1)); nc1 = nc1/nc1.norm(); Vw1 = directions.col(1); Vw1 = Vw1/Vw1.norm(); //the X axis of Model frame Xm = x_cross(nc1,Vw1); Xm = Xm/Xm.norm(); //the Y axis of Model frame Ym = nc1; //the Z axis of Model frame Zm = x_cross(Xm,Zm); Zm = Zm/Zm.norm(); //Rot * [Xm, Ym, Zm] = I. Rot.col(0) = Xm; Rot.col(1) = Ym; Rot.col(2) = Zm; Rot = Rot.transpose(); //rotate all the vector by Rot. //nc_bar(:,i) = Rot * nc(:,i) //Vw_bar(:,i) = Rot * Vw(:,i) #pragma omp parallel for for(int i = 0 ; i < n ; i++) { vfloat3 nc = x_cross(start_points.col(1),end_points.col(1)); nc = nc/nc.norm(); n_c[i] = nc; nc_bar[i] = Rot * nc; Vw_bar[i] = Rot * directions.col(i); } //Determine the angle psi, it is the angle between z axis and Vw_bar(:,1). //The rotation matrix Rx(psi) rotates Vw_bar(:,1) to z axis float cospsi = (Vw_bar[1])[2];//the angle between z axis and Vw_bar(:,1); cospsi=[0,0,1] * Vw_bar(:,1);. float sinpsi= sqrt(1 - cospsi*cospsi); Rx.row(0) = vfloat3(1,0,0); Rx.row(1) = vfloat3(0,cospsi,-sinpsi); Rx.row(2) = vfloat3(0,sinpsi,cospsi); vfloat3 Zaxis = Rx * Vw_bar[1]; if(1-fabs(Zaxis[3]) > 1e-5) { Rx = Rx.transpose(); } //estimate the rotation angle phi by least square residual. //i.e the rotation matrix Rz(phi) vfloat3 Vm2 = Rx * Vw_bar[1]; float A2 = Vm2[0]; float B2 = Vm2[1]; float C2 = Vm2[2]; float x2 = (nc_bar[1])[0]; float y2 = (nc_bar[1])[1]; float z2 = (nc_bar[1])[2]; Eigen::PolynomialSolver<double, Eigen::Dynamic> solver; Eigen::VectorXf coeff(9); std::vector<float> coef(9,0); //coefficients of equation (7) Eigen::VectorXf polyDF = VectorXf::Zero(16); //%dF = ployDF(1) * t^15 + ployDF(2) * t^14 + ... + ployDF(15) * t + ployDF(16); //construct the polynomial F' #pragma omp parallel for for(int i = 3 ; i < n ; i++) { vfloat3 Vm3 = Rx*Vw_bar[i]; float A3 = Vm3[0]; float B3 = Vm3[1]; float C3 = Vm3[2]; float x3 = (nc_bar[i])[0]; float y3 = (nc_bar[i])[1]; float z3 = (nc_bar[i])[2]; float u11 = -z2*A2*y3*B3 + y2*B2*z3*A3; float u12 = -y2*A2*z3*B3 + z2*B2*y3*A3; float u13 = -y2*B2*z3*B3 + z2*B2*y3*B3 + y2*A2*z3*A3 - z2*A2*y3*A3; float u14 = -y2*B2*x3*C3 + x2*C2*y3*B3; float u15 = x2*C2*y3*A3 - y2*A2*x3*C3; float u21 = -x2*A2*y3*B3 + y2*B2*x3*A3; float u22 = -y2*A2*x3*B3 + x2*B2*y3*A3; float u23 = x2*B2*y3*B3 - y2*B2*x3*B3 - x2*A2*y3*A3 + y2*A2*x3*A3; float u24 = y2*B2*z3*C3 - z2*C2*y3*B3; float u25 = y2*A2*z3*C3 - z2*C2*y3*A3; float u31 = -x2*A2*z3*A3 + z2*A2*x3*A3; float u32 = -x2*B2*z3*B3 + z2*B2*x3*B3; float u33 = x2*A2*z3*B3 - z2*A2*x3*B3 + x2*B2*z3*A3 - z2*B2*x3*A3; float u34 = z2*A2*z3*C3 + x2*A2*x3*C3 - z2*C2*z3*A3 - x2*C2*x3*A3; float u35 = -z2*B2*z3*C3 - x2*B2*x3*C3 + z2*C2*z3*B3 + x2*C2*x3*B3; float u36 = -x2*C2*z3*C3 + z2*C2*x3*C3; float a4 = u11*u11 + u12*u12 - u13*u13 - 2*u11*u12 + u21*u21 + u22*u22 - u23*u23 -2*u21*u22 - u31*u31 - u32*u32 + u33*u33 + 2*u31*u32; float a3 =2*(u11*u14 - u13*u15 - u12*u14 + u21*u24 - u23*u25 - u22*u24 - u31*u34 + u33*u35 + u32*u34); float a2 =-2*u12*u12 + u13*u13 + u14*u14 - u15*u15 + 2*u11*u12 - 2*u22*u22 + u23*u23 + u24*u24 - u25*u25 +2*u21*u22+ 2*u32*u32 - u33*u33 - u34*u34 + u35*u35 -2*u31*u32- 2*u31*u36 + 2*u32*u36; float a1 =2*(u12*u14 + u13*u15 + u22*u24 + u23*u25 - u32*u34 - u33*u35 - u34*u36); float a0 = u12*u12 + u15*u15+ u22*u22 + u25*u25 - u32*u32 - u35*u35 - u36*u36 - 2*u32*u36; float b3 =2*(u11*u13 - u12*u13 + u21*u23 - u22*u23 - u31*u33 + u32*u33); float b2 =2*(u11*u15 - u12*u15 + u13*u14 + u21*u25 - u22*u25 + u23*u24 - u31*u35 + u32*u35 - u33*u34); float b1 =2*(u12*u13 + u14*u15 + u22*u23 + u24*u25 - u32*u33 - u34*u35 - u33*u36); float b0 =2*(u12*u15 + u22*u25 - u32*u35 - u35*u36); float d0 = a0*a0 - b0*b0; float d1 = 2*(a0*a1 - b0*b1); float d2 = a1*a1 + 2*a0*a2 + b0*b0 - b1*b1 - 2*b0*b2; float d3 = 2*(a0*a3 + a1*a2 + b0*b1 - b1*b2 - b0*b3); float d4 = a2*a2 + 2*a0*a4 + 2*a1*a3 + b1*b1 + 2*b0*b2 - b2*b2 - 2*b1*b3; float d5 = 2*(a1*a4 + a2*a3 + b1*b2 + b0*b3 - b2*b3); float d6 = a3*a3 + 2*a2*a4 + b2*b2 - b3*b3 + 2*b1*b3; float d7 = 2*(a3*a4 + b2*b3); float d8 = a4*a4 + b3*b3; std::vector<float> v { a4, a3, a2, a1, a0, b3, b2, b1, b0 }; Eigen::VectorXf vp; vp << a4, a3, a2, a1, a0, b3, b2, b1, b0 ; //coef = coef + v; coeff = coeff + vp; polyDF[0] = polyDF[0] + 8*d8*d8; polyDF[1] = polyDF[1] + 15* d7*d8; polyDF[2] = polyDF[2] + 14* d6*d8 + 7*d7*d7; polyDF[3] = polyDF[3] + 13*(d5*d8 + d6*d7); polyDF[4] = polyDF[4] + 12*(d4*d8 + d5*d7) + 6*d6*d6; polyDF[5] = polyDF[5] + 11*(d3*d8 + d4*d7 + d5*d6); polyDF[6] = polyDF[6] + 10*(d2*d8 + d3*d7 + d4*d6) + 5*d5*d5; polyDF[7] = polyDF[7] + 9 *(d1*d8 + d2*d7 + d3*d6 + d4*d5); polyDF[8] = polyDF[8] + 8 *(d1*d7 + d2*d6 + d3*d5) + 4*d4*d4 + 8*d0*d8; polyDF[9] = polyDF[9] + 7 *(d1*d6 + d2*d5 + d3*d4) + 7*d0*d7; polyDF[10] = polyDF[10] + 6 *(d1*d5 + d2*d4) + 3*d3*d3 + 6*d0*d6; polyDF[11] = polyDF[11] + 5 *(d1*d4 + d2*d3)+ 5*d0*d5; polyDF[12] = polyDF[12] + 4 * d1*d3 + 2*d2*d2 + 4*d0*d4; polyDF[13] = polyDF[13] + 3 * d1*d2 + 3*d0*d3; polyDF[14] = polyDF[14] + d1*d1 + 2*d0*d2; polyDF[15] = polyDF[15] + d0*d1; } Eigen::VectorXd coefficientPoly = VectorXd::Zero(16); for(int j =0; j < 16 ; j++) { coefficientPoly[j] = polyDF[15-j]; } //solve polyDF solver.compute(coefficientPoly); const Eigen::PolynomialSolver<double, Eigen::Dynamic>::RootsType & r = solver.roots(); Eigen::VectorXd rs(r.rows()); Eigen::VectorXd is(r.rows()); std::vector<float> min_roots; for(int j =0;j<r.rows();j++) { rs[j] = fabs(r[j].real()); is[j] = fabs(r[j].imag()); } float maxreal = rs.maxCoeff(); for(int j = 0 ; j < rs.rows() ; j++ ) { if(is[j]/maxreal <= 0.001) { min_roots.push_back(rs[j]); } } std::vector<float> temp_v(15); std::vector<float> poly(15); for(int j = 0 ; j < 15 ; j++) { temp_v[j] = j+1; } for(int j = 0 ; j < 15 ; j++) { poly[j] = polyDF[j]*temp_v[j]; } Eigen::Matrix<double,16,1> polynomial; Eigen::VectorXd evaluation(min_roots.size()); for( int j = 0; j < min_roots.size(); j++ ) { evaluation[j] = poly_eval( polynomial, min_roots[j] ); } std::vector<float> minRoots; for( int j = 0; j < min_roots.size(); j++ ) { if(!evaluation[j]<=0) { minRoots.push_back(min_roots[j]); } } if(minRoots.size()==0) { cout << "No solution" << endl; return; } int numOfRoots = minRoots.size(); //for each minimum, we try to find a solution of the camera pose, then //choose the one with the least reprojection residual as the optimum of the solution. float minimalReprojectionError = 100; // In general, there are two solutions which yields small re-projection error // or condition error:"n_c * R_wc * V_w=0". One of the solution transforms the // world scene behind the camera center, the other solution transforms the world // scene in front of camera center. While only the latter one is correct. // This can easily be checked by verifying their Z coordinates in the camera frame. // P_c(Z) must be larger than 0 if it's in front of the camera. for(int rootId = 0 ; rootId < numOfRoots ; rootId++) { float cosphi = minRoots[rootId]; float sign1 = sign_of_number(coeff[0] * pow(cosphi,4) + coeff[1] * pow(cosphi,3) + coeff[2] * pow(cosphi,2) + coeff[3] * cosphi + coeff[4]); float sign2 = sign_of_number(coeff[5] * pow(cosphi,3) + coeff[6] * pow(cosphi,2) + coeff[7] * cosphi + coeff[8]); float sinphi= -sign1*sign2*sqrt(abs(1-cosphi*cosphi)); Eigen::MatrixXf Rz(3,3); Rz.row(0) = vfloat3(cosphi,-sinphi,0); Rz.row(1) = vfloat3(sinphi,cosphi,0); Rz.row(2) = vfloat3(0,0,1); //now, according to Sec4.3, we estimate the rotation angle theta //and the translation vector at a time. Eigen::MatrixXf RzRxRot(3,3); RzRxRot = Rz*Rx*Rot; //According to the fact that n_i^C should be orthogonal to Pi^c and Vi^c, we //have: scalarproduct(Vi^c, ni^c) = 0 and scalarproduct(Pi^c, ni^c) = 0. //where Vi^c = Rwc * Vi^w, Pi^c = Rwc *(Pi^w - pos_cw) = Rwc * Pi^w - pos; //Using the above two constraints to construct linear equation system Mat about //[costheta, sintheta, tx, ty, tz, 1]. Eigen::MatrixXf Matrice(2*n-1,6); #pragma omp parallel for for(int i = 0 ; i < n ; i++) { float nxi = (nc_bar[i])[0]; float nyi = (nc_bar[i])[1]; float nzi = (nc_bar[i])[2]; Eigen::VectorXf Vm(3); Vm = RzRxRot * directions.col(i); float Vxi = Vm[0]; float Vyi = Vm[1]; float Vzi = Vm[2]; Eigen::VectorXf Pm(3); Pm = RzRxRot * points.col(i); float Pxi = Pm(1); float Pyi = Pm(2); float Pzi = Pm(3); //apply the constraint scalarproduct(Vi^c, ni^c) = 0 //if i=1, then scalarproduct(Vi^c, ni^c) always be 0 if(i>1) { Matrice(2*i-3, 0) = nxi * Vxi + nzi * Vzi; Matrice(2*i-3, 1) = nxi * Vzi - nzi * Vxi; Matrice(2*i-3, 5) = nyi * Vyi; } //apply the constraint scalarproduct(Pi^c, ni^c) = 0 Matrice(2*i-2, 0) = nxi * Pxi + nzi * Pzi; Matrice(2*i-2, 1) = nxi * Pzi - nzi * Pxi; Matrice(2*i-2, 2) = -nxi; Matrice(2*i-2, 3) = -nyi; Matrice(2*i-2, 4) = -nzi; Matrice(2*i-2, 5) = nyi * Pyi; } //solve the linear system Mat * [costheta, sintheta, tx, ty, tz, 1]' = 0 using SVD, JacobiSVD<MatrixXf> svd(Matrice, ComputeThinU | ComputeThinV); Eigen::MatrixXf VMat = svd.matrixV(); Eigen::VectorXf vec(2*n-1); //the last column of Vmat; vec = VMat.col(5); //the condition that the last element of vec should be 1. vec = vec/vec[5]; //the condition costheta^2+sintheta^2 = 1; float normalizeTheta = 1/sqrt(vec[0]*vec[1]+vec[1]*vec[1]); float costheta = vec[0]*normalizeTheta; float sintheta = vec[1]*normalizeTheta; Eigen::MatrixXf Ry(3,3); Ry << costheta, 0, sintheta , 0, 1, 0 , -sintheta, 0, costheta; //now, we get the rotation matrix rot_wc and translation pos_wc Eigen::MatrixXf rot_wc(3,3); rot_wc = (Rot.transpose()) * (Ry * Rz * Rx) * Rot; Eigen::VectorXf pos_wc(3); pos_wc = - Rot.transpose() * vec.segment(2,4); //now normalize the camera pose by 3D alignment. We first translate the points //on line in the world frame Pw to points in the camera frame Pc. Then we project //Pc onto the line interpretation plane as Pc_new. So we could call the point //alignment algorithm to normalize the camera by aligning Pc_new and Pw. //In order to improve the accuracy of the aligment step, we choose two points for each //lines. The first point is Pwi, the second point is the closest point on line i to camera center. //(Pw2i = Pwi - (Pwi'*Vwi)*Vwi.) Eigen::MatrixXf Pw2(3,n); Pw2.setZero(); Eigen::MatrixXf Pc_new(3,n); Pc_new.setZero(); Eigen::MatrixXf Pc2_new(3,n); Pc2_new.setZero(); for(int i = 0 ; i < n ; i++) { vfloat3 nci = n_c[i]; vfloat3 Pwi = points.col(i); vfloat3 Vwi = directions.col(i); //first point on line i vfloat3 Pci; Pci = rot_wc * Pwi + pos_wc; Pc_new.col(i) = Pci - (Pci.transpose() * nci) * nci; //second point is the closest point on line i to camera center. vfloat3 Pw2i; Pw2i = Pwi - (Pwi.transpose() * Vwi) * Vwi; Pw2.col(i) = Pw2i; vfloat3 Pc2i; Pc2i = rot_wc * Pw2i + pos_wc; Pc2_new.col(i) = Pc2i - ( Pc2i.transpose() * nci ) * nci; } MatrixXf XXc(Pc_new.rows(), Pc_new.cols()+Pc2_new.cols()); XXc << Pc_new, Pc2_new; MatrixXf XXw(points.rows(), points.cols()+Pw2.cols()); XXw << points, Pw2; int nm = points.cols()+Pw2.cols(); cal_campose(XXc,XXw,nm,rot_wc,pos_wc); pos_cw = -rot_wc.transpose() * pos_wc; //check the condition n_c^T * rot_wc * V_w = 0; float conditionErr = 0; for(int i =0 ; i < n ; i++) { float val = ( (n_c[i]).transpose() * rot_wc * directions.col(i) ); conditionErr = conditionErr + val*val; } if(conditionErr/n < condition_err_threshold || HowToChooseFixedTwoLines ==3) { //check whether the world scene is in front of the camera. int numLineInFrontofCamera = 0; if(HowToChooseFixedTwoLines<3) { for(int i = 0 ; i < n ; i++) { vfloat3 P_c = rot_wc * (points.col(i) - pos_cw); if(P_c[2]>0) { numLineInFrontofCamera++; } } } else { numLineInFrontofCamera = n; } if(numLineInFrontofCamera > 0.5*n) { //most of the lines are in front of camera, then check the reprojection error. int reprojectionError = 0; for(int i =0; i < n ; i++) { //line projection function vfloat3 nc = rot_wc * x_cross(points.col(i) - pos_cw , directions.col(i)); float h1 = nc.transpose() * start_points.col(i); float h2 = nc.transpose() * end_points.col(i); float lineLen = (start_points.col(i) - end_points.col(i)).norm()/3; reprojectionError += lineLen * (h1*h1 + h1*h2 + h2*h2) / (nc[0]*nc[0]+nc[1]*nc[1]); } if(reprojectionError < minimalReprojectionError) { optimumrot_cw = rot_wc.transpose(); optimumpos_cw = pos_cw; minimalReprojectionError = reprojectionError; } } } } if(optimumrot_cw.rows()>0) { break; } } pos_cw = optimumpos_cw; rot_cw = optimumrot_cw; }