void milxQtDiffusionTensorModel::colourByDirection() { vtkSmartPointer<vtkPolyData> currentMesh = model.Result(); typedef double projectionType; ///Determine colours based on axes directions vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New(); scalars->SetNumberOfComponents(3); scalars->SetNumberOfTuples(currentMesh->GetNumberOfPoints()); scalars->SetName("Fibre Colours"); scalars->FillComponent(0, 0); scalars->FillComponent(1, 0); scalars->FillComponent(2, 0); vtkSmartPointer<vtkFloatArray> projections = vtkSmartPointer<vtkFloatArray>::New(); projections->SetNumberOfComponents(3); projections->SetNumberOfTuples(currentMesh->GetNumberOfPoints()); projections->SetName("Fibre Projections"); projections->FillComponent(0, 0.0); projections->FillComponent(1, 0.0); projections->FillComponent(2, 0.0); emit working(-1); if(currentMesh->GetNumberOfLines() == 0) { printInfo("No lines in model. Computing colours for mesh."); ///Use the dot product in each axis for(size_t j = 0; j < 3; j ++) { projectionType axis[3] = {0.0, 0.0, 0.0}; axis[j] = 1.0; cout << "Computing toward axis " << j << endl; ///Colour based on each of the gradient values in that direction for(vtkIdType k = 0; k < currentMesh->GetNumberOfPoints(); k ++) { coordinate currentProjection(projections->GetTuple3(k)), position(currentMesh->GetPoint(k)); projectionType projection = vtkMath::Dot(axis, position.data_block()); //project to axis being done, currentProjection[j] = projection; //projection in each direction projections->SetTuple3(k, currentProjection[0], currentProjection[1], currentProjection[2]); } } ///Colour based on each of the gradient values in that direction for(vtkIdType k = 0; k < currentMesh->GetNumberOfPoints(); k ++) { coordinate currentProjection(projections->GetTuple3(k)); coordinate currentProjSquared = element_product(currentProjection, currentProjection); projectionType maxProjection = currentProjSquared.max_value(); currentProjSquared /= maxProjection; unsigned char colourOfPoint[3] = {0, 0, 0}; colourOfPoint[0] = static_cast<unsigned char>( currentProjSquared[0]*255.0 ); colourOfPoint[1] = static_cast<unsigned char>( currentProjSquared[1]*255.0 ); colourOfPoint[2] = static_cast<unsigned char>( currentProjSquared[2]*255.0 ); scalars->SetTupleValue(k, colourOfPoint); } currentMesh->GetPointData()->SetVectors(projections); currentMesh->GetPointData()->SetScalars(scalars); } else { printInfo("Re-colouring lines by axes directions"); //Ensure lines done properly so can colour appropriately currentMesh->GetLines()->InitTraversal(); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New(); std::vector<vtkIdType> trackLengths; for(vtkIdType j = 0; j < currentMesh->GetNumberOfLines(); j ++) { currentMesh->GetLines()->GetNextCell(idList); trackLengths.push_back(idList->GetNumberOfIds()); for(vtkIdType pointId = 0; pointId < idList->GetNumberOfIds(); pointId ++) { // std::cout << idList->GetId(pointId) << " "; double position[3]; currentMesh->GetPoint(idList->GetId(pointId), position); points->InsertNextPoint(position); } } //Re-stitch lines together vtkIdType step = 0; vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); for(size_t j = 0; j < trackLengths.size(); j ++) { for(vtkIdType k = step; k < trackLengths[j]-1; k ++) { vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New(); line->GetPointIds()->SetId(0, k); line->GetPointIds()->SetId(1, k+1); lines->InsertNextCell(line); } qDebug() << trackLengths[j] << endl; step += trackLengths[j]; } vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData>::New(); //Add the points to the dataset linesPolyData->SetPoints(points); //Add the lines to the dataset linesPolyData->SetLines(lines); linesPolyData->Modified(); model.SetInput(linesPolyData); } emit done(-1); generateModel(); }
bool PivotCalibration2::ComputeSpinCalibration(bool snapRotation) { if (this->ToolToReferenceMatrices.size() < 10) { this->ErrorText = "Not enough input transforms are available"; return false; } if (this->GetMaximumToolOrientationDifferenceDeg() < this->MinimumOrientationDifferenceDeg) { this->ErrorText = "Not enough variation in the input transforms"; return false; } // Setup our system to find the axis of rotation unsigned int rows = 3, columns = 3; vnl_matrix<double> A(rows, columns, 0); vnl_matrix<double> I(3, 3, 0); I.set_identity(); vnl_matrix<double> RI(rows, columns); // this will store the maximum difference in orientation between the first transform and all the other transforms double maximumOrientationDifferenceDeg = 0; std::vector< vtkSmartPointer<vtkMatrix4x4> >::const_iterator previt = this->ToolToReferenceMatrices.end(); for (std::vector< vtkSmartPointer<vtkMatrix4x4> >::const_iterator it = this->ToolToReferenceMatrices.begin(); it != this->ToolToReferenceMatrices.end(); it++) { if (previt == this->ToolToReferenceMatrices.end()) { previt = it; continue; // No comparison to make for the first matrix } vtkSmartPointer< vtkMatrix4x4 > itinverse = vtkSmartPointer< vtkMatrix4x4 >::New(); vtkMatrix4x4::Invert((*it), itinverse); vtkSmartPointer< vtkMatrix4x4 > instRotation = vtkSmartPointer< vtkMatrix4x4 >::New(); vtkMatrix4x4::Multiply4x4(itinverse, (*previt), instRotation); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { RI(i, j) = instRotation->GetElement(i, j); } } RI = RI - I; A = A + RI.transpose() * RI; previt = it; } // Note: If the needle orientation protocol changes, only the definitions of shaftAxis and secondaryAxes need to be changed // Define the shaft axis and the secondary shaft axis // Current needle orientation protocol dictates: shaft axis -z, orthogonal axis +x // If StylusX is parallel to ShaftAxis then: shaft axis -z, orthogonal axis +y vnl_vector<double> shaftAxis_Shaft(columns, 0); shaftAxis_Shaft(0) = 0; shaftAxis_Shaft(1) = 0; shaftAxis_Shaft(2) = -1; vnl_vector<double> orthogonalAxis_Shaft(columns, 0); orthogonalAxis_Shaft(0) = 1; orthogonalAxis_Shaft(1) = 0; orthogonalAxis_Shaft(2) = 0; vnl_vector<double> backupAxis_Shaft(columns, 0); backupAxis_Shaft(0) = 0; backupAxis_Shaft(1) = 1; backupAxis_Shaft(2) = 0; // Find the eigenvector associated with the smallest eigenvalue // This is the best axis of rotation over all instantaneous rotations vnl_matrix<double> eigenvectors(columns, columns, 0); vnl_vector<double> eigenvalues(columns, 0); vnl_symmetric_eigensystem_compute(A, eigenvectors, eigenvalues); // Note: eigenvectors are ordered in increasing eigenvalue ( 0 = smallest, end = biggest ) vnl_vector<double> shaftAxis_ToolTip(columns, 0); shaftAxis_ToolTip(0) = eigenvectors(0, 0); shaftAxis_ToolTip(1) = eigenvectors(1, 0); shaftAxis_ToolTip(2) = eigenvectors(2, 0); shaftAxis_ToolTip.normalize(); // Snap the direction vector to be exactly aligned with one of the coordinate axes // This is if the sensor is known to be parallel to one of the axis, just not which one if (snapRotation) { int closestCoordinateAxis = element_product(shaftAxis_ToolTip, shaftAxis_ToolTip).arg_max(); shaftAxis_ToolTip.fill(0); shaftAxis_ToolTip.put(closestCoordinateAxis, 1); // Doesn't matter the direction, will be sorted out in the next step } // Make sure it is in the correct direction (opposite the StylusTipToStylus translation) vnl_vector<double> toolTipToToolTranslation(3); toolTipToToolTranslation(0) = this->ToolTipToToolMatrix->GetElement(0, 3); toolTipToToolTranslation(1) = this->ToolTipToToolMatrix->GetElement(1, 3); toolTipToToolTranslation(2) = this->ToolTipToToolMatrix->GetElement(2, 3); if (dot_product(shaftAxis_ToolTip, toolTipToToolTranslation) > 0) { shaftAxis_ToolTip = shaftAxis_ToolTip * (-1); } //set the RMSE this->SpinRMSE = (A * shaftAxis_ToolTip).rms(); // If the secondary axis 1 is parallel to the shaft axis in the tooltip frame, then use secondary axis 2 vnl_vector<double> orthogonalAxis_ToolTip; double angle = acos(dot_product(shaftAxis_ToolTip, orthogonalAxis_Shaft)); // Force angle to be between -pi/2 and +pi/2 if (angle > vtkMath::Pi() / 2) { angle -= vtkMath::Pi(); } if (angle < -vtkMath::Pi() / 2) { angle += vtkMath::Pi(); } if (fabs(angle) > vtkMath::RadiansFromDegrees(PARALLEL_ANGLE_THRESHOLD_DEGREES)) // If shaft axis and orthogonal axis are not parallel { orthogonalAxis_ToolTip = orthogonalAxis_Shaft; } else { orthogonalAxis_ToolTip = backupAxis_Shaft; } // Do the registration find the appropriate rotation orthogonalAxis_ToolTip = orthogonalAxis_ToolTip - dot_product(orthogonalAxis_ToolTip, shaftAxis_ToolTip) * shaftAxis_ToolTip; orthogonalAxis_ToolTip.normalize(); // Register X,Y,O points in the two coordinate frames (only spherical registration - since pure rotation) vnl_matrix<double> ToolTipPoints(3, 3, 0.0); vnl_matrix<double> ShaftPoints(3, 3, 0.0); ToolTipPoints.put(0, 0, shaftAxis_ToolTip(0)); ToolTipPoints.put(0, 1, shaftAxis_ToolTip(1)); ToolTipPoints.put(0, 2, shaftAxis_ToolTip(2)); ToolTipPoints.put(1, 0, orthogonalAxis_ToolTip(0)); ToolTipPoints.put(1, 1, orthogonalAxis_ToolTip(1)); ToolTipPoints.put(1, 2, orthogonalAxis_ToolTip(2)); ToolTipPoints.put(2, 0, 0); ToolTipPoints.put(2, 1, 0); ToolTipPoints.put(2, 2, 0); ShaftPoints.put(0, 0, shaftAxis_Shaft(0)); ShaftPoints.put(0, 1, shaftAxis_Shaft(1)); ShaftPoints.put(0, 2, shaftAxis_Shaft(2)); ShaftPoints.put(1, 0, orthogonalAxis_Shaft(0)); ShaftPoints.put(1, 1, orthogonalAxis_Shaft(1)); ShaftPoints.put(1, 2, orthogonalAxis_Shaft(2)); ShaftPoints.put(2, 0, 0); ShaftPoints.put(2, 1, 0); ShaftPoints.put(2, 2, 0); vnl_svd<double> ShaftToToolTipRegistrator(ShaftPoints.transpose() * ToolTipPoints); vnl_matrix<double> V = ShaftToToolTipRegistrator.V(); vnl_matrix<double> U = ShaftToToolTipRegistrator.U(); vnl_matrix<double> Rotation = V * U.transpose(); // Make sure the determinant is positve (i.e. +1) double determinant = vnl_determinant(Rotation); if (determinant < 0) { // Switch the sign of the third column of V if the determinant is not +1 // This is the recommended approach from Huang et al. 1987 V.put(0, 2, -V.get(0, 2)); V.put(1, 2, -V.get(1, 2)); V.put(2, 2, -V.get(2, 2)); Rotation = V * U.transpose(); } // Set the elements of the output matrix for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { this->ToolTipToToolMatrix->SetElement(i, j, Rotation[i][j]); } } this->ErrorText.empty(); return true; }