PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
PlusFidLabeling.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "PlusConfigure.h"
9 #include "PlusFidLabeling.h"
10 #include "igsioMath.h"
11 #include "PlusFidSegmentation.h"
12 
13 // VTK includes
14 #include <vtkPlane.h>
15 #include <vtkTriangle.h>
16 
17 // STL includes
18 #include <algorithm>
19 
20 //-----------------------------------------------------------------------------
22  : m_ApproximateSpacingMmPerPixel(-1.0)
23  , m_MaxAngleDiff(-1.0)
24  , m_MinLinePairDistMm(-1.0)
25  , m_MaxLinePairDistMm(-1.0)
26  , m_MinLinePairAngleRad(-1.0)
27  , m_MaxLinePairAngleRad(-1.0)
28  , m_MaxLineShiftMm(10.0)
29  , m_MaxLinePairDistanceErrorPercent(-1.0)
30  , m_MinThetaRad(-1.0)
31  , m_MaxThetaRad(-1.0)
32  , m_DotsFound(false)
33  , m_AngleToleranceRad(-1.0)
34  , m_InclinedLineAngleRad(-1.0)
35  , m_PatternIntensity(-1.0)
36 {
37  m_FrameSize[0] = 0;
38  m_FrameSize[1] = 0;
39  m_FrameSize[2] = 1;
40 }
41 
42 //-----------------------------------------------------------------------------
44 {
45 }
46 
47 //-----------------------------------------------------------------------------
49 {
50  LOG_TRACE("FidLabeling::UpdateParameters");
51 
52  // Distance between lines (= distance between planes of the N-wires)
53  std::vector<PlusFidPattern*>::size_type numOfPatterns = m_Patterns.size();
54  double epsilon = 0.001;
55 
56  // Compute normal of each pattern and evaluate the other wire endpoints if they are on the computed plane
57  std::vector<vtkSmartPointer<vtkPlane>> planes;
58  for (std::vector<PlusFidPattern*>::size_type i = 0; i < numOfPatterns; ++i)
59  {
60  double normal[3] = {0, 0, 0};
61  double v1[3], v2[3], v3[3];
62  memcpy(v1, m_Patterns[i]->GetWires()[0].EndPointFront, sizeof(double) * 3);
63  memcpy(v2, m_Patterns[i]->GetWires()[0].EndPointBack, sizeof(double) * 3);
64  memcpy(v3, m_Patterns[i]->GetWires()[2].EndPointFront, sizeof(double) * 3);
65  vtkTriangle::ComputeNormal(v1, v2, v3, normal);
66 
67  vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
68  plane->SetNormal(normal);
69  plane->SetOrigin(v1);
70  planes.push_back(plane);
71 
72  std::array<double, 3> point1 = { m_Patterns[i]->GetWires()[1].EndPointFront[0], m_Patterns[i]->GetWires()[1].EndPointFront[1], m_Patterns[i]->GetWires()[1].EndPointFront[2] };
73  double distance1F = plane->DistanceToPlane(point1.data());
74  std::array<double, 3> point2 = { m_Patterns[i]->GetWires()[1].EndPointBack[0], m_Patterns[i]->GetWires()[1].EndPointBack[1], m_Patterns[i]->GetWires()[1].EndPointBack[2] };
75  double distance1B = plane->DistanceToPlane(point2.data());
76  std::array<double, 3> point3 = { m_Patterns[i]->GetWires()[2].EndPointBack[0], m_Patterns[i]->GetWires()[2].EndPointBack[1], m_Patterns[i]->GetWires()[2].EndPointBack[2] };
77  double distance2B = plane->DistanceToPlane(point3.data());
78 
79  if (distance1F > epsilon || distance1B > epsilon || distance2B > epsilon)
80  {
81  LOG_ERROR("Pattern number " << i << " is invalid: the endpoints are not on the same plane");
82  }
83  }
84 
85  // Compute distances between each NWire pairs and determine the smallest and the largest distance
86  double maxNPlaneDistance = -1.0;
87  double minNPlaneDistance = std::numeric_limits<double>::max();
88  m_MinLinePairAngleRad = vtkMath::Pi() / 2.0;
90  for (std::vector<PlusFidPattern*>::size_type i = numOfPatterns - 1; i > 0; --i)
91  {
92  for (int j = static_cast<int>(i) - 1; j >= 0; --j)
93  {
94  double distance = planes.at(i)->DistanceToPlane(planes.at(j)->GetOrigin());
95  if (maxNPlaneDistance < distance)
96  {
97  maxNPlaneDistance = distance;
98  }
99  if (minNPlaneDistance > distance)
100  {
101  minNPlaneDistance = distance;
102  }
103  double angle = acos(vtkMath::Dot(planes.at(i)->GetNormal(), planes.at(j)->GetNormal())
104  / vtkMath::Norm(planes.at(i)->GetNormal())
105  / vtkMath::Norm(planes.at(j)->GetNormal()));
106  // Normalize between -pi/2 .. +pi/2
107  if (angle > vtkMath::Pi() / 2)
108  {
109  angle -= vtkMath::Pi();
110  }
111  else if (angle < -vtkMath::Pi() / 2)
112  {
113  angle += vtkMath::Pi();
114  }
115  // Return the absolute value (0..+pi/2)
116  angle = fabs(angle);
117  if (angle < m_MinLinePairAngleRad)
118  {
119  m_MinLinePairAngleRad = angle;
120  }
121  if (angle > m_MaxLinePairAngleRad)
122  {
123  m_MaxLinePairAngleRad = angle;
124  }
125  }
126  }
127 
128  m_MaxLinePairDistMm = maxNPlaneDistance * (1.0 + (m_MaxLinePairDistanceErrorPercent / 100.0));
129  m_MinLinePairDistMm = minNPlaneDistance * (1.0 - (m_MaxLinePairDistanceErrorPercent / 100.0));
130  LOG_DEBUG("Line pair distance - computed min: " << minNPlaneDistance << " , max: " << maxNPlaneDistance << "; allowed min: " << m_MinLinePairDistMm << ", max: " << m_MaxLinePairDistMm);
131 }
132 
133 //-----------------------------------------------------------------------------
134 PlusStatus PlusFidLabeling::ReadConfiguration(vtkXMLDataElement* configData, double minThetaRad, double maxThetaRad)
135 {
136  LOG_TRACE("FidLabeling::ReadConfiguration");
137 
138  XML_FIND_NESTED_ELEMENT_OPTIONAL(segmentationParameters, configData, "Segmentation");
139  if (!segmentationParameters)
140  {
141  segmentationParameters = igsioXmlUtils::GetNestedElementWithName(configData, "Segmentation");
143  }
144 
145  XML_READ_SCALAR_ATTRIBUTE_WARNING(double, ApproximateSpacingMmPerPixel, segmentationParameters);
146 
147 
148  //if the tolerance parameters are computed automatically
149  int computeSegmentationParametersFromPhantomDefinition(0);
150  if (segmentationParameters->GetScalarAttribute("ComputeSegmentationParametersFromPhantomDefinition", computeSegmentationParametersFromPhantomDefinition)
151  && computeSegmentationParametersFromPhantomDefinition != 0)
152  {
153  LOG_WARNING("Automatic computation of the MaxLinePairDistanceErrorPercent and MaxAngleDifferenceDegrees parameters are not yet supported, use the values that are in the config file");
154  }
155 
156  XML_READ_SCALAR_ATTRIBUTE_WARNING(double, MaxLinePairDistanceErrorPercent, segmentationParameters);
157  XML_READ_SCALAR_ATTRIBUTE_WARNING(double, MaxAngleDifferenceDegrees, segmentationParameters);
158  XML_READ_SCALAR_ATTRIBUTE_WARNING(double, AngleToleranceDegrees, segmentationParameters);
159  XML_READ_SCALAR_ATTRIBUTE_WARNING(double, MaxLineShiftMm, segmentationParameters);
160 
161  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, InclinedLineAngleDegrees, segmentationParameters); // only for CIRS
162 
164 
165  m_MinThetaRad = minThetaRad;
166  m_MaxThetaRad = maxThetaRad;
167 
168  return PLUS_SUCCESS;
169 }
170 
171 //-----------------------------------------------------------------------------
173 {
174  //LOG_TRACE("FidLabeling::Clear");
175  m_DotsVector.clear();
176  m_LinesVector.clear();
178  m_Results.clear();
179  m_FoundLines.clear();
180 
181  std::vector<PlusFidLine> emptyLine;
182  m_LinesVector.push_back(emptyLine); //initializing the 0 vector of lines (unused)
183  m_LinesVector.push_back(emptyLine); //initializing the 1 vector of lines (unused)
184 }
185 
186 //-----------------------------------------------------------------------------
187 void PlusFidLabeling::SetFrameSize(const FrameSizeType& frameSize)
188 {
189  LOG_TRACE("FidLineFinder::SetFrameSize(" << frameSize[0] << ", " << frameSize[1] << ")");
190 
191  if ((m_FrameSize[0] == frameSize[0]) && (m_FrameSize[1] == frameSize[1]))
192  {
193  return;
194  }
195 
196  m_FrameSize[0] = frameSize[0];
197  m_FrameSize[1] = frameSize[1];
198  m_FrameSize[2] = 1;
199 
200  if (m_FrameSize[0] < 0 || m_FrameSize[1] < 0)
201  {
202  LOG_ERROR("Dimensions of the frame size are not positive!");
203  return;
204  }
205 }
206 
207 //-----------------------------------------------------------------------------
209 {
210  m_AngleToleranceRad = vtkMath::RadiansFromDegrees(value);
211 }
212 
213 //-----------------------------------------------------------------------------
214 bool PlusFidLabeling::SortCompare(const std::vector<double>& temporaryLine1, const std::vector<double>& temporaryLine2)
215 {
216  //used for SortPointsByDistanceFromOrigin
217  return temporaryLine1[1] < temporaryLine2[1];
218 }
219 
220 //-----------------------------------------------------------------------------
222 {
223  std::vector<std::vector<double>> temporaryLine;
224  PlusFidDot startPointIndex = m_DotsVector[fiducials.GetStartPointIndex()];
225 
226  for (unsigned int i = 0 ; i < fiducials.GetNumberOfPoints() ; i++)
227  {
228  std::vector<double> temp;
229  PlusFidDot point = m_DotsVector[fiducials.GetPoint(i)];
230  temp.push_back(fiducials.GetPoint(i));
231  temp.push_back(sqrt((startPointIndex.GetX() - point.GetX()) * (startPointIndex.GetX() - point.GetX()) + (startPointIndex.GetY() - point.GetY()) * (startPointIndex.GetY() - point.GetY())));
232  temporaryLine.push_back(temp);
233  }
234 
235  //sort the indexes by the distance of their respective pioint to the startPointIndex
236  std::sort(temporaryLine.begin(), temporaryLine.end(), PlusFidLabeling::SortCompare);
237 
238  PlusFidLine resultLine = fiducials;
239 
240  for (unsigned int i = 0 ; i < fiducials.GetNumberOfPoints() ; i++)
241  {
242  resultLine.SetPoint(i, temporaryLine[i][0]);
243  }
244 
245  return resultLine;
246 }
247 
248 //----------------------------------------------------------------------------
249 std::vector<PlusFidPattern*>& PlusFidLabeling::GetPatterns()
250 {
251  return m_Patterns;
252 }
253 
254 //-----------------------------------------------------------------------------
256 {
257  //LOG_TRACE("FidLineFinder::ComputeSlope");
258  PlusFidDot dot1 = m_DotsVector[line.GetStartPointIndex()];
259  PlusFidDot dot2 = m_DotsVector[line.GetEndPointIndex()];
260 
261  double x1 = dot1.GetX();
262  double y1 = dot1.GetY();
263 
264  double x2 = dot2.GetX();
265  double y2 = dot2.GetY();
266 
267  double y = (y2 - y1);
268  double x = (x2 - x1);
269 
270  double t;
271  if (fabs(x) > fabs(y))
272  {
273  t = vtkMath::Pi() / 2 + atan(y / x);
274  }
275  else
276  {
277  double tanTheta = x / y;
278  if (tanTheta > 0)
279  {
280  t = vtkMath::Pi() - atan(tanTheta);
281  }
282  else
283  {
284  t = -atan(tanTheta);
285  }
286  }
287 
288  assert(t >= 0 && t <= vtkMath::Pi());
289  return t;
290 }
291 
292 //-----------------------------------------------------------------------------
294 {
295  double x[3], y[3], z[3];
296 
297  x[0] = m_DotsVector[line.GetStartPointIndex()].GetX();
298  x[1] = m_DotsVector[line.GetStartPointIndex()].GetY();
299  x[2] = 0;
300 
301  y[0] = m_DotsVector[line.GetEndPointIndex()].GetX();
302  y[1] = m_DotsVector[line.GetEndPointIndex()].GetY();
303  y[2] = 0;
304 
305  z[0] = dot.GetX();
306  z[1] = dot.GetY();
307  z[2] = 0;
308 
309  return igsioMath::ComputeDistanceLinePoint(x, y, z);
310 }
311 
312 //-----------------------------------------------------------------------------
314 {
315  //middle of the line 1
316  double midLine1[2] =
317  {
318  (m_DotsVector[line1.GetStartPointIndex()].GetX() + m_DotsVector[line1.GetEndPointIndex()].GetX()) / 2,
319  (m_DotsVector[line1.GetStartPointIndex()].GetY() + m_DotsVector[line1.GetEndPointIndex()].GetY()) / 2
320  };
321  //middle of the line 2
322  double midLine2[2] =
323  {
324  (m_DotsVector[line2.GetStartPointIndex()].GetX() + m_DotsVector[line2.GetEndPointIndex()].GetX()) / 2,
325  (m_DotsVector[line2.GetStartPointIndex()].GetY() + m_DotsVector[line2.GetEndPointIndex()].GetY()) / 2
326  };
327  //vector from one middle to the other
328  double midLine1_to_midLine2[3] =
329  {
330  midLine2[0] - midLine1[0],
331  midLine2[1] - midLine1[1],
332  0
333  };
334 
335  double line1vector[3] =
336  {
337  m_DotsVector[line1.GetEndPointIndex()].GetX() - m_DotsVector[line1.GetStartPointIndex()].GetX(),
338  m_DotsVector[line1.GetEndPointIndex()].GetY() - m_DotsVector[line1.GetStartPointIndex()].GetY(),
339  0
340  };
341  vtkMath::Normalize(line1vector); //need to normalize for the dot product to provide significant result
342 
343  double midLine1_to_midLine2_projectionToLine1_length = vtkMath::Dot(line1vector, midLine1_to_midLine2);
344 
345  return midLine1_to_midLine2_projectionToLine1_length;
346 }
347 
348 //-----------------------------------------------------------------------------
349 void PlusFidLabeling::UpdateNWiresResults(std::vector<PlusFidLine*>& resultLines)
350 {
351  int numberOfLines = m_Patterns.size(); //the number of lines in the pattern
352  double intensity = 0;
353  std::vector<double> dotCoords;
354  std::vector< std::vector<double> > foundDotsCoordinateValues = m_FoundDotsCoordinateValue;
355 
356  for (int i = 0; i < numberOfLines; ++i)
357  {
358  SortRightToLeft(*resultLines[i]);
359  }
360 
361  for (int line = 0; line < numberOfLines; ++line)
362  {
363  for (unsigned int i = 0 ; i < resultLines[line]->GetNumberOfPoints() ; i++)
364  {
365  PlusLabelingResults result;
366  result.x = m_DotsVector[resultLines[line]->GetPoint(i)].GetX();
367  dotCoords.push_back(result.x);
368  result.y = m_DotsVector[resultLines[line]->GetPoint(i)].GetY();
369  dotCoords.push_back(result.y);
370  result.patternId = 0;
371  result.wireId = i;
372  m_Results.push_back(result);
373  foundDotsCoordinateValues.push_back(dotCoords);
374  dotCoords.clear();
375  }
376 
377  intensity += resultLines[line]->GetIntensity();
378 
379  m_FoundLines.push_back(*(resultLines[line]));
380  }
381 
382  m_FoundDotsCoordinateValue = foundDotsCoordinateValues;
383  m_PatternIntensity = intensity;
384  m_DotsFound = true;
385 }
386 
387 //-----------------------------------------------------------------------------
388 void PlusFidLabeling::UpdateCirsResults(const PlusFidLine& resultLine1, const PlusFidLine& resultLine2, const PlusFidLine& resultLine3)
389 {
390  //resultLine1 is the left line, resultLine2 is the diagonal, resultLine3 is the right line
391  double intensity = 0;
392  std::vector<double> dotCoords;
393  std::vector<std::vector<double>> foundDotsCoordinateValues = m_FoundDotsCoordinateValue;
394 
395  for (unsigned int i = 0 ; i < resultLine1.GetNumberOfPoints() ; i++)
396  {
397  PlusLabelingResults result;
398  result.x = m_DotsVector[resultLine1.GetPoint(i)].GetX();
399  dotCoords.push_back(result.x);
400  result.y = m_DotsVector[resultLine1.GetPoint(i)].GetY();
401  dotCoords.push_back(result.y);
402  result.patternId = 0;
403  result.wireId = i;
404  m_Results.push_back(result);
405  foundDotsCoordinateValues.push_back(dotCoords);
406  dotCoords.clear();
407  }
408  intensity += resultLine1.GetIntensity();
409 
410  for (unsigned int i = 0 ; i < resultLine2.GetNumberOfPoints() ; i++)
411  {
412  PlusLabelingResults result;
413  result.x = m_DotsVector[resultLine2.GetPoint(i)].GetX();
414  dotCoords.push_back(result.x);
415  result.y = m_DotsVector[resultLine2.GetPoint(i)].GetY();
416  dotCoords.push_back(result.y);
417  result.patternId = 1;
418  result.wireId = i;
419  m_Results.push_back(result);
420  foundDotsCoordinateValues.push_back(dotCoords);
421  dotCoords.clear();
422  }
423  intensity += resultLine2.GetIntensity();
424 
425  for (unsigned int i = 0 ; i < resultLine3.GetNumberOfPoints() ; i++)
426  {
427  PlusLabelingResults result;
428  result.x = m_DotsVector[resultLine3.GetPoint(i)].GetX();
429  dotCoords.push_back(result.x);
430  result.y = m_DotsVector[resultLine3.GetPoint(i)].GetY();
431  dotCoords.push_back(result.y);
432  result.patternId = 2;
433  result.wireId = i;
434  m_Results.push_back(result);
435  foundDotsCoordinateValues.push_back(dotCoords);
436  dotCoords.clear();
437  }
438  intensity += resultLine3.GetIntensity();
439 
440  m_FoundLines.push_back(resultLine1);
441  m_FoundLines.push_back(resultLine2);
442  m_FoundLines.push_back(resultLine3);
443 
444  m_FoundDotsCoordinateValue = foundDotsCoordinateValues;
445  m_PatternIntensity = intensity;
446  m_DotsFound = true;
447 }
448 
449 //-----------------------------------------------------------------------------
451 {
452  //LOG_TRACE("FidLabeling::FindPattern");
453 
454  std::vector<PlusFidLine> maxPointsLines = m_LinesVector[m_LinesVector.size() - 1];
455  int numberOfLines = m_Patterns.size();//the number of lines in the pattern
456  int numberOfCandidateLines = maxPointsLines.size();
457  std::vector<int> lineIndices(numberOfLines);
458  std::vector<PlusLabelingResults> results;
459 
460  m_DotsFound = false;
461 
462  //permutation generator
463  for (unsigned int i = 0 ; i < lineIndices.size() ; i++)
464  {
465  lineIndices[i] = lineIndices.size() - 1 - i;
466  }
467  lineIndices[0]--;
468 
469  bool foundPattern = false;
470  do
471  {
472  for (int i = 0; i < numberOfLines; i++)
473  {
474  lineIndices[i]++;
475 
476  if (lineIndices[i] < numberOfCandidateLines - i)
477  {
478  // no need to carry over more
479  // the i-th index is correct, so just adjust all the ones before that
480  int nextIndex = lineIndices[i] + 1;
481  for (int j = i - 1; j >= 0; j--)
482  {
483  lineIndices[j] = nextIndex;
484  nextIndex++;
485  }
486  break; //valid permutation
487  }
488 
489  // need to carry over
490  if (i == numberOfLines - 1)
491  {
492  // we are already at the last index, cannot carry over more
493  return;
494  }
495  }
496 
497  // We have a new permutation in lineIndices.
498  // Check if the distance and angle between each possible line pairs within the permutation are within the allowed range.
499  // This is a quick filtering to keep only those line combinations for further processing that may form a valid pattern.
500  foundPattern = true; // assume that we've found a valid pattern (then set the flag to false if it turns out that one of the values are not within the allowed range)
501  for (int i = 0 ; i < numberOfLines - 1 && foundPattern; i++)
502  {
503  PlusFidLine currentLine1 = maxPointsLines[lineIndices[i]];
504  for (int j = i + 1 ; j < numberOfLines && foundPattern; j++)
505  {
506  PlusFidLine currentLine2 = maxPointsLines[lineIndices[j]];
507 
508  double angleBetweenLinesRad = PlusFidLine::ComputeAngleRad(currentLine1, currentLine2);
509  if (angleBetweenLinesRad < m_AngleToleranceRad) //The angle between 2 lines is close to 0
510  {
511  // Parallel lines
512 
513  // Check the distance between the lines
514  double distance = ComputeDistancePointLine(m_DotsVector[currentLine1.GetStartPointIndex()], currentLine2);
515  int maxLinePairDistPx = floor(m_MaxLinePairDistMm / m_ApproximateSpacingMmPerPixel + 0.5);
516  int minLinePairDistPx = floor(m_MinLinePairDistMm / m_ApproximateSpacingMmPerPixel + 0.5);
517  if ((distance > maxLinePairDistPx) || (distance < minLinePairDistPx))
518  {
519  // The distance between the lines is smaller or larger than the allowed range
520  foundPattern = false;
521  break;
522  }
523 
524  // Check the shift (along the direction of the lines)
525  double shift = ComputeShift(currentLine1, currentLine2);
526  int maxLineShiftDistPx = floor(m_MaxLineShiftMm / m_ApproximateSpacingMmPerPixel + 0.5);
527  //maxLineShiftDistPx = 35;
528  if (fabs(shift) > maxLineShiftDistPx)
529  {
530  // The shift between the is larger than the allowed value
531  foundPattern = false;
532  break;
533  }
534  }
535  else
536  {
537  // Non-parallel lines
538  double minAngle = m_MinLinePairAngleRad - m_AngleToleranceRad;
539  double maxAngle = m_MaxLinePairAngleRad + m_AngleToleranceRad;
540  if ((angleBetweenLinesRad > maxAngle) || (angleBetweenLinesRad < minAngle))
541  {
542  // The angle between the patterns are not in the valid range
543  foundPattern = false;
544  break;
545  }
546 
547  // If there are common endpoints between the lines then we check if the angle between the lines is correct
548  // (Needed e.g., for the CIRS phantom model 45)
549  int commonPointIndex = -1; // <0 if there are no common points between the lines, >=0 if there is a common endpoint
550  if ((currentLine1.GetStartPointIndex() == currentLine2.GetStartPointIndex()) || (currentLine1.GetStartPointIndex() == currentLine2.GetEndPointIndex()))
551  {
552  commonPointIndex = currentLine1.GetStartPointIndex();
553  }
554  else if ((currentLine1.GetEndPointIndex() == currentLine2.GetStartPointIndex()) || (currentLine1.GetEndPointIndex() == currentLine2.GetEndPointIndex()))
555  {
556  commonPointIndex = currentLine1.GetEndPointIndex();
557  }
558  if (commonPointIndex != -1)
559  {
560  // there is a common point
561  double minAngle = m_InclinedLineAngleRad - m_AngleToleranceRad;
562  double maxAngle = m_InclinedLineAngleRad + m_AngleToleranceRad;
563  if ((angleBetweenLinesRad > maxAngle) || (angleBetweenLinesRad < minAngle))
564  {
565  // The angle between the patterns are not in the valid range
566  foundPattern = false;
567  break;
568  }
569  }
570  }
571  }
572  }
573  }
574  while ((lineIndices[numberOfLines - 1] != numberOfCandidateLines - numberOfLines + 2) && (!foundPattern));
575 
576  if (foundPattern) //We have the right permutation of lines in lineIndices
577  {
578  //Update the results, this part is not generic but depends on the FidPattern we are looking for
579  PlusNWire* nWire = dynamic_cast<PlusNWire*>(m_Patterns.at(0));
580  PlusCoplanarParallelWires* coplanarParallelWire = dynamic_cast<PlusCoplanarParallelWires*>(m_Patterns.at(0));
581  if (nWire != nullptr) // NWires
582  {
583  std::vector<PlusFidLine*> resultLines(numberOfLines);
584  std::vector<double> resultLineMiddlePointYs;
585 
586  for (std::vector<int>::iterator it = lineIndices.begin(); it != lineIndices.end(); ++it)
587  {
588  resultLineMiddlePointYs.push_back((m_DotsVector[maxPointsLines[*it].GetStartPointIndex()].GetY() + m_DotsVector[maxPointsLines[*it].GetEndPointIndex()].GetY()) / 2);
589  }
590 
591  // Sort result lines according to middlePoint Y's
592  // TODO: If the wire pattern is asymmetric then use the pattern geometry to match the lines to the intersection points instead of just sort them by Y value (https://plustoolkit.github.io/legacytickets #435)
593  std::vector<double>::iterator middlePointYsBeginIt = resultLineMiddlePointYs.begin();
594  for (int i = 0; i < numberOfLines; ++i)
595  {
596  std::vector<double>::iterator middlePointYsMinIt = std::min_element(middlePointYsBeginIt, resultLineMiddlePointYs.end());
597  int minIndex = (int)std::distance(middlePointYsBeginIt, middlePointYsMinIt);
598  resultLines[i] = &maxPointsLines[lineIndices[minIndex]];
599  (*middlePointYsMinIt) = DBL_MAX;
600  }
601 
602  UpdateNWiresResults(resultLines);
603  }
604  else if (coplanarParallelWire) // CIRS phantom
605  {
606  PlusFidLine resultLine1 = maxPointsLines[lineIndices[0]];
607  PlusFidLine resultLine2 = maxPointsLines[lineIndices[1]];
608  PlusFidLine resultLine3 = maxPointsLines[lineIndices[2]];
609 
610  bool test1 = (resultLine1.GetStartPointIndex() == resultLine2.GetStartPointIndex()) || (resultLine1.GetStartPointIndex() == resultLine2.GetEndPointIndex());
611  bool test2 = (resultLine1.GetEndPointIndex() == resultLine2.GetStartPointIndex()) || (resultLine1.GetEndPointIndex() == resultLine2.GetEndPointIndex());
612  bool test3 = (resultLine1.GetStartPointIndex() == resultLine3.GetStartPointIndex()) || (resultLine1.GetStartPointIndex() == resultLine3.GetEndPointIndex());
613  //bool test4 = (resultLine1.GetEndPointIndex() == resultLine3.GetStartPointIndex()) || (resultLine1.GetEndPointIndex() == resultLine3.GetEndPointIndex());
614 
615  if (!test1 && !test2) //if line 1 and 2 have no point in common
616  {
617  if (m_DotsVector[resultLine1.GetStartPointIndex()].GetX() > m_DotsVector[resultLine2.GetStartPointIndex()].GetX()) //Line 1 is on the left on the image
618  {
619  UpdateCirsResults(resultLine1, resultLine3, resultLine2);
620  }
621  else
622  {
623  UpdateCirsResults(resultLine2, resultLine3, resultLine1);
624  }
625  }
626  else if (!test1 && !test3) //if line 1 and 3 have no point in common
627  {
628  if (m_DotsVector[resultLine1.GetStartPointIndex()].GetX() > m_DotsVector[resultLine3.GetStartPointIndex()].GetX()) //Line 1 is on the left on the image
629  {
630  UpdateCirsResults(resultLine1, resultLine2, resultLine3);
631  }
632  else
633  {
634  UpdateCirsResults(resultLine3, resultLine2, resultLine1);
635  }
636  }
637  else//if line 2 and 3 have no point in common
638  {
639  if (m_DotsVector[resultLine2.GetStartPointIndex()].GetX() > m_DotsVector[resultLine3.GetStartPointIndex()].GetX()) //Line 2 is on the left on the image
640  {
641  UpdateCirsResults(resultLine2, resultLine1, resultLine3);
642  }
643  else
644  {
645  UpdateCirsResults(resultLine3, resultLine1, resultLine2);
646  }
647  }
648  }
649  }
650 }
651 
652 //-----------------------------------------------------------------------------
654 {
655  //LOG_TRACE("FidLabeling::SortRightToLeft");
656 
657  std::vector<std::vector<PlusFidDot>::iterator> pointsIterator(line.GetNumberOfPoints());
658 
659  for (unsigned int i = 0; i < line.GetNumberOfPoints() ; i++)
660  {
661  pointsIterator[i] = m_DotsVector.begin() + line.GetPoint(i);
662  }
663 
664  std::sort(pointsIterator.begin(), pointsIterator.end(), PlusFidDot::PositionLessThan);
665 
666  for (unsigned int i = 0; i < line.GetNumberOfPoints(); i++)
667  {
668  line.SetPoint(i, pointsIterator[i] - m_DotsVector.begin());
669  }
670 }
671 
672 //-----------------------------------------------------------------------------
674 {
675  m_MinThetaRad = vtkMath::RadiansFromDegrees(value);
676 }
677 
678 //-----------------------------------------------------------------------------
680 {
681  m_MaxThetaRad = vtkMath::RadiansFromDegrees(value);
682 }
683 
684 //-----------------------------------------------------------------------------
686 {
687  m_MaxLineShiftMm = aValue;
688 }
689 
690 //-----------------------------------------------------------------------------
692 {
693  return m_MaxLineShiftMm;
694 }
695 
696 //-----------------------------------------------------------------------------
697 void PlusFidLabeling::SetAngleToleranceDegrees(double angleToleranceDegrees)
698 {
699  m_AngleToleranceRad = vtkMath::RadiansFromDegrees(angleToleranceDegrees);
700 }
701 
702 //-----------------------------------------------------------------------------
703 void PlusFidLabeling::SetInclinedLineAngleDegrees(double inclinedLineAngleDegrees)
704 {
705  m_InclinedLineAngleRad = vtkMath::RadiansFromDegrees(inclinedLineAngleDegrees);
706 }
void SortRightToLeft(PlusFidLine &line)
std::vector< PlusFidLine > m_FoundLines
int int int int y2
Definition: phidget22.h:4262
std::vector< PlusFidPattern * > & GetPatterns()
unsigned int GetNumberOfPoints() const
const char int line
Definition: phidget22.h:2458
PlusFidLine SortPointsByDistanceFromStartPoint(PlusFidLine &fiducials)
int
Definition: phidget22.h:3069
igsioStatus PlusStatus
Definition: PlusCommon.h:40
uint32_t * distance
Definition: phidget22.h:4650
double m_MaxLinePairDistMm
void SetMaxLineShiftMm(double aValue)
void SetAngleToleranceDegrees(double angleToleranceDegrees)
void UpdateCirsResults(const PlusFidLine &resultLine1, const PlusFidLine &resultLine2, const PlusFidLine &resultLine3)
double ComputeDistancePointLine(PlusFidDot &dot, PlusFidLine &line)
virtual ~PlusFidLabeling()
for i
int x1
Definition: phidget22.h:4262
double m_ApproximateSpacingMmPerPixel
std::vector< std::vector< PlusFidLine > > m_LinesVector
void SetFrameSize(const FrameSizeType &frameSize)
double m_MinLinePairAngleRad
void SetPoint(int aIndex, int aValue)
std::vector< PlusFidDot > m_DotsVector
double ComputeShift(PlusFidLine &line1, PlusFidLine &line2)
double ComputeSlope(PlusFidLine &line)
std::vector< PlusLabelingResults > m_Results
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
std::vector< PlusFidPattern * > m_Patterns
double m_InclinedLineAngleRad
int int y1
Definition: phidget22.h:4262
int int int x2
Definition: phidget22.h:4262
void SetMinThetaDeg(double value)
int x
Definition: phidget22.h:4265
double GetMaxLineShiftMm()
const char const char * value
Definition: phidget22.h:5111
std::array< unsigned int, 3 > m_FrameSize
PlusStatus ReadConfiguration(vtkXMLDataElement *rootConfigElement, double minThetaRad, double maxThetaRad)
double m_MaxLinePairAngleRad
double m_MaxLinePairDistanceErrorPercent
void SetInclinedLineAngleDegrees(double inclinedLineAngleDegrees)
static void SetDefaultSegmentationParameters(vtkXMLDataElement *segmentationElement)
int GetPoint(int aIndex) const
void SetMaxThetaDeg(double value)
static double ComputeAngleRad(const PlusFidLine &line1)
std::vector< std::vector< double > > m_FoundDotsCoordinateValue
double m_MinLinePairDistMm
Direction vectors of rods y
Definition: algo3.m:15
void UpdateNWiresResults(std::vector< PlusFidLine * > &resultLines)
for t
Definition: exploreFolders.m:9
static bool SortCompare(const std::vector< double > &temporaryLine1, const std::vector< double > &temporaryLine2)
void SetAngleToleranceDeg(double value)
static bool PositionLessThan(std::vector< PlusFidDot >::iterator b1, std::vector< PlusFidDot >::iterator b2)
double m_AngleToleranceRad