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

news2025/1/15 10:14:29

文章目录

  • 前言
  • 一、使用QImage进行水平拼接
  • 二、使用OpenCV进行水平拼接
  • 三、使用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);
}

二、使用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());
}

三、使用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.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

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,"警告","图像显示失败!");
    }
}

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


总结

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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux基础(二):环境搭建

本文准备从0开始&#xff0c;一步步搭建一套属于自己的Linux系统环境&#xff0c;这将是后续学Linux、用Linux、Linux环境编程、应用和项目部署、工具实验等一系列学习和实践的基石&#xff0c;希望对小伙伴们有帮助。提前备好Linux编程实验环境非常重要&#xff0c;建议人手一…

【小笔记】如何在docker中更新或导入neo4j数据?

如何在docker中更新或导入neo4j数据&#xff1f; &#xff08;1&#xff09;背景&#xff1a; 我尝试了4.4.9和5.19.0版本的Neo4j社区版&#xff0c;基于他们的镜像创建容器后&#xff0c;需要导入我准备好的csv文件或dump文件&#xff0c;因为数据量非常大&#xff0c;所以采…

IntelliJ IDEA集成Baidu Comate,商城系统支付交易功能开发实战

文章目录 Baidu Comate介绍安装配置体验安装插件配置体验注释生成代码技术问答 实战设计表生成代码导入数据 总结 Baidu Comate介绍 在科技互联网飞速发展的今天&#xff0c;百度凭借其深厚的技术积累和创新能力&#xff0c;推出了一款名为Baidu Comate智能代码助手的产品。该…

JS-03深入了解构造函数

目录 1 引入构造函数 2 通过构造函数创建对象-内置 3 自定义一个构造函数来创建对象 3.1 构造函数的概念 3.2关于new Object() 3.3 构造函数的执行过程 3.3.1构造函数的返回值 3.3.2 如何判断一个数据是否是复杂数据类型&#xff1f; 3.3.3为什么要理解构造函数的返回值&…

15、24年--信息系统管理——管理要点

1、数据管理 数据管理使指通过规划、控制与提供数据和信息资产的职能,包括开发、执行和监督有关数据的计划、策略、方案、项目、流程、方法和程序,以获取、控制、保护、交付和提高数据和信息资产价值。 DCMM定义了数据战略、数据治理、数据架构、数据应用、数据安全、…

如何官方查询论文分区,中科院及JCR

中科院分区 有一个小程序&#xff1a;中科院文献情报中心分区表 点2023升级版&#xff0c;输入期刊名 大类1区 JCR分区 进入官方网站 Journal Citation Reports 输入要查询的期刊名&#xff0c;点开 拼命往下拉 这就是根据影响因子的排名&#xff0c;在computer science&am…

柱状图中最大的矩形 - LeetCode 热题 73

大家好&#xff01;我是曾续缘&#x1f61b; 今天是《LeetCode 热题 100》系列 发车第 73 天 栈第 5 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xf…

使用docker-compose部署时序数据库InfluxDB1.8.4

背景 如今 InfluxDB 已经更新到了 2.x &#xff0c; InfluxDB 1.x 和 2.x 版本之间有几个主要的区别&#xff1a; 数据模型&#xff1a; 1.x&#xff1a;使用数据库和保留策略来组织数据。 2.x&#xff1a;引入了组织&#xff08;organizations&#xff09;和存储桶&#xff…

抖音极速版:抖音轻量精简版本,新人享大福利

和快手一样&#xff0c;抖音也有自己的极速版&#xff0c;可视作抖音的轻量精简版&#xff0c;更专注于刷视频看广告赚钱&#xff0c;收益比抖音要高&#xff0c;可玩性更佳。 抖音极速版简介 抖音极速版是一个提供短视频创业和收益任务的平台&#xff0c;用户可以通过观看广…

【LeetCode】【1】两数之和(1141字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示进阶Python实现哈希表 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给定一个整数数组nums和一个整数目标值target&#xff0c;请在该数组中找出…

【linux-kernel内核移植记录-踩坑以及注意事项】

目录 1. 环境介绍2.编译原厂的kernel2.1 通过tftp挂载原厂linux内核 3. 修改对应的驱动3.1 修改CPU频率3.2 修改MMC3.3 修改网络驱动 4. 总结 1. 环境介绍 ubuntu版本16.04I.MX6ULL开发板&#xff0c;阿尔法uboot正常启动&#xff0c;能ping通ubuntu&#xff0c;可通过tftpboo…

使用delphi11编写一个基于xls作为数据库的照片展示程序

1、创建xls文档可以参考前一篇博客&#xff0c;并使用wps将文档保存为2003格式xls后缀。 2、在form上面放置adoconnection、adotable、datasource、spinedit、timer、checkbox、image、4个button组件。 image的设置&#xff1a; Image1.Align : alClient; Image1.Center : Tr…

【全开源】答题考试系统源码(FastAdmin+ThinkPHP+Uniapp)

答题考试系统源码&#xff1a;构建高效、安全的在线考试平台 引言 在当今数字化时代&#xff0c;在线考试系统已成为教育机构和企业选拔人才的重要工具。一个稳定、高效、安全的答题考试系统源码是构建这样平台的核心。本文将深入探讨答题考试系统源码的关键要素&#xff0c;…

mysql binlog统一恢复误删数据库、表、数据(没有任何备份)

先将mysql文件夹中的my.ini进行设置 在 [mysqld]下边加上 # mysql-bin 是日志的基本名或前缀名&#xff0c;最后生成的日志文件是mysql-bin.000001类似&#xff0c;重启mysql数字会递增 log_binmysql-bin #binlog格式&#xff0c;statement&#xff0c;row&#xff0c;mixed可…

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第28课-avatar玩家3D形象

【WEB前端2024】开源智体世界&#xff1a;乔布斯3D纪念馆-第28课-avatar玩家3D形象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界…

Python列表,元组,集合,字典详解一篇搞懂

目录 介绍 列表(List) 集合(Set) 字典(Dict) 元组(Tuple) 列表 列表定义 ​编辑 列表切片 列表常用方法 append extend ​编辑 insert ​编辑 remove pop ​编辑 clear ​编辑 列表修改元素 sort 升序 倒序 reverse count ​编辑 index 浅拷贝和深拷贝 …

CV之Nougat:Nougat(一种基于神经网络实现OCR功能的视觉转换器模型)的简介、安装和使用方法、案例应用之详细攻略

CV之Nougat&#xff1a;Nougat(一种基于神经网络实现OCR功能的视觉转换器模型)的简介、安装和使用方法、案例应用之详细攻略 目录 相关论文 《Nougat: Neural Optical Understanding for Academic Documents》的翻译与解读 Nougat的简介 Nougat的安装和使用方法 1、安装 …

成犬必备!福派斯鲜肉狗粮,亮毛祛泪痕的神奇功效!

对于成犬来说&#xff0c;选择一款合适且高质量的狗粮至关重要。成犬时期的狗狗正处于身体和生理机能逐渐稳定的阶段&#xff0c;因此&#xff0c;需要选择能够满足其日常营养需求、维持健康状态并有助于长寿的狗粮。理想的狗粮应当包含狗狗所需的各种营养物质&#xff0c;如高…

使用CyberRT写第一个代码, test ok

简介 计算框架是自动驾驶系统中的重中之重,也是整个系统得以高效稳定运行的基础。为了实时地完成感知、决策和执行,系统需要一系列的模块相互紧密配合,高效地执行任务流。由于各种原因,这些模块可能位于不同进程,也可能位于不同机器。这就要求计算框架中具有灵活的、高性…

uniapp+canvas实现逐字手写效果

在移动端使用 UniApp 进行逐字手写的功能。用户可以在一个 inputCanvas 上书写单个字&#xff0c;然后在特定时间后将这个字添加到 outputCanvas 上&#xff0c;形成一个逐字的手写效果。用户还可以保存整幅图像或者撤销上一个添加的字。 初始化 Canvas&#xff1a; 使用 uni.c…