warpTriangle.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2016 Satya Mallick <spmallick@learnopencv.com>
  3. * All rights reserved. No warranty, explicit or implicit, provided.
  4. */
  5. #include <opencv2/opencv.hpp>
  6. #include <stdlib.h>
  7. using namespace cv;
  8. using namespace std;
  9. // Warps and alpha blends triangular regions from img1 and img2 to img
  10. void warpTriangle(Mat &img1, Mat &img2, vector<Point2f> tri1, vector<Point2f> tri2)
  11. {
  12. // Find bounding rectangle for each triangle
  13. Rect r1 = boundingRect(tri1);
  14. Rect r2 = boundingRect(tri2);
  15. // Offset points by left top corner of the respective rectangles
  16. vector<Point2f> tri1Cropped, tri2Cropped;
  17. vector<Point> tri2CroppedInt;
  18. for(int i = 0; i < 3; i++)
  19. {
  20. tri1Cropped.push_back( Point2f( tri1[i].x - r1.x, tri1[i].y - r1.y) );
  21. tri2Cropped.push_back( Point2f( tri2[i].x - r2.x, tri2[i].y - r2.y) );
  22. // fillConvexPoly needs a vector of Point and not Point2f
  23. tri2CroppedInt.push_back( Point((int)(tri2[i].x - r2.x), (int)(tri2[i].y - r2.y)) );
  24. }
  25. // Apply warpImage to small rectangular patches
  26. Mat img1Cropped;
  27. img1(r1).copyTo(img1Cropped);
  28. // Given a pair of triangles, find the affine transform.
  29. Mat warpMat = getAffineTransform( tri1Cropped, tri2Cropped );
  30. // Apply the Affine Transform just found to the src image
  31. Mat img2Cropped = Mat::zeros(r2.height, r2.width, img1Cropped.type());
  32. warpAffine( img1Cropped, img2Cropped, warpMat, img2Cropped.size(), INTER_LINEAR, BORDER_REFLECT_101);
  33. // Get mask by filling triangle
  34. Mat mask = Mat::zeros(r2.height, r2.width, CV_32FC3);
  35. fillConvexPoly(mask, tri2CroppedInt, Scalar(1.0, 1.0, 1.0), 16, 0);
  36. // Copy triangular region of the rectangular patch to the output image
  37. multiply(img2Cropped,mask, img2Cropped);
  38. multiply(img2(r2), Scalar(1.0,1.0,1.0) - mask, img2(r2));
  39. img2(r2) = img2(r2) + img2Cropped;
  40. }
  41. int main( int argc, char** argv)
  42. {
  43. // Read input image and convert to float
  44. Mat imgIn = imread("robot.jpg");
  45. imgIn.convertTo(imgIn, CV_32FC3, 1/255.0);
  46. // Output image is set to white
  47. Mat imgOut = Mat::ones(imgIn.size(), imgIn.type());
  48. imgOut = Scalar(1.0,1.0,1.0);
  49. // Input triangle
  50. vector <Point2f> triIn;
  51. triIn.push_back(Point2f(360,200));
  52. triIn.push_back(Point2d(60,250));
  53. triIn.push_back(Point2f(450,400));
  54. // Output triangle
  55. vector <Point2f> triOut;
  56. triOut.push_back(Point2f(400,200));
  57. triOut.push_back(Point2f(160,270));
  58. triOut.push_back(Point2f(400,400));
  59. // Warp all pixels inside input triangle to output triangle
  60. warpTriangle(imgIn, imgOut, triIn, triOut);
  61. // Draw triangle on the input and output image.
  62. // Convert back to uint because OpenCV antialiasing
  63. // does not work on image of type CV_32FC3
  64. imgIn.convertTo(imgIn, CV_8UC3, 255.0);
  65. imgOut.convertTo(imgOut, CV_8UC3, 255.0);
  66. // Draw triangle using this color
  67. Scalar color = Scalar(255, 150, 0);
  68. // cv::polylines needs vector of type Point and not Point2f
  69. vector <Point> triInInt, triOutInt;
  70. for(int i=0; i < 3; i++)
  71. {
  72. triInInt.push_back(Point(triIn[i].x,triIn[i].y));
  73. triOutInt.push_back(Point(triOut[i].x,triOut[i].y));
  74. }
  75. // Draw triangles in input and output images
  76. polylines(imgIn, triInInt, true, color, 2, 16);
  77. polylines(imgOut, triOutInt, true, color, 2, 16);
  78. imshow("Input", imgIn);
  79. imshow("Output", imgOut);
  80. waitKey(0);
  81. return 0;
  82. }