laplacian_pyramid_blending.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /**
  2. * OpenCV Laplacian Pyramid Blending Example
  3. *
  4. * Copyright 2017 by Satya Mallick <spmallick@gmail.com>
  5. *
  6. */
  7. #include "opencv2/opencv.hpp"
  8. using namespace cv;
  9. using namespace std;
  10. void getLaplacianPyramid(Mat& guassianPyramid, Mat& laplacianPyramid){
  11. // compute laplacian pyramid from the guassian pyramid
  12. Mat downSampled;
  13. pyrDown(guassianPyramid,downSampled);
  14. // up sample the down sampled
  15. Mat blurred;
  16. pyrUp(downSampled,blurred);
  17. subtract(guassianPyramid, blurred, laplacianPyramid);
  18. }
  19. void combineImages(Mat& A, Mat& B, Mat& mask, Mat& destination){
  20. destination = Mat::zeros(A.rows, A.cols, CV_32FC3);
  21. // destination is weighted sum of A and B, with weights mask, and 1-mask respectively
  22. for(int y = 0; y < A.rows; y++)
  23. {
  24. for(int x = 0; x < A.cols; x++)
  25. {
  26. Vec3f a = A.at<Vec3f>(Point(x,y));
  27. Vec3f b = B.at<Vec3f>(Point(x,y));
  28. Vec3f m = mask.at<Vec3f>(Point(x,y));
  29. float b_ = a[0]*m[0]+(1-m[0])*b[0];
  30. float g_ = a[1]*m[1]+(1-m[1])*b[1];
  31. float r_ = a[2]*m[2]+(1-m[2])*b[2];
  32. destination.at<Vec3f>(y,x)[0] = b_;
  33. destination.at<Vec3f>(y,x)[1] = g_;
  34. destination.at<Vec3f>(y,x)[2] = r_;
  35. }
  36. }
  37. }
  38. int main( int argc, char** argv )
  39. {
  40. // Read two images
  41. Mat A = imread("images/man.jpg");
  42. Mat B = imread("images/woman.jpg");
  43. // Convert to float
  44. A.convertTo(A, CV_32FC3, 1/255.0);
  45. B.convertTo(B, CV_32FC3, 1/255.0);
  46. // Create a rough mask around man's face in A.
  47. Mat mask = Mat::zeros(A.rows, A.cols, CV_8UC3);
  48. // Create some points around airplane
  49. Point points[11];
  50. points[0] = Point(164,226);
  51. points[1] = Point(209,225);
  52. points[2] = Point(238,188);
  53. points[3] = Point(252,133);
  54. points[4] = Point(248,75);
  55. points[5] = Point(240,29);
  56. points[6] = Point(192,15);
  57. points[7] = Point(150,15);
  58. points[8] = Point(100,70);
  59. points[9] = Point(106,133);
  60. points[10] = Point(123,194);
  61. const Point* polygon[1] = {points}; //Array of points arrays
  62. int npt[] = {11}; // Length of points array
  63. //Fill the polygon formed by the points
  64. fillPoly(mask, polygon, npt, 1, Scalar(255, 255, 255));
  65. // Convert to float
  66. mask.convertTo(mask, CV_32FC3, 1/255.0);
  67. // Multiply with float < 1.0 to take weighted average of man and woman's face
  68. mask = mask * 0.7;
  69. // Resizing to multiples of 2^(levels in pyramid), thus 32 in our case
  70. resize(A, A, Size(384,352));
  71. // B and mask should have same size as A for multiplication and addition operations later
  72. resize(B, B, A.size());
  73. resize(mask, mask, A.size());
  74. // Start with original images (base of pyramids)
  75. Mat guassianA = A.clone();
  76. Mat guassianB = B.clone();
  77. Mat guassianMask = mask.clone();
  78. // Number of levels in pyramids, try with different values. Be careful with image sizes
  79. int maxIterations = 2;
  80. // Combined laplacian pyramids of both images
  81. vector<Mat> combinedLaplacianPyramids;
  82. for (int i = 0; i < maxIterations; i++){
  83. // compute laplacian pyramids for A
  84. Mat laplacianA;
  85. getLaplacianPyramid(guassianA,laplacianA);
  86. // compute laplacian pyramids for B
  87. Mat laplacianB;
  88. getLaplacianPyramid(guassianB,laplacianB);
  89. // combine laplacian pyramids
  90. Mat combinedLaplacian;
  91. combineImages(laplacianA, laplacianB, guassianMask, combinedLaplacian);
  92. // Insert combinedLaplacian in the beginning of the list of combined laplacian pyramids
  93. combinedLaplacianPyramids.insert(combinedLaplacianPyramids.begin(),combinedLaplacian);
  94. // Update guassian pyramids for next iteration
  95. pyrDown(guassianA,guassianA);
  96. pyrDown(guassianB,guassianB);
  97. pyrDown(guassianMask,guassianMask);
  98. }
  99. // combine last guassians (top level of laplacian pyramids is same as that of guassian's)
  100. Mat lastCombined;
  101. combineImages(guassianA, guassianB, guassianMask, lastCombined);
  102. // Insert lastCombined in the beginning of the list of combined laplacian pyramids
  103. combinedLaplacianPyramids.insert(combinedLaplacianPyramids.begin(),lastCombined);
  104. // reconstructing image
  105. Mat blendedImage = combinedLaplacianPyramids[0];
  106. for (int i = 1; i < combinedLaplacianPyramids.size(); i++){
  107. // upSample and add to next level
  108. pyrUp(blendedImage,blendedImage);
  109. add(blendedImage, combinedLaplacianPyramids[i],blendedImage);
  110. }
  111. // put blended image back to sky image at original location
  112. imshow("blended",blendedImage);
  113. // direct combining both halves for comparison
  114. Mat directCombined;
  115. combineImages(A, B, mask, directCombined);
  116. imshow("directCombined",directCombined);
  117. waitKey(0);
  118. return 0;
  119. }