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;
}
如上即完成了鼠標的選點和放縮操作。