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,比大华还慢。

相关推荐
·薯条大王6 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
hansang_IR10 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集
东东最爱敲键盘10 小时前
day7.c++继承
c++
沫璃染墨11 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++
吃着火锅x唱着歌11 小时前
Effective C++ 学习笔记 条款40 明智而审慎地使用多重继承
c++·笔记·学习
醉城夜风~12 小时前
(超详细)C++ STL list容器详解:从使用方法到双向链表底层原理全面解析
c++·windows
烟花落o12 小时前
C++ 从 C 到进阶 ②:引用、inline 、nullptr
c++·引用·inline·nullptr·c++入门
liulilittle12 小时前
MOE路由:路由(logits: top-k/8)
c++·人工智能·算法·机器学习·llm
旖旎夜光12 小时前
LeetCode 11:盛最多水的容器(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针
我不会插花弄玉15 小时前
15.map,set下:AVL树,红黑树和map,set的封装【由浅入深-C++】
c++·stl