Qt 结合 OpenCV 的 Mat 对象绘制旋转矩形 ROI 区域

TB_DrawRotateRect 表示绘制旋转矩形类,在 QLabel 上实现绘制功能。其中,拖到 p0 点能实现旋转矩形的移动;拖到 p1、p2 能实现旋转矩形大小和位置的变化;拖到 p3、p4 能实现旋转矩形长度大小的变化。

// qScrollArea 实现图像的放大缩小显示
QScrollArea* qScrollArea=new QScrollArea(ui->framePicture);
QHBoxLayout* layout=new QHBoxLayout(ui->framePicture);
layout->addWidget(qScrollArea);
//qLabelView 表示图像的显示容器
QLabel* qLabelView=new QLabel(qScrollArea);
qLabelView->setScaledContents(true);
qLabelView->setBackgroundRole(QPalette::Background);
qLabelView->setFrameStyle(QFrame::StyledPanel);
qLabelView->setFrameShadow(QFrame::Sunken);
qLabelView->setGeometry(0, 0, qScrollArea->width(), qScrollArea->height());
qScrollArea->setWidget(qLabelView);
//旋转矩形的参数类
GRotateRectangle rect; 
//Opencv 的图像类
Mat image; 
//qDrawView 表示圆形绘制的对象
TB_DrawRotateRect* qDrawView=new TB_DrawRotateRect(qLabelView, &rect, &image);
qDrawView->setParent(qLabelView);
qDrawView->setWindowFlags(Qt::WindowStaysOnTopHint);
qDrawView->setAttribute(Qt::WA_TranslucentBackground,true);
qDrawView->setStyleSheet("background-color:transparent");

GRotateRectangle 类对象表示旋转矩形的参数对象

#define MOUSE_LENGTH_LEN 10
#define MOUSE_RADIU_LEN  5

//旋转矩形
class GRotateRectangle
{
public:
    GRotateRectangle();
    ~GRotateRectangle(){}
private:
    Point2f p0;
    Point2f p1;
    Point2f p2;
    Point2f p3;
    Point2f p4;
private:
    void UpdataPoint2fApi();
    void Arrow(QPointF p1, QPointF p2, QPointF &p3, QPointF &p4);
public: 
    void SetPosLimit(Size imageSize);
    void GetMinLength(Point2f p, float& length, int& index);
    void DragPointApi(QPointF point, Size imageSize, Size labelSize);
    void DrawApi(QPainter* painter, QColor color1, QColor color2, Size imageSize, Size labelSize);
public:
    Point2f p1_;
    Point2f p2_;
    float measureLength1;
    float measureLength2;
    bool oriented;
    bool arrowed;
};

//初始化
GRotateRectangle::GRotateRectangle()
{
    oriented=false;
    arrowed=false;
    measureLength1=100;
    measureLength2=10;
    p1_=Point2f(200 - measureLength1, 200);
    p2_=Point2f(200 + measureLength1, 200);
    p1=p1_;
    p2=p2_;
}

//更新点状态
void GRotateRectangle::UpdataPoint2fApi()
{
    p0=Point2f((p1.x + p2.x)/2, (p1.y + p2.y)/2);
    p3=Point2f(p0.x, p0.y - measureLength1);
    p4=Point2f(p0.x, p0.y + measureLength1);
    float x=p2.x-p0.x;
    float y=p2.y-p0.y;
    double a=atan2(y, x)*180.0/CV_PI;
    a = a<0 ? (360 + a) : a;
    p3=cvPointRotate(p3, p0, a);
    p4=cvPointRotate(p4, p0, a);
}

//获取最近距离
void GRotateRectangle::GetMinLength(Point2f p, float& length, int& index)
{
    vector<Point2f> sorts;
    sorts.push_back(p0);
    sorts.push_back(p1);
    sorts.push_back(p2);
    sorts.push_back(p3);
    sorts.push_back(p4);
    length=10e9;
    index=-1;
    for(size_t i=0;i<sorts.size();i++)
    {
        float l=cvPointDistance(p, sorts[i]);
        if(l<=length)
        {
            length=l;
            index=(int)i;
        }
    }
}

//箭头
void GRotateRectangle::Arrow(QPointF p1, QPointF p2, QPointF &p3, QPointF &p4)
{
    QLineF line(p1, p2);
    double angle=acos(line.dx()/line.length());
    angle = line.dy()>=0 ? (2.0*QM_PI - angle) : angle;
    float len=QPointDistance(p1, p2) / MOUSE_RADIU_LEN;
    len = len<=1 ? 1 : len;
    p3=p2 + QPointF(sin(angle - QM_PI/3)*len, cos(angle - QM_PI/3)*len);
    p4=p2 + QPointF(sin(angle - QM_PI + QM_PI/3)*len, cos(angle - QM_PI + QM_PI/3)*len);
}

//设置限制
void GRotateRectangle::SetPosLimit(Size imageSize)
{
    int w=imageSize.width;
    int h=imageSize.height;
    if(w==0 || h==0)
        return;
    p1.x = p1.x<0 ? 0 : (p1.x>=w ? w-1 : p1.x);
    p2.x = p2.x<0 ? 0 : (p2.x>=w ? w-1 : p2.x);
    p1.y = p1.y<0 ? 0 : (p1.y>=h ? h-1 : p1.y);
    p2.y = p2.y<0 ? 0 : (p2.y>=h ? h-1 : p2.y);
    if(p1.x==p2.x && p1.y==p2.y && (p1.x==0 || p1.x==w-1) && (p1.y==0 || p1.y==h-1))
    {
        p1=Point2f(w/2 - 10, h/2);
        p2=Point2f(w/2 + 10, h/2);
    }
    float l=(float)sqrt((double)(w*w + h*h))/2;
    measureLength1 = measureLength1>l ? l : measureLength1;
}

//拖动点位置, sX表示图像宽度/控件宽度, sY表示图像高度/控件高度
void GRotateRectangle::DragPointApi(QPointF point, Size imageSize, Size labelSize)
{
    float sX=(float)imageSize.width/labelSize.width;
    float sY=(float)imageSize.height/labelSize.height;
    float sZ=(sX + sY)/2;
    Point2f p(point.x()*sX, point.y()*sY);
    int index;
    float length;
    this->GetMinLength(p, length, index);
    if(length<=(MOUSE_LENGTH_LEN*sZ))
    {
        switch(index)
        {
        case 0:
        {
            float x=p.x-p0.x;
            float y=p.y-p0.y;
            p1=Point2f(p1.x+x, p1.y+y);
            p2=Point2f(p2.x+x, p2.y+y);
            break;
        }
        case 1:
            p1=Point2f(p.x, p.y);
            break;
        case 2:
            p2=Point2f(p.x, p.y);
            break;
        case 3:
        case 4:
            measureLength1=cvPointDistance(p, p0);
            break;
        default:
            break;
        }
    }
    //限制位置尺寸大小
    this->SetPosLimit(imageSize);
}

//绘图
void GRotateRectangle::DrawApi(QPainter* painter, QColor color1, QColor color2, Size imageSize, Size labelSize)
{
    float sX=(float)imageSize.width/labelSize.width;
    float sY=(float)imageSize.height/labelSize.height;
    if(!(labelSize.width>0 && imageSize.width>0))
        return;
    //更新位置点
    this->UpdataPoint2fApi();
    //实际点装换为灰度点
    QPointF P0(p0.x/sX, p0.y/sY);
    QPointF P1(p1.x/sX, p1.y/sY);
    QPointF P2(p2.x/sX, p2.y/sY);
    QPointF P3(p3.x/sX, p3.y/sY);
    QPointF P4(p4.x/sX, p4.y/sY);
    //初始化绘图工具
    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setPen(color1);
    //关键点1
    QRectF rect3(P0.x()-MOUSE_RADIU_LEN, P0.y()-MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN);
    painter->drawEllipse(rect3);
    QRectF rect4(P1.x()-MOUSE_RADIU_LEN, P1.y()-MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN);
    painter->drawEllipse(rect4);
    QRectF rect5(P2.x()-MOUSE_RADIU_LEN, P2.y()-MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN);
    painter->drawEllipse(rect5);
    //关键点2
    painter->setPen(color2);
    QRectF rect1(P3.x()-MOUSE_RADIU_LEN, P3.y()-MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN);
    painter->drawEllipse(rect1);
    QRectF rect2(P4.x()-MOUSE_RADIU_LEN, P4.y()-MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN, 2*MOUSE_RADIU_LEN);
    painter->drawEllipse(rect2);
    //边框直线
    QPointF l1=QPointF(P1.x() + P3.x() - P0.x(), P1.y() + P3.y() - P0.y());
    QPointF l2=QPointF(P1.x() + P4.x() - P0.x(), P1.y() + P4.y() - P0.y());
    QPointF l3=QPointF(P2.x() + P4.x() - P0.x(), P2.y() + P4.y() - P0.y());
    QPointF l4=QPointF(P2.x() + P3.x() - P0.x(), P2.y() + P3.y() - P0.y());
    painter->drawLine(l1, l2);
    painter->drawLine(l2, l3);
    painter->drawLine(l3, l4);
    painter->drawLine(l4, l1);
    //判断是否画箭头直线
    if(!arrowed)
        return;
    //画箭头线
    QPointF l5=QPointF((l1.x() + P3.x())/2, (l1.y() + P3.y())/2);
    QPointF l6=QPointF((l2.x() + P4.x())/2, (l2.y() + P4.y())/2);
    QPointF l7=QPointF(P3.x(), P3.y());
    QPointF l8=QPointF(P4.x(), P4.y());
    QPointF l9=QPointF((l4.x() + P3.x())/2, (l4.y() + P3.y())/2);
    QPointF l10=QPointF((l3.x() + P4.x())/2, (l3.y() + P4.y())/2);
    painter->drawLine(l5, l6);
    painter->drawLine(l7, l8);
    painter->drawLine(l9, l10);
    //箭头方向
    QPointF s1 = oriented ? l5 : l6;
    QPointF e1 = oriented ? l6 : l5;
    QPointF s2 = oriented ? l7 : l8;
    QPointF e2 = oriented ? l8 : l7;
    QPointF s3 = oriented ? l9 : l10;
    QPointF e3 = oriented ? l10 : l9;
    QPointF a1, a2, a3, a4, a5, a6;
    this->Arrow(s1, e1, a1, a2);
    this->Arrow(s2, e2, a3, a4);
    this->Arrow(s3, e3, a5, a6);
    painter->drawLine(a1, e1);
    painter->drawLine(a2, e1);
    painter->drawLine(a3, e2);
    painter->drawLine(a4, e2);
    painter->drawLine(a5, e3);
    painter->drawLine(a6, e3);
}

TB_DrawRotateRect 类实现拖到、绘制等功能

class TB_DrawRotateRect : public QWidget
{
    Q_OBJECT
public:
    explicit TB_DrawRotateRect(QWidget* parent, GRotateRectangle* rect, Mat* image);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
    void paintEvent(QPaintEvent *event);
    ~TB_DrawRotateRect(){}
public:
    GRotateRectangle* pGraphic;
    Mat* pImageSize;
};

//初始化
TB_DrawRotateRect::TB_DrawRotateRect(QWidget* parent, GRotateRectangle* rect, Mat* image) :
    QWidget(parent), pImageSize(image),
    pGraphic(rect)
{}

//鼠标移动
void TB_DrawRotateRect::mouseMoveEvent(QMouseEvent *e)
{
    if(!(e->buttons() & Qt::LeftButton))
        return;
    int x=e->x();
    int y=e->y();
    if(x<0 || y<0 || x>this->width() || y>this->height() || !pImageSize)
        return;
    QPointF point(x, y);
    Size imageSize(pImageSize->cols, pImageSize->rows);
    Size labelSize(this->width(), this->height());
    pGraphic->DragPointApi(point, imageSize, labelSize);
}

//鼠标释放
void TB_DrawRotateRect::mouseReleaseEvent(QMouseEvent *e)
{
    e->accept();
}

//鼠标绘制
void TB_DrawRotateRect::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    if(!pImageSize)
        return;
    Size imageSize(pImageSize->cols, pImageSize->rows);
    Size labelSize(this->width(), this->height());
    pGraphic->DrawApi(&painter, Qt::blue, Qt::red, imageSize, labelSize);
    this->update();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刚出道的菜鸟@丢丢

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

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

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

打赏作者

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

抵扣说明:

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

余额充值