Commit 4261d8e6a1050c7c68bf50719350524c354511c4
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) |