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

相关推荐
同学小张14 小时前
【端侧AI 与 C++】1. llama.cpp源码编译与本地运行
开发语言·c++·aigc·llama·agi·ai-native
爱学习的小邓同学18 小时前
C++ --- 多态
开发语言·c++
招摇的一半月亮1 天前
P2242 公路维修问题
数据结构·c++·算法
f***01931 天前
CC++链接数据库(MySQL)超级详细指南
c语言·数据库·c++
合方圆~小文1 天前
球型摄像机作为现代监控系统的核心设备
java·数据库·c++·人工智能
椰萝Yerosius1 天前
[题解]2024CCPC郑州站——Z-order Curve
c++·算法
滨HI01 天前
C++ opencv简化轮廓
开发语言·c++·opencv
学习路上_write1 天前
FREERTOS_互斥量_创建和使用
c语言·开发语言·c++·stm32·单片机·嵌入式硬件
闻缺陷则喜何志丹1 天前
【SOSDP模板 容斥原理 逆向思考】3757. 有效子序列的数量|分数未知
c++·算法·力扣·容斥原理·sosdp·逆向思考
BestOrNothing_20151 天前
一篇搞懂 C++ 重载:函数重载 + 运算符重载,从入门到会用(含 ++、<<、== 实战)
c++·函数重载·运算符重载·operator·前置后置++·重载与重写