欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt图片交互——QGraphicsView+鼠标选点+放大缩小+OpenCV

程序员文章站 2022-06-04 23:44:32
...

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.示例结果

Qt图片交互——QGraphicsView+鼠标选点+放大缩小+OpenCV