在本地选择多张图片进行景深合成|拉普拉斯金字塔

2023-12-14 08:34:29

拉普拉斯金字塔融合:

融合原理: step1:传入一个 mask掩膜; step2:分别计算 image1和 image2 的高斯金字塔和拉普拉斯金字塔。高斯金字塔是将原始图像按照一定的方式缩小若干次所得到的一系列图像。我们将缩小的每一幅图像比作金字塔的每一层。拉普拉斯金字塔原高斯金字塔的第 1 个level 的图像和这个经过 第 2 个level 图像上采样得到的图像相减(第 2 个 level 图像上采样之后就和原高斯金字塔第 1 个 level 图像的大小一样了),相减就会得到一个残差,这就是拉普拉斯金字塔的最高级; step3:计算得到 mask 的高斯金字塔;

step4:将 image1和 image2 高斯金字塔的顶层按照 mask 的权重(mask高斯金字塔的顶层)相加,得到复原的起点,记为 START; step5:将 image1 和 image2 的拉普拉斯金字塔每一层按照 mask 权重相加(mask高斯金字塔对应的层),得到混合的拉普拉斯金字塔 Blend_lp; step6:根据这个新的金字塔重建出最终的图像,具体来讲,先对 START 进行上采样,然后跟混合拉普拉斯金字塔 Blend_lp的顶层相加,得到B1,然后B1继续上采样,在和 Blend_lp的下一层相加,得到B2重复上述过程,最终得到融合的图像。

?

实现效果:

demo1.pro:mai

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

INCLUDEPATH += C:\opencv-3.4.5-64\include\
               C:\opencv-3.4.5-64\include\opencv2\
               C:\opencv-3.4.5-64\include\opencv

LIBS += -L C:\opencv-3.4.5-64\x64\mingw\lib\libopencv_*.a

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

?mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDir>
#include <QFileDialog>
#include <QPixmap>
#include <QLabel>
#include <QTextEdit>
#include "opencv2/opencv.hpp"
#include <vector>
#include <QDebug>
using namespace cv;
using namespace std;
#include <QTextCodec>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QStringList fileList;

private slots:

    void on_BtnPicture_clicked();

    void on_BtnFusion_clicked();

    void on_BtnClose_clicked();

private:
    Ui::MainWindow *ui;
    cv::Mat rightimg;
    cv::Mat leftimg;

};

class LaplacianBlending {
private:
    Mat_<Vec3f> left;
    Mat_<Vec3f> right;
    Mat_<float> blendMask;

    vector<Mat_<Vec3f> > leftLapPyr, rightLapPyr, resultLapPyr;//Laplacian Pyramids
    Mat leftHighestLevel, rightHighestLevel, resultHighestLevel;
    vector<Mat_<Vec3f> > maskGaussianPyramid; //masks are 3-channels for easier multiplication with RGB

    int levels;

    void buildPyramids() {
        buildLaplacianPyramid(left, leftLapPyr, leftHighestLevel);
        buildLaplacianPyramid(right, rightLapPyr, rightHighestLevel);
        buildGaussianPyramid();
    }

    void buildGaussianPyramid() {//金字塔内容为每一层的掩模
        assert(leftLapPyr.size() > 0);

        maskGaussianPyramid.clear();
        Mat currentImg;
        cvtColor(blendMask, currentImg, COLOR_GRAY2BGR);//store color img of blend mask into maskGaussianPyramid
        maskGaussianPyramid.push_back(currentImg); //0-level

        currentImg = blendMask;
        for (int l = 1; l < levels + 1; l++) {
            Mat _down;
            if (leftLapPyr.size() > l)
                pyrDown(currentImg, _down, leftLapPyr[l].size());
            else
                pyrDown(currentImg, _down, leftHighestLevel.size()); //lowest level

            Mat down;
            cvtColor(_down, down, COLOR_GRAY2BGR);
            maskGaussianPyramid.push_back(down);//add color blend mask into mask Pyramid
            currentImg = _down;
        }
    }

    void buildLaplacianPyramid(const Mat& img, vector<Mat_<Vec3f> >& lapPyr, Mat& HighestLevel) {
        lapPyr.clear();
        Mat currentImg = img;
        for (int l = 0; l < levels; l++) {
            Mat down, up;
            pyrDown(currentImg, down);
            pyrUp(down, up, currentImg.size());
            Mat lap = currentImg - up;
            lapPyr.push_back(lap);
            currentImg = down;
        }
        currentImg.copyTo(HighestLevel);
    }

    Mat_<Vec3f> reconstructImgFromLapPyramid() {
        //将左右laplacian图像拼成的resultLapPyr金字塔中每一层
        //从上到下插值放大并相加,即得blend图像结果
        Mat currentImg = resultHighestLevel;
        for (int l = levels - 1; l >= 0; l--) {
            Mat up;

            pyrUp(currentImg, up, resultLapPyr[l].size());
            currentImg = up + resultLapPyr[l];
        }
        return currentImg;
    }

    void blendLapPyrs() {
        //获得每层金字塔中直接用左右两图Laplacian变换拼成的图像resultLapPyr
        resultHighestLevel = leftHighestLevel.mul(maskGaussianPyramid.back()) +
            rightHighestLevel.mul(Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid.back());
        for (int l = 0; l < levels; l++) {
            Mat A = leftLapPyr[l].mul(maskGaussianPyramid[l]);
            Mat antiMask = Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid[l];
            Mat B = rightLapPyr[l].mul(antiMask);
            Mat_<Vec3f> blendedLevel = A + B;

            resultLapPyr.push_back(blendedLevel);
        }
    }

public:
    LaplacianBlending(const Mat_<Vec3f>& _left, const Mat_<Vec3f>& _right, const Mat_<float>& _blendMask, int _levels) ://construct function, used in LaplacianBlending lb(l,r,m,4);
        left(_left), right(_right), blendMask(_blendMask), levels(_levels)
    {
        assert(_left.size() == _right.size());
        assert(_left.size() == _blendMask.size());
        buildPyramids();    //construct Laplacian Pyramid and Gaussian Pyramid
        blendLapPyrs();    //blend left & right Pyramids into one Pyramid
    };

    Mat_<Vec3f> blend() {
        return reconstructImgFromLapPyramid();//reconstruct Image from Laplacian Pyramid
    }
};
#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}



void MainWindow::on_BtnPicture_clicked()
{
    QWidget *widget = new QWidget;
    QVBoxLayout *layout = new QVBoxLayout;  //设置垂直布局
    widget->setLayout(layout);

    QString curPath = QDir::currentPath();
    QString dlgTitle = "选择多个文件";
    QString filter = "图片文件(*.jpg *.gif *.tif *.png) ";
    QStringList fileList = QFileDialog::getOpenFileNames(this,dlgTitle,curPath,filter);

    qDebug()<<fileList.count();
    for(int i = 0;i<fileList.count();i++){

        QLabel *label  = new QLabel(widget);
        leftimg = imread(fileList[0].toStdString());
        rightimg = imread(fileList[i].toStdString());
        QImage qImage(rightimg.data, rightimg.cols,
                      rightimg.rows, rightimg.step, QImage::Format_RGB888);
        qImage = qImage.rgbSwapped();
        label ->setPixmap(QPixmap::fromImage(qImage.scaled(300, 300, Qt::KeepAspectRatio)));

        QScrollArea *scrollArea = new QScrollArea(this);
        scrollArea->setBackgroundRole(QPalette::Dark);  //设置背景色
        scrollArea->setWidgetResizable(true);  // 自动调整大小
        scrollArea->setAlignment(Qt::AlignCenter);  // 居中对齐
        label->setAlignment(Qt::AlignCenter);  // 图片居中

        layout->addWidget(label);

        ui->scrollArea->setWidget(widget);
    }

}

Mat_<Vec3f> LaplacianBlend(const Mat_<Vec3f>& l, const Mat_<Vec3f>& r, const Mat_<float>& m) {
    LaplacianBlending lb(l, r, m, 4);
    return lb.blend();
}

void MainWindow::on_BtnFusion_clicked()
{
    vector<Mat> images;

    images.push_back(leftimg);
    images.push_back(rightimg);


    int hight = leftimg.rows;
    int width = leftimg.cols;
    Mat leftImg32f, rightImg32f;
    leftimg.convertTo(leftImg32f, CV_32F);
    rightimg.convertTo(rightImg32f, CV_32F);



    //创建用于混合的掩膜,这里在中间进行混合
        Mat mask = Mat::zeros(hight, width, CV_32FC1);
        mask(Range::all(), Range(0, mask.cols * 0.5)) = 1.0;

        Mat blendImg = LaplacianBlend(leftImg32f, rightImg32f, mask);

        blendImg.convertTo(blendImg, CV_8UC3);



        //读取图片
//        readImages(imageLabel);


           //对齐图片
    Ptr<AlignMTB> alignMTB = createAlignMTB();
    alignMTB->process(images, images);

           //曝光合成(Mertens是该论文的作者)被OpenCV集成为函数了
    Mat Fusion;
    Ptr<MergeMertens> mergeMertens = createMergeMertens();
    mergeMertens->process(images,Fusion);

   //imshow("fusion", Fusion);
   Fusion = Fusion * 255;
   imwrite("fusion.png",Fusion);
   cv::Mat dst = imread("fusion.png");




   QImage mImage(dst.data, dst.cols,
                      dst.rows, dst.step, QImage::Format_RGB888);
   mImage = mImage.rgbSwapped();
   mImage = mImage.scaled(ui->labPicfusion->size(),Qt::KeepAspectRatio);
   ui->labPicfusion->setPixmap(QPixmap::fromImage(mImage));
   ui->labPicfusion->setScaledContents(true);
}

void MainWindow::on_BtnClose_clicked()
{
    this->close();
}

?main.cpp:没有变动

mainwindow.ui:

?

文章来源:https://blog.csdn.net/Heart912921/article/details/134976520
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。