OpenCV小项目:图像融合(泊松融合—Possion Blending)

简介: OpenCV小项目:图像融合(泊松融合—Possion Blending)

原理


太多了,看这些博客吧


主要参考博客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;
}
相关文章
|
机器学习/深度学习 API 计算机视觉
Qt5 和 OpenCV4 计算机视觉项目:6~9
Qt5 和 OpenCV4 计算机视觉项目:6~9
260 0
|
存储 机器学习/深度学习 算法
使用 OpenCV4 和 C++ 构建计算机视觉项目:1~5
使用 OpenCV4 和 C++ 构建计算机视觉项目:1~5
392 0
|
存储 算法 数据可视化
使用计算机视觉实战项目精通 OpenCV:6~8
使用计算机视觉实战项目精通 OpenCV:6~8
227 0
|
计算机视觉
使用计算机视觉实战项目精通 OpenCV:1~5
使用计算机视觉实战项目精通 OpenCV:1~5
547 0
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
576 7
|
机器学习/深度学习 存储 文字识别
Qt5 和 OpenCV4 计算机视觉项目:1~5(5)
Qt5 和 OpenCV4 计算机视觉项目:1~5(5)
217 0
|
存储 Linux 计算机视觉
Qt5 和 OpenCV4 计算机视觉项目:1~5(1)
Qt5 和 OpenCV4 计算机视觉项目:1~5(1)
227 0
|
文字识别 计算机视觉 开发者
基于QT的OCR和opencv融合框架FastOCRLearn实战
本文介绍了在Qt环境下结合OpenCV库构建OCR识别系统的实战方法,通过FastOCRLearn项目,读者可以学习Tesseract OCR的编译配置和在Windows平台下的实践步骤,文章提供了技术资源链接,帮助开发者理解并实现OCR技术。
738 9
基于QT的OCR和opencv融合框架FastOCRLearn实战
|
11月前
|
人工智能 算法 计算机视觉
【01】opencv项目实践第一步opencv是什么-opencv项目实践-opencv完整入门以及项目实践介绍-opencv以土壤和水滴分离的项目实践-人工智能AI项目优雅草卓伊凡
【01】opencv项目实践第一步opencv是什么-opencv项目实践-opencv完整入门以及项目实践介绍-opencv以土壤和水滴分离的项目实践-人工智能AI项目优雅草卓伊凡
392 63
【01】opencv项目实践第一步opencv是什么-opencv项目实践-opencv完整入门以及项目实践介绍-opencv以土壤和水滴分离的项目实践-人工智能AI项目优雅草卓伊凡
|
Ubuntu Linux 编译器
Linux/Ubuntu下使用VS Code配置C/C++项目环境调用OpenCV
通过以上步骤,您已经成功在Ubuntu系统下的VS Code中配置了C/C++项目环境,并能够调用OpenCV库进行开发。请确保每一步都按照您的系统实际情况进行适当调整。
2417 3