Qt 基于海康相机的视频绘图

需求

在视频窗口上进行绘图,包括圆,矩形,扇形等

效果

 思路:

自己取图然后转成QImage ,再向QWidget 进行渲染,根据以往的经验,无法达到很高的帧率。因此决定使用相机SDK自带的渲染功能,也就是传一个句柄给到sdk。但是这样视频渲染出来了,向上绘制图案,会被视频遮挡住,因此这里采用了两个窗口叠加,然后上层窗口设置透明背景的方式来实现。

底层取图窗口代码:

#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H#include <QWidget>
#include <windows.h>
#include <MvCameraControl.h>#include "./util/PSEventController.h"
#include "graphwidget.h"
class CameraWidget : public QWidget
{Q_OBJECT
public:explicit CameraWidget(QWidget *parent = nullptr);~CameraWidget();void updatePos(int x,int y);private:bool findDevice();bool printDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo);void getImage();bool openDevice();bool closeDevice();private:int nRet = MV_OK;void* handle = NULL;MV_CC_DEVICE_INFO_LIST stDeviceList = {0};std::atomic_bool bExit = true;HWND hwnd = NULL;GraphWidget * graphWidget=nullptr;QWidget *videoWidget =nullptr;std::atomic_bool isCapture{false};private:void initData();void mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo);public slots:void on_psEvent_capture(bool isChecked);void on_psEvent_adjustImage(bool isChecked);void on_psEvent_fixImage(bool isChecked);signals:void capture(QImage image);
};#endif // CAMERAWIDGET_H#include "camerawidget.h"#include <iostream>
#include <mutex>
#include <thread>
#include <QWidget>
#include <QPainter>
#include <QGridLayout>
#include <QStackedLayout>
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>CameraWidget::CameraWidget(QWidget *parent): QWidget{parent}
{graphWidget = new GraphWidget(this);graphWidget->setWindowFlags(Qt::FramelessWindowHint|Qt::Dialog|Qt::WindowStaysOnTopHint|Qt::SubWindow);graphWidget->setAttribute(Qt::WA_TranslucentBackground, true);QPalette pal;pal.setColor(QPalette::Window,QColor(0,0,0,0));graphWidget->setAutoFillBackground(true);graphWidget->setPalette(pal);graphWidget->show();hwnd = (HWND)this->winId();openDevice();this->setFixedSize(816,683);graphWidget->setFixedSize(this->size());setUpdatesEnabled(false);setAttribute(Qt::WA_OpaquePaintEvent);initData();
}CameraWidget::~CameraWidget()
{closeDevice();
}bool CameraWidget::findDevice()
{//枚举设备nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);if (MV_OK != nRet){printf("Enum Devices fail! nRet [0x%x]\n", nRet);return false;}if (stDeviceList.nDeviceNum > 0){for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++){printf("[device %d]:\n", i);MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];if (NULL == pDeviceInfo){break;}printDeviceInfo(pDeviceInfo);}}else{printf("Find No Devices!\n");return false;}return true;
}bool CameraWidget::openDevice()
{if(!findDevice()){return false;}unsigned int nIndex = 0;if (nIndex >= stDeviceList.nDeviceNum){printf("Invalid device index!\n");return false;}do{//选择设备并创建句柄nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);if (MV_OK != nRet){printf("Create Handle fail! nRet [0x%x]\n", nRet);break;}// ch:打开设备nRet = MV_CC_OpenDevice(handle);if (MV_OK != nRet){printf("Open Device fail! nRet [0x%x]\n", nRet);break;}// ch:探测网络最佳包大小(只对GigE相机有效)if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE){int nPacketSize = MV_CC_GetOptimalPacketSize(handle);if (nPacketSize > 0){nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);if(nRet != MV_OK){printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);}}else{printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);}}//设置触发模式为offnRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);if (MV_OK != nRet){printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);break;}// ch:开始取流 | en:Start grab imagenRet = MV_CC_StartGrabbing(handle);if (MV_OK != nRet){printf("Start Grabbing fail! nRet [0x%x]\n", nRet);break;}bExit=false;std::thread t([&](){getImage();});t.detach();return true;}while (0);if (nRet != MV_OK){if (handle != NULL){MV_CC_DestroyHandle(handle);handle = NULL;}}return false;
}bool CameraWidget::closeDevice()
{bExit=true;if (handle == NULL)return true;do{// ch:停止取流 | en:Stop grab imagenRet = MV_CC_StopGrabbing(handle);if (MV_OK != nRet){printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);break;}// ch:关闭设备 | Close devicenRet = MV_CC_CloseDevice(handle);if (MV_OK != nRet){printf("ClosDevice fail! nRet [0x%x]\n", nRet);break;}// ch:销毁句柄 | Destroy handlenRet = MV_CC_DestroyHandle(handle);if (MV_OK != nRet){printf("Destroy Handle fail! nRet [0x%x]\n", nRet);break;}handle = NULL;return true;}while (0);if (nRet != MV_OK){if (handle != NULL){MV_CC_DestroyHandle(handle);handle = NULL;}}return false;
}void CameraWidget::initData()
{PSEventController::subscribe(this,"capture");PSEventController::subscribe(this,"adjustImage");PSEventController::subscribe(this,"fixImage");connect(this,&CameraWidget::capture,this,[&](QImage image){graphWidget->setBackgroundImage(QPixmap::fromImage(image),true);},Qt::UniqueConnection);
}void CameraWidget::on_psEvent_capture(bool isChecked)
{if(!isChecked){QPixmap backgroundImage;graphWidget->setBackgroundImage(backgroundImage,false);}else{isCapture=true;}
}void CameraWidget::on_psEvent_adjustImage(bool isChecked)
{graphWidget->setIsScale(true);
}void CameraWidget::on_psEvent_fixImage(bool isChecked)
{graphWidget->setIsScale(false);
}void CameraWidget::updatePos(int x, int y)
{graphWidget->move(x,y);
}bool CameraWidget::printDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo)
{if (NULL == pstMVDevInfo){printf("The Pointer of pstMVDevInfo is NULL!\n");return false;}if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE){int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);// ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined nameprintf("CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);printf("UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);}else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE){printf("UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);printf("Serial Number: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);printf("Device Number: %d\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.nDeviceNumber);}else{printf("Not support.\n");}return true;
}//std::once_flag flag;
void CameraWidget::getImage()
{int nRet = MV_OK;MV_FRAME_OUT stImageInfo = {0};MV_DISPLAY_FRAME_INFO stDisplayInfo = {0};while(1){nRet = MV_CC_GetImageBuffer(handle, &stImageInfo, 1000);if (nRet == MV_OK){// printf("Get Image Buffer: Width[%d], Height[%d], FrameNum[%d]\n",//  stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);if (hwnd){stDisplayInfo.hWnd = hwnd;stDisplayInfo.pData = stImageInfo.pBufAddr;stDisplayInfo.nDataLen = stImageInfo.stFrameInfo.nFrameLen;stDisplayInfo.nWidth = stImageInfo.stFrameInfo.nWidth;stDisplayInfo.nHeight = stImageInfo.stFrameInfo.nHeight;stDisplayInfo.enPixelType = stImageInfo.stFrameInfo.enPixelType;//转qt QImage 给到绘图窗口if(isCapture){mvToQImage(stDisplayInfo);}//调整窗口尺寸//                std::call_once(flag, [&](){//                    int cW = stImageInfo.stFrameInfo.nWidth;//                    int cH = stImageInfo.stFrameInfo.nHeight;//                });MV_CC_DisplayOneFrame(handle, &stDisplayInfo);}nRet = MV_CC_FreeImageBuffer(handle, &stImageInfo);if(nRet != MV_OK){printf("Free Image Buffer fail! nRet [0x%x]\n", nRet);}}else{printf("Get Image fail! nRet [0x%x]\n", nRet);}if(bExit){break;}}
}void CameraWidget::mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo)
{QImage image;if(stDisplayInfo.enPixelType==PixelType_Gvsp_Mono8){image= QImage(stDisplayInfo.pData, stDisplayInfo.nWidth, stDisplayInfo.nHeight, QImage::Format_Indexed8);}else if(stDisplayInfo.enPixelType==PixelType_Gvsp_RGB8_Packed){image= QImage(stDisplayInfo.pData, stDisplayInfo.nWidth, stDisplayInfo.nHeight, QImage::Format_RGB888);}emit capture(image);isCapture=false;
}

上层绘图窗口代码:

#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H#include <QWidget>
#include <windows.h>
#include <MvCameraControl.h>#include "./util/PSEventController.h"
#include "graphwidget.h"
class CameraWidget : public QWidget
{Q_OBJECT
public:explicit CameraWidget(QWidget *parent = nullptr);~CameraWidget();void updatePos(int x,int y);private:bool findDevice();bool printDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo);void getImage();bool openDevice();bool closeDevice();private:int nRet = MV_OK;void* handle = NULL;MV_CC_DEVICE_INFO_LIST stDeviceList = {0};std::atomic_bool bExit = true;HWND hwnd = NULL;GraphWidget * graphWidget=nullptr;QWidget *videoWidget =nullptr;std::atomic_bool isCapture{false};private:void initData();void mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo);public slots:void on_psEvent_capture(bool isChecked);void on_psEvent_adjustImage(bool isChecked);void on_psEvent_fixImage(bool isChecked);signals:void capture(QImage image);
};#endif // CAMERAWIDGET_H#include "graphwidget.h"
#include <QGridLayout>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>#include "../graphics/bqgraphicsitem.h"#define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH  viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height()GraphWidget::GraphWidget(QWidget *parent): QGraphicsView{parent}
{setAttribute(Qt::WA_TranslucentBackground);setStyleSheet("background: transparent;border:0px");setWindowFlags(Qt::FramelessWindowHint);setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);setRenderHint(QPainter::Antialiasing);scene = new QGraphicsScene(this);this->setScene(scene);setDragMode(ScrollHandDrag);this->setSceneRect(this->geometry());centerOn(0, 0);initData();
}void GraphWidget::setIsScale(bool newIsScale)
{isScale = newIsScale;if(!isScale){revertSize();}
}void GraphWidget::setBackgroundImage(const QPixmap &newBackgroundImage,bool newIsSetBackground)
{qDebug()<<"setBackgroundImage "<<newIsSetBackground;isSetBackground=newIsSetBackground;if(backgroundItem){scene->removeItem(backgroundItem);backgroundItem=nullptr;}if(isSetBackground){setAttribute(Qt::WA_TranslucentBackground,false);backgroundImage = newBackgroundImage;if(!backgroundImage.isNull()){backgroundItem = scene->addPixmap(backgroundImage);backgroundItem->setPos(-this->width()/2,-this->height()/2);backgroundItem->setZValue(-1000);backgroundItem->setFlags(QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable |QGraphicsItem::ItemIsFocusable);update();}}else{setAttribute(Qt::WA_TranslucentBackground,true);revertSize();}}void GraphWidget::clearItem()
{for(int i=0;i<scene->items().size();i++){QGraphicsItem *item = scene->items().at(i);if(item->zValue()==-1000){continue;}else{scene->removeItem(scene->items().at(i));}}
}void GraphWidget::on_psEvent_addLine(bool isChecked)
{clearItem();BRectangle *m_rectangle = new BRectangle(0, 0, 100, 50, BGraphicsItem::ItemType::Rectangle);scene->addItem(m_rectangle);
}void GraphWidget::on_psEvent_addCircle(bool isChecked)
{clearItem();BConcentricCircle *m_conCircle = new BConcentricCircle(0, 0, 50, 80, BGraphicsItem::ItemType::Concentric_Circle);scene->addItem(m_conCircle);
}void GraphWidget::on_psEvent_addEllipse(bool isChecked)
{clearItem();BEllipse *m_ellipse = new BEllipse(0, 0, 100, 50, BGraphicsItem::ItemType::Ellipse);scene->addItem(m_ellipse);
}void GraphWidget::on_psEvent_addArc(bool isChecked)
{clearItem();BPie *m_pie = new BPie(0, 0, 80, 30, BGraphicsItem::ItemType::Pie);scene->addItem(m_pie);
}void GraphWidget::wheelEvent(QWheelEvent *event)
{if(isScale){static float scale = 1.1;auto angle = event->angleDelta();if(angle.y() > 0){this->scale(scale, scale);}else{this->scale(1/scale, 1/scale);}}
}void GraphWidget::initData()
{PSEventController::subscribe(this,"addLine");PSEventController::subscribe(this,"addCircle");PSEventController::subscribe(this,"addEllipse");PSEventController::subscribe(this,"addArc");
}void GraphWidget::revertSize()
{setTransformationAnchor(QGraphicsView::AnchorViewCenter);QMatrix q;q.setMatrix(1,this->matrix().m12(),this->matrix().m21(),1,this->matrix().dx(),this->matrix().dy());setMatrix(q,false);
}

主窗口移动和缩放时更新视频窗口位置:

void MainWindow::updateGraphWidgetPos()
{if(cameraWidget){QPoint p =  mapToGlobal(cameraWidget->parentWidget()->pos());cameraWidget->updatePos(p.x(),p.y()+22);}
}void MainWindow::resizeEvent(QResizeEvent *e)
{updateGraphWidgetPos();return QWidget::resizeEvent(e);
}void MainWindow::moveEvent(QMoveEvent *e)
{updateGraphWidgetPos();return QWidget::moveEvent(e);
}

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

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

相关文章

机器视觉系统选型-环形光源分类及应用场景

环形光源主要分为&#xff1f; 1.环形光源(高角度) 照射光线与水平方向成高角度夹角 外观缺陷检测字符识别PCB基板检测二维码读取- 2.环形光源(低角度) 照射光线与水平方向成低角度夹角各种边缘提取字符识别玻璃断面的损伤检测金属表面刻印、损伤 3.环形光源(高亮) 高亮度远…

谈谈你对mvc和mvvm的理解

MVC和MVVM是软件开发中两种常见的架构模式&#xff0c;各自有不同的优缺点。 MVC&#xff08;Model-View-Controller&#xff09;是一种经典的架构模式&#xff0c;将应用程序分为三个部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和…

从暗黑3D火炬之光技能系统说到-Laya非入门教学一~资源管理

我不知道那些喷Laya没有浏览器&#xff0c;嘲笑别人编辑器做不好&#xff0c;是什么水平&#xff1f; 首先目前国内除了WPS和飞书&#xff0c;就没有第三家公司能把编辑器做好。 要是一般的游戏开发者&#xff0c;如我&#xff0c;有一点点引擎代码&#xff08;某项目&#x…

opencv-图像对比度增强

对比度增强&#xff0c;即将图片的灰度范围拉宽&#xff0c;如图片灰度分布范围在[50,150]之间&#xff0c;将其范围拉升到[0,256]之间。这里介绍下 线性变换&#xff0c;直方图正规化&#xff0c;伽马变换&#xff0c;全局直方图均衡化&#xff0c;限制对比度自适应直方图均衡…

django+drf+vue 简单系统搭建 (4) 用户权限

权限控制是web中的重要组成部分。与以往的博客系统不同&#xff0c;本次工具页面仅支持注册用户。 每个注册用户都能访问到工具页面&#xff0c;并且提交自己的task来选择具体的工具来处理自己提交的文件。每个注册用户都只能访问到自己提交的task&#xff0c;而管理员则可以查…

SAP 调取http的x-www-form-urlencoded形式的接口

一、了解下x-www-form-urlencoded形式对于SAP来说有啥区别 简单来说&#xff0c; 1.raw格式就是标准的json格式&#xff1a;{“Name”:“John Smith”&#xff0c;“Age”: 23} 2.x-www格式是要转化一下的&#xff1a;NameJohnSmith&Age23 字段与字段相互连接要用 & 符…

pycharm 控制台中文乱码处理

今天使用pycharm&#xff0c;发现控制台输出又中文乱码了&#xff0c;看网上很多资料说把编码改为UTF-8&#xff0c;设置为并未生效&#xff0c;特此在此记录下本地设置。 1. 修改文件编码&#xff1a;Setting -> Editor ->File Encodings,修改配置如下&#xff1a; 2. …

车载数据中心方案

下面这张图是小鹏汽车嵌入式系统高级专家 唐黾 在同ARM一起的一个演讲稿中发布的&#xff0c;是一张未来车载数据中心单芯片方案构想图。主要针对的是智驾域和座舱域融合方案&#xff0c;下面对如上图的内外部组件及接口一一描述。 DMS: Driver Monitoring System&#xff0c;监…

02-微服务的拆分规则和基于RestTemplate的远程调用

微服务的拆分与远程调用 创建父工程 任何分布式架构都离不开服务的拆分, 微服务也是一样 , 微服务的拆分遵守三个原则 微服务需要根据业务模块拆分,不同微服务不要重复开发相同业务每个微服务都有自己独立的数据库, 不要直接访问其他微服务的数据库微服务可以将自己的业务暴…

【网络安全】-网络安全的分类详解

文章目录 介绍1. 网络层安全&#xff08;Network Layer Security&#xff09;理论实操使用VPN保护隐私 2. 应用层安全&#xff08;Application Layer Security&#xff09;理论实操使用密码管理器 3. 端点安全&#xff08;Endpoint Security&#xff09;理论实操定期更新防病毒…

武汉凯迪正大—盐雾试验机

产品概述 武汉凯迪正大KDYD-YW盐雾试验箱乃针对各种材质表面处理&#xff0c;包含涂料、电镀、有机及无机皮膜&#xff0c;阳极处理&#xff0c;防锈油等防腐处理后测试其耐腐蚀性&#xff0c;从而确立产品的质量。 产品特点 1、结构紧凑&#xff0c;体积小、携带方便&#…

艺术作品3D虚拟云展厅能让客户远程身临其境地欣赏美

艺术品由于货物昂贵、易碎且保存难度大&#xff0c;因此在艺术品售卖中极易受时空限制&#xff0c;艺术品三维云展平台在线制作是基于web端将艺术品的图文、模型及视频等资料进行上传搭配&#xff0c;构建一个线上艺术品3D虚拟展厅&#xff0c;为艺术家和观众提供了全新的展示和…

Chrome和chromedriver版本不匹配导致的UI自动化测试无法运行的问题

今天&#xff0c;遇到一个小问题&#xff0c;本来跑的好好UI自动化测试脚本突然不好使了&#xff0c;期初怀疑是页面元素有调整导致脚本出现异常无法正常执行&#xff0c;经排查后发现近期页面没有任何调整。 这下头大了&#xff0c;啥也没改&#xff0c;怎么好好的脚本不能跑…

Vue3鼠标拖拽生成区域块并选中元素

Vue3鼠标拖拽生成区域块并选中元素&#xff0c;选中的元素则背景高亮(或者其它逻辑)。 <script setup> import { ref } from vue// 区域ref const regionRef ref(null)// 内容ref const itemRefs ref(null)// 是否开启绘画区域 const enable ref(false)// 鼠标开始位置…

LVS+keepalived——高可用集群

lvskeepalived&#xff1a;高可用集群 keepalived为lvs应运而生的高可用服务。lvs的调度器无法做高可用&#xff0c;于是keepalived这个软件。实现的是调度器的高可用。但是&#xff1a;keepalived不是专门为lvs集群服务的&#xff0c;也可以做其他代理服务器的高可用。 lvs的…

基于SSM的进销存管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Vue typescript项目配置eslint+prettier

1.安装依赖 安装 eslint yarn add eslint --dev安装 eslint-plugin-vue yarn add eslint-plugin-vue --dev主要用于检查 Vue 文件语法 安装 prettier 及相关插件 yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev安装 typescript 解析器、规则补充 …

Spring-IOC-@Import的用法

1、Car.java package com.atguigu.ioc; import lombok.Data; Data public class Car {private String cname; }2、 MySpringConfiguration2.java package com.atguigu.ioc; import org.springframework.context.annotation.Bean; import org.springframework.context.annotatio…

树莓派的的串口通信协议

首先&#xff0c;回顾一下串口的核心知识点&#xff0c;也是面试重点&#xff1a; 串口通信通常使用在多机通讯中串口通信是全双工的决定串口通信的成功与否的是 数据格式 和 波特率数据格式&#xff1a;1. 数据位 2.停止位 3. 奇偶校验位 树莓派恢复串口 回忆前几节树莓派刷机…

Vue3 配置全局 scss 变量

variables.scss $color: #0c8ce9;vite.config.ts // 全局css变量css: {preprocessorOptions: {scss: {additionalData: import "/styles/variables.scss";,},},},.vue 文件使用