Commit 4261d8e6a1050c7c68bf50719350524c354511c4

Authored by Brendan Klare
1 parent 9f84bcdb

Finalized procrustes training and alignment

Showing 1 changed file with 66 additions and 15 deletions
openbr/plugins/landmarks.cpp
@@ -146,9 +146,24 @@ class ProcrustesAlignTransform : public Transform @@ -146,9 +146,24 @@ class ProcrustesAlignTransform : public Transform
146 Q_OBJECT 146 Q_OBJECT
147 147
148 Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false) 148 Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false)
149 - BR_PROPERTY(float, width, true) 149 + Q_PROPERTY(float padding READ get_padding WRITE set_padding RESET reset_padding STORED false)
  150 + BR_PROPERTY(float, width, 80)
  151 + BR_PROPERTY(float, padding, 8)
150 152
151 Eigen::MatrixXf referenceShape; 153 Eigen::MatrixXf referenceShape;
  154 + float minX;
  155 + float minY;
  156 + float maxX;
  157 + float maxY;
  158 + float aspectRatio;
  159 +
  160 + void init() {
  161 + minX = FLT_MAX,
  162 + minY = FLT_MAX,
  163 + maxX = -FLT_MAX,
  164 + maxY = -FLT_MAX;
  165 + aspectRatio = 0;
  166 + }
152 167
153 MatrixXf getRotation(MatrixXf ref, MatrixXf sample) const { 168 MatrixXf getRotation(MatrixXf ref, MatrixXf sample) const {
154 MatrixXf R = ref.transpose() * sample; 169 MatrixXf R = ref.transpose() * sample;
@@ -180,7 +195,6 @@ class ProcrustesAlignTransform : public Transform @@ -180,7 +195,6 @@ class ProcrustesAlignTransform : public Transform
180 return vector; 195 return vector;
181 } 196 }
182 197
183 -  
184 void train(const TemplateList &data) 198 void train(const TemplateList &data)
185 { 199 {
186 MatrixXf points(data[0].file.points().size() * 2, data.size()); 200 MatrixXf points(data[0].file.points().size() * 2, data.size());
@@ -206,7 +220,6 @@ class ProcrustesAlignTransform : public Transform @@ -206,7 +220,6 @@ class ProcrustesAlignTransform : public Transform
206 } 220 }
207 } 221 }
208 222
209 -  
210 //normalize scale 223 //normalize scale
211 for (int i = 0; i < points.cols(); i++) 224 for (int i = 0; i < points.cols(); i++)
212 points.col(i) = points.col(i) / points.col(i).norm(); 225 points.col(i) = points.col(i) / points.col(i).norm();
@@ -214,17 +227,40 @@ class ProcrustesAlignTransform : public Transform @@ -214,17 +227,40 @@ class ProcrustesAlignTransform : public Transform
214 //Normalize rotation 227 //Normalize rotation
215 MatrixXf refPrev; 228 MatrixXf refPrev;
216 referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); 229 referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols());
217 -  
218 - for (int j = 0; j < points.cols(); j++) {  
219 - MatrixXf p = vectorToMatrix(points.col(j));  
220 - MatrixXf R = getRotation(referenceShape, p);  
221 - p = p * R;  
222 - points.col(j) = matrixToVector(p); 230 + float diff = FLT_MAX;
  231 + while (diff > 1e-5) {//iterate until reference shape is stable
  232 + refPrev = referenceShape;
  233 +
  234 + for (int j = 0; j < points.cols(); j++) {
  235 + MatrixXf p = vectorToMatrix(points.col(j));
  236 + MatrixXf R = getRotation(referenceShape, p);
  237 + p = p * R.transpose();
  238 + points.col(j) = matrixToVector(p);
  239 + }
  240 + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols());
  241 + diff = (matrixToVector(referenceShape) - matrixToVector(refPrev)).norm();
223 } 242 }
224 243
225 referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); 244 referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols());
226 - }  
227 245
  246 + //Choose crop boundaries and adjustments that captures all data
  247 + for (int i = 0; i < points.rows(); i++) {
  248 + for (int j = 0; j < points.cols(); j++) {
  249 + if (i % 2 == 0) {
  250 + if (points(i,j) > maxX)
  251 + maxX = points(i, j);
  252 + if (points(i,j) < minX)
  253 + minX = points(i, j);
  254 + } else {
  255 + if (points(i,j) > maxY)
  256 + maxY = points(i, j);
  257 + if (points(i,j) < minY)
  258 + minY = points(i, j);
  259 + }
  260 + }
  261 + }
  262 + aspectRatio = (maxX - minX) / (maxY - minY);
  263 + }
228 264
229 void project(const Template &src, Template &dst) const 265 void project(const Template &src, Template &dst) const
230 { 266 {
@@ -234,7 +270,6 @@ class ProcrustesAlignTransform : public Transform @@ -234,7 +270,6 @@ class ProcrustesAlignTransform : public Transform
234 p(i * 2) = imagePoints[i].x(); 270 p(i * 2) = imagePoints[i].x();
235 p(i * 2 + 1) = imagePoints[i].y(); 271 p(i * 2 + 1) = imagePoints[i].y();
236 } 272 }
237 - float norm = p.norm();  
238 p = vectorToMatrix(p); 273 p = vectorToMatrix(p);
239 274
240 //Nomralize translation 275 //Nomralize translation
@@ -242,30 +277,46 @@ class ProcrustesAlignTransform : public Transform @@ -242,30 +277,46 @@ class ProcrustesAlignTransform : public Transform
242 p.col(1) = p.col(1) - MatrixXf::Ones(p.rows(),1) * (p.col(1).sum() / p.rows()); 277 p.col(1) = p.col(1) - MatrixXf::Ones(p.rows(),1) * (p.col(1).sum() / p.rows());
243 278
244 //Normalize scale 279 //Normalize scale
245 - p /= norm; 280 + p /= matrixToVector(p).norm();
246 281
247 //Normalize rotation 282 //Normalize rotation
248 MatrixXf R = getRotation(referenceShape, p); 283 MatrixXf R = getRotation(referenceShape, p);
249 - p = p * R; 284 + p = p * R.transpose();
250 285
  286 + for (int i = 0; i < p.rows(); i++) {
  287 + }
  288 +
  289 + //Translate and scale into output space and store in output list
251 QList<QPointF> procrustesPoints; 290 QList<QPointF> procrustesPoints;
252 for (int i = 0; i < p.rows(); i++) 291 for (int i = 0; i < p.rows(); i++)
253 - procrustesPoints.append(QPointF(p(i, 0), p(i, 1))); 292 + procrustesPoints.append( QPointF(
  293 + (p(i, 0) - minX) / (maxX - minX) * (width - 1) + padding,
  294 + (p(i, 1) - minY) / (maxY - minY) * (qRound( width / aspectRatio) - 1) + padding));
254 295
255 dst = src; 296 dst = src;
256 dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints); 297 dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints);
  298 + dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding)));
257 } 299 }
258 300
259 void store(QDataStream &stream) const 301 void store(QDataStream &stream) const
260 { 302 {
261 stream << referenceShape; 303 stream << referenceShape;
  304 + stream << minX;
  305 + stream << minY;
  306 + stream << maxX;
  307 + stream << maxY;
  308 + stream << aspectRatio;
262 } 309 }
263 310
264 void load(QDataStream &stream) 311 void load(QDataStream &stream)
265 { 312 {
266 stream >> referenceShape; 313 stream >> referenceShape;
  314 + stream >> minX;
  315 + stream >> minY;
  316 + stream >> maxX;
  317 + stream >> maxY;
  318 + stream >> aspectRatio;
267 } 319 }
268 -  
269 }; 320 };
270 321
271 BR_REGISTER(Transform, ProcrustesAlignTransform) 322 BR_REGISTER(Transform, ProcrustesAlignTransform)