前言
在图像处理中,有时候我们只想对图像的某部分区域执行处理,即所谓的Roi(感兴趣区域)。例如在做模板匹配之前,通常都需要人工在图像上框选一个Mask区域,以此建立基准模板。下面记录一下自己基于Qt实现的一个框选图片矩形区域的工具。
功能演示:
鼠标左键点击,该位置坐标位矩形的左上顶点,滑动鼠标即可实时看到自己所框选的矩形框,释放左键。矩形款选完成,左键释放时。这是界面会提示,右键点击鼠标,代表确认矩形框选完成。右窗口显示框选矩形区域之后的图像。底部窗口输出所有框选的矩形的左顶点,矩形的高还有宽。
若想重新框选,左键双击将全部清楚。
主要思路
1.继承QWidget类,重写鼠标双击,鼠标移动,鼠标单击和鼠标释放函数,
virtual void mouseDoubleClickEvent(QMouseEvent *event)
virtual void mouseMoveEvent(QMouseEvent *event)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
在这四个函数中,实现人机交互的逻辑。
2.矩形数据结构采用的是opencv提供的cv::Rect数据结构。右键点击确认完成,将所有的cv::Rect矩形存储在std::vector容器中。在文章opencv cv::Rect详解中,我们解析了该数据类型。
3.右窗口的实现是采用了opencv提供的rectangle函数,将所有框选的矩形以填充的形式画在一张画布上,再将画布与原图做与的操作,可以用“ | ”操作符,也可以调用opencv的bitwise_and()函数。
核心代码:
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton && event->pos().x() < srcOri.cols)
{
bIsDrawing = true;
cacheRect = cv::Rect(event->pos().x()-m_fRatioWidth, event->pos().y()-m_fRatioHeigh, 0, 0);
}
else if(event->button() == Qt::RightButton)
{
cropImage(result);
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
bIsDrawing = false;
if (cacheRect.width < 0) {
cacheRect.x += cacheRect.width;
cacheRect.width *= -1;
}
if (cacheRect.height < 0) {
cacheRect.y += cacheRect.height;
cacheRect.height *= -1;
}
if(cacheRect.height&&cacheRect.width)
{
drawRect(image, cacheRect);
vecRects.push_back(cacheRect);
bIsClickRButton = true;
}
}
}
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
bIsClickRButton = false;
vecRects.clear();
srcOri.copyTo(image);
srcOri.copyTo(result);
ui->textEdit->clear();
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if (bIsDrawing) {
if(event->pos().x() - cacheRect.x>2 ||event->pos().y() - cacheRect.y>2)
{
cacheRect.width = event->pos().x() - m_fRatioWidth - cacheRect.x;
cacheRect.height = event->pos().y()- m_fRatioHeigh - cacheRect.y;
}
}
}
//抠图
void Widget::cropImage(cv::Mat &img)
{
if(vecRects.empty())
{
srcOri.copyTo(img);
return;
}
cv::Mat roi = cv::Mat::zeros(img.size(),img.type());
ui->textEdit->clear();
for(int i = 0; i < vecRects.size(); i++)
{
qDebug()<<"rect"<<vecRects[i].width<<vecRects[i].height;
int x = vecRects[i].x;
int y = vecRects[i].y;
int h = vecRects[i].height;
int w = vecRects[i].width;
QString info = QString(QStringLiteral("左顶点坐标x:%1 左顶点坐标y:%2 高:%3 宽:%4")).arg(x).arg(y).arg(h).arg(w);
info = QString("%1.").arg(i+1) + info;
ui->textEdit->append(info);
cv::rectangle(roi, vecRects[i], cv::Scalar(255,255,255), -1);
}
cv::bitwise_and(srcOri, roi, img);
}