QT ROI 绘制区域

        之前做了一个项目中,需要画取ROI来进行图片区域选择,因为以前没有搞过就研究了一下。

        一开始想着是在界面加载一个QLabel来加载图像,然后直接画一个ROI出来,结果画的框总是在控件下面没解决。后来看到有篇博客是在一个自定义的QLabel中实现, 重写实现它的一些鼠标事件绘图事件等。计算好相应的位置值即可。

        本文和该功能的实现具体借鉴了两篇博客文章的而实现:1 QT-绘制ROI、矩形框、椭圆框,机器视觉_Create_Joy的博客-CSDN博客_qt绘制矩形框   2  qt+opencv实现视频中动态选取ROI_给算法爸爸上香的博客-CSDN博客

 本文作者原创,未经允许禁止转载。

QT ROI 绘制区域目录

1 效果图

1.1 示例1

 1.2 示例2

1.3 示例3

2 具体代码

2.1 示例1源码

2.2 示例2源码

3 其他说明


1 效果图

1.1 示例1

        该文章实现了画ROI的功能,可以画矩形、椭圆;

 1.2 示例2

        实现了画ROI 拖动功能;

1.3 示例3

        最后实现的效果图,可以看出正常画ROI均正常,也可以输出具体的XYWH信息。

2 具体代码

        这里没有附上完整版本代码,因为太多了。 文章结尾会提供CSDN下载链接,供下载参考。

2.1 示例1源码

///DrawQWidget.h

#ifndef DRAWQWIDGET_H
#define DRAWQWIDGET_H

#include <QWidget>
#include <QKeyEvent>
#include <qpoint.h>
#include <qpen.h>

/*
 *
 */
typedef enum draw_shap_e{
    DRAW_RECT,    //画矩形
    DRAW_ELLIPSE, //画椭圆
    DRAW_NO       //不画
}DRAW_SHAP_E;
/* 用来表示鼠标在矩形区域的位置信息
 *
 */
typedef enum rect_mouse_position_e{
    RECT_UPPER=0,     //上边缘
    RECT_LOWER=1,     //下边缘
    RECT_LEFT,        //左边缘
    RECT_RIGHT,       //右边缘
    RECT_LEFTUPPER,   //左上角
    RECT_LEFTLOWER,   //左下角
    RECT_RIGHTLOWER,  //右下角
    RECT_RIGHTUPPER,  //右上角
    RECT_INSIDE,      //区域内部
    RECT_OUTSIDE      //区域外部
}RECT_MOUSE_POSITION_E;

/* 用来表示鼠标在椭圆区域的位置信息
 *
 */
typedef enum ellipse_mouse_position_e{
    ELLIPSE_UPPER=0,     //上顶角
    ELLIPSE_LOWER=1,     //下顶角
    ELLIPSE_LEFT,        //左顶角
    ELLIPSE_RIGHT,       //右顶角
    ELLIPSE_INSIDE,      //区域内部
    ELLIPSE_OUTSIDE      //区域外部
}ELLIPSE_MOUSE_POSITION_E;

class DrawQWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DrawQWidget(QWidget *parent = 0);
    ~DrawQWidget();
    void set_draw_shap(DRAW_SHAP_E d);
    void set_picture_image(QString file_name);

protected:
    void timerEvent(QTimerEvent*);
    void paintEvent(QPaintEvent*) override;
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private:
    bool is_mouse_pressed;//是否按下鼠标
    DRAW_SHAP_E draw_shap;



    QPoint                           new_mouse_pos;
    QPoint                           old_mouse_pos;
    int                              m_difference_x;
    int                              m_difference_y;
    QPainter                        *painter;         //用来绘制图像
    QPen                             frame_pen;       //用来绘制区域边框
    QPen                             red_point_pen;   //用来绘制红色点
    const int                        BoundaryRange = 6;//用来表示边界的宽度范围,用于拖拽
    /* 矩形区域相关变量和函数
     * 注意:QPoint的0点是左上角,横向向右为X的正方向,竖向向下为Y的正方向
     */
    int        rect_left;        //表示矩形右上角的X坐标
    int        rect_top;         //表示矩形右上角的Y坐标
    int        rect_width;       //表示矩形的宽(即水平长度)
    int        rect_height;      //表示矩形的高(即垂直长度)
    int        rect_top_left_x,   rect_top_left_y;       //左上
    int        rect_top_right_x,  rect_top_right_y;      //右上
    int        rect_low_left_x,   rect_low_left_y;       //左下
    int        rect_low_right_x,  rect_low_right_y;      //右下
    QPolygon                      rect_polygon;          //装载8个红点的坐标
    RECT_MOUSE_POSITION_E         rect_mouse_pos;
    void                          rect_init_region();
    void                          rect_update_region();
    void                          rect_change_region();
    RECT_MOUSE_POSITION_E         rect_get_mouse_pos(int pos_x, int pos_y);


    /* 椭圆区域相关变量和函数
     * 注意:drawEllipse(20,20,210,160);
     * 第1,2个参数表示圆/椭圆距屏幕左上角的像素数,第3,4个参数表示圆/椭圆的宽度和高度。
     * 更加确切地表述,这个圆或椭圆是在矩形中,这个矩形的左上角的顶点在坐标轴中的位置为(20,20),
     * 这个圆或椭圆的中心为这个矩形的中心
     */
    int        ellipse_left;        //表示椭圆右上角的X坐标
    int        ellipse_top;         //表示椭圆右上角的Y坐标
    int        ellipse_width;       //表示椭圆的宽(即水平长度)
    int        ellipse_height;      //表示椭圆的高(即垂直长度)
    int        ellipse_middle_x;
    int        ellipse_middle_y;
    QPolygon                         ellipse_polygon;          //装载4个红点的坐标
    ELLIPSE_MOUSE_POSITION_E         ellipse_mouse_pos;
    void                             ellipse_init_region();
    void                             ellipse_update_region();
    void                             ellipse_change_region();
    ELLIPSE_MOUSE_POSITION_E         ellipse_get_mouse_pos(int pos_x, int pos_y);

    /* other
     *
     */
    int                 timer_id;
    QImage              picture_image;
    int                 picture_image_w;
    int                 picture_image_h;
public slots:
};
#endif // DRAWQWIDGET_H
///DrawQWidget.cpp

#include "DrawQWidget.h"
#include <qdebug.h>
#include <qpainter.h>
DrawQWidget::DrawQWidget(QWidget *parent) : QWidget(parent)
{
    setAttribute(Qt::WA_StyledBackground);
    setStyleSheet("background-color: rgb(0, 0, 0);");
    grabKeyboard();
    setMouseTracking(true);

    m_difference_x                = 0;
    m_difference_y                = 0;
    draw_shap                     = DRAW_NO;
    painter                       = new QPainter(this);
    frame_pen                     = QPen(QColor(0,174,255),2);
    red_point_pen                 = QPen(QColor(255,0,0),4);
    is_mouse_pressed              = false;
    timer_id = startTimer(20);


    rect_init_region();
    ellipse_init_region();
    /// 开启鼠标实时追踪
    setMouseTracking(true);

}

DrawQWidget::~DrawQWidget()
{
    killTimer(timer_id);
}


/* Event function
 *
 */
void DrawQWidget::timerEvent(QTimerEvent *)
{
    this->update();
}
void DrawQWidget::paintEvent(QPaintEvent *)
{
    painter->begin(this);
    painter->drawImage(QRectF(0,0,width(),height()), picture_image);
    switch (draw_shap) {
    case (DRAW_RECT)     :{
        painter->setPen(frame_pen);//绘制边框线
        painter->drawRect(QRect(rect_left, rect_top, rect_width, rect_height));
        painter->setPen(red_point_pen);//绘制八个点
        painter->drawPoints(rect_polygon);
        }break;
    case (DRAW_ELLIPSE)  :{
        painter->setPen(frame_pen);//绘制边框线
        painter->drawEllipse(QRect(ellipse_left, ellipse_top, ellipse_width, ellipse_height));
        painter->setPen(red_point_pen);//绘制四个点
        painter->drawPoints(ellipse_polygon);
        }break;
    case (DRAW_NO)       :break;
    }

    painter->end();
}

void DrawQWidget::mousePressEvent(QMouseEvent *event)
{
//    if (!is_start_draw) return;
    is_mouse_pressed = true;
}

void DrawQWidget::mouseMoveEvent(QMouseEvent *event)
{
//    if (!is_start_draw) return;
    new_mouse_pos = event->pos();
    if (is_mouse_pressed) {
        m_difference_x = new_mouse_pos.x() - old_mouse_pos.x();
        m_difference_y = new_mouse_pos.y() - old_mouse_pos.y();
        switch (draw_shap) {
        case (DRAW_RECT)     :rect_change_region();break;
        case (DRAW_ELLIPSE)  :ellipse_change_region();break;
        case (DRAW_NO)       :break;
        }
    }else{
        switch (draw_shap) {
        case (DRAW_RECT)     :rect_mouse_pos = rect_get_mouse_pos(new_mouse_pos.x(), new_mouse_pos.y());break;
        case (DRAW_ELLIPSE)  :ellipse_mouse_pos = ellipse_get_mouse_pos(new_mouse_pos.x(), new_mouse_pos.y());break;
        case (DRAW_NO)       :break;
        }

    }

    old_mouse_pos = new_mouse_pos;
}

void DrawQWidget::mouseReleaseEvent(QMouseEvent *event)
{
//    if (!is_start_draw) return;
    is_mouse_pressed = false;
}


/* Rect function
 *
 */
void DrawQWidget::rect_init_region()
{
    rect_left   = 100;
    rect_top    = 200;
    rect_width  = 101;
    rect_height = 101;
    rect_mouse_pos = RECT_OUTSIDE;
    rect_update_region();
}
void DrawQWidget::rect_update_region()
{
    rect_top_left_x  = rect_left;            rect_top_left_y  = rect_top;
    rect_top_right_x = rect_left+rect_width; rect_top_right_y = rect_top;
    rect_low_left_x  = rect_left;            rect_low_left_y  = rect_top+rect_height;
    rect_low_right_x = rect_left+rect_width; rect_low_right_y = rect_top+rect_height;

    int Middle_X = rect_left + (rect_width>>1);
    int Middle_Y = rect_top + (rect_height>>1);
    rect_polygon.clear();
    rect_polygon<<QPoint(Middle_X, rect_top)      //上中
                <<QPoint(rect_top_right_x, Middle_Y)   //右中
                <<QPoint(Middle_X, rect_low_left_y)    //下中
                <<QPoint(rect_left, Middle_Y)     //左中
                <<QPoint(rect_left, rect_top)     //左上角
                <<QPoint(rect_top_right_x, rect_top)   //右上角
                <<QPoint(rect_top_right_x, rect_low_left_y) //右下角
                <<QPoint(rect_left, rect_low_left_y);  //左下角

}

void DrawQWidget::rect_change_region()
{
    switch (rect_mouse_pos) {
    case (RECT_UPPER): rect_top += m_difference_y; rect_height -= m_difference_y;break;//上边界
    case (RECT_LOWER): rect_height += m_difference_y;break; //下边界
    case (RECT_LEFT) : rect_left += m_difference_x; rect_width -= m_difference_x;break;//左边界
    case (RECT_RIGHT): rect_width += m_difference_x;break; //右边界
    case (RECT_LEFTUPPER) : {//左上角
        rect_top += m_difference_y; rect_height -= m_difference_y;
        rect_left += m_difference_x; rect_width -= m_difference_x;
        }break;
    case (RECT_LEFTLOWER) : {//左下角
        rect_height += m_difference_y;
        rect_left += m_difference_x; rect_width -= m_difference_x;
        }break;
    case (RECT_RIGHTLOWER) : {//右下角
        rect_height += m_difference_y;
        rect_width += m_difference_x;
        }break;
    case (RECT_RIGHTUPPER) : {//右上角
        rect_top += m_difference_y; rect_height -= m_difference_y;
        rect_width += m_difference_x;
        }break;
    case (RECT_INSIDE) : {//内部
        rect_top += m_difference_y;rect_left += m_difference_x;
        }break;
    case (RECT_OUTSIDE) : return;//外部
    }
    rect_update_region();
}

RECT_MOUSE_POSITION_E DrawQWidget::rect_get_mouse_pos(int pos_x, int pos_y)
{
    if (pos_x < rect_top_left_x || pos_x > rect_top_right_x || pos_y < rect_top_left_y || pos_y > rect_low_left_y) {
        this->setCursor(QCursor(Qt::ArrowCursor));
        return RECT_OUTSIDE;
    }else if (pos_y <= rect_top_left_y+BoundaryRange){ //1:左上角  2:右上角  3:上边缘
          if      (pos_x <= rect_top_left_x+BoundaryRange) {this->setCursor(QCursor(Qt::SizeFDiagCursor));return RECT_LEFTUPPER;}
          else if (pos_x >= rect_top_right_x-BoundaryRange){this->setCursor(QCursor(Qt::SizeBDiagCursor));return RECT_RIGHTUPPER;}
          else                                        {this->setCursor(QCursor(Qt::SizeVerCursor));  return RECT_UPPER;}
    }else if (pos_y >= rect_low_left_y-BoundaryRange){ //1:左下角  2:右下角  3:下边缘
          if      (pos_x <= rect_low_left_x+BoundaryRange) {this->setCursor(QCursor(Qt::SizeBDiagCursor));return RECT_LEFTLOWER;}
          else if (pos_x >= rect_low_right_x-BoundaryRange){this->setCursor(QCursor(Qt::SizeFDiagCursor));return RECT_RIGHTLOWER;}
          else                                        {this->setCursor(QCursor(Qt::SizeVerCursor));  return RECT_LOWER;}
    }else if (pos_x <= rect_top_left_x+BoundaryRange) {   //左边缘
        this->setCursor(QCursor(Qt::SizeHorCursor));  return RECT_LEFT;
    }else if (pos_x >= rect_top_right_x-BoundaryRange) {  //右边缘
        this->setCursor(QCursor(Qt::SizeHorCursor));  return RECT_RIGHT;
    }else {
        this->setCursor(QCursor(Qt::SizeAllCursor));
        return RECT_INSIDE;
    }
}
/* Ellipse function
 *
 */
void DrawQWidget::ellipse_init_region()
{
    ellipse_left   = 100;
    ellipse_top    = 200;
    ellipse_width  = 101;
    ellipse_height = 101;
    ellipse_mouse_pos = ELLIPSE_OUTSIDE;
    ellipse_update_region();
}

void DrawQWidget::ellipse_update_region()
{
    ellipse_middle_x = ellipse_left + (ellipse_width>>1);
    ellipse_middle_y = ellipse_top + (ellipse_height>>1);
    ellipse_polygon.clear();
    ellipse_polygon<<QPoint(ellipse_middle_x,        ellipse_top)            //上顶角
                   <<QPoint(ellipse_left+ellipse_width, ellipse_middle_y)    //右顶角
                   <<QPoint(ellipse_middle_x, ellipse_top+ellipse_height)    //下顶角
                   <<QPoint(ellipse_left, ellipse_middle_y);                 //左顶角
}

void DrawQWidget::ellipse_change_region()
{
    switch (ellipse_mouse_pos) {
    case (ELLIPSE_UPPER)  : ellipse_top += m_difference_y; ellipse_height -= m_difference_y;break;
    case (ELLIPSE_LOWER)  : ellipse_height += m_difference_y;break;
    case (ELLIPSE_LEFT)   : ellipse_left += m_difference_x; ellipse_width -= m_difference_x;break;
    case (ELLIPSE_RIGHT)  : ellipse_width += m_difference_x;break;
    case (ELLIPSE_INSIDE) : ellipse_top += m_difference_y;ellipse_left += m_difference_x;break;
    case (ELLIPSE_OUTSIDE): return;
    }
    ellipse_update_region();
}

ELLIPSE_MOUSE_POSITION_E DrawQWidget::ellipse_get_mouse_pos(int pos_x, int pos_y)
{
    if (pos_x < ellipse_left || pos_x > (ellipse_left+ellipse_width) || pos_y < ellipse_top || pos_y > (ellipse_top+ellipse_height)) {
        this->setCursor(QCursor(Qt::ArrowCursor));
        return ELLIPSE_OUTSIDE;
    }else if (pos_y <= ellipse_top+BoundaryRange){ //上顶角
          if (pos_x >= (ellipse_middle_x-3) && pos_x <= (ellipse_middle_x+3)){
              this->setCursor(QCursor(Qt::SizeVerCursor));  return ELLIPSE_UPPER;
          }else{
            this->setCursor(QCursor(Qt::SizeAllCursor));  return ELLIPSE_INSIDE;
          }
    }else if (pos_y >= ellipse_top+ellipse_height-BoundaryRange){ //下顶角
        if (pos_x >= (ellipse_middle_x-3) && pos_x <= (ellipse_middle_x+3)) {
            this->setCursor(QCursor(Qt::SizeVerCursor));  return ELLIPSE_LOWER;
        }else{
            this->setCursor(QCursor(Qt::SizeAllCursor));  return ELLIPSE_INSIDE;
        }
    }else if (pos_x <= ellipse_left+BoundaryRange) {   //左顶角
        if (pos_y >= (ellipse_middle_y-3) && pos_y <= (ellipse_middle_y+3)) {
            this->setCursor(QCursor(Qt::SizeHorCursor));  return ELLIPSE_LEFT;
        }else{
            this->setCursor(QCursor(Qt::SizeAllCursor));  return ELLIPSE_INSIDE;
        }
    }else if (pos_x >= ellipse_left+ellipse_width-BoundaryRange) {  //右顶角
        if (pos_y >= (ellipse_middle_y-3) && pos_y <= (ellipse_middle_y+3)) {
            this->setCursor(QCursor(Qt::SizeHorCursor));  return ELLIPSE_RIGHT;
        }else{
            this->setCursor(QCursor(Qt::SizeAllCursor));  return ELLIPSE_INSIDE;
        }
    }else {
        this->setCursor(QCursor(Qt::SizeAllCursor));
        return ELLIPSE_INSIDE;
    }
}


/* other function
 *
 */
void DrawQWidget::set_draw_shap(DRAW_SHAP_E d)
{
    draw_shap = d;
}

void DrawQWidget::set_picture_image(QString file_name)
{
    QImage image_tmp;
    image_tmp.load(file_name);
    if (!image_tmp.isNull()){
        picture_image   = image_tmp;
        picture_image_w = image_tmp.width();
        picture_image_h = image_tmp.height();
    }
}

2.2 示例2源码

///MyLabel.h

#pragma once

#include <QLabel>

/* 缩放方向 */
enum EmDirection
{
	DIR_TOP = 0,
	DIR_BOTTOM,
	DIR_LEFT,
	DIR_RIGHT,
	DIR_LEFTTOP,
	DIR_LEFTBOTTOM,
	DIR_RIGHTTOP,
	DIR_RIGHTBOTTOM,
	DIR_MIDDLE,
	DIR_NONE
};

#define EDGPADDING       5        //四周边缘可拉伸宽度
#define CORPADDING       6        //四角可拉伸宽度

#define MIN_WIDTH        5        //可拉伸的最小宽度
#define MIN_HEIGHT       5        //可拉伸的最小高度

#define POINT_WIDTH      6        //边缘9点的宽度
#define POINT_HEIGHT     6        //边缘9点的高度

#define EDGE_WIDTH       3        //边框的宽度
#define MIDDLELINE_WIDTH 2        //辅助线的宽度

#define DRAW_TEN_POINT            //绘制十个点
#define DRAW_SUB_LINE             //绘制辅助线

class QMenu;
class QAction;

class MyLabel : public QLabel
{
	Q_OBJECT

public:
	MyLabel(QWidget *parent = nullptr);
	~MyLabel();
	QRect getRoiRect() const;               //获取已经圈选的框 外部调用
	void setBackImage(const QImage &img);   //设置背景图片  外部调用

protected:
	void paintEvent(QPaintEvent *event);
	void mousePressEvent(QMouseEvent *ev);
	void mouseMoveEvent(QMouseEvent *ev);
	void mouseReleaseEvent(QMouseEvent *ev);
	void keyPressEvent(QKeyEvent *ev);
	void contextMenuEvent(QContextMenuEvent *ev);

private:
	void initViewer();                         //初始化
	void saveROIImage();                       //把ROI区域的图片存储下来
	EmDirection region(const QPoint &point);   //根据鼠标位置设置鼠标形状
	void scaleRect(const QPoint &mousePoint);  //缩放矩形
	void paintRect(const QPoint &mousePoint);  //绘制矩形
	void moveRect(const QPoint &mousePoint);   //移动矩形

private:
	bool m_bPainterPressed;        //是否正在绘制
	bool m_bMovedPressed;          //是否正在拖动
	bool m_bScalePressed;          //是否正在缩放大小
	QPoint m_paintStartPoint;      //绘制的初始位置
	QPoint m_moveStartPoint;       //拖动的初始位置
	QRect m_roiRect;               //绘制的ROI
	EmDirection m_emCurDir;        //拖动的方向

	QImage m_backImage;            //背景图

	QMenu *m_pOptMenu;
	QAction *m_pDelAction;
	QAction *m_pSaveAction;
};
///MyLabel.cpp

#include "MyLabel.h"
#include <QPainter>
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <QStandardPaths>
#include <QFileDialog>
#include <QDebug>

MyLabel::MyLabel(QWidget *parent)
	: QLabel(parent)
{
	this->initViewer();
}

MyLabel::~MyLabel()
{
}

void MyLabel::initViewer()
{
	m_bPainterPressed = false;
	m_bMovedPressed = false;
	m_bScalePressed = false;
	m_roiRect = QRect(0, 0, 0, 0);
	m_emCurDir = EmDirection::DIR_NONE;

	this->setMouseTracking(true);
	this->setFocusPolicy(Qt::StrongFocus);

	m_pOptMenu = new QMenu(this);
	m_pDelAction = new QAction(QStringLiteral("删除"), this);
	connect(m_pDelAction, &QAction::triggered, this, [&]() { m_roiRect = QRect(0, 0, 0, 0); });
	m_pSaveAction = new QAction(QStringLiteral("保存"), this);
	connect(m_pSaveAction, &QAction::triggered, this, &MyLabel::saveROIImage);

	m_pOptMenu->addAction(m_pDelAction);
	m_pOptMenu->addAction(m_pSaveAction);
}

/**
 * @brief				保存roi图形
 *
 * @return				void
 */
void MyLabel::saveROIImage()
{
	QString fileName = QFileDialog::getSaveFileName(this, "Save", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation), "*.png");
	if (fileName.isEmpty())
	{
		return;
	}

	QImage saveImg = m_backImage.copy(m_roiRect);
	saveImg.save(fileName);
}

/**
 * @brief				获取绘制的矩形
 *
 * @return				绘制的矩形
 */
QRect MyLabel::getRoiRect() const
{
	return m_roiRect;
}

/**
 * @brief				设置背景图片
 * @param img        	QImage图片
 *
 * @return				void
 */
void MyLabel::setBackImage(const QImage & img)
{
	m_backImage = img;
    this->setMinimumSize(img.width(), img.height());
	update();
}

/**
 * @brief				绘制矩形
 * @param event         绘图事件
 *
 * @return				void
 */
void MyLabel::paintEvent(QPaintEvent * event)
{
#if 1
	QLabel::paintEvent(event);

	if (m_backImage.isNull())
		return;

	QPixmap rawImg = QPixmap::fromImage(m_backImage);
	QString strPoint = QString("X:%0, Y:%1").arg(m_roiRect.x()).arg(m_roiRect.y());           //位置信息
	QString strSize = QString("W:%0, H:%1").arg(m_roiRect.width()).arg(m_roiRect.height());   //大小信息

	QPen pen;
	pen.setColor(Qt::yellow);
	pen.setWidth(EDGE_WIDTH);
	
	QFont font;
	font.setPixelSize(16);

	QPainter painter;
	painter.begin(this);
	painter.setBrush(QBrush(QColor(0, 0, 200, 120)));
	painter.setPen(pen);
	painter.setFont(font);
	painter.drawPixmap(0, 0, rawImg);
	painter.drawText(m_roiRect.topLeft().x(), m_roiRect.topLeft().y() - 5, strSize);
	painter.drawText(m_roiRect.topLeft().x(), m_roiRect.topLeft().y() - 18, strPoint);
	painter.drawRect(m_roiRect);

	if (m_roiRect.width() != 0 && m_roiRect.height() != 0)
	{
#ifdef DRAW_SUB_LINE
		//绘制中间十字架
		QPen dashPen(Qt::white);
		dashPen.setWidth(MIDDLELINE_WIDTH);
		dashPen.setStyle(Qt::DashDotLine);
		painter.setPen(dashPen);
		painter.drawLine(m_roiRect.topLeft().x() + m_roiRect.width() / 2, m_roiRect.topLeft().y() + EDGE_WIDTH, m_roiRect.bottomRight().x() - m_roiRect.width() / 2, m_roiRect.bottomRight().y());
		painter.drawLine(m_roiRect.topLeft().x() + EDGE_WIDTH, m_roiRect.topLeft().y() + m_roiRect.height() / 2, m_roiRect.bottomRight().x(), m_roiRect.bottomRight().y() - m_roiRect.height() / 2);
#endif

#ifdef DRAW_TEN_POINT
		//绘制边缘十个点
		painter.setBrush(Qt::green);
		pen.setWidth(0);
		painter.setPen(pen);

		painter.drawRect(m_roiRect.topLeft().x(), m_roiRect.topLeft().y(), POINT_WIDTH, POINT_HEIGHT); //左上角
		painter.drawRect(m_roiRect.topLeft().x(), m_roiRect.topLeft().y() + m_roiRect.height() / 2 - POINT_WIDTH / 2, POINT_WIDTH, POINT_HEIGHT); //左边中心点
		painter.drawRect(m_roiRect.bottomLeft().x(), m_roiRect.bottomLeft().y()- POINT_WIDTH, POINT_WIDTH, POINT_HEIGHT); //左下角
		painter.drawRect(m_roiRect.topLeft().x() + m_roiRect.width() / 2 - POINT_WIDTH / 2, m_roiRect.topLeft().y(), POINT_WIDTH, POINT_HEIGHT);  //顶部中心
		painter.drawRect(m_roiRect.topLeft().x() + m_roiRect.width() / 2 - POINT_WIDTH /2, m_roiRect.topLeft().y() + m_roiRect.height() / 2 - POINT_WIDTH / 2, POINT_WIDTH, POINT_HEIGHT);  //中心点
		painter.drawRect(m_roiRect.bottomLeft().x() + m_roiRect.width() / 2 - POINT_WIDTH / 2, m_roiRect.bottomLeft().y() - POINT_WIDTH, POINT_WIDTH, POINT_HEIGHT); //底部中心点
		painter.drawRect(m_roiRect.topRight().x() - POINT_WIDTH, m_roiRect.topRight().y(), POINT_WIDTH, POINT_HEIGHT); //右上角
		painter.drawRect(m_roiRect.topRight().x() - POINT_WIDTH / 2, m_roiRect.topRight().y() + m_roiRect.height() / 2 - POINT_WIDTH /2, POINT_WIDTH, POINT_HEIGHT); //右边中心点
		painter.drawRect(m_roiRect.bottomRight().x() - POINT_WIDTH, m_roiRect.bottomRight().y() - POINT_WIDTH, POINT_WIDTH, POINT_HEIGHT); //右下角点
#endif
	}
	

	painter.end();

	qDebug() << m_roiRect;
#else
	QLabel::paintEvent(event);

	if (m_backImage.isNull())
		return;
	QPixmap rawImg = QPixmap::fromImage(m_backImage);
	QPainter painter(this);
	painter.begin(&rawImg);
	painter.setBrush(Qt::gray);
	painter.drawRect(30,30,100,100);
	painter.end();
	this->setPixmap(rawImg);
#endif
}

/**
 * @brief				鼠标按下事件 用于拖动绘制缩放起始
 * @param ev	        鼠标事件
 *
 * @return				void
 */
void MyLabel::mousePressEvent(QMouseEvent * ev)
{
	if (ev->buttons() & Qt::LeftButton)
	{
		EmDirection dir = region(ev->pos());     //获取鼠标当前的位置

		if (dir == DIR_MIDDLE)
		{
			//鼠标在矩形中心位置
			this->setCursor(Qt::ClosedHandCursor);
			m_moveStartPoint.setX(ev->pos().x());
			m_moveStartPoint.setY(ev->pos().y());
			m_bMovedPressed = true;
		}
		else if (dir == DIR_NONE)
		{
			//鼠标在矩形外部
			this->setCursor(Qt::ArrowCursor);
			m_bPainterPressed = true;
			m_paintStartPoint.setX(ev->pos().x());
			m_paintStartPoint.setY(ev->pos().y());
		}
		else
		{
			//矩形在矩形边缘
			m_moveStartPoint.setX(ev->pos().x());
			m_moveStartPoint.setY(ev->pos().y());
			m_bScalePressed = true;
			m_emCurDir = dir;
		}
	}
}

/**
 * @brief				鼠标移动事件
 * @param ev         	鼠标事件
 *
 * @return				void
 */
void MyLabel::mouseMoveEvent(QMouseEvent * ev)
{
	if (ev->buttons() & Qt::LeftButton)
	{
		if (m_bPainterPressed)
		{
			//正在绘制状态
			paintRect(ev->pos());
			
		}
		else if (m_bMovedPressed)
		{
			//正在移动状态
			moveRect(ev->pos());
		}
		else if (m_bScalePressed)
		{
			//正在缩放大小状态
			scaleRect(ev->pos());
		}

		//更新界面
		update();
		return;
	}

	//根据鼠标的位置设置当前的鼠标形状
	EmDirection dir = region(ev->pos());

	if (dir == DIR_NONE)
	{
		setCursor(Qt::ArrowCursor);
	}
	else if (dir == DIR_MIDDLE)
	{
		setCursor(Qt::OpenHandCursor);
	}
}

/**
 * @brief				鼠标松开事件
 * @param ev	        鼠标事件
 *
 * @return				void
 */
void MyLabel::mouseReleaseEvent(QMouseEvent * ev)
{
	//判断鼠标是否在矩形中
	if (m_roiRect.contains(ev->pos()))
	{
		//松开鼠标前是否正在拖放
		if (m_bMovedPressed)
		{
			this->setCursor(Qt::OpenHandCursor);
		}
		else
		{
			this->setCursor(Qt::ArrowCursor);
		}
	}

	m_paintStartPoint = QPoint();
	m_bMovedPressed = false;
	m_bPainterPressed = false;
	m_bScalePressed = false;
}

/**
 * @brief				键盘按下事件
 * @param ev	        键盘事件
 *
 * @return				void
 */
void MyLabel::keyPressEvent(QKeyEvent * ev)
{
	if (ev->key() == Qt::Key_Delete)
	{
		m_roiRect = QRect(0,0,0,0);
		update();
	}
}

/**
 * @brief				右键菜单
 * @param ev	        菜单事件
 *
 * @return				void
 */
void MyLabel::contextMenuEvent(QContextMenuEvent * ev)
{
	QPoint mousePos = ev->pos();

	if (m_roiRect.contains(mousePos))
	{
		m_pOptMenu->exec(QCursor::pos());
	}
	
	ev->accept();
}

/**
 * @brief				判断鼠标的位置
 * @param point         鼠标的位置	
 *
 * @return				EmDirection 方向
 */
EmDirection MyLabel::region(const QPoint & point)
{
	int mouseX = point.x();
	int mouseY = point.y();

	QPoint roiTopLeft = m_roiRect.topLeft();
	QPoint roiBottomRight = m_roiRect.bottomRight();

	EmDirection dir = DIR_NONE;

	if (mouseX <= roiTopLeft.x() + CORPADDING && mouseX >= roiTopLeft.x() && mouseY <= roiTopLeft.y() + CORPADDING && mouseY >= roiTopLeft.y())
	{
		//左上角
		this->setCursor(Qt::SizeFDiagCursor);
		dir = DIR_LEFTTOP;
	}
	else if (mouseX >= roiBottomRight.x() - CORPADDING && mouseX < roiBottomRight.x() && mouseY <= roiTopLeft.y() + CORPADDING && mouseY >= roiTopLeft.y())
	{
		//右上角
		this->setCursor(Qt::SizeBDiagCursor);
		dir = DIR_RIGHTTOP;
	}
	else if (mouseX <= roiTopLeft.x() + CORPADDING && mouseX >= roiTopLeft.x() && mouseY >= roiBottomRight.y() - CORPADDING && mouseY <= roiBottomRight.y())
	{
		//左下角
		this->setCursor(Qt::SizeBDiagCursor);
		dir = DIR_LEFTBOTTOM;
	}
	else if (mouseX >= roiBottomRight.x() - CORPADDING && mouseX < roiBottomRight.x() && mouseY >= roiBottomRight.y() - CORPADDING && mouseY <= roiBottomRight.y())
	{
		//右下角
		this->setCursor(Qt::SizeFDiagCursor);
		dir = DIR_RIGHTBOTTOM;
	}
	else if (mouseX >= roiBottomRight.x() - EDGPADDING && mouseX <= roiBottomRight.x() && mouseY >= roiTopLeft.y() && mouseY <= roiBottomRight.y())
	{
		//右边
		this->setCursor(Qt::SizeHorCursor);
		dir = DIR_RIGHT;
	}
	else if (mouseY <= roiTopLeft.y() + EDGPADDING && mouseY >= roiTopLeft.y() && mouseX >= roiTopLeft.x() && mouseX <= roiBottomRight.x())
	{
		//上边
		this->setCursor(Qt::SizeVerCursor);
		dir = DIR_TOP;
	}
	else if (mouseY >= roiBottomRight.y() - EDGPADDING && mouseY <= roiBottomRight.y() && mouseX >= roiTopLeft.x() && mouseX <= roiBottomRight.x())
	{
		//下边
		this->setCursor(Qt::SizeVerCursor);
		dir = DIR_BOTTOM;
	}
	else if (mouseX <= roiTopLeft.x() + EDGPADDING && mouseX >= roiTopLeft.x() && mouseY >= roiTopLeft.y() && mouseY <= roiBottomRight.y())
	{
		//左边
		this->setCursor(Qt::SizeHorCursor);
		dir = DIR_LEFT;
	}
	else if(m_roiRect.contains(point))
	{
		//中间
		dir = DIR_MIDDLE;
	}
	else
	{
		dir = DIR_NONE;
	}

	return dir;
}

/**
 * @brief				缩放矩形
 * @param mousePoint    鼠标的位置
 *
 * @return				void
 */
void MyLabel::scaleRect(const QPoint & mousePoint)
{
	QRect newRect(m_roiRect.topLeft(), m_roiRect.bottomRight());
	int width = mousePoint.x() - m_moveStartPoint.x();   //移动的宽度
	int height = mousePoint.y() - m_moveStartPoint.y();  //移动的高度

	//根据当前的缩放状态来改变矩形的位置大小信息
	switch (m_emCurDir)
	{
	case DIR_LEFT:
		newRect.setLeft(mousePoint.x());
		break;
	case DIR_RIGHT:
		newRect.setRight(mousePoint.x());
		break;
	case DIR_TOP:
		newRect.setTop(mousePoint.y());
		break;
	case DIR_BOTTOM:
		newRect.setBottom(mousePoint.y());
		break;
	case DIR_LEFTTOP:
		newRect.setTopLeft(mousePoint);
		break;
	case DIR_LEFTBOTTOM:
		newRect.setBottomLeft(mousePoint);
		break;
	case DIR_RIGHTTOP:
		newRect.setTopRight(mousePoint);
		break;
	case DIR_RIGHTBOTTOM:
		newRect.setBottomRight(mousePoint);
		break;
	}

	if (newRect.width() < MIN_WIDTH || newRect.height() < MIN_HEIGHT)
	{
		//缩放的大小限制
		return;
	}

	m_roiRect = newRect;
	m_moveStartPoint = mousePoint;  //更新鼠标的起始位置
}

/**
 * @brief				绘制矩形
 * @param mousePoint    鼠标的位置
 *
 * @return				void
 */
void MyLabel::paintRect(const QPoint & mousePoint)
{
	this->setCursor(Qt::ArrowCursor);                    //设置鼠标为指针形状

	int width = mousePoint.x() - m_paintStartPoint.x();  //移动的宽度
	int height = mousePoint.y() - m_paintStartPoint.y(); //移动的高度

	if (width < 0 && height < 0)
	{
		//鼠标向左上角移动
		m_roiRect.setX(mousePoint.x());
		m_roiRect.setY(mousePoint.y());
	}
	else if (width < 0)
	{
		//鼠标向负X位置移动
		m_roiRect.setX(mousePoint.x());
		m_roiRect.setY(m_paintStartPoint.y());
	}
	else if (height < 0)
	{
		//鼠标向负Y位置移动
		m_roiRect.setX(m_paintStartPoint.x());
		m_roiRect.setY(mousePoint.y());
	}
	else
	{
		//正常  向右下移动
		m_roiRect.setX(m_paintStartPoint.x());
		m_roiRect.setY(m_paintStartPoint.y());
	}

	//设置矩形大小 绝对值 避免反方向的产生的负值
	m_roiRect.setSize(QSize(abs(width), abs(height)));
}

/**
 * @brief				绘制矩形
 * @param mousePoint    鼠标的位置
 *
 * @return				void
 */
void MyLabel::moveRect(const QPoint & mousePoint)
{
	this->setCursor(Qt::ClosedHandCursor);

	int width = mousePoint.x() - m_moveStartPoint.x();
	int height = mousePoint.y() - m_moveStartPoint.y();

	QRect ret;
	ret.setX(m_roiRect.x() + width);
	ret.setY(m_roiRect.y() + height);
	ret.setSize(m_roiRect.size());
	m_roiRect = ret;
	m_moveStartPoint = mousePoint;
}

3 其他说明

提供示例1 示例2 的源码,可以在以下链接下载资源,本地环境 QT6 , QT5也可以。

文章下载链接: https://download.csdn.net/download/qq_37529913/86810065

解压密码:123456

本文没有提提供示例3源码,因为准备在公司内部分析,所以不放示例3源代码。

在研究玩示例1和示例2之后大概率可以完成类似博主做完的效果。

有其它问题请留言。

  • 6
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在使用Qt和Halcon进行图像处理时,可以通过在窗口上绘制ROI(兴趣区域)来选择特定区域进行分析和处理。 首先,需要在Qt的窗口中创建一个用于显示图像的QLabel控件。然后,通过Halcon的API函数,将图像从Halcon的数据类型转换为Qt能够显示的数据类型,并将其显示在QLabel控件上。 接下来,可以使用Qt的绘图功能来实现ROI绘制。一种常用的方法是使用鼠标事件来捕捉用户的交互操作。通过重写QLabel控件的鼠标事件函数,可以监听鼠标按下、移动和释放的动作,并根据鼠标的位置在窗口上绘制ROI。 具体操作包括: 1. 在QLabel控件的构造函数中设置鼠标追踪功能,以便能够捕捉到鼠标移动的事件。 2. 重写QLabel控件的鼠标事件函数,例如mousePressEvent、mouseMoveEvent和mouseReleaseEvent函数。在这些函数中,根据鼠标的位置和操作来绘制ROI。 3. 定义一个ROI类,用于保存ROI的坐标和属性。每次鼠标操作(按下、移动和释放)时,更新ROI的坐标和属性,并在窗口上重绘ROI。 4. 根据应用的需求,可以使用不同的图形绘制API,例如Qt的绘图函数或Halcon的绘图函数,来绘制ROI。例如,可以使用Qt的QPainter对象在窗口上绘制矩形、圆形等形状。 5. 在窗口上绘制ROI后,可以通过ROI的坐标和属性,对选择的区域进行进一步的处理和分析。 通过上述步骤,我们可以在Qt和Halcon的结合中实现窗口绘制ROI的功能,以实现图像处理中对特定区域的选择和分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双子座断点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值