Qt+opencv 鼠标画线实现几何图形识别并动态创建

news2024/9/20 16:53:36

前言

使用Qt + OpenCV实现,通过鼠标画线绘制几何图形,然后通过opencv进行图形轮廓识别,返回图形顶点,然后创建对应的几何图形添加到场景中。绘制使用QGraphics体系完成。

看效果图:
在这里插入图片描述


本文demo在这里
点击下载

环境: Qt5.15.2 + vs2019 64bit


支持图形:直线、圆、椭圆、矩形、三角形。
快捷键:数字3 清屏

正文

demo的功能实现流程如下:

在临时画线层绘制,然后将绘制的图形保存成一张临时图片,再将其传给opencv进行轮廓检测,返回轮廓点后再计算出轮廓顶点坐标,将坐标交给Qt层动态创建几何图形,添加到scene中。

opencv下载

本文中需要用到opencv的轮廓识别,所以先要准备好opencv的库,本文下载的是当前最新版本V4.6.0
opencv下载地址

在这里插入图片描述安装后,将其头文件和动态库拷贝到自己的工程项目中,并创建一个pri文件进行管理,也方便其他项目使用。

在这里插入图片描述
这里用到的动态库是opencv_world460.dll

opencv.pri

INCLUDEPATH += $$PWD/include

win32 {
CONFIG(release, debug|release) {
LIBS += -L$$PWD/lib/ -lopencv_world460
}

CONFIG(debug, debug|release) {
LIBS += -L$$PWD/lib/ -lopencv_world460d
}
}

OpenCV轮廓提取算法使用findContours()接口,详情可参考这里

绘制

本文使用QGraphics体系进行鼠标画线,是在之前的博客文章代码基础上复用的
详情参考:

Qt 鼠标/触屏绘制平滑曲线,支持矢量/非矢量方式
Qt实现桌面画线、标记,流畅绘制,支持鼠标和多点触控绘制

检测

调用opencv的接口进行检测

void ShapeDetecter::shapeDetect(string path_to_image)
{
    RNG rng(123);
    // Read image
    Mat3b src = imread(path_to_image);
    // Convert to grayscale
    Mat1b gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    // Binarize
    Mat1b bin;
    threshold(gray, bin, 175, 255, THRESH_OTSU|THRESH_BINARY_INV);
    // Perform thinning
    _thinning(bin, bin);
    // Create result image
//    Mat3b res = src.clone();
    // Find contours
    vector<vector<Point>> contours;
    findContours(bin.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    // For each contour

    if(contours.size() <=0)
        return;
    vector<Point> contour = contours[0];
    for (vector<Point>& contour : contours)
    {
        // Compute convex hull
        vector<Point> hull;
        convexHull(contour, hull);

        // Compute circularity, used for shape classification
        double area = contourArea(hull);
        double perimeter = arcLength(hull, true);
        double circularity = (4 * CV_PI * area) / (perimeter * perimeter);
        // Shape classification
        qDebug() << __FUNCTION__ << "circularity" << circularity;

        if(circularity > 0.85)
        {
            // circle
              RotatedRect rect = fitEllipse(contour);
             _drawCircle(rect.boundingRect());

        }
        else if(circularity > 0.68)
        {
            // Minimum oriented bounding box ...
            RotatedRect rect = minAreaRect(contour);
            Point2f pts[4];
            rect.points(pts);

            QVector<QPoint> points;
            for (int i = 0; i < 4; ++i)
            {
               points.push_back(QPoint( pts[i].x,pts[i].y));
            }

            emit sigDrawPolygon(points);

        }
        else if (circularity > 0.5)
        {
            // TRIANGLE
            // Select the portion of the image containing only the wanted contour
            Rect roi = boundingRect(contour);
            Mat1b maskRoi(bin.rows, bin.cols, uchar(0));
            rectangle(maskRoi, roi, Scalar(255), FILLED);
            Mat1b triangle(roi.height, roi.height, uchar(0));
            bin.copyTo(triangle, maskRoi);

            // Find min encolsing circle on the contour
            Point2f center;
            float radius;
            minEnclosingCircle(contour, center, radius);

            // decrease the size of the enclosing circle until it intersects the contour
            // in at least 3 different points (i.e. the 3 vertices)
            vector<vector<Point>> vertices;
            do
            {
                vertices.clear();
                radius--;

                Mat1b maskCirc(bin.rows, bin.cols, uchar(0));
                circle(maskCirc, center, radius, Scalar(255), 5);

                maskCirc &= triangle;
                findContours(maskCirc.clone(), vertices, RETR_LIST, CHAIN_APPROX_NONE);

            } while (vertices.size() < 3);

            qDebug() << __FUNCTION__ <<"TRIANGLE "<< "vertices_size = " <<vertices.size();
            // Just get the first point in each vertex blob.
            // You could get the centroid for a little better accuracy
            QVector<QPoint> points;
            points.push_back(QPoint(vertices[0][0].x,vertices[0][0].y));
            points.push_back(QPoint(vertices[1][0].x,vertices[1][0].y));
            points.push_back(QPoint(vertices[2][0].x,vertices[2][0].y));
//            emit sigDrawTriangle(points);
            emit sigDrawPolygon(points);
        }
        else
        {
           _drawLine(contours.at(0), boundingRect(contours.at(0)));
        }
    }
}

动态创建图形

从opencv返回顶点接口后,这里直接快捷创建QGraphicsLineItemQGraphicsEllipseItemQGraphicsPolygonItem,也可以自定义QGraphicsItem 然后在paint中进行绘制,自由度更高,比如设置平滑及其他参数等。
可以参考之前的博客
Qt鼠标拖动绘制基本几何图形

void WbCanvasItem::onDrawLine(const QPoint &point1, const QPoint &point2)
{
    auto item = new QGraphicsLineItem(QLineF(point1,point2),this);
    item->setPen(QPen(Qt::red,5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    m_pChildItems.append(item);
}

void WbCanvasItem::onDrawCircle(const QRect &rect)
{
    auto item = new QGraphicsEllipseItem(rect,this);
    item->setPen(QPen(Qt::red,5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    m_pChildItems.append(item);
}

void WbCanvasItem::onDrawPolygon(const QVector<QPoint> &pointVec)
{
    auto item = new QGraphicsPolygonItem(QPolygonF(pointVec),this);
    item->setPen(QPen(Qt::red,5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    m_pChildItems.append(item);
}

本示例通过简单演示整个流程,若运用到实际项目中需要进一步优化。


本文demo在这里
点击下载

环境: Qt5.15.2 + vs2019 64bit


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/60569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python在centos下安装以及配置

python在centos下安装以及配置 1.背景 centos下默认的都是python2.7下载需要更换为3.x使用&#xff0c;目前大部分应用都是基于pyhton3了 具体步骤&#xff1a; 我下载一个3.8.15的包 https://www.python.org/ftp/python/3.8.15/Python-3.8.15.tgz 小注释&#xff1a;如果…

动手学深度学习(2)—— 线性神经网络

文章目录线性神经网络线性回归线性回归从零开始的实现生成数据集读取数据集初始化模型参数定义模型定义损失函数定义优化算法训练线性回归的简洁实现生成数据集读取数据集定义模型初始化模型参数定义损失函数定义优化算法训练softmax 回归softmax运算交叉熵损失图像分类数据集读…

浅谈降维实操,一种用于处理特征的方式——后附Python代码

&#x1f466;&#x1f466;一个帅气的boy&#xff0c;你可以叫我Love And Program &#x1f5b1; ⌨个人主页&#xff1a;Love And Program的个人主页 &#x1f496;&#x1f496;如果对你有帮助的话希望三连&#x1f4a8;&#x1f4a8;支持一下博主 降维实操前言线性降维低…

list的模拟实现(万字解读+由浅入深)

先申明一下本篇总体介绍过程是按照逐步深入去写的&#xff0c;所以可能有些同样类型不在一块&#xff01; 前言&#xff1a; 写这篇博客的时候&#xff0c;我是边思考边写它&#xff01;自己其中感觉自己对于list的理解更加的深入&#xff0c;其中提出的很多问题让我明白了lis…

Android Studio 实现桌面小组件(APPWidget)

前言 微件是定制主屏幕的一个重要方面。它允许您从用户的主屏幕直接看到最重要的应用程序数据和功能。用户可以在主屏幕面板之间移动微件、调整其大小&#xff0c;并根据自己的喜好自定义微件中的信息量。微贱类型主要分为&#xff1a;信息微件&#xff08;显示对用户来说很重…

Service详解

Service详解 文章目录Service详解Service介绍kube-proxy目前支持三种工作模式:userspace 模式iptables 模式ipvs 模式Service类型Service使用实验环境准备ClusterIP类型的ServiceEndpoint负载分发策略HeadLiness类型的ServiceNodePort类型的ServiceLoadBalancer类型的ServiceEx…

嵌入式Linux 开发经验:编写用户态应用程序 ioctl 控制 misc 设备

参考文章 VSCode SSH 连接远程ubuntu Linux 主机 ubuntu 20.04 qemu linux6.0.1 开发环境搭建 ubuntu 20.04 qemu linux6.0.1 制作ext4根文件系统 嵌入式Linux 开发经验&#xff1a;platform_driver_register 的使用方法 嵌入式Linux 开发经验&#xff1a;注册一个 misc 设…

阿里巴巴专场——第322场周赛题解

目录 模拟法&#xff1a;6253.回环句 排序后模拟&#xff1a;6254. 划分技能点相等的团队 BFS&#xff1a;6255. 两个城市间路径的最小分数 BFS&#xff1a;6256. 将节点分成尽可能多的组 模拟法&#xff1a;6253.回环句 这道题直接按照题目的意思暴力模拟即可&#xff1a;…

Ubuntu20.04 安装配置 Ros2

记录一下折磨了一周的ros2配置qaq以及踩的无数坑 第一次按照一个教程安装后&#xff0c;命令行输入sudo apt-update 报错 The repository http://packages.ros.org/ros/ubuntu $(lsb_release-sc) Release does not have a Release file. 卸载后&#xff0c;按照第二个教程安装…

(十) 共享模型之内存【有序性】

JVM 会在不影响正确性的前提下&#xff0c;可以调整语句的执行顺序这种特性称之为『指令重排』&#xff0c;多线程下『指令重排』会影响正确性。为什么要有重排指令这项优化呢&#xff1f;从 CPU 执行指令的原理来理解一下吧 一、原理之指令级并行&#xff08;了解&#xff09;…

[附源码]Python计算机毕业设计Django企业人事管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

如何使用HTML制作个人网站( web期末大作业)

&#x1f4c2;文章目录一、&#x1f468;‍&#x1f393;网站题目二、✍️网站描述三、&#x1f4da;网站介绍四、&#x1f310;网站演示五、⚙️ 网站代码&#x1f9f1;HTML结构代码&#x1f492;CSS样式代码六、&#x1f947; 如何让学习不再盲目七、&#x1f381;更多干货一…

Linux安装mysql

1、 查看是否已经安装 Mysql rpm -qa | grep mysql 如果你查看出来有东西&#xff0c;可以使用下面命令将其删除 rpm -e 文件名 2 、下载官方 Mysql 包 wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 如果安装有提示&#xff1a;Cannot…

HTML5期末大作业:北京旅游网页设计制作(1页) 简单静态HTML网页作品 我的旅游网页作业成品 学生旅游网站模板

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

gin 集成 Swagger

前言 一个好的项目工程&#xff0c;必然离不开一个好的 API 文档&#xff0c;如果要自己编写 API 文档&#xff0c;维护起来比较困难&#xff0c;而且难以保证一致性&#xff0c;因此我们要自动生成在线接口文档。 swaggo swagger 在 java 里面&#xff0c;是一个非常流行的…

后渗透之日志分析实验

目录 一、实验项目名称 二、实验目的 三、实验内容 四、实验环境 五、实验步骤 六、实验结果 七、实验总结 一、实验项目名称 后渗透之日志分析实验 二、实验目的 1.掌握meterpreter进行端口转发的方法 2.掌握网站日志的分析方法 三、实验内容 针对目标网站服务器…

AlphaFold2源码解析(7)--模型之Evoformer

AlphaFold2源码解析(7)–模型之Evoformer 这篇文章我们主要药讲解AlphaFold2的Evoformer的代码细节。 Evoformer Stack 该网络有一个双塔结构&#xff0c;在MSA堆栈中具有轴向的自我注意&#xff1b;在Pair堆栈中具有三角形的乘法更新和三角形的自我注意&#xff1b;以及外积…

Windows多线程编程

一、 实验内容或题目&#xff1a; 以多线程编程的方式完成&#xff1a; 1&#xff09;随机生成一个数组&#xff0c;求其平均值 2&#xff09;随机生成一个数组&#xff0c;求其最大值 3&#xff09;随机生成一个数组&#xff0c;求其最小值 二、 实验目的与要求&#xff1a;…

Kaggle Feedback Prize 3比赛总结:如何高效使用hidden states输出(2)

比赛链接&#xff1a;https://www.kaggle.com/competitions/feedback-prize-english-language-learning 在Kaggle Feedback Prize 3比赛总结&#xff1a;如何高效使用hidden states输出(2)中介绍了针对last layer hidden state的各种pooling的方法。 在利用Transformer类的预…

Vue学习:Hello小案例

使用Vue的目的&#xff1a;构建用户界面&#xff08;需要使用容器 摆放这个界面的内容&#xff09; favicon.ico:1 GET http://127.0.0.1:5500/favicon.ico 404 (Not Found) 没有页签图标 在者服务器中 http://127.0.0.1:5500没有/favicon.ico 强制刷新网页&#xff1a;s…