Qt圖片交互——QGraphicsView+鼠標選點+放大縮小+OpenCV

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;
}

如上即完成了鼠標的選點和放縮操作。

3.示例結果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章