QT+opencv ROI区域图像叠加&初级图像混合 label里输出Mat图片要做的变换

本文介绍如何在Qt中显示OpenCV处理后的图像,并通过示例演示如何使用addWeighted函数实现图像线性混合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虽然使用opencv大多不使用ui,但是这次输出的图像用来对比比较有意义,我为了让他们输出在界面上好看一些,弄了一下午,达到如下效果。

这里写图片描述

1.

先说一下QT label中输出opencv Mat图像的事情:
因为使用Imread读入的Mat图像,其矩阵格式是BGR的,我们在label上输出只能使用QT自带的比如QPixmap函数,此时就要对Mat图像进行转化。
主要就3行代码,如下 srcImage4就是用imread读入的图像,或者你经过各种其他处理之后的Mat型的数据就行。先使用cvtColor把BGR颜色空间换成QImage图像的RGB颜色空间,用QImage读入数据,在label上输出就行。
后两句代码是对label中输出图像的设置,可以使图像按照label大小直接输出。

    Mat srcImage4 = imread("girl.jpg");
    QImage img4;

    cvtColor(srcImage4,srcImage4,CV_BGR2RGB);
    img4=QImage((const unsigned char*)(srcImage4.data),                                                              
            srcImage4.cols,srcImage4.rows,QImage::Format_RGB888);                                        

    ui->label_4->setScaledContents(true);
    ui->label_4->resize(ui->label->width(),ui->label->height());

2.

    void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);  
第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
第二个参数,alpha,表示第一个数组的权重
第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
第四个参数,beta,表示第二个数组的权重值。
第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。
第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

简单来说,就是把Mat类型的图片src1和src2以alpha:beta的比例加在一起显示出来。

如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:

          dst = src1[I]*alpha+ src2[I]*beta + gamma;

其中的I,是多维数组元素的索引值。而且,在遇到多通道数组的时候,每个通道都需要独立地进行处理。另外需要注意的是,当输出数组的深度为CV_32S时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

窗口输出源代码:

#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <qdebug.h>
using namespace cv;
using namespace std;

 //-----------------------------------【全局函数声明部分】--------------------------------------
    //  描述:全局函数声明
    //-----------------------------------------------------------------------------------------------
    bool  ROI_AddImage();
    bool  LinearBlending();
    bool  ROI_LinearBlending();

    //-----------------------------------【main( )函数】--------------------------------------------
    //  描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main(   )
    {

        if(ROI_AddImage( )&& LinearBlending( )&&ROI_LinearBlending( ))
        {
             qDebug() << QString::fromLocal8Bit("输出貌似成功了!");
        }

        waitKey(0);
        return 0;
    }

    //----------------------------------【ROI_AddImage( )函数】----------------------------------
    // 函数名:ROI_AddImage()
    //  描述:利用感兴趣区域ROI实现图像叠加
    //----------------------------------------------------------------------------------------------
    bool  ROI_AddImage()
    {

        // 【1】读入图像
        Mat srcImage1= imread("dota_pa.jpg");
        Mat logoImage= imread("dota_logo.jpg");
        if( !srcImage1.data ) { printf("  读取srcImage1错误~! \n"); return false; }
        if( !logoImage.data ) { printf("  读取logoImage错误~! \n"); return false; }

        // 【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));

        // 【3】加载掩模(必须是灰度图)
        Mat mask= imread("dota_logo.jpg",0);

        //【4】将掩膜拷贝到ROI
        logoImage.copyTo(imageROI,mask);

        // 【5】显示结果
        namedWindow("<1>利用ROI实现图像叠加示例窗口",WINDOW_NORMAL);
        imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);

        return true;
    }


    //---------------------------------【LinearBlending()函数】-------------------------------------
    // 函数名:LinearBlending()
    // 描述:利用cv::addWeighted()函数实现图像线性混合
    //--------------------------------------------------------------------------------------------
    bool  LinearBlending()
    {
        //【0】定义一些局部变量
        double alphaValue = 0.5;
        double betaValue;
        Mat srcImage2, srcImage3, dstImage;

        // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
        srcImage2 = imread("mogu.jpg");
        srcImage3 = imread("rain.jpg");

        if( !srcImage2.data ) { printf("  读取srcImage2错误~! \n"); return false; }
        if( !srcImage3.data ) { printf("  读取srcImage3错误~! \n"); return false; }

        // 【2】进行图像混合加权操作
        betaValue = ( 1.0 - alphaValue );
        addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);

        // 【3】创建并显示原图窗口
        namedWindow("<2>线性混合示例窗口【原图】  ", WINDOW_NORMAL);
        imshow( "<2>线性混合示例窗口【原图】  ", srcImage2 );

        namedWindow("<3>线性混合示例窗口【效果图】  ", WINDOW_NORMAL);
        imshow( "<3>线性混合示例窗口【效果图】  ", dstImage );

        return true;

    }

    //---------------------------------【ROI_LinearBlending()】-------------------------------------
    // 函数名:ROI_LinearBlending()
    // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
    //            感兴趣区域ROI,实现自定义区域的线性混合
    //--------------------------------------------------------------------------------------------
    bool  ROI_LinearBlending()
    {

        //【1】读取图像
        Mat srcImage4= imread("dota_pa.jpg",1);
        Mat logoImage= imread("dota_logo.jpg");

        if( !srcImage4.data ) { printf("  读取srcImage4错误~! \n"); return false; }
        if( !logoImage.data ) { printf("  读取logoImage错误~! \n"); return false; }

        //【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI;
            //方法一
        imageROI= srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
        //方法二
        //imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

        //【3】将logo加到原图上
        addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);

        //【4】显示结果
        namedWindow("<4>区域线性图像混合示例窗口  " ,WINDOW_NORMAL);
        imshow("<4>区域线性图像混合示例窗口  ",srcImage4);

         return true;
      }

MIX1 无ui界面版

UI输出源代码

3个文件
- mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <qdebug.h>
#include <qlabel.h>

using namespace cv;
using namespace std;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    Mat srcImage1;
    Mat logoImage;
    Mat imageROI;
    Mat mask;
    Mat srcImage2, srcImage3, dstImage;
    Mat srcImage4;
    QImage img1,img2,img2_1,img2_2,img4;
};

#endif // MAINWINDOW_H
  • mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <qdebug.h>
#include <qlabel.h>

using namespace cv;
using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    srcImage1= imread("dota_pa.jpg");
    logoImage= imread("dota_logo.jpg");

    // 【2】定义一个Mat类型并给其设定ROI区域
    imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));

    // 【3】加载掩模(必须是灰度图)
    mask= imread("dota_logo.jpg",0);

    //【4】将掩膜拷贝到ROI
    logoImage.copyTo(imageROI,mask);

    cvtColor(srcImage1,srcImage1,CV_BGR2RGB);
    img1=QImage((const unsigned char*)(srcImage1.data),srcImage1.cols,srcImage1.rows,QImage::Format_RGB888);
    ui->label->setPixmap(QPixmap::fromImage(img1));
    ui->label->setScaledContents(true);
    ui->label->resize(ui->label->width(),ui->label->height());
    //ui->label->resize(ui->label->pixmap()->size());





    // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
    srcImage2 = imread("mogu.jpg");
    srcImage3 = imread("rain.jpg");

    // 【2】进行图像混合加权操作

    addWeighted( srcImage2, 0.5, srcImage3, 0.5, 0.0, dstImage);

    cvtColor(dstImage,dstImage,CV_BGR2RGB);
    img2=QImage((const unsigned char*)(dstImage.data),dstImage.cols,dstImage.rows,QImage::Format_RGB888);
    ui->label_2->setPixmap(QPixmap::fromImage(img2));
    ui->label_2->setScaledContents(true);
    ui->label_2->resize(ui->label->width(),ui->label->height());

    cvtColor(srcImage2,srcImage2,CV_BGR2RGB);
    img2_1=QImage((const unsigned char*)(srcImage2.data),srcImage2.cols,srcImage2.rows,QImage::Format_RGB888);
    ui->label_3->setPixmap(QPixmap::fromImage(img2_1));
    ui->label_3->setScaledContents(true);
    ui->label_3->resize(ui->label->width(),ui->label->height());

    cvtColor(srcImage3,srcImage3,CV_BGR2RGB);
    img2_2=QImage((const unsigned char*)(srcImage3.data),srcImage3.cols,srcImage3.rows,QImage::Format_RGB888);
    ui->label_5->setPixmap(QPixmap::fromImage(img2_2));
    ui->label_5->setScaledContents(true);
    ui->label_5->resize(ui->label->width(),ui->label->height());





    srcImage4= imread("dota_pa.jpg",1);
    logoImage= imread("dota_logo.jpg");

        //方法一
    imageROI= srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));


    //【3】将logo加到原图上
    addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);

    cvtColor(srcImage4,srcImage4,CV_BGR2RGB);
    img4=QImage((const unsigned char*)(srcImage4.data),srcImage4.cols,srcImage4.rows,QImage::Format_RGB888);
    ui->label_4->setPixmap(QPixmap::fromImage(img4));
    ui->label_4->setScaledContents(true);
    ui->label_4->resize(ui->label->width(),ui->label->height());




}

MainWindow::~MainWindow()
{
    delete ui;
}
  • main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <qdebug.h>
#include <qlabel.h>
using namespace cv;
using namespace std;


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

         qDebug() << QString::fromLocal8Bit("输出貌似成功了!");

    waitKey(0);
    return a.exec();
}

MIX2 ui界面版

&lt;think&gt;好的,我现在需要回答用户关于在QT绘制ROI区域的方法和示例的问题。首先,用户提到了OpenCV和Halcon的相关引用,但主要是在QT环境下实现。我需要结合QT的绘图功能和可能的OpenCV集成来给出解决方案。 首先,我应该回顾一下QT中常用的绘图方法。QT提供了QPainter类,用于在窗口部件上进行绘图。用户可能需要通过鼠标交互来选取ROI区域,比如矩形、圆形等。这涉及到事件处理,比如鼠标按下、移动和释放事件来绘制动态的ROI区域。 然后,考虑用户提到的OpenCV的示例代码,其中使用了Rect来选择ROI。在QT中,可能需要将OpenCVMat图像转换为QT的QImage来显示,然后在QWidget上绘制ROI的矩形或其他形状。同时,用户可能需要将绘制ROI区域传递给OpenCV进行处理,这需要坐标转换。 接下来,引用3提到了QTOpenCV图像叠加,使用addWeighted函数。这可能涉及到在QT界面中显示处理后的图像,比如高亮显示ROI区域。需要将OpenCVMatQT图像显示结合,可能使用QLabel来显示图像,并通过QPainter在QLabel绘制ROI的轮廓。 现在,需要整合这些步骤:在QT窗口中显示图像,允许用户通过鼠标绘制ROI,并将ROI的坐标传递给OpenCV进行处理。可能的步骤包括: 1. 在QT中加载并显示图像,可能需要将OpenCVMat转换为QImage。 2. 重写鼠标事件处理函数(mousePressEvent, mouseMoveEvent, mouseReleaseEvent)来捕获用户的绘制动作。 3. 使用QPainter在图像上实时绘制ROI的形状,比如矩形。 4. 将用户选择的ROI区域转换为OpenCV的Rect或ROI Mat,用于后续处理。 5. 可能需要在QLabel或其他组件上叠加显示ROI,使用绘图事件(paintEvent)来重绘。 需要注意的问题包括坐标系统的转换,因为QT的坐标原点在左上角,而OpenCVMat也是如此,所以可能不需要转换,但需要确保绘制的位置正确。另外,图像缩放可能会影响ROI的坐标,如果QLabel中的图像被缩放,则需要调整鼠标事件捕获的坐标与实际图像像素坐标的关系。 可能的示例代码结构: - 创建一个继承自QWidget或QMainWindow的类,重写paintEvent和鼠标事件。 - 在类中维护一个QRect或QPolygon来存储用户绘制ROI。 - 在paintEvent中使用QPainter绘制图像和当前的ROI区域。 - 鼠标按下时记录起点,移动时更新ROI的大小,释放时完成绘制。 - 将最终的ROI坐标转换为OpenCV的Rect,并提取对应的Mat区域。 同时,需要确保OpenCVQT图像数据转换正确,比如颜色空间(BGR转RGB)和内存数据的正确拷贝。 可能还需要引用用户提供的引用内容,比如引用1中的OpenCV设置ROI的方法,引用3中的addWeighted用于图像混合,以及引用2中Halcon生成区域的方法,但需要转换为QT的实现方式。 最后,需要验证示例代码的正确性,确保能够编译运行,并且用户能够通过鼠标交互选择ROI区域,同时在界面上正确显示。&lt;/think&gt;### QT绘制ROI区域的方法与示例 在QT绘制ROI区域需结合`QPainter`类与鼠标事件处理,通过以下步骤实现: --- #### **步骤1:图像显示与坐标转换** 1. **加载图像**:使用OpenCV读取图像并转换为QT支持的`QImage`格式(注意BGR到RGB的转换): ```cpp cv::Mat cvImage = cv::imread(&quot;image.jpg&quot;); QImage qtImage(cvImage.data, cvImage.cols, cvImage.rows, QImage::Format_RGB888).rgbSwapped(); ``` 2. **显示图像**:通过`QLabel`显示图像,并启用鼠标跟踪: ```cpp QLabel *imageLabel = new QLabel; imageLabel-&gt;setPixmap(QPixmap::fromImage(qtImage)); imageLabel-&gt;setMouseTracking(true); ``` --- #### **步骤2:鼠标事件处理** 重写`mousePressEvent`、`mouseMoveEvent`和`mouseReleaseEvent`捕获用户交互: ```cpp class ImageWidget : public QLabel { Q_OBJECT public: QRect roiRect; QPoint startPoint; protected: void mousePressEvent(QMouseEvent *event) override { startPoint = event-&gt;pos(); roiRect.setTopLeft(startPoint); } void mouseMoveEvent(QMouseEvent *event) override { roiRect.setBottomRight(event-&gt;pos()); update(); // 触发重绘 } void mouseReleaseEvent(QMouseEvent *event) override { // 最终ROI坐标可通过roiRect获取 emit roiSelected(roiRect); } }; ``` --- #### **步骤3:绘制动态ROI** 在`paintEvent`中使用`QPainter`实时绘制矩形: ```cpp void ImageWidget::paintEvent(QPaintEvent *event) { QLabel::paintEvent(event); QPainter painter(this); painter.setPen(Qt::red); painter.drawRect(roiRect); } ``` --- #### **步骤4:与OpenCV交互** 将QT的`QRect`转换为OpenCV的`cv::Rect`以提取ROI区域: ```cpp // 假设图像未缩放,坐标直接对应 cv::Rect cvROI(roiRect.x(), roiRect.y(), roiRect.width(), roiRect.height()); cv::Mat roiMat = cvImage(cvROI).clone(); ``` --- #### **示例:完整代码片段** ```cpp #include &lt;QApplication&gt; #include &lt;QLabel&gt; #include &lt;QPainter&gt; #include &lt;opencv2/opencv.hpp&gt; class ImageWidget : public QLabel { Q_OBJECT public: ImageWidget(const QImage &amp;image) { setPixmap(QPixmap::fromImage(image)); } signals: void roiSelected(QRect); protected: QRect roiRect; QPoint startPoint; void mousePressEvent(QMouseEvent *event) override { startPoint = event-&gt;pos(); roiRect = QRect(startPoint, startPoint); } void mouseMoveEvent(QMouseEvent *event) override { roiRect.setBottomRight(event-&gt;pos()); update(); } void mouseReleaseEvent(QMouseEvent *event) override { emit roiSelected(roiRect); } void paintEvent(QPaintEvent *event) override { QLabel::paintEvent(event); QPainter painter(this); painter.setPen(QPen(Qt::red, 2)); painter.drawRect(roiRect); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); // 加载图像 cv::Mat cvImage = cv::imread(&quot;test.jpg&quot;); QImage qtImage(cvImage.data, cvImage.cols, cvImage.rows, QImage::Format_RGB888).rgbSwapped(); // 显示窗口 ImageWidget widget(qtImage); widget.show(); // 连接ROI选择信号 QObject::connect(&amp;widget, &amp;ImageWidget::roiSelected, [&amp;](QRect rect) { cv::Rect cvROI(rect.x(), rect.y(), rect.width(), rect.height()); cv::Mat roiMat = cvImage(cvROI).clone(); cv::imshow(&quot;OpenCV ROI&quot;, roiMat); }); return app.exec(); } ``` --- #### **关键点说明** 1. **坐标对齐**:需确保图像在`QLabel`中未缩放,否则需根据缩放比例调整坐标[^3]。 2. **性能优化**:频繁调用`update()`可能影响性能,可通过设置绘制频率阈值优化。 3. **扩展功能**:支持圆形、多边形等ROI需修改绘图逻辑与数据结构[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值