当前位置:   article > 正文

Qt QGraphicsScene 基于视频的绘图

Qt QGraphicsScene 基于视频的绘图

需求:

基于视频进行 图形的绘制。

方案:

 上一篇文章分享了如何将视频实时渲染到QGraphicsScene 系统里,并简单讲述了如何进行绘图,但在实际使用时还是发现了一些技巧,现在总结一下。

Qt 基于海康相机 的视频标绘-CSDN博客文章浏览阅读652次,点赞6次,收藏6次。利用qml 基于opengl 进行渲染,可以达到任意图形的绘制,但是帧率 只有25帧左右。如今要开发光学测量仪,发现使用QGraphicsPixmapItem 进行图片的渲染,可以利用QGraphicsItem 进行任务图形的叠加绘制,并且帧率目测大概在25帧所有,满足需求。曾经搞在线教育时,尝试在视频上进行文字或者图形的绘制,但是发现利用Qt widget 传sdk 句柄的方式,只能使用窗口叠加的方式(同时将QGraphicsPixmapItem放到最底层,即可达到在上边绘制任意图形的目的。https://blog.csdn.net/weixin_38416696/article/details/135844799?spm=1001.2014.3001.55021,效果

直线:

矩形:

圆:

弧:

2,实现

定义一个控制点,用于旋转或者改变大小。开始也尝试了 通过hover事件 来改变鼠标形状,但是这样判断地方有点多,通过使用控制点的方式,实现起来相对简单,使用上也还可以。

  1. #ifndef BPOINTITEM_H
  2. #define BPOINTITEM_H
  3. #include <QObject>
  4. #include <QAbstractGraphicsShapeItem>
  5. #include <QPointF>
  6. #include <QPen>
  7. #include <QPainter>
  8. #include <QGraphicsSceneMouseEvent>
  9. #include <QGraphicsScene>
  10. #include <QCursor>
  11. #include <QKeyEvent>
  12. #include <QList>
  13. #include <QMutex>
  14. #include <QThread>
  15. //控制点
  16. class EPointItem :public QObject, public QGraphicsItem {
  17. Q_OBJECT
  18. public:
  19. enum class PointType{
  20. MovePoint=0,
  21. RotatePoint=1
  22. };
  23. EPointItem(QGraphicsItem* parent, QPointF p,PointType type = PointType::MovePoint);
  24. public:
  25. virtual QRectF boundingRect() const override;
  26. virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
  27. virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
  28. virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
  29. virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
  30. signals:
  31. void posMove(QPointF curPos, QPointF lastPos);
  32. void posRotate(QPointF curPos,QPointF lastPos);
  33. void posRelease();
  34. private:
  35. PointType m_type;
  36. };
  37. #endif // BPOINTITEM_H
  38. #include "bpointitem.h"
  39. #include <QDebug>
  40. #include <QtMath>
  41. EPointItem::EPointItem(QGraphicsItem* parent, QPointF p,PointType type)
  42. : QGraphicsItem(parent),m_type(type)
  43. {
  44. this->setPos(p);
  45. this->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
  46. this->setCursor(Qt::PointingHandCursor);
  47. }
  48. QRectF EPointItem::boundingRect() const
  49. {
  50. if(m_type==PointType::MovePoint){
  51. return QRectF(-4, -4, 8, 8);
  52. }else if(m_type==PointType::RotatePoint){
  53. return QRectF(-8, -8, 16, 16);
  54. }else{
  55. return QRectF(-4, -4, 8, 8);
  56. }
  57. }
  58. void EPointItem::mousePressEvent(QGraphicsSceneMouseEvent* event) {
  59. setSelected(true);
  60. QGraphicsItem::mousePressEvent(event);
  61. }
  62. void EPointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
  63. emit posRelease();
  64. setSelected(false);
  65. QGraphicsItem::mouseReleaseEvent(event);
  66. }
  67. void EPointItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
  68. {
  69. Q_UNUSED(option);
  70. Q_UNUSED(widget);
  71. if (isSelected()) {
  72. painter->setBrush(QBrush(Qt::green));
  73. }
  74. else {
  75. painter->setBrush(QBrush(Qt::white));
  76. }
  77. if(m_type==PointType::MovePoint){
  78. painter->setPen(QPen(Qt::gray, 1));
  79. painter->drawEllipse(-4, -4, 8, 8);
  80. }else if(m_type==PointType::RotatePoint){
  81. painter->setPen(QPen(Qt::gray, 2));
  82. painter->drawEllipse(-8, -8, 16, 16);
  83. painter->drawEllipse(-4, -4, 8, 8);
  84. }
  85. }
  86. void EPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
  87. if (event->buttons() == Qt::LeftButton) {
  88. if(m_type==PointType::MovePoint)
  89. emit posMove(event->scenePos(), event->lastScenePos());
  90. else if(m_type==PointType::RotatePoint){
  91. emit posRotate(event->scenePos(), event->lastScenePos());
  92. }
  93. }
  94. }

 以直线为例,实现的时候 先画一个普通的矩形,然后添加两个控制点,用于改变大小和旋转,通过控制点中 推拽的信号 来改变矩形的大小和旋转的角度,并且在矩形的paint函数中,更新控制点的位置。

  1. class EItemUtil{
  2. public:
  3. void rotateItem(QGraphicsItem* item,QPointF &curPos, QPointF &lastPos){
  4. // 设置中心点为原点
  5. QPointF originPos = item->boundingRect().center();
  6. // 从原点延伸出去两条线
  7. QLineF p1 = QLineF(originPos, item->mapFromScene(lastPos));
  8. QLineF p2 = QLineF(originPos, item->mapFromScene(curPos));
  9. // 两条线的夹角 为旋转角度
  10. qreal dRotateAngle = p2.angleTo(p1);
  11. item->setTransformOriginPoint(originPos);
  12. qreal dCurAngle = item->rotation() + dRotateAngle;
  13. while (dCurAngle > 360.0) {
  14. dCurAngle -= 360.0;
  15. }
  16. item->setRotation(dCurAngle);
  17. item->update();
  18. }
  19. };
  20. //直线
  21. class ELine : public QObject, public QGraphicsRectItem
  22. {
  23. Q_OBJECT
  24. public:
  25. ELine(const QRectF& rect, QGraphicsItem* parent = nullptr);
  26. protected:
  27. void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
  28. private:
  29. EPointItem* resizeItem;
  30. EPointItem* rotateItem;
  31. EItemUtil util;
  32. private:
  33. //改变大小后 旋转中心会改变,这里要处理一下
  34. void resetCenter();
  35. };
  36. ELine::ELine(const QRectF& rect, QGraphicsItem* parent)
  37. : QGraphicsRectItem(rect, parent)
  38. {
  39. setFlag(QGraphicsItem::ItemIsMovable);
  40. setFlag(QGraphicsItem::ItemSendsGeometryChanges);
  41. setAcceptHoverEvents(true);
  42. //定义一个旋转的控制点
  43. rotateItem = new EPointItem(this,QPointF(this->rect().x()+this->rect().width(), this->rect().y()),EPointItem::PointType::RotatePoint);
  44. connect(rotateItem, &EPointItem::posRotate, this, [this](QPointF curPos, QPointF lastPos) {
  45. util.rotateItem(this,curPos,lastPos);
  46. });
  47. //定义一个改变大小的控制点
  48. resizeItem = new EPointItem(this, QPointF(this->rect().x(), this->rect().y()));
  49. resizeItem->setParentItem(this);
  50. connect(resizeItem, &EPointItem::posMove, this, [&](QPointF curPos, QPointF lastPos) {
  51. this->prepareGeometryChange();
  52. QRectF newRect = this->rect();
  53. qreal dMouseX = mapFromScene(curPos).x();
  54. qreal dMouseY = mapFromScene(curPos).y();
  55. double dRemainWidth = newRect.width();
  56. double dRemainHeight = newRect.height();
  57. dRemainWidth = newRect.right() - dMouseX;
  58. dRemainHeight = newRect.bottom() - dMouseY;
  59. if(dRemainHeight<0||dRemainWidth<0)
  60. return;
  61. newRect.setTopLeft(QPointF(newRect.right() - dRemainWidth, newRect.bottom() - dRemainHeight));
  62. this->setRect(newRect);
  63. });
  64. connect(resizeItem, &EPointItem::posRelease, this, [this]{
  65. resetCenter();
  66. });
  67. }
  68. void ELine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
  69. {
  70. QPen mPen = QPen(Qt::red, 1);
  71. painter->setPen(mPen);
  72. painter->drawRect(rect());
  73. //更新两个控制点的位置
  74. resizeItem->setPos(QPointF(this->rect().x(), this->rect().y()));
  75. rotateItem->setPos(QPointF(this->rect().x()+this->rect().width(), this->rect().y()));
  76. }
  77. void ELine::resetCenter()
  78. {
  79. //处理旋转后,改变大小的导致的旋转中心位置偏差
  80. auto rr = this->boundingRect();
  81. auto angle = this->rotation()*PI/180;
  82. auto p1 = rr.center();
  83. auto origin = this->transformOriginPoint();
  84. QPointF p2 = QPointF(0, 0);
  85. p2.setX(origin.x() + qCos(angle) * (p1.x() - origin.x()) - qSin(angle) * (p1.y() - origin.y()));
  86. p2.setY(origin.y() + qSin(angle) * (p1.x() - origin.x()) + qCos(angle) * (p1.y() - origin.y()));
  87. auto diff = p1 - p2;
  88. this->setRect(rr.adjusted(-diff.x(), -diff.y(), -diff.x(), -diff.y()));
  89. this->setTransformOriginPoint(this->boundingRect().center());
  90. this->update();
  91. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/91735
推荐阅读
相关标签
  

闽ICP备14008679号