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

相关推荐
qwertyuiop_i2 小时前
QT6(鼠标键盘事件)
qt6·鼠标键盘事件
北冥湖畔的燕雀4 小时前
C++泛型编程(函数模板以及类模板)
开发语言·c++
Larry_Yanan8 小时前
QML学习笔记(四十二)QML的MessageDialog
c++·笔记·qt·学习·ui
R-G-B8 小时前
【35】MFC入门到精通——MFC运行 不显示对话框 MFC界面不显示
c++·mfc·mfc运行 不显界面·mfc界面不显示
Madison-No79 小时前
【C++】探秘vector的底层实现
java·c++·算法
晚风残9 小时前
【C++ Primer】第十二章:动态内存管理
开发语言·c++·c++ primer
liu****9 小时前
8.list的模拟实现
linux·数据结构·c++·算法·list
保持低旋律节奏9 小时前
C++ stack、queue栈和队列的使用——附加算法题
c++
初圣魔门首席弟子10 小时前
【C++ 学习】单词统计器:从 “代码乱炖” 到 “清晰可品” 的复习笔记
开发语言·c++
十五年专注C++开发10 小时前
CFF Explorer: 一款Windows PE 文件分析的好工具
c++·windows·microsoft