Commit 48d184af11d199e4c9079d49d3c910abfcdababc

Authored by Brendan Klare
1 parent 260843b5

Killed

Showing 1 changed file with 0 additions and 369 deletions
openbr/plugins/landmarks.cpp
@@ -141,204 +141,6 @@ BR_REGISTER(Transform, ProcrustesTransform) @@ -141,204 +141,6 @@ BR_REGISTER(Transform, ProcrustesTransform)
141 141
142 /*! 142 /*!
143 * \ingroup transforms 143 * \ingroup transforms
144 - * \brief Improved procrustes alignment of points, to include a post processing scaling of points  
145 - * to faciliate subsequent texture mapping.  
146 - * \author Brendan Klare \cite bklare  
147 - * \param width Width of output coordinate space (before padding)  
148 - * \param padding Amount of padding around the coordinate space  
149 - * \param useFirst whether or not to use the first instance as the reference object  
150 - */  
151 -class ProcrustesAlignTransform : public Transform  
152 -{  
153 - Q_OBJECT  
154 -  
155 - Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false)  
156 - Q_PROPERTY(float padding READ get_padding WRITE set_padding RESET reset_padding STORED false)  
157 - Q_PROPERTY(bool useFirst READ get_useFirst WRITE set_useFirst RESET reset_useFirst STORED false)  
158 - BR_PROPERTY(float, width, 80)  
159 - BR_PROPERTY(float, padding, 8)  
160 - BR_PROPERTY(bool, useFirst, false)  
161 -  
162 -  
163 - Eigen::MatrixXf referenceShape;  
164 - float minX;  
165 - float minY;  
166 - float maxX;  
167 - float maxY;  
168 - float aspectRatio;  
169 -  
170 - void init() {  
171 - aspectRatio = 0;  
172 - }  
173 -  
174 - static MatrixXf getRotation(MatrixXf ref, MatrixXf sample) {  
175 - MatrixXf R = sample.transpose() * ref;  
176 - JacobiSVD<MatrixXf> svd(R, ComputeFullU | ComputeFullV);  
177 - R = svd.matrixU() * svd.matrixV().transpose();  
178 - return R;  
179 - }  
180 -  
181 - //Converts x y points in a single vector to two column matrix  
182 - static MatrixXf vectorToMatrix(MatrixXf vector) {  
183 - int n = vector.rows();  
184 - MatrixXf matrix(n / 2, 2);  
185 - for (int i = 0; i < n / 2; i++) {  
186 - for (int j = 0; j < 2; j++) {  
187 - matrix(i, j) = vector(i * 2 + j);  
188 - }  
189 - }  
190 - return matrix;  
191 - }  
192 -  
193 - static MatrixXf matrixToVector(MatrixXf matrix) {  
194 - int n2 = matrix.rows();  
195 - MatrixXf vector(n2 * 2, 1);  
196 - for (int i = 0; i < n2; i++) {  
197 - for (int j = 0; j < 2; j++) {  
198 - vector(i * 2 + j) = matrix(i, j);  
199 - }  
200 - }  
201 - return vector;  
202 - }  
203 -  
204 - void train(const TemplateList &data)  
205 - {  
206 - MatrixXf points(data[0].file.points().size() * 2, data.size());  
207 -  
208 - // Normalize all sets of points  
209 - for (int j = 0; j < data.size(); j++) {  
210 - QList<QPointF> imagePoints = data[j].file.points();  
211 -  
212 - float meanX = 0,  
213 - meanY = 0;  
214 - for (int i = 0; i < imagePoints.size(); i++) {  
215 - points(i * 2, j) = imagePoints[i].x();  
216 - points(i * 2 + 1, j) = imagePoints[i].y();  
217 - meanX += imagePoints[i].x();  
218 - meanY += imagePoints[i].y();  
219 - }  
220 - meanX /= imagePoints.size();  
221 - meanY /= imagePoints.size();  
222 -  
223 - for (int i = 0; i < imagePoints.size(); i++) {  
224 - points(i * 2, j) -= meanX;  
225 - points(i * 2 + 1, j) -= meanY;  
226 - }  
227 - }  
228 -  
229 - //normalize scale  
230 - for (int i = 0; i < points.cols(); i++)  
231 - points.col(i) = points.col(i) / points.col(i).norm();  
232 -  
233 - //Normalize rotation  
234 - if (!useFirst) {  
235 - referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols());  
236 - } else {  
237 - referenceShape = vectorToMatrix(points.col(0));  
238 - }  
239 -  
240 - for (int i = 0; i < points.cols(); i++) {  
241 - MatrixXf p = vectorToMatrix(points.col(i));  
242 - MatrixXf R = getRotation(referenceShape, p);  
243 - points.col(i) = matrixToVector(p * R);  
244 - }  
245 -  
246 - //Choose crop boundaries and adjustments that captures most data  
247 - MatrixXf minXs(points.cols(),1);  
248 - MatrixXf minYs(points.cols(),1);  
249 - MatrixXf maxXs(points.cols(),1);  
250 - MatrixXf maxYs(points.cols(),1);  
251 - for (int j = 0; j < points.cols(); j++) {  
252 - minX = FLT_MAX,  
253 - minY = FLT_MAX,  
254 - maxX = -FLT_MAX,  
255 - maxY = -FLT_MAX;  
256 - for (int i = 0; i < points.rows(); i++) {  
257 - if (i % 2 == 0) {  
258 - if (points(i,j) > maxX)  
259 - maxX = points(i, j);  
260 - if (points(i,j) < minX)  
261 - minX = points(i, j);  
262 - } else {  
263 - if (points(i,j) > maxY)  
264 - maxY = points(i, j);  
265 - if (points(i,j) < minY)  
266 - minY = points(i, j);  
267 - }  
268 - }  
269 -  
270 - minXs(j) = minX;  
271 - maxXs(j) = maxX;  
272 - minYs(j) = minY;  
273 - maxYs(j) = maxY;  
274 - }  
275 -  
276 - minX = eigMean(minXs) - 0 * eigStd(minXs);  
277 - minY = eigMean(minYs) - 0 * eigStd(minYs);  
278 - maxX = eigMean(maxXs) + 0 * eigStd(maxXs);  
279 - maxY = eigMean(maxYs) + 0 * eigStd(maxYs);  
280 - aspectRatio = (maxX - minX) / (maxY - minY);  
281 - }  
282 -  
283 - void project(const Template &src, Template &dst) const  
284 - {  
285 - QList<QPointF> imagePoints = src.file.points();  
286 - MatrixXf p(imagePoints.size() * 2, 1);  
287 - for (int i = 0; i < imagePoints.size(); i++) {  
288 - p(i * 2) = imagePoints[i].x();  
289 - p(i * 2 + 1) = imagePoints[i].y();  
290 - }  
291 - p = vectorToMatrix(p);  
292 -  
293 - //Normalize translation  
294 - p.col(0) = p.col(0) - MatrixXf::Ones(p.rows(),1) * (p.col(0).sum() / p.rows());  
295 - p.col(1) = p.col(1) - MatrixXf::Ones(p.rows(),1) * (p.col(1).sum() / p.rows());  
296 -  
297 - //Normalize scale  
298 - p /= matrixToVector(p).norm();  
299 -  
300 - //Normalize rotation  
301 - MatrixXf R = getRotation(referenceShape, p);  
302 - p = p * R;  
303 -  
304 - //Translate and scale into output space and store in output list  
305 - QList<QPointF> procrustesPoints;  
306 - for (int i = 0; i < p.rows(); i++)  
307 - procrustesPoints.append( QPointF(  
308 - (p(i, 0) - minX) / (maxX - minX) * (width - 1) + padding,  
309 - (p(i, 1) - minY) / (maxY - minY) * (qRound( width / aspectRatio) - 1) + padding));  
310 -  
311 - dst = src;  
312 - dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints);  
313 - dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding)));  
314 - dst.file.set("ProcrustesPadding", padding);  
315 - }  
316 -  
317 - void store(QDataStream &stream) const  
318 - {  
319 - stream << referenceShape;  
320 - stream << minX;  
321 - stream << minY;  
322 - stream << maxX;  
323 - stream << maxY;  
324 - stream << aspectRatio;  
325 - }  
326 -  
327 - void load(QDataStream &stream)  
328 - {  
329 - stream >> referenceShape;  
330 - stream >> minX;  
331 - stream >> minY;  
332 - stream >> maxX;  
333 - stream >> maxY;  
334 - stream >> aspectRatio;  
335 - }  
336 -};  
337 -  
338 -BR_REGISTER(Transform, ProcrustesAlignTransform)  
339 -  
340 -/*!  
341 - * \ingroup transforms  
342 * \brief Creates a Delaunay triangulation based on a set of points 144 * \brief Creates a Delaunay triangulation based on a set of points
343 * \author Scott Klum \cite sklum 145 * \author Scott Klum \cite sklum
344 */ 146 */
@@ -481,177 +283,6 @@ BR_REGISTER(Transform, DelaunayTransform) @@ -481,177 +283,6 @@ BR_REGISTER(Transform, DelaunayTransform)
481 283
482 /*! 284 /*!
483 * \ingroup transforms 285 * \ingroup transforms
484 - * \brief Maps texture from one set of points to another. Assumes that points are rigidly transformed  
485 - * \author Brendan Klare \cite bklare  
486 - * \author Scott Klum \cite sklum  
487 - */  
488 -class TextureMapTransform : public UntrainableTransform  
489 -{  
490 - Q_OBJECT  
491 -  
492 - static QRectF getBounds(QList<QPointF> points, int dstPadding) {  
493 - float srcMinX = FLT_MAX;  
494 - float srcMinY = FLT_MAX;  
495 - float srcMaxX = -FLT_MAX;  
496 - float srcMaxY = -FLT_MAX;  
497 - for (int i = 0; i < points.size(); i++) {  
498 - if (points[i].x() < srcMinX) srcMinX = points[i].x();  
499 - if (points[i].y() < srcMinY) srcMinY = points[i].y();  
500 - if (points[i].x() > srcMaxX) srcMaxX = points[i].x();  
501 - if (points[i].y() > srcMaxY) srcMaxY = points[i].y();  
502 - }  
503 -  
504 - float padding = (srcMaxX - srcMinX) / 80 * dstPadding;  
505 - return QRectF(qRound(srcMinX - padding), qRound(srcMinY - padding), qRound(srcMaxX - srcMinX + 2 * padding), qRound(srcMaxY - srcMinY + 2 * padding));  
506 - }  
507 -  
508 - static int getVertexIndex(QPointF trianglePts, QList<QPointF> pts)  
509 - {  
510 - for (int i = 0; i < pts.size(); i++)  
511 - if (trianglePts.x() == pts[i].x() && trianglePts.y() == pts[i].y())  
512 - return i;  
513 - return -1;  
514 - }  
515 -  
516 - static QList<QPointF> addBounds(const QList<QPointF> _points, const QRectF bound)  
517 - {  
518 - QList<QPointF> points(_points);  
519 - points.append(bound.topLeft());  
520 - points.append(QPointF(bound.right() - 1, bound.top()));  
521 - points.append(QPointF(bound.left(), bound.bottom() - 1));  
522 - points.append(QPointF(bound.right() - 1, bound.bottom() - 1));  
523 - return points;  
524 - }  
525 -  
526 - static QList<QList<int> > getTriangulation(const QList<QPointF> _points, const QRectF bound)  
527 - {  
528 - QList<QPointF> points(_points);  
529 -  
530 - Subdiv2D subdiv(OpenCVUtils::toRect(bound));  
531 - for (int i = 0; i < points.size(); i++)  
532 - subdiv.insert(OpenCVUtils::toPoint(points[i]));  
533 -  
534 - vector<Vec6f> triangleList;  
535 - subdiv.getTriangleList(triangleList);  
536 -  
537 - QList<QList<int> > triangleIndices;  
538 - for (size_t i = 0; i < triangleList.size(); i++) {  
539 - bool valid = true;  
540 - QList<QPointF> vertices;  
541 - vertices.append(QPointF(triangleList[i][0],triangleList[i][1]));  
542 - vertices.append(QPointF(triangleList[i][2],triangleList[i][3]));  
543 - vertices.append(QPointF(triangleList[i][4],triangleList[i][5]));  
544 - for (int j = 0; j < 3; j++)  
545 - if (vertices[j].x() > bound.right() || vertices[j].y() > bound.bottom() || vertices[j].x() < bound.left() || vertices[j].y() < bound.top())  
546 - valid = false;  
547 -  
548 - if (valid) {  
549 - QList<int> tri;  
550 - for (int j = 0; j < 3; j++)  
551 - tri.append(getVertexIndex(vertices[j], points));  
552 - triangleIndices.append(tri);  
553 - }  
554 - }  
555 -  
556 - return triangleIndices;  
557 - }  
558 -  
559 - void project(const Template &src, Template &dst) const  
560 - {  
561 - QList<QPointF> dstPoints = dst.file.getList<QPointF>("ProcrustesPoints");  
562 - QList<QPointF> srcPoints = dst.file.points();  
563 - QRectF dstBound = dst.file.get<QRectF>("ProcrustesBound");  
564 - QRectF srcBound = getBounds(srcPoints, dst.file.get<int>("ProcrustesPadding"));  
565 - if (dstPoints.empty() || srcPoints.empty()) {  
566 - dst = src;  
567 - if (Globals->verbose) qWarning("Delauney triangulation failed because points or rects are empty.");  
568 - return;  
569 - }  
570 -  
571 - dstPoints = addBounds(dstPoints, dstBound);  
572 - srcPoints = addBounds(srcPoints, srcBound);  
573 -  
574 - QList<QList<int> > triIndices = getTriangulation(srcPoints, srcBound);  
575 -  
576 - int dstWidth = dstBound.width() + dstBound.x();  
577 - int dstHeight = dstBound.height() + dstBound.y();  
578 - dst.m() = Mat::zeros(dstHeight, dstWidth, src.m().type());  
579 - for (int i = 0; i < triIndices.size(); i++) {  
580 - Point2f srcPoint1[3];  
581 - Point2f dstPoint1[3];  
582 - for (int j = 0; j < 3; j++) {  
583 - srcPoint1[j] = OpenCVUtils::toPoint(srcPoints[triIndices[i][j]]);  
584 - dstPoint1[j] = OpenCVUtils::toPoint(dstPoints[triIndices[i][j]]);  
585 - }  
586 -  
587 - Mat buffer(dstHeight, dstWidth, src.m().type());  
588 - warpAffine(src.m(), buffer, getAffineTransform(srcPoint1, dstPoint1), Size(dstBound.width(), dstBound.height()));  
589 -  
590 - Mat mask = Mat::zeros(dstHeight, dstWidth, CV_8UC1);  
591 - Point maskPoints[1][3];  
592 - maskPoints[0][0] = dstPoint1[0];  
593 - maskPoints[0][1] = dstPoint1[1];  
594 - maskPoints[0][2] = dstPoint1[2];  
595 - const Point* ppt = { maskPoints[0] };  
596 - fillConvexPoly(mask, ppt, 3, Scalar(255, 255, 255), 8);  
597 -  
598 - for (int i = 0; i < dstHeight; i++) {  
599 - for (int j = 0; j < dstWidth; j++) {  
600 - if (mask.at<uchar>(i,j) == 255) {  
601 - if (dst.m().type() == CV_32FC3 || dst.m().type() == CV_8UC3)  
602 - dst.m().at<cv::Vec3b>(i,j) = buffer.at<cv::Vec3b>(i,j);  
603 - else if (dst.m().type() == CV_32F)  
604 - dst.m().at<float>(i,j) = buffer.at<float>(i,j);  
605 - else if (dst.m().type() == CV_8U)  
606 - dst.m().at<uchar>(i,j) = buffer.at<uchar>(i,j);  
607 - else  
608 - qFatal("Unsupported pixel format.");  
609 - }  
610 - }  
611 - }  
612 -  
613 - }  
614 -  
615 - dst.file.clearPoints();  
616 - dst.file.clearRects();  
617 - dst.file.setPoints(dstPoints);  
618 - }  
619 -};  
620 -  
621 -BR_REGISTER(Transform, TextureMapTransform)  
622 -  
623 -/*!  
624 - * \ingroup initializers  
625 - * \brief Initialize Procrustes croppings  
626 - * \author Brendan Klare \cite bklare  
627 - */  
628 -class ProcrustesInitializer : public Initializer  
629 -{  
630 - Q_OBJECT  
631 -  
632 - void initialize() const  
633 - {  
634 - Globals->abbreviations.insert("ProcrustesStasmFace","ProcrustesAlign(padding=16)+TextureMap+Resize(48,48)");  
635 - Globals->abbreviations.insert("ProcrustesStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)");  
636 - Globals->abbreviations.insert("ProcrustesStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(36,48)");  
637 - Globals->abbreviations.insert("ProcrustesStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)");  
638 - Globals->abbreviations.insert("ProcrustesStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=8)+TextureMap+Resize(36,48)");  
639 - Globals->abbreviations.insert("ProcrustesStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=10)+TextureMap+Resize(36,48)");  
640 - Globals->abbreviations.insert("ProcrustesStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(36,48)");  
641 -  
642 - Globals->abbreviations.insert("ProcrustesLargeStasmFace","ProcrustesAlign(padding=16)+TextureMap+Resize(480,480)");  
643 - Globals->abbreviations.insert("ProcrustesLargeStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)");  
644 - Globals->abbreviations.insert("ProcrustesLargeStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(360,480)");  
645 - Globals->abbreviations.insert("ProcrustesLargeStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)");  
646 - Globals->abbreviations.insert("ProcrustesLargeStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=8)+TextureMap+Resize(360,480)");  
647 - Globals->abbreviations.insert("ProcrustesLargeStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=20)+TextureMap+Resize(360,480)");  
648 - Globals->abbreviations.insert("ProcrustesLargeStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(360,480)");  
649 - }  
650 -};  
651 -BR_REGISTER(Initializer, ProcrustesInitializer)  
652 -  
653 -/*!  
654 - * \ingroup transforms  
655 * \brief Creates a Delaunay triangulation based on a set of points 286 * \brief Creates a Delaunay triangulation based on a set of points
656 * \author Scott Klum \cite sklum 287 * \author Scott Klum \cite sklum
657 */ 288 */