1.功能目标
通过 QGraphicsView 实现 OpenCV Mat 的显示,并且可以响应鼠标事件,绘制选择的点,同时可以进行放大缩小操作。
备注:QLabel 也能够完成同样的操作,但是QLabel的放缩是对控件本身缩放,像素显示会自动插值,图片放大时无法显示单个像素点,控件放大太大时响应会很慢,如果仅固定大小图片进行展示,可以选择使用QLabel。需要放缩操作时,QGraphicsView 更好用。
2.核心代码
2.1.初始化
在窗体中增加QGraphicsView
控件,示例中命名为 imageBox。
窗体类中增加变量:
//控制缩放的比例因子
double m_scaleFactor;
//场景
QGraphicsScene * m_scene;
//画布
QGraphicsPixmapItem * m_imageItem;
//绘制的OpenCV图像
cv::Mat m_imageShow;
变量初始化:
//缩放因子初始化为1
m_scaleFactor = 1.0;
m_scene = new QGraphicsScene();
m_imageItem = new QGraphicsPixmapItem();
//场景增加画布
m_scene->addItem(m_imageItem);
//控件绑定场景
ui.imageBox->setScene(m_scene);
//对QGraphcisView控件注册事件响应
ui.imageBox->installEventFilter(this);
//使能QGraphcisView控件的鼠标跟踪
ui.imageBox->setMouseTracking(true);
2.2.图片绘制、放大缩小
将 OpenCV Mat 绘制到控件上的代码如下:
//将OpenCV Mat绘制到QGraphicsView
ShowImage(const cv::Mat & image)
{
//记录绘制图片
m_imageShow = image.clone();
//三通道RGB
if (image.type() == CV_8UC3)
m_imageItem->setPixmap(QPixmap::fromImage(QImage((const unsigned char*)image.data, image.cols, image.rows, QImage::Format::Format_RGB888)));
//四通道RGBA
else if (image.type() == CV_8UC4)
m_imageItem->setPixmap(QPixmap::fromImage(QImage((const unsigned char*)image.data, image.cols, image.rows, QImage::Format::Format_RGBA8888_Premultiplied)));
//单通道Gray
else if (image.type() == CV_8UC1)
m_imageItem->setPixmap(QPixmap::fromImage(QImage((const unsigned char*)image.data, image.cols, image.rows, QImage::Format::Format_Grayscale8)));
else
return;
//更新显示
ui.imageBox->show();
}
//放缩图片(例如:放大时factor=1.2f,缩小时factor=0.8f)
ScaleImage(float factor)
{
//累计放缩因子
m_scaleFactor *= factor;
//构造放缩矩阵
QMatrix matrix;
matrix.scale(m_scaleFactor, m_scaleFactor);
//QGraphicsView执行放缩
ui.imageBox->setMatrix(matrix);
}
2.3.鼠标响应
首先在类函数中增加:
private slots: bool eventFilter(QObject* watched, QEvent* event);
该函数是初始化中的installEventFilter
信号对应的槽。
函数的实现如下:
bool eventFilter(QObject* watched, QEvent* event)
{
//如果信号不是来自于QGraphicsView,返回。
if (watched != ui.imageBox)
return false;
switch (event->type())
{
//按键事件(操作放缩)
case QEvent::KeyPress:
{
QKeyEvent * kEvent = (QKeyEvent*)event;
//‘+’即键盘中的‘=’,执行放大
if (kEvent->key() == '=')
{
ScaleImage(1.2);
}
//‘-’执行缩小
else if (kEvent->key() == '-')
{
ScaleImage(0.8);
}
}
//鼠标事件响应
case QEvent::MouseButtonPress:
{
//执行鼠标左键选点
QMouseEvent * mEvent = (QMouseEvent*)event;
if (mEvent->button() != Qt::LeftButton)
break;
//鼠标点在QGraphics控件上的坐标
QPoint p = mEvent->pos();
//控件的视场尺寸
QSize size = ui.imageBox->viewport()->size();
//当前显示图片的尺寸,换算为放缩后的尺寸
cv::Size imgSize = m_imageShow.size();
imgSize.width *= m_scaleFactor;
imgSize.height *= m_scaleFactor;
//运算鼠标点对应图像中的像素坐标
float xErr = (size.width() - imgSize.width) / 2.;
float yErr = (size.height() - imgSize.height) / 2.;
if (xErr < 0)xErr = 0;
if (yErr < 0)yErr = 0;
int hv = ui.imageBox->horizontalScrollBar()->value();
int vv = ui.imageBox->verticalScrollBar()->value();
int x = (hv + p.x() - xErr) / _scaleFactor;
int y = (vv + p.y() - yErr) / _scaleFactor;
//执行选点操作
SelectPoint(x, y);
break;
}
default:
break;
}
return false;
}
如上即完成了鼠标的选点和放缩操作。