00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <new>
00047
00048 #include "RAPiD.h"
00049
00050 #include "Math/FloatMatrix.h"
00051 #include "Math/FloatVector.h"
00052 #include "Math/LinearAlgebra.h"
00053 #include "Calibration/Calibration.h"
00054 #include "DataStructures/DynamicArray.h"
00055 #include "Image/ImageProcessor.h"
00056 #include "Image/ByteImage.h"
00057 #include "Tracking/ICP.h"
00058
00059 #include <stdio.h>
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 CRAPiD::CRAPiD()
00076 {
00077 m_nPixelsSearchDistance = 15;
00078 m_nPixelsDelta = 15;
00079 }
00080
00081 CRAPiD::~CRAPiD()
00082 {
00083 }
00084
00085
00086
00087
00088
00089
00090 void CRAPiD::Init(const CCalibration *pCalibration)
00091 {
00092 m_pCalibration = pCalibration;
00093 }
00094
00095 bool CRAPiD::Track(const CByteImage *pEdgeImage, Vec3d *pOutlinePoints, int nOutlinePoints,
00096 Mat3d &rotation, Vec3d &translation)
00097 {
00098 if (pEdgeImage->type != CByteImage::eGrayScale)
00099 {
00100 printf("error: input image must be grayscale image for CRAPiD::Track\n");
00101 return false;
00102 }
00103
00104 if (m_pCalibration->GetCameraParameters().width != pEdgeImage->width ||
00105 m_pCalibration->GetCameraParameters().height != pEdgeImage->height)
00106 {
00107 printf("error: calibration does not match image in CRAPiD::Track\n");
00108 return false;
00109 }
00110
00111 CDynamicArray rapidList(1000);
00112
00113 const unsigned char *pixels = pEdgeImage->pixels;
00114 const int width = pEdgeImage->width;
00115 const int height = pEdgeImage->height;
00116
00117 for (int i = 0; i < nOutlinePoints; i += 2)
00118 {
00119 Vec3d p1, p2;
00120 Math3d::SetVec(p1, pOutlinePoints[i]);
00121 Math3d::SetVec(p2, pOutlinePoints[i + 1]);
00122
00123 Vec2d p1_, p2_;
00124 {
00125 Vec3d temp;
00126
00127 Math3d::MulMatVec(rotation, p1, translation, temp);
00128 m_pCalibration->WorldToImageCoordinates(temp, p1_, false);
00129
00130 Math3d::MulMatVec(rotation, p2, translation, temp);
00131 m_pCalibration->WorldToImageCoordinates(temp, p2_, false);
00132 }
00133
00134 const float length_ = Math2d::Distance(p1_, p2_);
00135
00136 const int nControlPoints = int(length_ / m_nPixelsDelta) - 1;
00137 if (nControlPoints < 1)
00138 continue;
00139
00140 Vec3d u;
00141 Math3d::SubtractVecVec(p2, p1, u);
00142 const float delta_length = Math3d::Length(u) / nControlPoints;
00143 Math3d::NormalizeVec(u);
00144 Math3d::MulVecScalar(u, delta_length, u);
00145
00146 Vec2d u_ = { p1_.x - p2_.x, p1_.y - p2_.y };
00147 Math2d::NormalizeVec(u_);
00148
00149
00150 Vec2d n = { p1_.y - p2_.y, p2_.x - p1_.x };
00151 Math2d::NormalizeVec(n);
00152
00153 Vec3d p;
00154 Math3d::SetVec(p, p1);
00155
00156 for (int j = 0; j < nControlPoints; j++)
00157 {
00158 Math3d::AddToVec(p, u);
00159
00160 Vec2d p_;
00161 {
00162 Vec3d temp;
00163 Math3d::MulMatVec(rotation, p, translation, temp);
00164 m_pCalibration->WorldToImageCoordinates(temp, p_, false);
00165 }
00166
00167
00168 Vec2d pn1, pn2;
00169 int k, l = -1;
00170 bool bPlus = true;
00171
00172 Math2d::SetVec(pn1, p_);
00173 Math2d::SetVec(pn2, p_);
00174 for (k = 0; k < m_nPixelsSearchDistance; k++)
00175 {
00176 int x, y;
00177
00178
00179 x = int(pn1.x + 0.5f);
00180 y = int(pn1.y + 0.5f);
00181 if (x > 0 && x < width && y > 0 && y < height && pixels[y * width + x])
00182 {
00183 l = k;
00184 bPlus = true;
00185 break;
00186 }
00187
00188 x = int(pn2.x + 0.5f);
00189 y = int(pn2.y + 0.5f);
00190 if (x > 0 && x < width && y > 0 && y < height && pixels[y * width + x])
00191 {
00192 l = k;
00193 bPlus = false;
00194 break;
00195 }
00196
00197 Math2d::AddToVec(pn1, n);
00198 Math2d::SubtractFromVec(pn2, n);
00199 }
00200
00201 if (l != -1)
00202 {
00203 CRAPiDElement *pRAPiDElement = new CRAPiDElement();
00204
00205 pRAPiDElement->l = float(l);
00206 Math2d::SetVec(pRAPiDElement->n, n);
00207 Math2d::NormalizeVec(pRAPiDElement->n);
00208 Math3d::SetVec(pRAPiDElement->p, p);
00209
00210 if (!bPlus)
00211 Math2d::MulVecScalar(pRAPiDElement->n, -1, pRAPiDElement->n);
00212
00213 rapidList.AddElement(pRAPiDElement);
00214 }
00215 }
00216 }
00217
00218 return RAPiD(rapidList, m_pCalibration, rotation, translation);
00219 }
00220
00221 bool CRAPiD::RAPiD(CDynamicArray &elementList, const CCalibration *pCalibration, Mat3d &rotation, Vec3d &translation)
00222 {
00223 if (elementList.GetSize() < 6)
00224 {
00225 printf("error: not enough input points for RAPiD::RAPiD\n");
00226 return false;
00227 }
00228
00229 const CCalibration::CCameraParameters &cameraParameters = pCalibration->GetCameraParameters();
00230 const float fx = cameraParameters.focalLength.x;
00231 const float fy = cameraParameters.focalLength.y;
00232
00233 Vec3d t;
00234 Math3d::MulMatVec(cameraParameters.rotation, translation, cameraParameters.translation, t);
00235
00236 Mat3d R;
00237 Math3d::MulMatMat(cameraParameters.rotation, rotation, R);
00238
00239 const int nPoints = elementList.GetSize();
00240
00241 int i;
00242
00243 CFloatMatrix A(6, 6);
00244 ImageProcessor::Zero(&A);
00245
00246 CFloatVector b(6);
00247 b.data[0] = b.data[1] = b.data[2] = b.data[3] = b.data[4] = b.data[5] = 0;
00248
00249 CFloatMatrix C(1, 6), CT(6, 1);
00250 CFloatMatrix CTC(6, 6);
00251
00252 for (i = 0; i < nPoints; i++)
00253 {
00254 CRAPiDElement *pElement = (CRAPiDElement *) elementList.GetElement(i);
00255
00256 Vec3d p;
00257 Math3d::MulMatVec(R, pElement->p, p);
00258
00259 const float x = p.x;
00260 const float y = p.y;
00261 const float z = p.z;
00262
00263 const float xc = x + t.x;
00264 const float yc = y + t.y;
00265 const float zc = z + t.z;
00266
00267 const float u0 = fx * xc / zc;
00268 const float v0 = fy * yc / zc;
00269
00270 const float nx = pElement->n.x;
00271 const float ny = pElement->n.y;
00272
00273 const float c1 = (-nx * u0 * y - ny * (fy * z + v0 * y)) / zc;
00274 const float c2 = (nx * (fx * z + u0 * x) + ny * v0 * x) / zc;
00275 const float c3 = (-nx * fx * y + ny * fy * x) / zc;
00276 const float c4 = (nx * fx) / zc;
00277 const float c5 = (ny * fy) / zc;
00278 const float c6 = (-nx * u0 - ny * v0) / zc;
00279
00280 const float l = pElement->l;
00281
00282 b.data[0] += l * c1;
00283 b.data[1] += l * c2;
00284 b.data[2] += l * c3;
00285 b.data[3] += l * c4;
00286 b.data[4] += l * c5;
00287 b.data[5] += l * c6;
00288
00289 C(0, 0) = c1;
00290 C(0, 1) = c2;
00291 C(0, 2) = c3;
00292 C(0, 3) = c4;
00293 C(0, 4) = c5;
00294 C(0, 5) = c6;
00295
00296 LinearAlgebra::Transpose(&C, &CT);
00297 LinearAlgebra::MulMatMat(&C, &CT, &CTC);
00298 LinearAlgebra::AddToMat(&A, &CTC);
00299 }
00300
00301 CFloatVector q(6);
00302 LinearAlgebra::SolveLinearLeastSquaresSVD(&A, &b, &q);
00303
00304 Vec3d delta_theta = { q.data[0], q.data[1], q.data[2] };
00305 Vec3d delta_t = { q.data[3], q.data[4], q.data[5] };
00306
00307
00308 Vec3d *pPoints = new Vec3d[nPoints];
00309 Vec3d *pNewPoints = new Vec3d[nPoints];
00310
00311 for (i = 0; i < nPoints; i++)
00312 {
00313 CRAPiDElement *pElement = (CRAPiDElement *) elementList.GetElement(i);
00314
00315 Math3d::SetVec(pPoints[i], pElement->p);
00316
00317 Vec3d p;
00318 Math3d::MulMatVec(R, pElement->p, p);
00319
00320 Vec3d temp;
00321 Math3d::CrossProduct(delta_theta, p, temp);
00322 Math3d::AddVecVec(p, temp, pNewPoints[i]);
00323 Math3d::AddToVec(pNewPoints[i], delta_t);
00324 Math3d::AddToVec(pNewPoints[i], t);
00325
00326
00327 Math3d::MulMatVec(pCalibration->m_rotation_inverse, pNewPoints[i], pCalibration->m_translation_inverse, pNewPoints[i]);
00328 }
00329
00330
00331 CICP::CalculateOptimalTransformation(pPoints, pNewPoints, nPoints, rotation, translation);
00332
00333 delete [] pPoints;
00334 delete [] pNewPoints;
00335
00336 return true;
00337 }