OpenCV手拉手01 — 读取图像并显示

OpenCV手拉手01 — 读取图像并显示

OpenCV,开源计算机视觉库,集成了众多优秀的图像处理算法,是从事机器视觉、计算机视觉相关领域开发及研究工作必备技能。

本文使用的开发工具为QT6.4.2、OpenCV4.7.0;

目标:使用OpenCV读取一张图片,并在QT界面上显示。

1、打开QT ,文件–>新建工程–>Application(Qt)–>Qt Widgets Application–>选择

能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻_山能金控和山金金控是一家吗

2、输入项目名称—>下一步

文能提笔控萝莉,武能床上定人妻_能显示并缩放图片的控件_山能金控和山金金控是一家吗

3、选择qmake—>下一步

能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻_山能金控和山金金控是一家吗

4填写类名,选择base class ,勾选Generate form —>下一步

山能金控和山金金控是一家吗_能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻

5、选择语言(可直接点击下一步,或选择自己喜欢的语言)

山能金控和山金金控是一家吗_能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻

6、选择套件(推荐使用MSVC64bit)—>下一步

能显示并缩放图片的控件_山能金控和山金金控是一家吗_文能提笔控萝莉,武能床上定人妻

7、点击完成

能显示并缩放图片的控件_山能金控和山金金控是一家吗_文能提笔控萝莉,武能床上定人妻

8、设计UI :双击ui文件,进入设计界面,拖拽控件至相关位置,并给控件命名(命名需具备一定规范,养成良好习惯便于高效开发)

能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻_山能金控和山金金控是一家吗

注意:右键单击GraphicView,提升为ImageView类

能显示并缩放图片的控件_文能提笔控萝莉,武能床上定人妻_山能金控和山金金控是一家吗

9、编写ImageView.h文件

#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "opencv2/opencv.hpp"
class ImageViewer : public QGraphicsView
{
    Q_OBJECT
public:
    // 构造函数 explicit关键字为禁止隐式转换,可参考《Effective C++》
    explicit ImageViewer(QWidget *parent = nullptr);
public:  // 公共成员函数
    void setQImage(QImage);  //显示QImage
    void setMatImage(cv::Mat ); //显示Mat
    void setPixmap(QPixmap); // 显示QPixmap
    void resetImage(); //清楚图像
    QImage getQImage(); //获取QImage
    cv::Mat getMatImage(); // 获取矩阵
    QPixmap getPixmap(); // 获取QPixmap
protected: // 保护成员函数
    // 重载父类QGraphicsView的成员函数
    virtual void wheelEvent(QWheelEvent *event) override;    // virtual 虚函数;override 重载
    virtual void keyPressEvent(QKeyEvent *event) override;   
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseMoveEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    void zoom(QPoint factor); // 缩放
    void togglePan(bool pan, const QPoint &startPos = QPoint()); 
    void pan(const QPoint &panTo);
    void initShow(); // 
  
private: // 私有成员变量
    QPixmap m_image; 
    bool m_isPan;
    QPoint m_prevPan;
    QGraphicsScene *scene;
};
#endif // IMAGEVIEWER_H

10、编写ImageView.cpp 文件

#include "imageviewer.h"
#include 
ImageViewer::ImageViewer(QWidget *parent) // 构造函数
    : QGraphicsView{parent}, // 父类
    m_isPan(false), // 私有变量初始化
    m_prevPan(0,0),
    scene(nullptr)
{
    scene = new QGraphicsScene(this);
    this->setScene(scene);
    setDragMode(QGraphicsView::DragMode::NoDrag); // 拖拽模式
    setInteractive(false); // 交互
    setEnabled(false);
}
// Mat转QImage
QImage cvMatToQImage(cv::Mat &src)
{
    if(src.channels() == 1) { // if grayscale image
        return QImage((uchar*)src.data, src.cols, src.rows, static_cast(src.step), QImage::Format_Grayscale8).copy();
    }
    if(src.channels() == 3) { // if 3 channel color image
        cv::Mat rgbMat;
        cv::cvtColor(src, rgbMat, cv::COLOR_BGR2RGB); // invert BGR to RGB
        return QImage((uchar*)rgbMat.data, src.cols, src.rows, static_cast(src.step), QImage::Format_RGB888).copy();
    }
    return QImage();
}
//将QImage转化为Mat
cv::Mat qImageToCvMat( const QImage &inImage)
{
    switch (inImage.format())
    {
    case QImage::Format_RGB32:
    case QImage::Format_RGB888:
    {
        QImage   swapped = inImage;
        if ( inImage.format() == QImage::Format_RGB32 )
        {
            swapped = swapped.convertToFormat( QImage::Format_RGB888 );
        }
        cv::Mat matImg = cv::Mat(swapped.height(), swapped.width(),
                                  CV_8UC3,
                                  const_cast(swapped.bits()),
                                  static_cast(swapped.bytesPerLine())
                                  );
        cv::cvtColor(matImg,matImg,cv::COLOR_RGB2BGR);
        return matImg.clone();
    }
    case QImage::Format_Indexed8:
    {
        cv::Mat  mat( inImage.height(), inImage.width(),
                      CV_8UC1,
                      const_cast(inImage.bits()),
                      static_cast(inImage.bytesPerLine())
                      );
        return mat.clone();
    }
    default:
        break;
    }
    return cv::Mat();
}
void ImageViewer::setQImage(QImage image)
{   if(image.isNull())
        return;
    m_image = QPixmap::fromImage(image);
    initShow();
}
void ImageViewer::setMatImage(cv::Mat src)
{
    if(src.empty())
        return;
    m_image = QPixmap::fromImage(cvMatToQImage(src));
    initShow();
}
void ImageViewer::setPixmap(QPixmap pixmap)
{
    m_image = pixmap.copy();
    initShow();
}
void ImageViewer::resetImage()
{
    if(m_image.isNull())
        return;
    scene->clear();
    setEnabled(false);
}
QImage  ImageViewer::getQImage()
{
    return m_image.toImage();
}
cv::Mat ImageViewer::getMatImage()
{
    return qImageToCvMat(m_image.toImage());
}
QPixmap ImageViewer::getPixmap()
{
    return m_image;
}
void ImageViewer::initShow()
{
    setEnabled(true);
    setMouseTracking(true);
    scene->clear();
    scene->addPixmap(m_image);
    scene->update();
    this->resetTransform();
    this->setSceneRect(m_image.rect());
    this->fitInView(QRect(0, 0, m_image.width(), m_image.height()), Qt::KeepAspectRatio);
}
// 鼠标点击事件
void ImageViewer::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        togglePan(true, event->pos());
        event->accept();
        return;
    }
    event->ignore();
}
// 鼠标移动事件
void ImageViewer::mouseMoveEvent(QMouseEvent *event)
{
    if(m_isPan) {
        pan(event->pos());
        event->accept();
        return;
    }
    event->ignore();
}
// 鼠标释放事件
void ImageViewer::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        togglePan(false);
        event->accept();
        return;
    }
    event->ignore();
}
// 缩放
void ImageViewer::zoom(QPoint factor)
{
    QRectF FOV = this->mapToScene(this->rect()).boundingRect();
    QRectF FOVImage = QRectF(FOV.left(), FOV.top(), FOV.width(), FOV.height());
    float scaleX = static_cast(m_image.width()) / FOVImage.width();
    float scaleY = static_cast(m_image.height()) / FOVImage.height();
    float minScale = scaleX > scaleY ? scaleY : scaleX;
    float maxScale = scaleX > scaleY ? scaleX : scaleY;
    if ((factor.y() > 0 && minScale > 100) || (factor.y() < 0 && maxScale 0)
        scale(1.2, 1.2);
    else
        scale(0.8, 0.8);
}
//键盘按键事件
void ImageViewer::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_O) {
        this->resetTransform();
        this->setSceneRect(m_image.rect());
        this->fitInView(QRect(0, 0, m_image.width(), m_image.height()), Qt::KeepAspectRatio);
    }
}
void ImageViewer::pan(const QPoint &panTo)
{
    auto hBar = horizontalScrollBar();
    auto vBar = verticalScrollBar();
    auto delta = panTo - m_prevPan;
    m_prevPan = panTo;
    hBar->setValue(hBar->value() - delta.x());
    vBar->setValue(vBar->value() - delta.y());
}
// 滚轮事件
void ImageViewer::wheelEvent(QWheelEvent *event)
{
    if(m_image.isNull())
        return;
    QPoint numDegrees = event->angleDelta() / 8;
    if (!numDegrees.isNull()) {
        QPoint numSteps = numDegrees / 15;
        zoom(numSteps);
    }
    event->accept();
}
void ImageViewer::togglePan(bool pan, const QPoint &startPos)
{
    if(pan){
        if(m_isPan) {
            return;
        }
        m_isPan = true;
        m_prevPan = startPos;
        setCursor(Qt::ClosedHandCursor);
    } else {
        if(!m_isPan) {
            return;
        }
        m_isPan = false;
        m_prevPan = QPoint(0,0);
        setCursor(Qt::ArrowCursor);
    }
}

11、编写read_and_show_img.h文件

#ifndef READANDSHOWIMG_H
#define READANDSHOWIMG_H
#include 
#include "ImageViewer.h"
QT_BEGIN_NAMESPACE
namespace Ui { class ReadAndShowImg; }
QT_END_NAMESPACE
class ReadAndShowImg : public QMainWindow
{
    Q_OBJECT
public:
    ReadAndShowImg(QWidget *parent = nullptr);
    ~ReadAndShowImg();
private slots:
    void on_btn_filePath_clicked();
    void on_btn_readAndShow_clicked();
private:
    Ui::ReadAndShowImg *ui;
    QString filePath;
//    ImageViewer * m_view;
};
#endif // READANDSHOWIMG_H

12、编写read_and_show_img.cpp文件

#include "read_and_show_img.h"
#include "ui_read_and_show_img.h"
#include 
#include "opencv2/opencv.hpp"
ReadAndShowImg::ReadAndShowImg(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ReadAndShowImg)
{
    ui->setupUi(this);
    setWindowTitle("读取并显示图片");   // 注意这一句要在setupUi之后,否则不起效果
}
ReadAndShowImg::~ReadAndShowImg()
{
    delete ui;
}
void ReadAndShowImg::on_btn_filePath_clicked()
{
    filePath = QFileDialog::getOpenFileName(this,"open file dialog","E:\Img\","JPG(*.jpg);;PNG(*.png);;BMP(*.jpeg)");
    ui->let_filePath->setText(filePath);
}
void ReadAndShowImg::on_btn_readAndShow_clicked()
{
    cv::Mat src = cv::imread(filePath.toStdString(),1);
    ui->gpv_img->setMatImage(src);
}

13、main文件保持原样

#include "read_and_show_img.h"
#include 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ReadAndShowImg w;
    w.show();
    return a.exec();
}

完成以上文件的编写,即可运行程序。ImageView控件支持图像的缩放,拖拽等操作。

运行效果:

文能提笔控萝莉,武能床上定人妻_能显示并缩放图片的控件_山能金控和山金金控是一家吗

注意,为图省事,本文中的ImageView类摘自互联网,原文链接为:

【[Qt]基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动】_qt 图像控件_xiaohuihuihuige的博客-CSDN博客

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注