Commit 59acf29449553755b093799c14c2ebdc170c49de

Authored by Brendan Klare
1 parent d5677d9b

Initial texture map changes

Showing 1 changed file with 109 additions and 1 deletions
openbr/plugins/landmarks.cpp
@@ -268,11 +268,19 @@ class ProcrustesAlignTransform : public Transform @@ -268,11 +268,19 @@ class ProcrustesAlignTransform : public Transform
268 268
269 void project(const Template &src, Template &dst) const 269 void project(const Template &src, Template &dst) const
270 { 270 {
  271 + float srcMinX = FLT_MAX;
  272 + float srcMinY = FLT_MAX;
  273 + float srcMaxX = -FLT_MAX;
  274 + float srcMaxY = -FLT_MAX;
271 QList<QPointF> imagePoints = src.file.points(); 275 QList<QPointF> imagePoints = src.file.points();
272 MatrixXf p(imagePoints.size() * 2, 1); 276 MatrixXf p(imagePoints.size() * 2, 1);
273 for (int i = 0; i < imagePoints.size(); i++) { 277 for (int i = 0; i < imagePoints.size(); i++) {
274 p(i * 2) = imagePoints[i].x(); 278 p(i * 2) = imagePoints[i].x();
275 p(i * 2 + 1) = imagePoints[i].y(); 279 p(i * 2 + 1) = imagePoints[i].y();
  280 + if (imagePoints[i].x() < srcMinX) srcMinX = imagePoints[i].x();
  281 + if (imagePoints[i].y() < srcMinY) srcMinY = imagePoints[i].y();
  282 + if (imagePoints[i].x() < srcMaxX) srcMaxX = imagePoints[i].x();
  283 + if (imagePoints[i].y() < srcMaxY) srcMaxY = imagePoints[i].y();
276 } 284 }
277 p = vectorToMatrix(p); 285 p = vectorToMatrix(p);
278 286
@@ -297,6 +305,9 @@ class ProcrustesAlignTransform : public Transform @@ -297,6 +305,9 @@ class ProcrustesAlignTransform : public Transform
297 dst = src; 305 dst = src;
298 dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints); 306 dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints);
299 dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding))); 307 dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding)));
  308 + dst.file.set("ProcrustesSrcBound", QRectF(qRound(srcMinX - padding), qRound(srcMinY - padding),
  309 + qRound(srcMaxX - srcMinX + 2 * padding),
  310 + qRound(srcMaxY - srcMinY + 2 * padding)));
300 } 311 }
301 312
302 void store(QDataStream &stream) const 313 void store(QDataStream &stream) const
@@ -336,7 +347,7 @@ class DelaunayTransform : public UntrainableTransform @@ -336,7 +347,7 @@ class DelaunayTransform : public UntrainableTransform
336 BR_PROPERTY(float, scaleFactor, 1) 347 BR_PROPERTY(float, scaleFactor, 1)
337 BR_PROPERTY(bool, warp, true) 348 BR_PROPERTY(bool, warp, true)
338 349
339 - void project(const Template &src, Template &dst) const 350 + void project(const Template &src, Template &dst, ) const
340 { 351 {
341 QList<QPointF> points = src.file.points(); 352 QList<QPointF> points = src.file.points();
342 QList<QRectF> rects = src.file.rects(); 353 QList<QRectF> rects = src.file.rects();
@@ -466,6 +477,103 @@ BR_REGISTER(Transform, DelaunayTransform) @@ -466,6 +477,103 @@ BR_REGISTER(Transform, DelaunayTransform)
466 477
467 /*! 478 /*!
468 * \ingroup transforms 479 * \ingroup transforms
  480 + * \brief Maps texture from one set of points to another. Assumes that points are rigidly transformed
  481 + * \author Scott Klum \cite sklum
  482 + * \author Brendan Klare \cite bklare
  483 + */
  484 +class TextureMapTransform : public UntrainableTransform
  485 +{
  486 + Q_OBJECT
  487 +
  488 + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
  489 + Q_PROPERTY(bool warp READ get_warp WRITE set_warp RESET reset_warp STORED false)
  490 + BR_PROPERTY(float, scaleFactor, 1)
  491 + BR_PROPERTY(bool, warp, true)
  492 +
  493 + QList<QPointF> getTriangulation(QList<QPointF> points, QRect bound) {
  494 + points.append(bound.topLeft());
  495 + points.append(bound.topRight());
  496 + points.append(bound.bottomLeft());
  497 + points.append(bound.bottomRight());
  498 +
  499 + Subdiv2D subdiv();
  500 + for (int i = 0; i < points.size(); i++)
  501 + subdiv.insert(OpenCVUtils::toPoint(points[i]));
  502 +
  503 + vector<Vec6f> triangleList;
  504 + subdiv.getTriangleList(triangleList);
  505 +
  506 + QList<QPointF> validTriangles;
  507 + for (size_t i = 0; i < triangleList.size(); i++) {
  508 + bool valid = true;
  509 + QList<QPointF> vertices;
  510 + vertices.append(QPointF(triangleList[i][0],triangleList[i][1]));
  511 + vertices.append(QPointF(triangleList[i][2],triangleList[i][3]));
  512 + vertices.append(QPointF(triangleList[i][4],triangleList[i][5]));
  513 + for (int j = 0; j < 3; j++)
  514 + if (vertices[j].x() > cols || vertices[j].y() > rows || vertices[j].x() < 0 || vertices[j].y() < 0)
  515 + valid = false;
  516 +
  517 + if (valid)
  518 + validTriangles.append(vertices);
  519 + }
  520 +
  521 + return validTriangles;
  522 + }
  523 +
  524 + void project(const Template &src, Template &dst) const
  525 + {
  526 + QList<QPointF> dstPoints = dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints);
  527 + QRectF dstBound = dst.file.setList<QPointF>("ProcrustesBound", procrustesPoints);
  528 + QList<QPointF> srcPoints = dst.file.points();
  529 + QRectF srcBound = dst.file.setList<QPointF>("ProcrustesSrcBound", procrustesPoints);
  530 +
  531 + if (dstPoints.empty() || srcPoints.empty()) {
  532 + dst = src;
  533 + if (Globals->verbose) qWarning("Delauney triangulation failed because points or rects are empty.");
  534 + return;
  535 + }
  536 +
  537 + QList<QPointF> dstTri = getTriangulation(dstPoints, dstBound);
  538 + QList<QPointF> srcTri = getTriangulation(srcPoints, srcBound);
  539 +
  540 + dst.m() = Mat::zeros(dstBound.height(), dstBound.width(), src.m().type());
  541 + for (int i = 0; i < srcTriangles.size(); i+=3) {
  542 + Point2f srcPoints[3];
  543 + Point2f dstPoints[3];
  544 + for (int j = 0; j < 3; j++) {
  545 + srcPoints[j] = OpenCVUtils::toPoint(srcTri[i+j]);
  546 + srcPoints[j] = OpenCVUtils::toPoint(dstTri[i+j]);
  547 + }
  548 +
  549 + Mat buffer(dstBound.height(), dstBound.width(), src.m().type());
  550 + warpAffine(src.m(), buffer, getAffineTransform(srcPoints, dstPoints), Size(cols,rows));
  551 +
  552 + Mat mask = Mat::zeros(rows, cols, CV_8UC1);
  553 + Point maskPoints[1][3];
  554 + maskPoints[0][0] = dstPoints[0];
  555 + maskPoints[0][1] = dstPoints[1];
  556 + maskPoints[0][2] = dstPoints[2];
  557 + const Point* ppt = { maskPoints[0] };
  558 + fillConvexPoly(mask, ppt, 3, Scalar(255,255,255), 8);
  559 +
  560 + Mat output(dstBound.height(), dstBound.width(), src.m().type());
  561 +
  562 + if (i > 0) {
  563 + Mat overlap;
  564 + bitwise_and(dst.m(),mask,overlap);
  565 + mask.setTo(0, overlap!=0);
  566 + }
  567 +
  568 + bitwise_and(buffer,mask,output);
  569 +
  570 + dst.m() += output;
  571 + }
  572 + }
  573 +};
  574 +
  575 +/*!
  576 + * \ingroup transforms
469 * \brief Creates a Delaunay triangulation based on a set of points 577 * \brief Creates a Delaunay triangulation based on a set of points
470 * \author Scott Klum \cite sklum 578 * \author Scott Klum \cite sklum
471 */ 579 */