原理
太多了,看这些博客吧
主要参考博客1: http://blog.csdn.net/hjimce/article/details/45716603
主要参考博客2: http://blog.csdn.net/wd1603926823/article/details/49867069
主要参考博客3: http://blog.csdn.net/baimafujinji/article/details/46787837
代码示例
#include <iostream> #include <math.h> #include <opencv2/opencv.hpp> #include <opencv2/highgui.hpp> #include <opencv2/highgui/highgui_c.h> using namespace std; using namespace cv; #define elif else if #define ATD at<double> // 图像水平梯度的正向计算,即img(i,j+1)-img(i,j) // img:要计算其梯度的图像 Mat getGradientXp(Mat &img) { int height = img.rows; int width = img.cols; Mat casimg = repeat(img, 1, 2); // repeat the input img for two times, they are horizontally arranged. Rect roi = Rect(1, 0, width, height); Mat roimat = casimg(roi); // roimat is the version of img that the first column is in the last one, the other columns move one column forward. return roimat - img; // img(i, j + 1) - img(i, j) } // 图像垂直梯度的正向计算,即img(i+1,j)-img(i,j) // img:要计算其梯度的图像 Mat getGradientYp(Mat &img) { int height = img.rows; int width = img.cols; Mat casimg = repeat(img, 2, 1); // repeat the input img for two times, they are vertically arranged. Rect roi = Rect(0, 1, width, height); Mat roimat = casimg(roi); // roimat is the version of img that the first row is in the last one, the other rows move one row forward. return roimat - img; // img(i + 1, j) - img(i, j) } // 图像水平梯度的负向计算,即img(i,j-1)-img(i,j) // img:要计算其梯度的图像 Mat getGradientXn(Mat &img) { int height = img.rows; int width = img.cols; Mat casimg = repeat(img, 1, 2); // repeat the input img for two times, they are horizontally arranged. Rect roi = Rect(width - 1, 0, width, height); Mat roimat = casimg(roi); // roimat is the version of img that the last column is in the first one, the other columns move one column backward. return roimat - img; // img(i, j - 1) - img(i, j) } // 图像垂直梯度的负向计算,即img(i-1,j)-img(i,j) // img:要计算其梯度的图像 Mat getGradientYn(Mat &img) { int height = img.rows; int width = img.cols; Mat casimg = repeat(img, 2, 1); // repeat the input img for two times, they are vertically arranged. Rect roi = Rect(0, height - 1, width, height); Mat roimat = casimg(roi); // roimat is the version of img that the last row is in the first one, the other rows move one row backward. return roimat - img; // img(i - 1, j) - img(i, j) } int getLabel(int i, int j, int height, int width) { return i * width + j; // i is in height axis; j is in width axis. } // 得到矩阵A Mat getA(int height, int width) { Mat A = Mat::eye(height * width, height * width, CV_64FC1); A *= -4; // M: the label matrix of roi from im2; divede M into three parts, 0,1,2, respectively. // 0: the corners of roi // 1: boundaries but not corners // 2: inner part of roi // different parts represent different methods to asssign A values Mat M = Mat::zeros(height, width, CV_64FC1); Mat temp = Mat::ones(height, width - 2, CV_64FC1); Rect roi = Rect(1, 0, width - 2, height); Mat roimat = M(roi); temp.copyTo(roimat); temp = Mat::ones(height - 2, width, CV_64FC1); roi = Rect(0, 1, width, height - 2); roimat = M(roi); temp.copyTo(roimat); temp = Mat::ones(height - 2, width - 2, CV_64FC1); temp *= 2; roi = Rect(1, 1, width - 2, height - 2); roimat = M(roi); temp.copyTo(roimat); // get Matrix A for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // get index of M(i,j) int label = getLabel(i, j, height, width); // when M(i,j) is the corner, assign coeffients to A if (M.ATD(i, j) == 0) { if (i == 0) A.ATD(getLabel(i + 1, j, height, width), label) = 1; // left upper elif(i == height - 1) A.ATD(getLabel(i - 1, j, height, width), label) = 1; // right upper if (j == 0) A.ATD(getLabel(i, j + 1, height, width), label) = 1; // left lower elif(j == width - 1) A.ATD(getLabel(i, j - 1, height, width), label) = 1; // right lower } // when M(i,j) is the boundary but not corner, assign coeffients to A elif(M.ATD(i, j) == 1) { if (i == 0) { A.ATD(getLabel(i + 1, j, height, width), label) = 1; A.ATD(getLabel(i, j - 1, height, width), label) = 1; A.ATD(getLabel(i, j + 1, height, width), label) = 1; }elif(i == height - 1) { A.ATD(getLabel(i - 1, j, height, width), label) = 1; A.ATD(getLabel(i, j - 1, height, width), label) = 1; A.ATD(getLabel(i, j + 1, height, width), label) = 1; } if (j == 0) { A.ATD(getLabel(i, j + 1, height, width), label) = 1; A.ATD(getLabel(i - 1, j, height, width), label) = 1; A.ATD(getLabel(i + 1, j, height, width), label) = 1; }elif(j == width - 1) { A.ATD(getLabel(i, j - 1, height, width), label) = 1; A.ATD(getLabel(i - 1, j, height, width), label) = 1; A.ATD(getLabel(i + 1, j, height, width), label) = 1; } } // when M(i,j) is the inner point, assign coeffients to A else { A.ATD(getLabel(i, j - 1, height, width), label) = 1; A.ATD(getLabel(i, j + 1, height, width), label) = 1; A.ATD(getLabel(i - 1, j, height, width), label) = 1; A.ATD(getLabel(i + 1, j, height, width), label) = 1; } } } return A; } // 计算b // 使用getGradient函数。 Mat getB2(Mat &img1, Mat &img2, int posX, int posY, Rect ROI) { // calculate the divergence of img1 Mat MergeGradXp = getGradientXp(img1); Mat GradXp2 = getGradientXp(img2); Mat MergeGradXpROI = MergeGradXp(ROI); GradXp2.copyTo(MergeGradXpROI); Mat MergeGradXn = getGradientXn(img1); Mat GradXn2 = getGradientXn(img2); Mat MergeGradXnROI = MergeGradXn(ROI); GradXn2.copyTo(MergeGradXnROI); Mat MergeGradYp = getGradientYp(img1); Mat GradYp2 = getGradientYp(img2); Mat MergeGradYpROI = MergeGradYp(ROI); GradYp2.copyTo(MergeGradYpROI); Mat MergeGradYn = getGradientYn(img1); Mat GradYn2 = getGradientYn(img2); Mat MergeGradYnROI = MergeGradYn(ROI); GradYn2.copyTo(MergeGradYnROI); Mat grad = MergeGradXp + MergeGradXn + MergeGradYp + MergeGradYn; int roiheight = ROI.height; int roiwidth = ROI.width; Mat B = Mat::zeros(roiheight * roiwidth, 1, CV_64FC1); for (int i = 0; i < roiheight; i++) { for (int j = 0; j < roiwidth; j++) { double temp = 0.0; temp += grad.ATD(i + ROI.y, j + ROI.x); if (i == 0) temp -= img2.ATD(i - 1 + posY, j + posX); if (i == roiheight - 1) temp -= img2.ATD(i + 1 + posY, j + posX); if (j == 0) temp -= img2.ATD(i + posY, j - 1 + posX); if (j == roiwidth - 1) temp -= img2.ATD(i + posY, j + 1 + posX); B.ATD(getLabel(i, j, roiheight, roiwidth), 0) = temp; } } return B; } // 求解方程,并将其重塑为正确的高度和宽度。 // Solve equation and reshape it back to the right height and width. Mat getResult(Mat &A, Mat &B, Rect &ROI) { Mat result; solve(A, B, result); result = result.reshape(0, ROI.height); return result; } /// 泊松混合 // img1: 3-channel image, we wanna move something in it into img2. // img2: 3-channel image, dst image. // ROI: the position and size of the block we want to move in img1. // posX, posY: where we want to move the block to in img2 Mat poisson_blending(Mat &img1, Mat &img2, Rect ROI, int posX, int posY) { int roiheight = ROI.height; int roiwidth = ROI.width; Mat A = getA(roiheight, roiwidth); // we must do the poisson blending to each channel. vector<Mat> rgb1; split(img1, rgb1); vector<Mat> rgb2; split(img2, rgb2); vector<Mat> result; Mat merged, res, Br, Bg, Bb; Br = getB2(rgb1[0], rgb2[0], posX, posY, ROI); res = getResult(A, Br, ROI); result.push_back(res); cout << "R channel finished..." << endl; Bg = getB2(rgb1[1], rgb2[1], posX, posY, ROI); res = getResult(A, Bg, ROI); result.push_back(res); cout << "G channel finished..." << endl; Bb = getB2(rgb1[2], rgb2[2], posX, posY, ROI); res = getResult(A, Bb, ROI); result.push_back(res); cout << "B channel finished..." << endl; // merge the 3 gray images into a 3-channel image merge(result, merged); return merged; } int main(int argc, char** argv) { Mat img1, img2; Mat in1 = imread("./image/niao.jpg"); Mat in2 = imread("./image/park.jpg"); imshow("src", in1); imshow("dst", in2); in1.convertTo(img1, CV_64FC3); in2.convertTo(img2, CV_64FC3); Rect rc = Rect(50, 62, 74, 38);//the part in im2 that we wanna move into im1 // img1: 3-channel image, we wanna move something in it into img2. // img2: 3-channel image, dst image. // ROI: the position and size of the block we want to move in img1. // posX, posY: where we want to move the block to in img2 Mat result = poisson_blending(img1, img2, rc, 90, 60); result.convertTo(result, CV_8UC1); Rect rc2 = Rect(400, 50, 74, 38); Mat roimat = in2(rc2); result.copyTo(roimat); imshow("roi", result); imshow("result", in2); imwrite("./image/niao_park.jpg", in2); waitKey(0); return 0; }


