void PropagatedDeformableModel::computeNewBand(SpinalCord* mesh, CVector3 initialPoint, CVector3 nextPoint, int resolution) { CMatrix4x4 transformationFromOrigin; double angle; CMatrix3x3 trZ; CVector3 point, normale; CVector3 directionCourante = nextPoint-initialPoint, lastNormal = (nextPoint-initialPoint).Normalize(), directionCourantePerpendiculaire; if (lastNormal[2] == 0.0) directionCourantePerpendiculaire = CVector3(0.0,0.0,1.0); else directionCourantePerpendiculaire = CVector3(1.0,2.0,-(lastNormal[0]+2*lastNormal[1])/lastNormal[2]).Normalize(); CVector3 stretchingFactorWorld = image3D_->TransformContinuousIndexToPhysicalPoint(CVector3((1-1.0/stretchingFactor_), 0.0, 0.0))-image3D_->getOrigine(); int offsetTriangles = mesh->getNbrOfPoints()-resolutionRadiale_; for (int len=1; len<=resolution; len++) { CVector3 pointIntermediaire = initialPoint + len*directionCourante/(double)resolutionAxiale_; Referential refCourant = Referential(lastNormal^directionCourantePerpendiculaire, directionCourantePerpendiculaire, lastNormal, pointIntermediaire); transformationFromOrigin = refCourant.getTransformationInverse(); for (int k=0; k<resolutionRadiale_; k++) { angle = 2*M_PI*k/(double)resolutionRadiale_; trZ[0] = cos(angle), trZ[1] = sin(angle), trZ[3] = -sin(angle), trZ[4] = cos(angle); point = transformationFromOrigin*(trZ*CVector3(rayon_,0.0,0.0)); CVector3 vecPoint = initialPoint - point; point[0] += stretchingFactorWorld[0]*vecPoint[0]; point[1] += stretchingFactorWorld[1]*vecPoint[1]; point[2] += stretchingFactorWorld[2]*vecPoint[2]; mesh->addPoint(new Vertex(point,(point-pointIntermediaire).Normalize())); } // Ajout des triangles - attention � la structure en cercle for (int k=0; k<resolutionRadiale_-1; k++) { mesh->addTriangle(offsetTriangles+(len-1)*resolutionRadiale_+k,offsetTriangles+(len-1)*resolutionRadiale_+k+1,offsetTriangles+len*resolutionRadiale_+k); mesh->addTriangle(offsetTriangles+(len-1)*resolutionRadiale_+k+1,offsetTriangles+len*resolutionRadiale_+k+1,offsetTriangles+len*resolutionRadiale_+k); } // Ajout des deux derniers triangles pour fermer le tube mesh->addTriangle(offsetTriangles+(len-1)*resolutionRadiale_+resolutionRadiale_-1,offsetTriangles+(len-1)*resolutionRadiale_,offsetTriangles+len*resolutionRadiale_+resolutionRadiale_-1); mesh->addTriangle(offsetTriangles+(len-1)*resolutionRadiale_,offsetTriangles+len*resolutionRadiale_,offsetTriangles+len*resolutionRadiale_+resolutionRadiale_-1); } }
void Transformer::transform() { // convert translation and rotation from local to global coords Eigen::Quaterniond refq = ref_.get_rotation(); Eigen::Vector3d global_t(refq * t_); Eigen::Quaterniond global_q(pick_positive(refq * q_ * refq.conjugate())); // get rb centroid as a translation Eigen::Vector3d centroid(Referential(m_, target_).get_centroid()); // transform each rigid member RigidBody d(m_, target_); ParticleIndexes pis(d.get_member_particle_indexes()); for (unsigned i = 0; i < pis.size(); i++) { XYZ xyz(m_, pis[i]); Eigen::Vector3d coords; coords << xyz.get_x(), xyz.get_y(), xyz.get_z(); Eigen::Vector3d newcoords = global_q * (coords - centroid) + centroid + global_t; xyz.set_x(newcoords(0)); xyz.set_y(newcoords(1)); xyz.set_z(newcoords(2)); } // update rigid body d.set_reference_frame_from_members(pis); }
SpinalCord* PropagatedDeformableModel::propagationMesh(int numberOfMesh) { double const_contrast = 200.0; if (image3D_->getTypeImageFactor() == 1.0) const_contrast = 445.0; // if T2 /****************************************************************************************** * Initialization of the spinal cord mesh * Depending of the choice of propagation, the contrast vector is reversed to take the correct values *****************************************************************************************/ SpinalCord* initialMesh = new SpinalCord(); if (numberOfMesh == 1) initialMesh = initialTube1; else if (numberOfMesh == 2) { reverse(contrast.begin(),contrast.end()); initialMesh = initialTube2; } vector< vector<CVector3> > lastDisks; /****************************************************************************************** * Deformation of the initial mesh. * This deformation must be accurate to have a correct initialization. If not, errors can be propagated. * The number of iteration and the stop condition of the deformation is 0.05 mm by default *****************************************************************************************/ if (verbose_) cout << endl << endl << "Initial deformation : " << initialMesh->getNbrOfPoints() << " points and " << initialMesh->getNbrOfTriangles() << " triangles" << endl; DeformableModelBasicAdaptator *deformableAdaptator = new DeformableModelBasicAdaptator(image3D_,initialMesh,numberOfDeformIteration_,const_contrast,false); deformableAdaptator->setVerbose(verbose_); deformableAdaptator->setNumberOfIteration(8); //8 deformableAdaptator->setStopCondition(0.05); if (tradeoff_d_bool) deformableAdaptator->setTradeOff(tradeoff_d_); //deformableAdaptator->setProgressiveLineSearchLength(true);// tested but not optimal deformableAdaptator->addCorrectionPoints(points_mask_correction_); deformableAdaptator->adaptation(); // launch the deformation meshOutput = deformableAdaptator->getSpinalCordOutput(); // get the spinal cord segmentation mesh delete deformableAdaptator; // release memory meshOutput->setRadialResolution(resolutionRadiale_); // the output of DeformableModelBasicAdaptator is a mesh and we need to provide the radial resolution for further computation // we remove the last disk to prevent edges issues in the deformation process. Indeed, edges have less neighbors and the last disk retract itself. meshOutput->removeLastPoints(resolutionRadiale_); meshOutput->removeLastTriangles(2*resolutionRadiale_); /****************************************************************************************** * Initialization of variables * numberOfDisks is a constant of propagation - don't change it * uniqueMesh is the part of the mesh that will be deformed at each iteration * newStartPoint is the center of the last disk of the mesh. It is the new start point of the propagation. The mesh is duplicated and translated on this point. *****************************************************************************************/ unsigned int numberOfDisks = resolutionAxiale_+1; CVector3 nextPoint, newStartPoint, lastPoint, firstPoint = meshOutput->computeGravityCenterFirstDisk(numberOfDisks); // computation of first point = center of mass of the fisrt disk centerline.push_back(firstPoint); // add point to centerline - first point necessary SpinalCord *uniqueMesh = meshOutput->extractPartOfMesh(numberOfDisks,true,true); // extraction of a part of the mesh uniqueMesh->computeConnectivity(); uniqueMesh->computeTrianglesBarycentre(); newStartPoint = meshOutput->computeGravityCenterFirstDisk(numberOfDisks); // compute first point of the mesh /****************************************************************************************** * Computation of the initial rotation value. * It is used as a mesh refreshing condition. If the difference between initial and updated rotation value if too high, a new part of mesh is used as the template to be duplicated. Rotation value is the sum of intensity at vertices positions. *****************************************************************************************/ GlobalAdaptation* gAdaptI = new GlobalAdaptation(image3D_,uniqueMesh,newStartPoint,"rotation"); CVector3 normal_mesh = CVector3(initialNormal2_[0],initialNormal2_[1],initialNormal2_[2]); gAdaptI->setNormalMesh(normal_mesh); gAdaptI->setVerbose(verbose_); double initialRotationValue = gAdaptI->getInitialValue(), rotationValue = 0.0; delete gAdaptI; CVector3 position; /****************************************************************************************** * initialization of stop condition variables *****************************************************************************************/ bool done = false; area[0] = 0.0; area[1] = 0.0; area[2] = 0.0; double meanVoxels[3]; meanVoxels[0] = 0.0; meanVoxels[1] = 0.0; meanVoxels[2] = 0.0; //double meanVoxelsInit = meshOutput->computeStandardDeviationFromPixelsInside(image3D_->getImageOriginale()); // homogeneity stop condition - not optimal int numberOfBadOrientation = 0, numberOfBadOrientationTotal = 0, maxBadOrientation = 150; meanContrast = 0.0; /****************************************************************************************** * Iterative deformation by adding a portion of mesh at each iteration *****************************************************************************************/ int i; for (i=1; i<=numberOfPropagationIteration_ && !done; i++) { if (verbose_) cout << endl << "Propagation step " << i << "/" << numberOfPropagationIteration_ << endl; centerline = meshOutput->computeCenterline(); double segmentationLength = 0.0; for (unsigned int c=1; c<centerline.size(); c++) segmentationLength += (centerline[c]-centerline[c-1]).Norm(); if (verbose_) cout << "Propagation length [mm] : " << segmentationLength << " / " << propagationLength_ << endl; /****************************************************************************************** * Referential computation on the last disk of the mesh * Computation of the local spinal cord / CSF contrast along the mesh * Computation of the mean contrast from last disk positions. The mean contrast is used as a parameter in the local deformation and as a stop condition *****************************************************************************************/ CVector3 sourcePoint1 = centerline[centerline.size()-1], sourcePoint2 = centerline[centerline.size()-5]; CVector3 lastNormal = (sourcePoint1-sourcePoint2).Normalize(), directionCourantePerpendiculaire; if (lastNormal[2] == 0.0) directionCourantePerpendiculaire = CVector3(0.0,0.0,1.0); else directionCourantePerpendiculaire = CVector3(1.0,2.0,-(lastNormal[0]+2*lastNormal[1])/lastNormal[2]).Normalize(); Referential refCourant = Referential(lastNormal^directionCourantePerpendiculaire, directionCourantePerpendiculaire, lastNormal, sourcePoint2); contrast.push_back(pair<CVector3,double>(refCourant.getOrigine(),computeContrast(refCourant))); int nbContrast = contrast.size()-1; if (verbose_) cout << "Contrast = " << contrast[nbContrast].second << endl; if (nbContrast == 0) meanContrast = (contrast[0].second+2*const_contrast)/3.0; else if (nbContrast == 1) meanContrast = (contrast[nbContrast].second+contrast[nbContrast-1].second+const_contrast)/3.0; else meanContrast = (contrast[nbContrast].second+contrast[nbContrast-1].second+contrast[nbContrast-2].second)/3.0; // mean 445.8476 std 113.5695 max 708.9200 min 148.6900 if (verbose_) cout << "Iteration Position = " << sourcePoint1 << endl; /****************************************************************************************** * newStartPoint is the last point of the mesh and will be the first point of the new section (for duplication and translation) *****************************************************************************************/ newStartPoint = meshOutput->computeGravityCenterLastDisk(numberOfDisks); CVector3 indexPosition, temp; bool inOut = image3D_->TransformPhysicalPointToIndex(newStartPoint,indexPosition); // stop condition CVector3 lastPointReal = lastPoint; if (lastPointReal == CVector3::ZERO) lastPointReal = newStartPoint; /****************************************************************************************** * stop conditions: * length of propagation * mean local contrast between CSF and spinal cord * abnormalities - not good if the new starting point is behind the last starting point * inferior and superior limits can be imposed by the user *****************************************************************************************/ if (segmentationLength < propagationLength_ && meanContrast > minContrast && abs(newStartPoint[1]-lastPointReal[1]) <= 15.0 && indexPosition[1]<upLimit && indexPosition[1]>downLimit) { lastPoint = meshOutput->computeGravityCenterFirstDisk(numberOfDisks); if (position == CVector3()) position = lastPoint; SpinalCord *partMesh = meshOutput->extractLastDiskOfMesh(false); CMatrix4x4 translation, transformation; translation[12] = newStartPoint[0]-position[0]; translation[13] = newStartPoint[1]-position[1]; translation[14] = newStartPoint[2]-position[2]; position = newStartPoint; uniqueMesh->transform(translation); bool orientationBool = true; /****************************************************************************************** * GlobalAdaptation compute the rigid transformation of the mesh to the image using the gradient magnitude * It can provide a value of the gradient at the surface vertice positions for a quality control with the function getInitialValue() * This value is used to change the mesh when it doesn't correspond anymore to the spinal cord edges - this value is negative * The function adaptation() compute the orientation and transform the mesh *****************************************************************************************/ GlobalAdaptation* gAdapt = new GlobalAdaptation(image3D_,uniqueMesh,newStartPoint,"rotation"); normal_mesh = CVector3(translation[12],translation[13],translation[14]); gAdapt->setNormalMesh(normal_mesh); gAdapt->setVerbose(verbose_); rotationValue = gAdapt->getInitialValue(); if (rotationValue >= 0.75*initialRotationValue || rotationValue <= 1.5*initialRotationValue) { // if the value of GlobalAdaptation isn't in range, we replace the mesh // release the memory and create a new mesh using the last disks delete uniqueMesh; uniqueMesh = meshOutput->extractPartOfMesh(numberOfDisks,true,true); uniqueMesh->computeConnectivity(); uniqueMesh->computeTrianglesBarycentre(); lastPoint = meshOutput->computeGravityCenterFirstDisk(numberOfDisks); CMatrix4x4 translation, transformation; translation[12] = newStartPoint[0]-lastPoint[0]; translation[13] = newStartPoint[1]-lastPoint[1]; translation[14] = newStartPoint[2]-lastPoint[2]; position = newStartPoint; uniqueMesh->transform(translation); // translate the mesh to its new position gAdapt = new GlobalAdaptation(image3D_,uniqueMesh,newStartPoint,"rotation"); normal_mesh = CVector3(translation[12],translation[13],translation[14]); gAdapt->setNormalMesh(normal_mesh); gAdapt->setVerbose(verbose_); initialRotationValue = gAdapt->getInitialValue(); rotationValue = gAdapt->getInitialValue(); } /****************************************************************************************** * if the centerline of the spinal cord is provided by the user, it is what it's used to compute the rotation at each propagation iteration * TODO: spline interpolation *****************************************************************************************/ if (propCenterline_) { // Computation of the rotation based on the centerline // Find the point in centerline that is the nearest point to our new starting point. double nearest_point_value = centerline_approximator.getNearestPoint(newStartPoint, range); // Evaluate the derivative of the centerline at this location CVector3 normal = centerline_approximator.EvaluateGradient(nearest_point_value).Normalize(); // Compute normal of our mesh at the starting position if (numberOfMesh == 1) normal = -normal; // the normal is inverted for the first mesh CVector3 lastNormalMesh = (newStartPoint-lastPoint).Normalize(); // Compute rotation between the two normals. We need to compute all the necessary axis for establishing referentials. CVector3 directionCourantePerpendiculaireMesh, directionCourantePerpendiculaireCenterline; if (lastNormalMesh[2] == 0.0) directionCourantePerpendiculaireMesh = CVector3(0.0,0.0,1.0); else directionCourantePerpendiculaireMesh = CVector3(1.0,2.0,-(lastNormalMesh[0]+2*lastNormalMesh[1])/lastNormalMesh[2]).Normalize(); Referential refMesh = Referential(lastNormalMesh^directionCourantePerpendiculaireMesh, directionCourantePerpendiculaireMesh, lastNormalMesh, newStartPoint); if (normal[2] == 0.0) directionCourantePerpendiculaireCenterline = CVector3(0.0,0.0,1.0); else directionCourantePerpendiculaireCenterline = CVector3(1.0,2.0,-(normal[0]+2*normal[1])/normal[2]).Normalize(); Referential refCenterline = Referential(normal^directionCourantePerpendiculaireCenterline, directionCourantePerpendiculaireCenterline, normal, newStartPoint); CMatrix4x4 transformationRotation = refMesh.getTransformation(refCenterline); // As the referential origin is the starting point of our mesh, the transformation that is computed is only a rotation and does not contain any translation. uniqueMesh->transform(transformationRotation,newStartPoint); } /****************************************************************************************** * if the centerline is not provided, the rotation computation used GlobalAdaptation *****************************************************************************************/ else { gAdapt->adaptation(true); // bad orientation (out of known orientation range) can happened if (gAdapt->getBadOrientation()) { numberOfBadOrientation++; numberOfBadOrientationTotal++; } else numberOfBadOrientation = 0; } if (orientationBool) // The program can stop if too much bad orientation - not used for now { /****************************************************************************************** * Creation of a new mesh with the last disk of meshOutput and the new mesh (uniqueMesh) correctly oriented *****************************************************************************************/ partMesh->assembleMeshes(uniqueMesh,numberOfDisks,resolutionRadiale_); partMesh->computeConnectivity(); partMesh->computeTrianglesBarycentre(); if (verbose_) cout << "Mesh deformation : " << partMesh->getNbrOfPoints() << " points and " << partMesh->getNbrOfTriangles() << " triangles" << endl; /****************************************************************************************** * Creation of the deformation object, including the image, the mesh and the deformation parameters *****************************************************************************************/ deformableAdaptator = new DeformableModelBasicAdaptator(image3D_,partMesh,numberOfDeformIteration_,meanContrast,false); if (tradeoff_d_bool) deformableAdaptator->setTradeOff(tradeoff_d_); deformableAdaptator->setVerbose(verbose_); if (this->changedParameters_) { deformableAdaptator->changedParameters(); deformableAdaptator->setAlpha(alpha); deformableAdaptator->setBeta(beta); deformableAdaptator->setLineSearch(line_search); } deformableAdaptator->addCorrectionPoints(points_mask_correction_); /****************************************************************************************** * Deformation of the mesh *****************************************************************************************/ double deformation = deformableAdaptator->adaptation(); /****************************************************************************************** * Extraction of the deformation result and verification of stop conditions: * mesh consistency * maximum deformation * maximum cross-sectional area * number of wrong orientation (sign of a wrong orientation) *****************************************************************************************/ SpinalCord* deformed_spinalcord = deformableAdaptator->getSpinalCordOutput(); deformed_spinalcord->computeConnectivity(); deformed_spinalcord->computeTrianglesBarycentre(); deformed_spinalcord->Initialize(resolutionRadiale_); CVector3 secondPoint = deformed_spinalcord->computeGravityCenterSecondDisk(); double lastCrossSectionalArea = deformed_spinalcord->computeLastCrossSectionalArea(); area[0] = area[1]; area[1] = area[2]; area[2] = lastCrossSectionalArea; meanArea = (area[0]+area[1]+area[2])/3.0; if ((secondPoint-lastPoint)*(newStartPoint-lastPoint)<0.0) { if (verbose_) cout << "Stop by deformation error : overlap during propagation" << endl; done = true; } if (deformation >= maxDeformation) { if (verbose_) cout << "Stop by too large deformation : " << deformation << "/" << maxDeformation << endl; done = true; } if ((meanArea >= maxArea && abs(area[2]-area[1]) >= maxArea/7.0) || meanArea >= 1.2*maxArea) {// || (area[1]>=maxArea && area[2]<maxArea)) { if (verbose_) cout << "Stop by too large cross sectionnal area : " << meanArea << "/" << maxArea << endl; done = true; } if (numberOfBadOrientation >= maxBadOrientation) { if (verbose_) cout << "Stop by too much bad orientation during propagation : " << numberOfBadOrientation << "/" << maxBadOrientation << endl; done = true; } /****************************************************************************************** * Assembling meshOutput (whole spinal cord segmentation) and the new part of the deformed mesh *****************************************************************************************/ if (!done) { meshOutput->assembleMeshes(deformed_spinalcord,numberOfDisks,resolutionRadiale_); meshOutput->computeConnectivity(); meshOutput->computeTrianglesBarycentre(); // if the mesh get out the image, the propagation has to stop if(!inOut || indexPosition[1]>upLimit || indexPosition[1]<downLimit) { done = true; if (!inOut && verbose_) cout << "Stop because out of image" << endl; if (indexPosition[1]>upLimit && verbose_) cout << "Stop because out of range: up" << endl; if (indexPosition[1]<downLimit && verbose_) cout << "Stop because out of range: down" << endl; } } delete deformed_spinalcord; } else { if (verbose_) cout << "Stop by bad orientation" << endl; done = true; } delete partMesh, gAdapt, deformableAdaptator;//, orientationFilter; } else { done = true; if (!inOut && verbose_) cout << "Stop because out of image" << endl; if (indexPosition[1]>=upLimit && verbose_) cout << "Stop because out of range: up" << endl; if (indexPosition[1]<=downLimit && verbose_) cout << "Stop because out of range: down" << endl; if (abs(newStartPoint[1]-lastPointReal[1]) > 15.0 && verbose_) cout << "Stop because bad direction" << endl; } if (verbose_) cout << "Number of bad orientation = " << numberOfBadOrientationTotal << " / " << i << endl; if (verbose_) cout << "Contrast : " << meanContrast << " / " << minContrast << endl; /****************************************************************************************** * Computation of the new spinal cord centerline *****************************************************************************************/ centerline = meshOutput->computeCenterline(); if (verbose_) { double distanceSegmentation = 0.0; int interval = 1; for (unsigned int c=interval; c<centerline.size(); c+=interval) distanceSegmentation += (centerline[c]-centerline[c-interval]).Norm(); cout << "Distance of segmentation [mm] = " << distanceSegmentation << endl; } } /****************************************************************************************** * Smoothing of the low-resolution mesh *****************************************************************************************/ meshOutput->smoothing(70); return meshOutput; }
void PropagatedDeformableModel::computeMeshInitial() { // centerline can be added to be followed. Points of centerline have to be added from bottom to top if (propCenterline_) { if (centerline.size() < 1) { cerr << "Error: Not enought points in centerline" << endl; return; } else { //int init = centerline.size()*init_position_; /****************************************************************************************** * If a centerline is used for the orientation computation, we compute its BSpline approximation. This approximation is used for centerline position and orientation extraction * The parameter range is the centerline approximation accuracy *****************************************************************************************/ initial_centerline = centerline; centerline_approximator = BSplineApproximation(&initial_centerline); initialPoint_ = centerline_approximator.EvaluateBSpline(init_position_); initialNormal1_ = -centerline_approximator.EvaluateGradient(init_position_-0.01).Normalize(); initialNormal2_ = centerline_approximator.EvaluateGradient(init_position_+0.01).Normalize();; //initialNormal1_ = (centerline[init-1]-centerline[init]).Normalize(); //initialNormal2_ = (centerline[init+1]-centerline[init]).Normalize(); hasInitialPointAndNormals_ = true; } } if (centerline.size() < 1 && !hasInitialPointAndNormals_) { cerr << "Error: Not enought points in centerline" << endl; } else if (centerline.size() == 2) { initialTube1 = new SpinalCord; CVector3 directionInitiale = (centerline[1]-centerline[0]).Normalize(), directionInitialePerpendiculaire; if (directionInitiale[2] == 0.0) directionInitialePerpendiculaire = CVector3(0.0,0.0,1.0); else directionInitialePerpendiculaire = CVector3(1.0,2.0,-(directionInitiale[0]+2*directionInitiale[1])/directionInitiale[2]).Normalize(); Referential refInitial = Referential(directionInitiale^directionInitialePerpendiculaire, directionInitialePerpendiculaire, directionInitiale, centerline[0]); CMatrix4x4 transformationFromOrigin = refInitial.getTransformationInverse(); double angle; CMatrix3x3 trZ; CVector3 point, normale; // Compute initial disk for (int k=0; k<resolutionRadiale_; k++) { angle = 2*M_PI*k/(double)resolutionRadiale_; trZ[0] = cos(angle), trZ[1] = sin(angle), trZ[3] = -sin(angle), trZ[4] = cos(angle); point = transformationFromOrigin*(trZ*CVector3(rayon_,0.0,0.0)); initialTube1->addPoint(new Vertex(point,(point-centerline[0]).Normalize())); } CVector3 nextPoint = centerline[0] + deplacementAxial_*directionInitiale; computeNewBand(initialTube1,centerline[0],nextPoint,resolutionAxiale_+2); initialTube1->computeConnectivity(); initialTube1->computeTrianglesBarycentre(); isMeshInitialized = true; meanContrast = computeContrast(refInitial); //cout << "Contrast = " << contrast << endl; } else if (hasInitialPointAndNormals_) { initialTube1 = new SpinalCord; CVector3 directionInitiale = initialNormal1_, directionInitialePerpendiculaire; if (directionInitiale[2] == 0.0) directionInitialePerpendiculaire = CVector3(0.0,0.0,1.0); else directionInitialePerpendiculaire = CVector3(1.0,2.0,-(directionInitiale[0]+2*directionInitiale[1])/directionInitiale[2]).Normalize(); Referential refInitial = Referential(directionInitiale^directionInitialePerpendiculaire, directionInitialePerpendiculaire, directionInitiale, initialPoint_); CMatrix4x4 transformationFromOrigin = refInitial.getTransformationInverse(); double angle; CMatrix3x3 trZ; CVector3 point, normale; CVector3 stretchingFactorWorld = image3D_->TransformContinuousIndexToPhysicalPoint(CVector3((1.0-1.0/stretchingFactor_), 0.0, 0.0))-image3D_->getOrigine(); // Compute initial disk for (int k=0; k<resolutionRadiale_; k++) { angle = 2*M_PI*k/(double)resolutionRadiale_; trZ[0] = cos(angle), trZ[1] = sin(angle), trZ[3] = -sin(angle), trZ[4] = cos(angle); point = transformationFromOrigin*(trZ*CVector3(rayon_,0.0,0.0)); CVector3 vecPoint = initialPoint_ - point; point[0] += stretchingFactorWorld[0]*vecPoint[0]; point[1] += stretchingFactorWorld[1]*vecPoint[1]; point[2] += stretchingFactorWorld[2]*vecPoint[2]; initialTube1->addPoint(new Vertex(point,(point-initialPoint_).Normalize())); } CVector3 nextPoint = initialPoint_ + deplacementAxial_*directionInitiale; computeNewBand(initialTube1,initialPoint_,nextPoint,resolutionAxiale_+2); initialTube1->computeConnectivity(); initialTube1->computeTrianglesBarycentre(); initialTube2 = new SpinalCord; directionInitiale = initialNormal2_; if (directionInitiale[2] == 0.0) directionInitialePerpendiculaire = CVector3(0.0,0.0,1.0); else directionInitialePerpendiculaire = CVector3(1.0,2.0,-(directionInitiale[0]+2*directionInitiale[1])/directionInitiale[2]).Normalize(); refInitial = Referential(directionInitiale^directionInitialePerpendiculaire, directionInitialePerpendiculaire, directionInitiale, initialPoint_); transformationFromOrigin = refInitial.getTransformationInverse(); // Compute initial disk for (int k=0; k<resolutionRadiale_; k++) { angle = 2*M_PI*k/(double)resolutionRadiale_; trZ[0] = cos(angle), trZ[1] = sin(angle), trZ[3] = -sin(angle), trZ[4] = cos(angle); point = transformationFromOrigin*(trZ*CVector3(rayon_,0.0,0.0)); CVector3 vecPoint = initialPoint_ - point; point[0] += stretchingFactorWorld[0]*vecPoint[0]; point[1] += stretchingFactorWorld[1]*vecPoint[1]; point[2] += stretchingFactorWorld[2]*vecPoint[2]; initialTube2->addPoint(new Vertex(point,(point-initialPoint_).Normalize())); } nextPoint = initialPoint_ + deplacementAxial_*directionInitiale; computeNewBand(initialTube2,initialPoint_,nextPoint,resolutionAxiale_+2); initialTube2->computeConnectivity(); initialTube2->computeTrianglesBarycentre(); isMeshInitialized = true; meanContrast = computeContrast(refInitial); } else { initialTube1 = new SpinalCord; CVector3 directionInitiale = (centerline[1]-centerline[0]).Normalize(), directionInitialePerpendiculaire; if (directionInitiale[2] == 0.0) directionInitialePerpendiculaire = CVector3(0.0,0.0,1.0); else directionInitialePerpendiculaire = CVector3(1.0,2.0,-(directionInitiale[0]+2*directionInitiale[1])/directionInitiale[2]).Normalize(); Referential refInitial = Referential(directionInitiale^directionInitialePerpendiculaire, directionInitialePerpendiculaire, directionInitiale, centerline[0]); CMatrix4x4 transformationFromOrigin = refInitial.getTransformationInverse(); double angle; CMatrix3x3 trZ; CVector3 point, normale; // Compute initial disk for (int k=0; k<resolutionRadiale_; k++) { angle = 2*M_PI*k/(double)resolutionRadiale_; trZ[0] = cos(angle), trZ[1] = sin(angle), trZ[3] = -sin(angle), trZ[4] = cos(angle); point = transformationFromOrigin*(trZ*CVector3(rayon_,0.0,0.0)); initialTube1->addPoint(new Vertex(point,(point-centerline[0]).Normalize())); } for (unsigned int i=1; i<centerline.size(); i++) { computeNewBand(initialTube1,centerline[i-1],centerline[i],resolutionAxiale_); } initialTube1->computeConnectivity(); initialTube1->computeTrianglesBarycentre(); isMeshInitialized = true; } }