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

相关推荐
Golinie2 分钟前
【C++高并发服务器WebServer】-7:共享内存
linux·服务器·c++·webserver
CHANG_THE_WORLD7 小时前
C++并发编程指南08
开发语言·c++·算法
黎明blooms7 小时前
编译原理之基于自动机的词法分析器的设计与实现
c++·算法·编译原理
bawangtianzun8 小时前
vector有用的自己不太熟悉的函数
c++·算法
Ciderw8 小时前
Go的垃圾回收(GC)机制
开发语言·c++·后端·面试·golang·gc
荣--8 小时前
回顾我的软件开发经历:开发DAB
c++·单元测试·项目管理·nodejs·dab·多平台支持·正交性原则
CodeWizard~9 小时前
原码、反码、补码以及lowbit运算
c语言·开发语言·c++·算法
Icomi_10 小时前
【PyTorch】6.张量运算函数:一键开启!PyTorch 张量函数的宝藏工厂
c语言·c++·人工智能·pytorch·python·深度学习·机器学习
软工在逃男大学生11 小时前
8642 快速排序
c语言·数据结构·c++·算法