项目实战:Qt+Opencv相机标定工具v1.3.0(支持打开摄像头、视频文件和网络地址,支持标定过程查看、删除和动态评价误差率,支持追加标定等等)

若该文为原创文章,转载请注明出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141334834

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Qt开发专栏:项目实战(点击传送门)


需求

  1.打开摄像头,可设置帧率、分辨率(可设置);
  2.可打开usb、rtsp和本地文件(直接输入地址自动判断);
  3.opencv摄像头操作子线程处理;
  4.支持设置棋盘格的行列角点数;
  5.支持标定过程可控制;
  6.采集标定图、可对标定图进行查看、删除;
  7.可对已有的标定图查看评价像素误差率;
  8.标定完成后,可以追加标定,继续开始基于原来的标定采集图继续标定;
  9.支持定制配置文件的导出和导出(测试运行包不对外开放该功能);


相关博客

  《OpenCV开发笔记(〇):使用mingw530_32编译openCV3.4.1源码,搭建Qt5.9.3的openCV开发环境》
  《OpenCV开发笔记(三):OpenCV图像的概念和基本操作》
  《OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储》
  《OpenCV开发笔记(五):OpenCV读取与操作摄像头》
  《OpenCV开发笔记(六):OpenCV基础数据结构、颜色转换函数和颜色空间》
  《OpenCV开发笔记(七十六):相机标定(一):识别棋盘并绘制角点》
  《OpenCV开发笔记(七十七):相机标定(二):通过棋盘标定计算相机内参矩阵矫正畸变摄像头图像》


Demo:calibrateTool_v1.3.0 windows运行包

  广角摄像头标定过程
  请添加图片描述

  请添加图片描述

  鱼眼摄像头标定过程
  请添加图片描述

  请添加图片描述

  动态标定过程:查看、删除和评价
  请添加图片描述

  请添加图片描述

  CSDN粉丝0积分下载:https://download.csdn.net/download/qq21497936/89652658
  QQ群:博客首页扫码进入QQ技术群,点击“文件”搜索“calibrateTool”,群内与博文同步更新)


模块化部署

  在这里插入图片描述

关键源码

CalibrateManager.h

#ifndef CALIBRATEMANAGER_H
#define CALIBRATEMANAGER_H// opencv
#include "opencv/highgui.h"
#include "opencv/cxcore.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/xphoto.hpp"
#include "opencv2/dnn/dnn.hpp"
// opencv_contrib
#include <opencv2/xphoto.hpp>
#include <opencv2/ximgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>#include "cvui.h"
#include "calibrateCommon.h"
#include <QImage>
#include <QTimer>class CalibrateManager: public QObject
{Q_OBJECT
public:explicit CalibrateManager(QObject *parent = 0);~CalibrateManager();public slots:void testOpencvEnv();                       // 测试环境public:double  getBrightness()     const;          // 亮度double  getContrast()       const;          // 对比度double  getSaturation()     const;          // 饱和度double  getHue()            const;          // 色调double  getGain()           const;          // 增益double  getExposure()       const;          // 曝光度bool    getShowProperty()   const;          // 显示属性int     getCalibrateRegionX() const;        // 区域xint     getCalibrateRegionY() const;        // 区域yint     getCalibrateRegionWidth() const;    // 区域widthint     getCalibrateRegionHeight() const;   // 区域heightint     getChessboardColCornerCount() const;// 棋盘行角点数量int     getChessboardRowCornerCount() const;// 棋盘列角点数量QString getSerialize() const;               // 获取序列化参数public:void setBrightness  (double value);         // 亮度void setContrast    (double value);         // 对比度void setSaturation  (double value);         // 饱和度void setHue         (double value);         // 色调void setGain        (double value);         // 增益void setExposure    (double value);         // 曝光度void setShowProperty(bool value);           // 显示属性void setCalibrateRegionX(int x);            // 区域xvoid setCalibrateRegionY(int y);            // 区域yvoid setCalibrateRegionWidth(int width);    // 区域widthvoid setCalibrateRegionHeight(int height);  // 区域heightvoid setChessboardColCornerCount(int count);// 棋盘行角点数量void setChessboardRowCornerCount(int count);// 棋盘列角点数量bool setSerialize(QString str);             // 获取序列化参数signals:void signal_opened(bool result);            // 打开摄像头信号void signal_closed();                       // 关闭摄像头信号void signal_captureOneFrame(cv::Mat mat);   // 接收图像后抛出信号void signal_captureOneFrame(QImage image);  // 接收图像后抛出信号void signal_captureOneResultFrame(cv::Mat mat);   // 接收图像后抛出信号void signal_captureOneResultFrame(QImage image);  // 接收图像后抛出信号void signal_startedCalibrate(bool result);  // 开始标定结果void signal_regionChanged(int x, int y, int width, int height);void signal_fpsChanged(int fps);            // 帧率void signal_stopedCalibrate();              // 结束标定结果(这是强制中断,不是标定完成)void signal_finishedCalibrate();            // 标定完成void signal_cameraInfo(CameraInfo cameraInfo);  // 更新截图相机信息public slots:void slot_startCapture(int usb, int width = 0, int height = 0, int fps = 0);// 打开摄像头, 0...void slot_startCapture(QString url, int width = 0, int height = 0, int fps = 0);// 打开摄像头, 网络摄像头地址void slot_stopCapture();                    // 当正在采集中时(>>时),关闭摄像头会导致程序崩溃,所以采集与停止放一个线程中(消息循环)void slot_startCalibrate();                 // 开始标定void slot_addCalibrate();                   // 继续标定void slot_snapshot();                       // 快照void slot_deleteSnapshot(int index);        // 删除快照void slot_stopCalibrate();                  // 停止标定void slot_finishCalibrate();                // 完成标定public slots:void slot_start();                       // 开启线程void slot_stop();                        // 关闭线程protected slots:void slot_captrueFrame();           // 消息循环获取图像protected:void initControl();void updateCalibrateResult();       // 更新标定结果void calculateCalibrateErrors();    // 计算误差protected:bool findChessboard(int rowCornerCount, int colCornerCount, cv::Mat &mat, std::vector<cv::Point2f> &vectorPoint2fCorners);public:static QImage mat2Image(cv::Mat mat);      // cv::Mat 转 QImageprivate:bool _running;                      // 线程是否运行private:cv::VideoCapture *_pVideoCapture;   // 摄像头实例bool _showProperty;                 // 是否显示属性参数double _brightness;                 // 亮度double _contrast;                   // 对比度double _saturation;                 // 饱和度double _hue;                        // 色调double _gain;                       // 增益double _exposure;                   // 曝光度int _width;                         // 宽度int _height;                        // 高度int _fps;                           // 帧率bool _opened;                       // 摄像头是否打开bool _calibratingBefore;            // 标定前一个变化状态bool _calibrating;                  // 正在标定bool _calibratFinished;             // 校准完了(当前最近一个已经校准)int _calibrateRegionX;              // 标定region区域像素起始x坐标int _calibrateRegionY;              // 标定region区域像素起始y坐标int _calibrateRegionWidth;          // 标定region区域像素宽度int _calibrateRegionHeight;         // 标定region区域像素高度cv::Mat _mat;                       // 缓存一帧cv::Mat _resultMat;                 // 结果int _chessboardColCornerCount;      // 一列多少个角点int _chessboardRowCornerCount;      // 一行多少个角点std::vector<std::vector<cv::Point3f>> _vectorObjectPoint;    // 缓存点std::vector<std::vector<cv::Point2f>> _vectorImagePoint;bool _snapshot;                     // 拍照private:                                // 计算内参和畸变系数cv::Mat _cameraMatrix;              // 相机矩阵(接收输出)cv::Mat _distCoeffs;                // 畸变系数(接收输出)std::vector<cv::Mat> _rotate;       // 旋转量(接收输出)std::vector<cv::Mat> _translate;    // 偏移量(接收输出)private:CameraInfo _cameraInfo;
};#endif // CALIBRATEMANAGER_H

CalibrateManager.cpp

...
void CalibrateManager::slot_captrueFrame()
{if(!_running){return;}if(_pVideoCapture->isOpened()){*_pVideoCapture >> _mat;if(_showProperty){cv::putText(_mat, QString("brightness: %1").arg(_brightness).toStdString(),cvPoint(0, 30), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("  contrast: %1").arg(_contrast  ).toStdString(),cvPoint(0, 60), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("saturation: %1").arg(_saturation).toStdString(),cvPoint(0, 90), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("       hue: %1").arg(_hue       ).toStdString(),cvPoint(0, 120), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("      gain: %1").arg(_gain      ).toStdString(),cvPoint(0, 150), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("  exposure: %1").arg(_exposure  ).toStdString(),cvPoint(0, 180), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));cv::putText(_mat, QString("press ESC out").toStdString(),cvPoint(0, 210), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));}// 第一次进入标定if(!_calibratingBefore && _calibrating){_calibrateRegionX = 0;_calibrateRegionY = 0;_calibrateRegionWidth = _width;_calibrateRegionHeight = _height;_calibratingBefore = true;emit signal_regionChanged(_calibrateRegionX, _calibrateRegionY, _calibrateRegionWidth, _calibrateRegionHeight);QImage srcImage = mat2Image(_mat);emit signal_captureOneResultFrame(srcImage);}else if(_calibrating){QImage srcImage = mat2Image(_mat);// 获取std::vector<cv::Point2f> imagePoints;if(findChessboard(_chessboardRowCornerCount,_chessboardColCornerCount,_mat,imagePoints)){// 这是拍照截图if(_snapshot){// 三维世界坐标系std::vector<cv::Point3f> objectPoints;for(int i = 0; i < _chessboardRowCornerCount; i++){for(int j = 0; j < _chessboardColCornerCount; j++){objectPoints.push_back(cv::Point3f(j, i, 0));}}// 图像识别出来的角点(一张图一组)_vectorObjectPoint.push_back(objectPoints);_vectorImagePoint.push_back(imagePoints);_snapshot = false;{SnapShot snapShot;snapShot.dateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz");snapShot.srcImage = srcImage;snapShot.drawChessboardImage = mat2Image(_mat);snapShot.imagePoints = imagePoints;snapShot.objectPoints = objectPoints;_cameraInfo.listSnapShot.append(snapShot);// 更新标定结果updateCalibrateResult();// 计算误差率calculateCalibrateErrors();// 抛出更新emit signal_cameraInfo(_cameraInfo);}}}
//            if(_cameraInfo.listSnapShot.size() == 0)
//            {
//                QImage srcImage = mat2Image(_mat);
//                emit signal_captureOneResultFrame(srcImage);
//            }else{
//                cv::undistort(_mat, _resultMat, _cameraMatrix, _distCoeffs);
//                QImage image = mat2Image(_resultMat);
//                emit signal_captureOneResultFrame(image);
//            }}else if(_calibratFinished){
//            if(_cameraInfo.listSnapShot.size() == 0)
//            {
//                QImage srcImage = mat2Image(_mat);
//                emit signal_captureOneResultFrame(srcImage);
//            }else{
//                cv::undistort(_mat, _resultMat, _cameraMatrix, _distCoeffs);
//                QImage image = mat2Image(_resultMat);
//                emit signal_captureOneResultFrame(image);
//            }}// 抛出原图QImage image = mat2Image(_mat);emit signal_captureOneFrame(image);// 抛出校正图if(_cameraMatrix.empty()){emit signal_captureOneResultFrame(image);}else{LOG;cv::undistort(_mat, _resultMat, _cameraMatrix, _distCoeffs);QImage dstImage = mat2Image(_resultMat);emit signal_captureOneResultFrame(dstImage);}QTimer::singleShot(5, this, SLOT(slot_captrueFrame()));}
}
...

入坑

  算法的研究优化过程中,受到摄像头光学、标定板、标定板所占视口大小,图像处理过程原本的流程优化、标定过程中动态的处理等多方面因素,坑多暂时未记录。


本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141334834

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

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

相关文章

二十二、状态模式

文章目录 1 基本介绍2 案例2.1 Season 接口2.2 Spring 类2.3 Summer 类2.4 Autumn 类2.5 Winter 类2.6 Person 类2.7 Client 类2.8 Client 类的运行结果2.9 总结 3 各角色之间的关系3.1 角色3.1.1 State ( 状态 )3.1.2 ConcreteState ( 具体的状态 )3.1.3 Context ( 上下文 )3.…

Airtest 的使用

Airtest 介绍 Airtest Project 是网易游戏推出的一款自动化测试框架&#xff0c;其项目由以下几个部分构成 Airtest : 一个跨平台的&#xff0c;基于图像识别的 UI 自动化测试框架&#xff0c;适用于游戏和 App &#xff0c; 支持 Windows, Android 和 iOS 平台&#xff0c…

解决银河麒麟V10登录循环的方法

解决银河麒麟V10登录循环的方法 一&#xff1a;进入命令行二&#xff1a;删除.Xauthority文件三&#xff1a;重启系统 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在使用银河麒麟桌面操作系统V10时&#xff0c;有时可能会遇到一个令人头…

【题解】—— LeetCode一周小结32

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结31 5.不含连续1的非负整数 题目链接&#xff1a;600. 不含连续…

redis列表若干记录

2、列表 ziplist ziplist参数 entry结构 entry-data:节点存储的元素prelen&#xff1a;记录前驱节点长度encoding&#xff1a;当前节点编码格式encoding encoding属性 使用多个子节点存储节点元素长度&#xff0c;这种多字节数据存储在计算机内存中或者进行网络传输的时的字节…

小型超声波清洗机哪个品牌好用?小型超声波清洗机排名前四

第一次见识到超声波清洗机的神奇是在几年前&#xff0c;当时我去眼镜店配眼镜。等待的过程中&#xff0c;店员把旧的眼镜拿去清洁了&#xff0c;30秒&#xff0c;我就看到了到小污渍和油污被震出来了&#xff0c;感觉特别神奇。几分钟后&#xff0c;清洁完毕&#xff0c;擦干镜…

3个常用zip压缩包文件打来密码删除方法

ZIP压缩包作为一种广泛使用的文件压缩格式&#xff0c;常常用于节省存储空间或便于文件传输。一般情况下为保护文件数据的安全我们会给zip压缩文件设置密码安全保护&#xff0c;但如果后续不需要密码保护了&#xff0c;如何删除密码呢&#xff1f;下面小编给大家介绍三种常用的…

java 函数接口Consumer简介与示例【函数式编程】【Stream】

Java 8 中的 消费者接口Consumer 是一个函数接口&#xff0c;它可以接受一个泛型 类型参数&#xff0c;它属于java.util.function包。 accept(T) 方法&#xff1a;是 Consumer 函数式接口的方法&#xff0c;传入单个输入参数&#xff0c;无返回值&#xff0c;可以用于 Lambda 表…

电脑监控软件有哪些,哪款更好用?一网打尽!电脑监控软件大搜罗,总有一款适合你!

甲&#xff1a;哎&#xff0c;您听说了吗&#xff1f;这年头&#xff0c;电脑监控软件那是五花八门&#xff0c;跟变戏法似的&#xff01; 乙&#xff1a;哦&#xff1f;怎么个五花八门法&#xff1f; 甲&#xff1a;嘿&#xff0c;您还别说&#xff0c;从实时监控到网络追踪…

最佳实践:敏捷需求管理——如何写好用户故事丨IDCF

丁仿&#xff0c;圣略咨询首席敏捷教练&#xff0c;研发效能&#xff08;DevOps&#xff09;工程师&#xff08;中级&#xff09;课程学员 在敏捷项目管理中&#xff0c;用户故事&#xff08;User Stories&#xff09;是需求管理的核心工具。本篇文章将从用户故事的基本概念、编…

复习之 java 锁

裁员在家&#xff0c;没有面试机会&#xff0c;整理整理面试知识点吧&#xff01; 不得不知道的java 锁 Java 中&#xff0c;提供了两种方式来实现同步互斥访问&#xff08;也就是锁&#xff09;&#xff1a;synchronized 和 Lock 多线程编程中&#xff0c;有可能会出现多个线…

期权中非常重要的行权!不懂行权先别交易!

今天带你了解期权中非常重要的行权&#xff01;不懂行权先别交易&#xff01;期权是金融市场中一种常见的衍生品工具&#xff0c;它给予持有者在特定时间内以特定价格购买或出售某个资产的权利。而“行权”是指期权持有者行使期权权利的行为。 期权行权是指期权持有者选择执行…

超网和无类间路由是什么?

​一、超网概述 超网是将多个连续的网络地址组合成一个增加的网络地址的技术。常用于减少路由器的路由表大小&#xff0c;网络的可扩展性。通过合并连续的子网&#xff0c;超网可以减少路由入侵的数量&#xff0c;从而提高网络的效率。 超网的实现基于合并多个具有连续IP地址…

java知识点详解——异常

当输入的数不是整数时 会报错 当输入的被除数为0时 会报错 在以前我们会使用if—else语句用来堵住漏洞&#xff0c;但是那样相当繁琐&#xff0c;很难穷举所有错误 Scanner in new Scanner(System.in); System.out.print("请输入被除数:"); int num1 in.nextInt(…

【Python快速入门和实践016】Python常用脚本-对视频抽取指定帧数并保存

一、功能介绍 这段代码的功能是从一个视频文件中抽取指定数量的帧&#xff0c;并将这些帧保存为图像文件。步骤如下&#xff1a; 设置路径和参数&#xff1a; video_path&#xff1a;视频文件的路径。image_folder&#xff1a;保存抽取图像的目录。num_frames_to_extract&#…

工业相机图像采集卡

什么是图像采集卡&#xff1f; 图像采集卡又称为图像卡&#xff0c;它将相机的图像视频信号&#xff0c;以帧为单位传送到计算机的内存和VGA帧存&#xff0c;供计算机处理&#xff0c;存储&#xff0c;显示和传输等使用。在机器视觉系统中&#xff0c;图像采集卡采集到的图像供…

【C语言】双链表

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:C语言数据结构_小米里的大麦的博客-CSDN博客 &#x1f381;代码托管:黄灿灿/数据结构 (gitee.com) ⚙️操作环境:Visual Studio 2022 目录 一、什么是双链表&#xff1f; 二、双链表温习 1. 双链表的结构…

【Django开发】前后端分离django美多商城项目第2篇:展示用户注册页面,1. 创建用户模块子应用【附代码文档】

全套笔记资料代码移步&#xff1a; 前往gitee仓库查看 感兴趣的小伙伴可以自取哦~ 本教程的知识点为&#xff1a; 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计&#xff1a; 视图原型 2. 具体…

如何诱导AI犯罪-提示词注入

我们用到的大模型基本把政治类信息、犯罪相关信息都已屏蔽。但是&#xff0c;黑客依旧可以使用提示词诱导和提示词注入的方式对大模型进行攻击。 1、提示词诱导 如果直接让AI提供犯罪过程&#xff0c;AI会直接拒绝。虽然AI对于大部分知识了然于心&#xff0c;但因为经过了人工…

javase综合案例3 -- 通讯录

文章目录 一&#xff0c;项目要求基础功能拓展 二&#xff0c;导入jar包 pinyin4j.jar三&#xff0c;程序报下建立Pinyin4j类四&#xff0c;创建实体类Contact五&#xff0c;创建通讯录接口ContactDao六&#xff0c;创建ContactDao接口的视线子类ContactDaoImpl6.1 创建全局的M…