最近需要做一个将图像放大至格子级别以及随着鼠标移动(不需要按下鼠标),实时显示鼠标位置以及对应的RGB的值。因此结合了opencv以及Qt做了一个这样的东西
实现的主要的主要思路是,通过OpenCV进行图像的处理和放大,然后转换为QImage在Qt中显示出来。
首先是利用opencv进行图像的放大,利用的函数是resize函数。
需要更进一步了解opencv图像的缩放,可以了解一下博客内容:【OpenCV入门教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放。以下是resize函数的相关内容:
resize( )为OpenCV中专职调整图像大小的函数。
此函数将源图像精确地转换为指定尺寸的目标图像。如果源图像中设置了ROI(Region Of Interest ,感兴趣区域),那么resize( )函数会对源图像的ROI区域进行调整图像尺寸的操作,来输出到目标图像中。若目标图像中已经设置ROI区域,不难理解resize( )将会对源图像进行尺寸调整并填充到目标图像的ROI中。
很多时候,我们并不用考虑第二个参数dst的初始图像尺寸和类型(即直接定义一个Mat类型,不用对其初始化),因为其尺寸和类型可以由src,dsize,fx和fy这其他的几个参数来确定。
函数原型为:
C++: void resize(InputArray src,OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )
接着就是跟踪鼠标位置,如何在不点击鼠标的情况下,移动鼠标就可以得到鼠标的位置呢,在qt的官网文档中,给出了关于mouseMoveEvent的解释:
所以为了在不按下鼠标就能获取到鼠标移动的事先,需要对setMouseTracking()进行设置,默认是false,因此我们需要在代码中显示的设置为true。另外,需要注意到的是,我们是对对指定的控件类型进行鼠标移动的进行跟踪,几乎所有的控件如QLabel,都是继承自QWidget,因此我们需要针对我们的控件进行设置鼠标跟踪,如接下来我是在我的对象ui.display(class为QLabel)进行鼠标跟踪,因此我需要进行ui.display->setMouseTracking(true)的设置。
此外,我的目的是为了判断进行到ui.display的区域类之后,才会进行鼠标跟踪以及对鼠标样式的修改,如进入到区域内,会变成cross样式,离开后又会重新变成Arrow样式。因此QLabel需要进行事件监听,对此,我的博文有详细的介绍: Qt(四)--- 事件处理机制以及QLabel的交互实现
现将部分的关键代码贴出来:
类中的定义:
proctected:
virtual bool eventFilter(QObject *, QEvent *);
proctected slots:
void onScaleUp();
void onScaleDown();
private:
double m_scale_factor;
m_scale_factor=1.0;
//这里是在display设置mouseTracking,而不是直接setMouseTracking,不然display没有办法跟踪鼠标移动
ui.display->setMouseTracking(true);
ui.display->installEventFilter(this);
connect(ui.scaleUpBtn,SIGNAL(clicked()),this,SLOT(onScaleUp()));
connect(ui.scaleDownBtn,SIGNAL(clicked()),this,SLOT(onScaleDown()));
函数实现:
bool FrameGrabber::eventFilter(QObject *obj, QEvent *event)
{
if(obj==ui.display && (event->type()==QMouseEvent::MouseMove))
{
if(!displayImage.isNull())
{
ui.textBrowser->clear();
QMouseEvent *mouseEvent=static_cast(event);
setCursor(Qt::CrossCursor);
QPoint qPos=mouseEvent->globalPos();
QPoint qPos1=ui.display->mapFromGlobal(qPos);
QRect rect=ui.display->contentsRect();
QPoint qPos2 = qPos1 + rect.topLeft();
QString posInfo;
int x, y;
if(m_scale_factor> 1.0 || m_scale_factor<1.0)
{
x=(int)(qPos2.x()*(1/m_scale_factor));
y=(int)(qPos2.y()*(1/m_scale_factor));
}
else
{
x=qPos2.x();
y=qPos2.y();
}
posInfo="(x,y) = ";
posInfo+="(";
posInfo+=QString::number(x);
posInfo+=",";
posInfo+=QString::number(y);
posInfo+=")";
ui.textBrowser->append(posInfo);
QImage infoImage=QImage(image.data,width,height,QImage::Format_Grayscale8);
QString rgbInfo;
QRgb qRgb=infoImage.pixel(x,y);
rgbInfo="(r,g,b) = ";
rgbInfo+="(";
rgbInfo+=QString::number(qRed(qRgb));
rgbInfo+=",";
rgbInfo+=QString::number(qGreen(qRgb));
rgbInfo+=",";
rgbInfo+=QString::number(qBlue(qRgb));
rgbInfo+=")";
ui.textBrowser->append(rgbInfo);
}
}
else if(obj==ui.display && (event->type()==QEvent::Leave))
{
setCursor(Qt::ArrowCursor);
}
return QWidget::eventFilter(obj,event);
}
oid FrameGrabber::onScaleUp()
{
if(timer->isActive())
{
QMessageBox qb;qb.setIcon(QMessageBox::Information);qb.setWindowFlags(Qt::FramelessWindowHint);
qb.setText(QString::fromLocal8Bit("连续帧显示中,请先暂停图像抓取,然后进行图像缩放查看"));
qb.exec();
return;
}
if(m_scale_factor<16.0)
{
if(image.empty())
return;
m_scale_factor*=2.0;
QString factorStr;
if(m_scale_factor*1.0==1.0f)
factorStr="1/1";
else if(m_scale_factor*2.0==1.0f)
factorStr="1/2";
else if(m_scale_factor*4.0==1.0f)
factorStr="1/4";
else if(m_scale_factor*8.0==1.0f)
factorStr="1/8";
else if(m_scale_factor*16.0==1.0f)
factorStr="1/16";
else if(m_scale_factor*32.0==1.0f)
factorStr="1/32";
else if(m_scale_factor/2.0==1.0f)
factorStr="2/1";
else if(m_scale_factor/4.0==1.0f)
factorStr="4/1";
else if(m_scale_factor/8.0==1.0f)
factorStr="8/1";
else if(m_scale_factor/16.0==1.0f)
factorStr="16/1";
else if(m_scale_factor/32.0==1.0f)
factorStr="32/1";
ui.label_factor->setText(factorStr);
Mat scaleMat;
cv::resize(image,scaleMat,Size(0,0),m_scale_factor,m_scale_factor,INTER_AREA);
displayImage=QImage(scaleMat.data,scaleMat.cols,scaleMat.rows,QImage::Format_Grayscale8);
ui.display->setPixmap(QPixmap::fromImage(displayImage));
}
else
return;
}
void FrameGrabber::onScaleDown()
{
if(timer->isActive())
{
QMessageBox qb;qb.setIcon(QMessageBox::Information);qb.setWindowFlags(Qt::FramelessWindowHint);
qb.setText(QString::fromLocal8Bit("连续帧显示中,请先暂停图像抓取,然后进行图像缩放查看"));
qb.exec();
return;
}
if(m_scale_factor*16>1.0)
{
if(image.empty())
return;
m_scale_factor=m_scale_factor/2.0;
QString factorStr;
if(m_scale_factor*1.0==1.0f)
factorStr="1/1";
else if(m_scale_factor*2.0==1.0f)
factorStr="1/2";
else if(m_scale_factor*4.0==1.0f)
factorStr="1/4";
else if(m_scale_factor*8.0==1.0f)
factorStr="1/8";
else if(m_scale_factor*16.0==1.0f)
factorStr="1/16";
else if(m_scale_factor*32.0==1.0f)
factorStr="1/32";
else if(m_scale_factor/2.0==1.0f)
factorStr="2/1";
else if(m_scale_factor/4.0==1.0f)
factorStr="4/1";
else if(m_scale_factor/8.0==1.0f)
factorStr="8/1";
else if(m_scale_factor/16.0==1.0f)
factorStr="16/1";
else if(m_scale_factor/32.0==1.0f)
factorStr="32/1";
ui.label_factor->setText(factorStr);
Mat scaleMat;
cv::resize(image,scaleMat,Size(0,0),m_scale_factor,m_scale_factor,INTER_AREA);
displayImage=QImage(scaleMat.data,scaleMat.cols,scaleMat.rows,QImage::Format_Grayscale8);
ui.display->setPixmap(QPixmap::fromImage(displayImage));
}
}
最后的结果如图: