fw4spl
SPointListRegistration.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "basicRegistration/SPointListRegistration.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 #include <fwCom/Slots.hxx>
11 
12 #include <fwData/Composite.hpp>
13 #include <fwData/Mesh.hpp>
14 #include <fwData/PointList.hpp>
15 #include <fwData/String.hpp>
16 #include <fwData/TransformationMatrix3D.hpp>
17 
18 #include <fwDataTools/fieldHelper/Image.hpp>
19 
20 #include <fwGui/dialog/MessageDialog.hpp>
21 
22 #include <fwServices/macros.hpp>
23 
24 #include <vtkLandmarkTransform.h>
25 #include <vtkMatrix4x4.h>
26 #include <vtkPoints.h>
27 #include <vtkSmartPointer.h>
28 
30 
31 namespace basicRegistration
32 {
33 
34 const ::fwCom::Slots::SlotKeyType SPointListRegistration::s_CHANGE_MODE = "changeMode";
35 static const ::fwCom::Signals::SignalKeyType s_ERROR_COMPUTED_SIG = "errorComputed";
36 
37 SPointListRegistration::SPointListRegistration() :
38  m_registrationMode(RIGID)
39 {
40  newSignal<ErrorComputedSignalType>(s_ERROR_COMPUTED_SIG);
41  newSlot(s_CHANGE_MODE, &SPointListRegistration::changeMode, this);
42 }
43 
44 // ----------------------------------------------------------------------------
45 
46 SPointListRegistration::~SPointListRegistration()
47 {
48 }
49 
50 // ----------------------------------------------------------------------------
51 
52 void SPointListRegistration::configuring()
53 {
54  const auto configTree = this->getConfigTree();
55  const auto config = configTree.get_child_optional("config.<xmlattr>");
56 
57  if (config)
58  {
59  const std::string mode = config->get< std::string >("mode", "rigid");
60 
61  if(mode == "rigid")
62  {
63  m_registrationMode = RIGID;
64  }
65  else if(mode == "similarity")
66  {
67  m_registrationMode = SIMILARITY;
68  }
69  else if(mode == "affine")
70  {
71  m_registrationMode = AFFINE;
72  }
73  else
74  {
75  SLM_ERROR("Unknown registration mode: '" + mode + "', it must be 'rigid', 'similarity' or 'affine'."
76  " Defaulting to 'rigid'.")
77  }
78  }
79  else
80  {
81  m_registrationMode = RIGID;
82  }
83 }
84 
85 // ----------------------------------------------------------------------------
86 
87 void SPointListRegistration::starting()
88 {
89 }
90 
91 // ----------------------------------------------------------------------------
92 
93 void SPointListRegistration::stopping()
94 {
95 }
96 
97 //-----------------------------------------------------------------------------
98 
99 void SPointListRegistration::computeRegistration(::fwCore::HiResClock::HiResClockType)
100 {
101  ::fwData::PointList::sptr registeredPL = this->getInOut< ::fwData::PointList >("registeredPL");
102  ::fwData::PointList::sptr referencePL = this->getInOut< ::fwData::PointList >("referencePL");
103  ::fwData::TransformationMatrix3D::sptr matrix = this->getInOut< ::fwData::TransformationMatrix3D >("output");
104 
105  if( registeredPL->getPoints().size() >= 3 &&
106  registeredPL->getPoints().size() == referencePL->getPoints().size() )
107  {
108  vtkSmartPointer<vtkLandmarkTransform> landmarkTransform = vtkSmartPointer<vtkLandmarkTransform>::New();
109 
110  vtkSmartPointer<vtkPoints> sourcePts = vtkSmartPointer<vtkPoints>::New();
111  vtkSmartPointer<vtkPoints> targetPts = vtkSmartPointer<vtkPoints>::New();
112 
113  const auto& firstPoint = referencePL->getPoints()[0];
114 
115  // If the points have labels ...
116  if(firstPoint->getField< ::fwData::String >(::fwDataTools::fieldHelper::Image::m_labelId ) != nullptr)
117  {
118  // ... Then match them according to that label.
119  for( ::fwData::Point::sptr pointRef : referencePL->getPoints() )
120  {
121  const std::string& labelRef =
122  pointRef->getField< ::fwData::String >(::fwDataTools::fieldHelper::Image::m_labelId )->value();
123 
124  for( ::fwData::Point::sptr pointReg : registeredPL->getPoints() )
125  {
126  const std::string& labelReg =
127  pointReg->getField< ::fwData::String >(::fwDataTools::fieldHelper::Image::m_labelId )->value();
128 
129  if(labelRef == labelReg)
130  {
131  auto coord = pointRef->getCoord();
132  sourcePts->InsertNextPoint(coord[0], coord[1], coord[2]);
133 
134  OSLM_TRACE("referencePL : " << pointRef->getField< ::fwData::String >(
136  OSLM_TRACE(
137  "referencePL : " << pointRef->getCoord()[0] << " " << pointRef->getCoord()[1] << " " <<
138  pointRef->getCoord()[2] );
139 
140  coord = pointReg->getCoord();
141  targetPts->InsertNextPoint(coord[0], coord[1], coord[2]);
142  OSLM_TRACE("registeredPL : " << pointReg->getField< ::fwData::String >(
144  OSLM_TRACE(
145  "registeredPL : " << pointReg->getCoord()[0] << " " << pointReg->getCoord()[1] << " " <<
146  pointReg->getCoord()[2] );
147  }
148  }
149  }
150  }
151  else
152  {
153  // ... Else match them according to their order.
154  for(const auto& refPoint : referencePL->getPoints())
155  {
156  const auto& coords = refPoint->getCoord();
157  sourcePts->InsertNextPoint(coords[0], coords[1], coords[2]);
158  }
159 
160  for(const auto& regPoint : registeredPL->getPoints())
161  {
162  const auto& coords = regPoint->getCoord();
163  targetPts->InsertNextPoint(coords[0], coords[1], coords[2]);
164  }
165  }
166 
167  landmarkTransform->SetSourceLandmarks(sourcePts);
168  landmarkTransform->SetTargetLandmarks(targetPts);
169 
170  if(m_registrationMode == AFFINE)
171  {
172  landmarkTransform->SetModeToAffine();
173  }
174  else if(m_registrationMode == SIMILARITY)
175  {
176  landmarkTransform->SetModeToSimilarity();
177  }
178  else
179  {
180  landmarkTransform->SetModeToRigidBody();
181  }
182 
183  landmarkTransform->Update();
184 
185  // Get the resulting transformation matrix (this matrix takes the source points to the target points)
186  vtkSmartPointer<vtkMatrix4x4> m = landmarkTransform->GetMatrix();
187  m->Invert();
188  for(std::uint8_t l = 0; l < 4; ++l)
189  {
190  for(std::uint8_t c = 0; c < 4; ++c)
191  {
192  matrix->setCoefficient(l, c, m->GetElement(l, c));
193  }
194  }
195 
196  //compute RMSE
197  double errorValue = 0.;
198 
199  for(vtkIdType i = 0; i < sourcePts->GetNumberOfPoints(); ++i)
200  {
201  double p1[3];
202  sourcePts->GetPoint(i, p1);
203  double p2[3];
204  targetPts->GetPoint(i, p2);
205 
206  // to have homogeneous coordinates (x,y,z,w)
207  double p2H[4] = { 1., 1., 1., 1.};
208  std::copy(std::begin(p2), std::end(p2), std::begin(p2H));
209 
210  //p' = M*p
211  double newP[4];
212  m->MultiplyPoint(p2H, newP);
213 
214  errorValue += std::sqrt(((p1[0] - newP[0]) * (p1[0] - newP[0])) +
215  ((p1[1] - newP[1]) * (p1[1] - newP[1])) +
216  ((p1[2] - newP[2]) * (p1[2] - newP[2])));
217  }
218 
219  errorValue /= sourcePts->GetNumberOfPoints();
220 
221  OSLM_TRACE("RMSE : "<<errorValue);
222 
223  this->signal<ErrorComputedSignalType>(s_ERROR_COMPUTED_SIG)->asyncEmit(errorValue);
224 
225  // Notify Matrix modified
227  {
228  ::fwCom::Connection::Blocker block(sig->getConnection(m_slotUpdate));
229  sig->asyncEmit();
230  }
231  }
232  else
233  {
234  if(registeredPL->getPoints().size() < 3)
235  {
237  "You must enter 3 or more points for the registration to work.",
238  ::fwGui::dialog::IMessageDialog::WARNING);
239  }
240  else
241  {
242  std::string msg = "The pointlists doesn't have the same number of points : ";
243  msg += std::to_string(registeredPL->getPoints().size()) + " != " + std::to_string(
244  referencePL->getPoints().size());
245  ::fwGui::dialog::MessageDialog::showMessageDialog("Error", msg, ::fwGui::dialog::IMessageDialog::WARNING);
246  }
247  }
248 }
249 
250 // ----------------------------------------------------------------------------
251 
252 void SPointListRegistration::updating()
253 {
254  const ::fwCore::HiResClock::HiResClockType timestamp = ::fwCore::HiResClock::getTimeInMilliSec();
255  this->computeRegistration(timestamp);
256 }
257 
258 //----------------------------------------------------------------------------
259 
260 void SPointListRegistration::swapping()
261 {
262  // Classic default approach to update service when object change
263  this->stopping();
264  this->starting();
265 }
266 
267 //----------------------------------------------------------------------------
268 
269 void SPointListRegistration::changeMode(std::string _value)
270 {
271  if(_value == "RIGID")
272  {
273  m_registrationMode = RIGID;
274  }
275  else if( _value == "SIMILARITY")
276  {
277  m_registrationMode = SIMILARITY;
278  }
279  else if(_value == "AFFINE")
280  {
281  m_registrationMode = AFFINE;
282  }
283  else
284  {
285  SLM_ERROR("key "+ _value +" is not handled.");
286  }
287 }
288 
289 //----------------------------------------------------------------------------
290 
291 } // namespace basicRegistration
Class allowing to block a Connection.
Definition: Connection.hpp:20
static FWGUI_API IMessageDialog::Buttons showMessageDialog(const std::string &title, const std::string &message,::fwGui::dialog::IMessageDialog::Icons icon=INFO)
The namespace basicRegistration contains services to perfom a basic registration between images and m...
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
double HiResClockType
Type returned by HiResClock Functions.
Definition: HiResClock.hpp:29
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
Definition: SPointList.cpp:94
T & value() noexcept
Get the value (mutable version).
UpdateSlotType::sptr m_slotUpdate
Slot to call update method.
Definition: IService.hpp:690
#define SLM_ERROR(message)
Definition: spyLog.hpp:272
This interface defines registerer service API. Must be implemented for services that register objects...
Definition: IRegisterer.hpp:21
static FWDATATOOLS_API const std::string m_labelId
to assign a label
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
Definition: SPointList.cpp:135
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
Register a point list against a reference point list. Each point in the list to register is matched w...
This class contains an std::string value.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247