Qt6+libonvif从大华相机抓拍图片

复制代码
#pragma once
#include <QObject>
#include <QUrl>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QFile>
#include <QtCore/QElapsedTimer>
#include "Response.h"
#include "SoapHelper.h"
#include "OnvifDevice.h"
#include "OnvifDiscovery.h"
#include "OnvifMedia2Client.h"
#include "opencv2/opencv.hpp"
class CameraOnvif : public QObject
{
	Q_OBJECT

public:
	CameraOnvif();
	~CameraOnvif();
	QObject* _parent = nullptr;

public slots:
	void discovery();
	void snap();

private:

	QElapsedTimer timer;
signals:
	void msg(int id, QString s);
};
cpp 复制代码
void CameraOnvif::snap()
{
	//获取snap uri
	auto cb = SoapCtx::Builder();
	cb.SetSendTimeout(1000);
	cb.SetReceiveTimeout(1000);
	auto media = new OnvifMedia2Client(QUrl("http://192.168.1.9/onvif/device_service"), cb.Build(), nullptr);

	Request<_tr2__GetSnapshotUri> request;
	Request<_tr2__GetProfiles> request_2;
	request.ProfileToken = "MediaProfile00000";

	request.SetSoapAction("GetProfiles");
	auto profile = media->GetProfiles(request_2);

	request.SetSoapAction("GetSnapshotUri");
	auto url = media->GetSnapshotUri(request);
	qDebug() << "snap uri" << url.GetResultObject()->Uri;
	//抓拍
	QNetworkRequest r;
	r.setUrl(QString("http://192.168.1.9/onvif/snapshot?channel=1&subtype=0"));
	QNetworkAccessManager* manager = new QNetworkAccessManager();

	if (timer.isValid())
		timer.restart();
	else
		timer.start();

	QNetworkReply* reply = manager->get(r);
	connect(reply, &QNetworkReply::finished, this, [=]() {
		auto a = reply->readAll();

		std::vector<uchar> buf;
		int len = a.size();
		for (int i = 0;i < len;i++)
			buf.push_back(a[i]);
		//解码
		cv::Mat img = cv::imdecode(buf,0);
		//缩小
		cv::Mat img_scaled; 
		cv::resize(img, img_scaled, cv::Size(img.cols / 4, img.rows / 4));
		cv::imshow("img", img_scaled);
		qDebug() << "time cost:" << timer.elapsed() << Qt::endl;
		timer.invalidate();
		QFile file("e:\\a.jpg");
		file.open(QIODevice::WriteOnly);
		file.write(a);
		file.close();
		});

}

缺外部链接符号,就检查附加依赖项,譬如用到OnvifMedia2Client函数,就要附加onvifmedia2.lib。

发现libonvif只能提供相机控制及信息查询,得到相机的endpoint地址及SnapshotUri后,如果抓拍图片,则需要使用Qt的network库。

libonvif库没有example,对于复制粘贴不是很方便。

注意QNetworkReply返回结果是QByte,要用opencv的imdecode函数转换到Mat格式,中间需要用vect数组复制一遍。

感觉用goap生成的c++函数搜索和查询相机的onvif参数,用libonvif更适合做相机控制、设置的程序。

大华提供的sdk进行抓拍,最多耗时间是1秒多一点,用onvif方式通用性有了,抓拍速度也不稳定,这相机性能一般,试试海康威视的相机。

对于海康相机(DS-2CD4A10FWD-IZ),GetProfiles和GetSnapshotUri执行都失败,提示:

Optional Action Not Implemented

应该是libonvif需要提供认证,我还不会用。

用ONVIF Device Test Tool查询得到海康相机的snapuri:

http://172.29.168.12/onvif-http/snapshot?

访问海康相机的抓拍地址,需要提供用户名和密码,但大华相机是不需要的。

因此用Qt的摘要认证:

cpp 复制代码
	//摘要认证
	connect(manager, &QNetworkAccessManager::authenticationRequired, this, [=](QNetworkReply* reply, QAuthenticator* authenticator) {
		authenticator->setUser("admin");
		authenticator->setPassword("admin12345");
		});

可以抓到画面。

耗时最多到1500ms,比大华还慢。

相关推荐
Chester_19995 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
会周易的程序员7 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
小灰灰搞电子7 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt
QT界面美化性能优化7 小时前
QT+AI:使用AI技术为QT应用程序赋能
c++·人工智能·qt·opencv·qt教程·qt6.3
学习星球10 小时前
单调栈——从“找下一个更大的“到柱状图中的最大矩形
数据库·c++·算法·leetcode·xcode
小灰灰搞电子10 小时前
C++ 引用折叠详解
c++
布莱克60511 小时前
数组详解:定义、作用、应用场景及与链表的区别(C/C++ 代码讲解)
c语言·开发语言·c++·数组
牛油果子哥q12 小时前
C++内存池与对象池精讲:内存碎片、自定义分配器、对象池实现、STL allocator原理、工程落地与性能对比
java·开发语言·c++
万法若空12 小时前
C/C++ 类型别名定义方式对比
java·c语言·c++
小小晓.14 小时前
C++ 值类别与完美转发深度剖析:从左值右值到 std::forward 源码解密
开发语言·c++·算法