复现 OpenCV Qt源码之:滚轮缩放移动图像像素级显示

参考了OpenCV源码highgui 的 Qt 部分,在 QtCreater 中 复现了滚轮缩放移动图像像素级显示。

把这个功能封装成了一个类,可以随意使用,使用时参考Qt协议。

见代码:

#ifndef MYZOOMVIEW_H
#define MYZOOMVIEW_H
#include <QImage>
#include <QPainter>
#include <QGraphicsView>
#include <opencv2/opencv.hpp>
#include <QDebug>
#include <QWheelEvent>
using namespace cv;
class MyZoomView :public QGraphicsView
{
public:
    //用于绘图的QImage
    QImage image2Draw_qt;
    //Opencv Mat 的引用
    Mat *image2Draw_mat = nullptr;
    //变换矩阵
    QTransform param_matrixWorld;
    //反向变换矩阵
    QTransform matrixWorld_inv;
    //鼠标位置
    QPointF positionGrabbing;
public:
    MyZoomView(){
        positionGrabbing = QPointF(0, 0);
        this->setGeometry(0,0,viewport()->width(),viewport()->height());
    };

    //适应窗口大小画图
    void Draw2D(QPainter *painter){
        if(image2Draw_mat == nullptr)
            return;

        image2Draw_qt = QImage(image2Draw_mat->data, image2Draw_mat->cols,
                               image2Draw_mat->rows,image2Draw_mat->step,QImage::Format_RGB888);

        painter->drawImage(
                    QRect(0,0,viewport()->width(),viewport()->height()),
                    image2Draw_qt,
                    QRect(0,0, image2Draw_qt.width(),
                    image2Draw_qt.height()));

    }
    //设置图像对象的引用
    void setMat(Mat& mat){
        image2Draw_mat = &mat;
        this->setGeometry(0,0,image2Draw_mat->cols/2,image2Draw_mat->rows/2);

    }
    //show
    void showviewport(){
        this->show();
    }
    //控制图像位置
    void controlImagePosition()
    {
        qreal left, top, right, bottom;

        //after check top-left, bottom right corner to avoid getting "out" during zoom/panning
        param_matrixWorld.map(0,0,&left,&top);

        if (left > 0)
        {
            param_matrixWorld.translate(-left,0);
            left = 0;
        }
        if (top > 0)
        {
            param_matrixWorld.translate(0,-top);
            top = 0;
        }
        //-------

        QSize sizeImage = size();
        param_matrixWorld.map(sizeImage.width(),sizeImage.height(),&right,&bottom);
        if (right < sizeImage.width())
        {
            param_matrixWorld.translate(sizeImage.width()-right,0);
            right = sizeImage.width();
        }
        if (bottom < sizeImage.height())
        {
            param_matrixWorld.translate(0,sizeImage.height()-bottom);
            bottom = sizeImage.height();
        }
    }
    void scaleView(qreal factor,QPointF center)
    {
        factor/=5;//-0.1 <-> 0.1
        factor+=1;//0.9 <-> 1.1

        //限制缩小图像,m11()是横向缩放比率
        if (param_matrixWorld.m11()==1 && factor < 1)
            return;
        if (param_matrixWorld.m11()*factor<1)
            factor = 1/param_matrixWorld.m11();
        //限制放大图像
        if (param_matrixWorld.m11()>100 && factor > 1)
            return;

        int a, b;
        //反向映射坐标
        matrixWorld_inv.map(center.x(),center.y(),&a,&b);
        //平移
        param_matrixWorld.translate(a-factor*a,b-factor*b);
        //缩放
        param_matrixWorld.scale(factor,factor);

        controlImagePosition();

        if (param_matrixWorld.m11()>1)
            setCursor(Qt::OpenHandCursor);
        else
            unsetCursor();
    }
    void moveView(QPointF delta)
    {
        //平移
        param_matrixWorld.translate(delta.x(),delta.y());
        controlImagePosition();
        viewport()->update();
    }
protected:
    //绘图事件,本例中由viewport()->update()触发,由其他默认事件触发(调整大小等等)
    void paintEvent(QPaintEvent* paintEventInfo) override{
        //用viewport()初始化QPainter
        QPainter myPainter(viewport());
        //给画笔设置变换矩阵
        myPainter.setWorldTransform(param_matrixWorld);
        qDebug()<<"Painting...\n";
        Draw2D(&myPainter);
    };
    //鼠标滚轮事件
    void wheelEvent(QWheelEvent* evnt) override
    {
        scaleView(evnt->delta() / 240.0, evnt->pos());
        viewport()->update();
        QWidget::wheelEvent(evnt);
    }
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent* evnt) override
    {
        if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton)
        {
            //当前鼠标位置
            QPoint pt = evnt->pos();
            //移动矢量
            QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11();
            positionGrabbing = pt;
            moveView(dxy);
        }
        QWidget::mouseMoveEvent(evnt);
    }
    //鼠标按下事件
    void mousePressEvent(QMouseEvent* evnt)
    {
        if (param_matrixWorld.m11()>1)
        {
            setCursor(Qt::ClosedHandCursor);
            positionGrabbing = evnt->pos();
        }

        QWidget::mousePressEvent(evnt);
    }

};

#endif // MYZOOMVIEW_H

使用方法:

#include "mainwindow.h"
#include "myzoomview.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyZoomView mzv;
    mzv.showviewport();
    Mat image2Draw_mat = imread("D:\\a.bmp");
    mzv.setMat(image2Draw_mat);
    return a.exec();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值