root/juggler/branches/2.2/modules/gadgeteer/gadget/Filter/Position/PositionCalibrationFilter.cpp

Revision 19729, 13.2 kB (checked in by patrick, 2 years ago)

Copyright update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  *************** <auto-copyright.pl END do not edit this line> ***************/
26
27 #include <gadget/gadgetConfig.h>
28
29 #include <sstream>
30 #include <fstream>
31
32 #include <cppdom/cppdom.h>
33 #include <gmtl/Math.h>
34 #include <gmtl/Matrix.h>
35 #include <gmtl/MatrixOps.h>
36 #include <gmtl/Output.h>
37 #include <gmtl/Vec.h>
38 #include <gmtl/VecOps.h>
39
40 #include <vpr/Util/Debug.h>
41 #include <vpr/Util/Assert.h>
42 #include <jccl/Config/ParseUtil.h>
43 #include <jccl/Config/ConfigElement.h>
44 #include <gadget/Filter/Position/PositionCalibrationFilter.h>
45 #include <gadget/Filter/Position/PositionFilterFactory.h>
46
47 namespace gadget
48 {
49
50    GADGET_REGISTER_POSFILTER_CREATOR( PositionCalibrationFilter );
51    
52    PositionCalibrationFilter::~PositionCalibrationFilter()
53    {
54       for (size_t i = 0; i < mTable.size(); ++i)
55       {
56          delete[] mWMatrix[i];
57       }
58       delete[] mWMatrix;
59    }
60    
61    std::string
62    PositionCalibrationFilter::getElementType()
63    {
64       return std::string("position_calibration_filter");
65    }
66    
67    bool
68    PositionCalibrationFilter::config(jccl::ConfigElementPtr e)
69    {
70       vprASSERT(e->getID() == PositionCalibrationFilter::getElementType());
71       vprDEBUG_OutputGuard(vprDBG_ALL, vprDBG_VERB_LVL,
72                            std::string("PositionCalibrationFilter::config:  ") +
73                            e->getFullName() + std::string(":") + e->getID() +
74                            std::string("\n"),
75                     std::string("PositionCalibrationFilter::config: done.\n") );
76       std::string file_name = e->getProperty<std::string>("calibration_file",0);
77       mFileName = jccl::ParseUtil::expandFileName(file_name, std::string("") );
78
79       // Parse the calibration file.
80       vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
81          << "[PositionCalibrationFilter::config] Parsing " << mFileName << "\n"
82          << vprDEBUG_FLUSH;
83
84       cppdom::ContextPtr context( new cppdom::Context() );
85       cppdom::DocumentPtr document( new cppdom::Document(context) );
86      
87       try
88       {
89          document->loadFile(mFileName);
90       }
91       catch (cppdom::Error e)
92       {
93          vprDEBUG(vprDBG_ERROR, vprDBG_CONFIG_LVL)
94             << "[PositionCalibrationFilter::config] Unable to load calibration "
95             << "file " << mFileName << ".  " << e.getString() << " at "
96             << e.getInfo() << vprDEBUG_FLUSH;
97          return false;
98       }
99
100       cppdom::NodePtr root = document->getChild("CalibrationTable");
101       if (NULL == root.get())
102       {
103          vprDEBUG(vprDBG_ERROR, vprDBG_CONFIG_LVL)
104             << "[PositionCalibrationFilter::config] Bad calibration file "
105             << mFileName << "; could not retrieve the root node "
106             << "'CalibrationTable'.  " << vprDEBUG_FLUSH;
107          return false;
108       }
109      
110       cppdom::NodeList offset_list;
111       offset_list = root->getChildren("Offset");
112       cppdom::NodeListIterator itr;
113      
114       for (itr = offset_list.begin(); itr != offset_list.end(); ++itr)
115       {
116          gmtl::Vec3d real_position;
117          gmtl::Vec3d dev_position;
118          
119          if ( (*itr)->hasAttribute("X") &&
120               (*itr)->hasAttribute("Y") &&
121               (*itr)->hasAttribute("Z") )
122          {
123             real_position.set( (*itr)->getAttribute("X").getValue<double>(),
124                                (*itr)->getAttribute("Y").getValue<double>(),
125                                (*itr)->getAttribute("Z").getValue<double>() );
126             std::istringstream offset_stream((*itr)->getCdata());
127             //XXX:  Error checking on the Cdata needs to be more robust.
128             offset_stream >> dev_position[gmtl::Xelt];
129             offset_stream >> dev_position[gmtl::Yelt];
130             offset_stream >> dev_position[gmtl::Zelt];
131
132             vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
133                << "[PositionCalibrationFilter::config()] Added "
134                << real_position << " --> " << dev_position << " "
135                << "to the table.\n"
136                << vprDEBUG_FLUSH;
137            
138             mTable.push_back( std::make_pair(real_position, dev_position) );
139          }
140          else
141          {
142             vprDEBUG(vprDBG_ERROR, vprDBG_CONFIG_LVL)
143                << "[PositionCalibrationFilter::config()] Malformed Offset "
144                << "Element.  The element does not contain X, Y, and Z "
145                << "attributes that represent a position; skipping.\n"
146                << vprDEBUG_FLUSH;
147          }
148       }
149
150       // Now that we have the offsets, loop through the alpha elements to
151       // obtain the coefficients.
152       mAlphaVec.reserve(mTable.size());
153       cppdom::NodeList alpha_list = root->getChildren("Alpha");
154       if (alpha_list.empty())
155       {
156          vprDEBUG(vprDBG_ERROR, vprDBG_CONFIG_LVL)
157             << "[PositionCalibrationFilter::config()] Bad calibration file "
158             << "'" << mFileName << "'\n" << "This file contains no Alpha "
159             << " elements; these coefficients are necessary for calibration!\n"
160             << vprDEBUG_FLUSH;
161          return false;
162       }
163       for (itr = alpha_list.begin(); itr != alpha_list.end(); ++itr)
164       {
165          if ( (*itr)->hasAttribute("X") &&
166               (*itr)->hasAttribute("Y") &&
167               (*itr)->hasAttribute("Z") )
168          {
169             gmtl::Vec3d alpha_value(
170                   (*itr)->getAttribute("X").getValue<double>(),
171                   (*itr)->getAttribute("Y").getValue<double>(),
172                   (*itr)->getAttribute("Z").getValue<double>() );
173             vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
174                << "[PositionCalibrationFilter::config()] Added "
175                << alpha_value
176                << " to the alpha vector.\n"
177                << vprDEBUG_FLUSH;
178             mAlphaVec.push_back(alpha_value);
179          }
180          else
181          {
182             vprDEBUG(vprDBG_ERROR, vprDBG_CONFIG_LVL)
183                << "[PositionCalibrationFilter::config()] "
184                << "Malformed Alpha Element; this element does not contain "
185                << "X="", Y="", Z="" attributes.\n"
186                << vprDEBUG_FLUSH;
187          }
188       }
189
190       // Now that we have the calibration table, compute the W Matrix and then
191       // solve for the Alpha Vector.
192
193       vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
194          << "[PositionCalibrationFilter::config()] Calibration table parsed; "
195          << "preparing W Matrix...\n" << vprDEBUG_FLUSH;
196
197       // The "W" Matrix is an NxN matrix where N = mTable.size()
198       // It is composed of elements computed using the w(p) function:
199       // w[j](p) = sqrt( length(p - p[j])^2 + R^2 )
200       // where 10 <= R^2 <= 1000.
201       // The matrix looks like:
202       // ( w[1](p[1]) w[2](p[1]) w[3](p[1]) ... w[N](p[1]) )
203       // ( w[1](p[2]) w[2](p[2]) w[3](p[2]) ... w[N](p[2]) )
204       // ( w[1](p[3]) w[2](p[3]) w[3](p[3]) ... w[N](p[3]) )
205       // (                      .                          )
206       // (                      .                          )
207       // (                      .                          )
208       // ( w[1](p[N]) w[2](p[N]) w[3](p[N]) ... w[N](p[N]) )
209
210       vprDEBUG(vprDBG_ALL, vprDBG_DETAILED_LVL)
211          << "[PositionCalibrationFilter::config()] The W matrix is "
212          << mTable.size() << "x" << mTable.size() << ".\n"
213          << vprDEBUG_FLUSH;
214      
215       double r_squared(0.4f);
216       double r(0.63245553203367588f);
217       mWMatrix = new double*[mTable.size()];
218       for (unsigned int i = 0; i < mTable.size(); ++i)
219       {
220          mWMatrix[i] = new double[mTable.size()];
221          for (unsigned int j = 0; j < mTable.size(); ++j)
222          {
223             if (i == j)
224             {
225                // Shortcut; the diagonal will always be equal to R.
226                mWMatrix[i][j] = r;
227             }
228             else
229             {
230                // XXX: This is a workaround for GMTL CVS Head which supports
231                //      template meta-programming for vectors; unfortunately,
232                //      gmtl::length(v1 - v2) will not compile since the types
233                //      are NOT gmtl::Vec.
234                gmtl::Vec3d difference = mTable[i].second - mTable[j].second;
235                //double length = gmtl::length( difference );
236                mWMatrix[i][j] = gmtl::Math::sqrt(
237                                 gmtl::dot(difference, difference) +
238                                 r_squared );
239             }
240             vprDEBUG(vprDBG_ALL, vprDBG_HEX_LVL)
241                << "[PositionCalibrationFilter::config()] Assigning "
242                << mWMatrix[i][j]
243                << " to mWMatrix( " << i << ", " << j << ").\n"
244                << vprDEBUG_FLUSH;
245          }
246       }
247
248       return true; 
249    }
250
251    void
252    PositionCalibrationFilter::apply(std::vector< PositionData >& posSample)
253    {
254       vprDEBUG(vprDBG_ALL, vprDBG_DETAILED_LVL)
255          << "[PositionCalibrationFilter::apply()] Received " << posSample.size()
256          << " samples.\n"
257          << vprDEBUG_FLUSH;
258       std::vector< PositionData >::iterator itr;
259       for (itr = posSample.begin(); itr != posSample.end(); ++itr)
260       {
261          // Prepare the position matrix for Hardy's multi-quadric method.
262          //
263          // Right now, we only calibrate the position, not the orientation, so
264          // first, we need to pull out the translation matrix of posSample.
265          // We do this using the standard method: 
266          // pull the rotation matrix R out
267          // of the transformation matrix Tr and multiply R-inverse by Tr, ie,
268          // inverse(R) * Tr = T
269          // and since rotation matrices are orthogonal,
270          // inverse(R) = transpose(R), so...
271          // transpose(R) * Tr = T
272          gmtl::Matrix44f rotation(itr->getPosition());
273          rotation[0][3] = 0;
274          rotation[1][3] = 0;
275          rotation[2][3] = 0;
276          rotation[3][3] = 1;
277          
278          gmtl::Matrix44f translation = gmtl::transpose(rotation) * itr->getPosition();
279          vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
280             << "[PositionCalibrationFilter::apply()] Received tracked "
281             << "position\n" << translation << "\n"
282             << vprDEBUG_FLUSH;
283          gmtl::Vec3d tracked_pos( translation[0][3],
284                                   translation[1][3],
285                                   translation[2][3] );
286
287          // Now, we apply the following to the tracked position:
288          // real_pos = alpha[j] * w[j](tracked_pos) + ... + alpha[N] *
289          // w[N](tracked_pos)
290          // where w[j](p) = sqrt( length( p - p[j] )^2 + R^2 )
291          // where 10 <= R^2 <= 1000.
292          gmtl::Vec3d real_pos(0.0f, 0.0f, 0.0f);
293          double r_squared = 40.0f;
294          vprDEBUG(vprDBG_ALL, vprDBG_DETAILED_LVL)
295             << "[PositionCalibrationFilter::apply()] Summing real position...\n"
296             << vprDEBUG_FLUSH;
297          for (unsigned int i = 0; i < mTable.size(); ++i)
298          {
299             // XXX: This is a workaround for GMTL CVS Head which supports
300             //      template meta-programming for vectors; unfortunately,
301             //      gmtl::length(v1 - v2) will not compile since the types are
302             //      NOT gmtl::Vec.
303             gmtl::Vec3d difference = tracked_pos - mTable[i].second;
304             //double length = gmtl::length(difference);
305             real_pos += mAlphaVec[i] *
306                        gmtl::Math::sqrt( gmtl::dot(difference, difference) +
307                                          r_squared );
308             vprDEBUG(vprDBG_ALL, vprDBG_DETAILED_LVL)
309                << "[PositionCalibrationFilter::apply()] real_pos: "
310                << real_pos << "\n" << vprDEBUG_FLUSH;
311          }
312
313          
314          // Now we clobber the old transformation and replace it with a
315          // translation to our real position.
316          gmtl::Matrix44f new_translation;
317          new_translation[0][3] = static_cast<float>(real_pos[0]);
318          new_translation[1][3] = static_cast<float>(real_pos[1]);
319          new_translation[2][3] = static_cast<float>(real_pos[2]);
320          
321          vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
322             << "[PositionCalibrationFilter::apply()] Replaced "
323             << tracked_pos << " with \n"
324             << real_pos << "\n"
325             << vprDEBUG_FLUSH;
326          vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
327             << "[PositionCalibrationFilter::apply()] Replaced \n" << translation
328             << "\nwith " << new_translation
329             << vprDEBUG_FLUSH;
330
331          // Rebuild the position sample (transformation matrix).
332          itr->setPosition(rotation * new_translation);
333       }
334    }
335 }
Note: See TracBrowser for help on using the browser.