当前位置:   article > 正文

Qt下使用QImage和OpenCV实现图像的拼接与融合

Qt下使用QImage和OpenCV实现图像的拼接与融合


前言

本文主要讲述了在Qt下使用QImage和OpenCV实现图像的拼接与融合,并结合相应的示例进行讲解,以便大家学习,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、使用QImage进行水平拼接

这里新建了一个QImage对象,然后通过QPainter来将两张图像绘制在一起,并且可以通过QImage的save函数来保存拼接后的图像:
请添加图片描述

//使用QImage进行水平拼接
QPixmap Widget::imageMosaic(const QImage &image1,const QImage &image2)
{
    //检查图像是否有效
    if(image1.isNull() || image2.isNull())
    {
        return QPixmap();
    }

    //计算拼接后的图像尺寸
    int newWidth = image1.width() + image2.width();
    int newHeight = std::max(image1.height(),image2.height());

    //创建一个新的QImage对象
    QImage newImage(newWidth,newHeight,QImage::Format_RGB32);
    newImage.fill(Qt::transparent);   //填充为透明,如果背景不是透明的则可以选择其他颜色

    //使用QPainter来绘制图像
    QPainter painter(&newImage);
    painter.drawImage(0,0,image1);   //在新图像的(0,0)位置绘制第一张图像
    painter.drawImage(image1.width(),0,image2);   //在新图像的(image1.width(),0)位置绘制第二张图像

    //结束绘制
    painter.end();

    //保存拼接图像
    newImage.save("E:/myPhoto/imageMosaic.jpg");

    //返回拼接图像
    return QPixmap::fromImage(newImage);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

二、使用OpenCV进行水平拼接

在Qt中配置好OpenCV环境后,就可以使用OpenCV中的hconcat函数来进行图像的拼接了,同时可以使用imwrite来保存拼接图像:
请添加图片描述

//使用OpenCV进行水平拼接
QPixmap Widget::opencvMosaic(const cv::Mat &mat1,const cv::Mat &mat2)
{
    //检查图像是否有效
    if(mat1.empty() || mat2.empty())
    {
        return QPixmap();
    }

    //判断两张图像的高度
    if(mat1.rows != mat2.rows)
    {
        return QPixmap();
    }

    //水平拼接图像
    cv::Mat resultMat;
    cv::hconcat(mat1,mat2,resultMat);

    //将OpenCV的Mat转换为QImage
    //cv::cvtColor(resultMat,resultMat,cv::COLOR_BGR2RGB);
    QImage newImage((const unsigned char*)(resultMat.data),resultMat.cols,resultMat.rows,resultMat.step,QImage::Format_RGB888);

    //QImage的save保存拼接图像
    //newImage.save("E:/myPhoto/opencvMosaic.jpg");

    //OpenCV的imwrite保存拼接图像
    cv::imwrite("E:/myPhoto/opencvMosaic.jpg",resultMat);

    //返回拼接图像
    return QPixmap::fromImage(newImage.rgbSwapped());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

三、使用OpenCV进行图像融合

这个示例的图像融合比较简单,使用了OpenCV中的addWeighted函数来进行融合:
请添加图片描述

//使用OpenCV进行图像融合
QPixmap Widget::opencvMerge(const cv::Mat &mat1,const cv::Mat &mat2)
{
    //检查图像是否有效
    if(mat1.empty() || mat2.empty())
    {
        return QPixmap();
    }

    //图像融合(这里只是一个简单的示例,使用加权平均)
    cv::Mat resultMat;
    double alpha = 0.5;   //融合系数,可以根据需要调整
    cv::addWeighted(mat1,alpha,mat2,1.0 - alpha,0.0,resultMat);

    //将OpenCV的Mat转换为QImage
    //cv::cvtColor(resultMat,resultMat,cv::COLOR_BGR2RGB);
    QImage newImage((const unsigned char*)(resultMat.data),resultMat.cols,resultMat.rows,resultMat.step,QImage::Format_RGB888);

    //QImage的save保存拼接图像
    //newImage.save("E:/myPhoto/opencvMerge.jpg");

    //OpenCV的imwrite保存拼接图像
    cv::imwrite("E:/myPhoto/opencvMerge.jpg",resultMat);

    //返回拼接图像
    return QPixmap::fromImage(newImage.rgbSwapped());

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

四、示例完整代码

1.widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>
#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    QPixmap imageMosaic(const QImage &image1,const QImage &image2);
    QPixmap opencvMosaic(const cv::Mat &mat1,const cv::Mat &mat2);
    QPixmap opencvMerge(const cv::Mat &mat1,const cv::Mat &mat2);

    void setShowImage(int index);

private slots:
    void on_pb_image_1_clicked();
    void on_pb_image_2_clicked();
    void on_pb_imageMosaic_clicked();
    void on_pb_opencvMosaic_clicked();
    void on_pb_opencvMerge_clicked();
    void on_pb_keep_clicked();
    void on_pb_fill_clicked();

private:
    Ui::Widget *ui;

    //QImage对象
    QImage m_image_1;
    QImage m_image_2;
    QPixmap m_showPixmap;

    //CV::Mat对象
    cv::Mat m_mat_1;
    cv::Mat m_mat_2;

};
#endif // WIDGET_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

2.widget.cpp

#include "widget.h"
#include "ui_widget.h"

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

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

//使用QImage进行水平拼接
QPixmap Widget::imageMosaic(const QImage &image1,const QImage &image2)
{
    //检查图像是否有效
    if(image1.isNull() || image2.isNull())
    {
        return QPixmap();
    }

    //计算拼接后的图像尺寸
    int newWidth = image1.width() + image2.width();
    int newHeight = std::max(image1.height(),image2.height());

    //创建一个新的QImage对象
    QImage newImage(newWidth,newHeight,QImage::Format_RGB32);
    newImage.fill(Qt::transparent);   //填充为透明,如果背景不是透明的则可以选择其他颜色

    //使用QPainter来绘制图像
    QPainter painter(&newImage);
    painter.drawImage(0,0,image1);   //在新图像的(0,0)位置绘制第一张图像
    painter.drawImage(image1.width(),0,image2);   //在新图像的(image1.width(),0)位置绘制第二张图像

    //结束绘制
    painter.end();

    //保存拼接图像
    newImage.save("E:/myPhoto/imageMosaic.jpg");

    //返回拼接图像
    return QPixmap::fromImage(newImage);
}

//使用OpenCV进行水平拼接
QPixmap Widget::opencvMosaic(const cv::Mat &mat1,const cv::Mat &mat2)
{
    //检查图像是否有效
    if(mat1.empty() || mat2.empty())
    {
        return QPixmap();
    }

    //判断两张图像的高度
    if(mat1.rows != mat2.rows)
    {
        return QPixmap();
    }

    //水平拼接图像
    cv::Mat resultMat;
    cv::hconcat(mat1,mat2,resultMat);

    //将OpenCV的Mat转换为QImage
    //cv::cvtColor(resultMat,resultMat,cv::COLOR_BGR2RGB);
    QImage newImage((const unsigned char*)(resultMat.data),resultMat.cols,resultMat.rows,resultMat.step,QImage::Format_RGB888);

    //QImage的save保存拼接图像
    //newImage.save("E:/myPhoto/opencvMosaic.jpg");

    //OpenCV的imwrite保存拼接图像
    cv::imwrite("E:/myPhoto/opencvMosaic.jpg",resultMat);

    //返回拼接图像
    return QPixmap::fromImage(newImage.rgbSwapped());
}

//使用OpenCV进行图像融合
QPixmap Widget::opencvMerge(const cv::Mat &mat1,const cv::Mat &mat2)
{
    //检查图像是否有效
    if(mat1.empty() || mat2.empty())
    {
        return QPixmap();
    }

    //图像融合(这里只是一个简单的示例,使用加权平均)
    cv::Mat resultMat;
    double alpha = 0.5;   //融合系数,可以根据需要调整
    cv::addWeighted(mat1,alpha,mat2,1.0 - alpha,0.0,resultMat);

    //将OpenCV的Mat转换为QImage
    //cv::cvtColor(resultMat,resultMat,cv::COLOR_BGR2RGB);
    QImage newImage((const unsigned char*)(resultMat.data),resultMat.cols,resultMat.rows,resultMat.step,QImage::Format_RGB888);

    //QImage的save保存拼接图像
    //newImage.save("E:/myPhoto/opencvMerge.jpg");

    //OpenCV的imwrite保存拼接图像
    cv::imwrite("E:/myPhoto/opencvMerge.jpg",resultMat);

    //返回拼接图像
    return QPixmap::fromImage(newImage.rgbSwapped());

}

//设置显示图像
void Widget::setShowImage(int index)
{
    QPixmap showPixmap;
    if(index == 0)
    {
        //使用QImage水平拼接
        showPixmap = imageMosaic(m_image_1,m_image_2);
    }
    else if(index == 1)
    {
        //使用OpenCV水平拼接
        showPixmap = opencvMosaic(m_mat_1,m_mat_2);
    }
    else if(index == 2)
    {
        //使用OpenCV图像融合
        showPixmap = opencvMerge(m_mat_1,m_mat_2);
    }

    //更新显示
    m_showPixmap = showPixmap;
    if(!m_showPixmap.isNull())
    {
        ui->lb_imageShow->setPixmap(showPixmap.scaled(ui->lb_imageShow->size(),Qt::KeepAspectRatio));   //保持比例
    }
    else
    {
        QMessageBox::warning(this,"警告","图像显示失败!");
    }
}

//选择图像1
void Widget::on_pb_image_1_clicked()
{
    //打开文件对话框,选择图像文件
    QString fileName = QFileDialog::getOpenFileName(this,"选择图像文件","E:/myPhoto/","Image Files(*.png *.jpg)");
    if(!fileName.isEmpty())
    {
        //赋值Mat图像
        m_mat_1 = cv::imread(fileName.toStdString(),cv::IMREAD_COLOR);

        //读取图像文件
        QImage image(fileName);
        if(!image.isNull())
        {
            //赋值QImage图像
            m_image_1 = image;

            //将QImage转换为QPixmap以在QLabel上显示
            QPixmap pixmap = QPixmap::fromImage(m_image_1);
            ui->lb_image_1->setPixmap(pixmap.scaled(ui->lb_image_1->size(),Qt::KeepAspectRatio));   //保持比例
        }
        else
        {
            //图像文件无效或无法读取
            QMessageBox::warning(this,"警告","图像文件打开失败!");
        }
    }
}

//选择图像2
void Widget::on_pb_image_2_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,"选择图像文件","E:/myPhoto/","Image Files(*.png *.jpg)");
    if(!fileName.isEmpty())
    {
        m_mat_2 = cv::imread(fileName.toStdString(),cv::IMREAD_COLOR);
        QImage image(fileName);
        if(!image.isNull())
        {
            m_image_2 = image;
            QPixmap pixmap = QPixmap::fromImage(m_image_2);
            ui->lb_image_2->setPixmap(pixmap.scaled(ui->lb_image_2->size(),Qt::KeepAspectRatio));   //保持比例
        }
        else
        {
            QMessageBox::warning(this,"警告","图像文件打开失败!");
        }
    }
}

//使用QImage拼接
void Widget::on_pb_imageMosaic_clicked()
{
    setShowImage(0);
}

//使用OpenCV拼接
void Widget::on_pb_opencvMosaic_clicked()
{
    setShowImage(1);
}

//使用OpenCV进行图像融合
void Widget::on_pb_opencvMerge_clicked()
{
    setShowImage(2);
}

//保持比例显示图像
void Widget::on_pb_keep_clicked()
{
    if(!m_showPixmap.isNull())
    {
        ui->lb_imageShow->setPixmap(m_showPixmap.scaled(ui->lb_imageShow->size(),Qt::KeepAspectRatio));   //保持比例
    }
    else
    {
        QMessageBox::warning(this,"警告","图像显示失败!");
    }
}

//填充显示图像
void Widget::on_pb_fill_clicked()
{
    if(!m_showPixmap.isNull())
    {
        ui->lb_imageShow->setPixmap(m_showPixmap.scaled(ui->lb_imageShow->size(),Qt::IgnoreAspectRatio));   //自由缩放
    }
    else
    {
        QMessageBox::warning(this,"警告","图像显示失败!");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234

3.widget.ui
请添加图片描述


总结

Qt中的图像类有QImage和QPixmap等,并且一般会与QPainter类结合起来使用,这些在Qt中是常见且常用的,我们要熟悉相关的函数接口然后灵活使用。另外涉及图像的操作我们还可以调用OpenCV这个图像库,这个能够实现更加复杂的图像变换操作,在Qt下使用也是比较好用呢。


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/626590
推荐阅读
相关标签
  

闽ICP备14008679号