belt server build & pkg
This commit is contained in:
parent
e66a0cfc1e
commit
551fbc575a
@ -5,10 +5,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += c++17
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
|
||||
SUBDIRS += ../BeltTearingConfig/BeltTearingConfig.pro \
|
||||
../VrNet/VrTcpClient.pro
|
||||
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# Include paths
|
||||
INCLUDEPATH += $$PWD/Presenter/Inc
|
||||
@ -26,9 +26,9 @@ win32:CONFIG(debug, debug|release) {
|
||||
LIBS += -L../VrNets/release -lVrTcpClient
|
||||
LIBS += -L../VrUtils/release -lVrUtils
|
||||
}else:unix:!macx {
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
LIBS += -L../BeltTearingConfig -lBeltTearingConfig
|
||||
LIBS += -L../VrNets -lVrTcpClient
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
}
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
@ -46,10 +46,10 @@ SOURCES += \
|
||||
widgets/ImageGridWidget.cpp \
|
||||
widgets/ImageGridWithTableWidget.cpp \
|
||||
widgets/ImageTileWidget.cpp \
|
||||
Presenter/Src/PathManager.cpp \
|
||||
Presenter/Src/BeltTearingPresenter.cpp \
|
||||
widgets/TearingDataTableWidget.cpp \
|
||||
widgets/StyledMessageBox.cpp \
|
||||
widgets/TearingDataTableWidget.cpp
|
||||
Presenter/Src/PathManager.cpp \
|
||||
Presenter/Src/BeltTearingPresenter.cpp
|
||||
|
||||
HEADERS += \
|
||||
IStatusUpdate.h \
|
||||
@ -61,10 +61,10 @@ HEADERS += \
|
||||
widgets/ImageGridWidget.h \
|
||||
widgets/ImageGridWithTableWidget.h \
|
||||
widgets/ImageTileWidget.h \
|
||||
Presenter/Inc/PathManager.h \
|
||||
Presenter/Inc/BeltTearingPresenter.h \
|
||||
widgets/TearingDataTableWidget.h \
|
||||
widgets/StyledMessageBox.h \
|
||||
widgets/TearingDataTableWidget.h
|
||||
Presenter/Inc/PathManager.h \
|
||||
Presenter/Inc/BeltTearingPresenter.h
|
||||
|
||||
FORMS += \
|
||||
dialognetconfig.ui \
|
||||
|
||||
@ -16,7 +16,6 @@ CONFIG += staticlib
|
||||
|
||||
# 头文件路径
|
||||
INCLUDEPATH += $$PWD/Inc
|
||||
INCLUDEPATH += $$PWD/../VrUtils/tinyxml2
|
||||
|
||||
# 源文件
|
||||
HEADERS += \
|
||||
|
||||
@ -91,6 +91,8 @@ struct BeltTearingConfigResult
|
||||
DebugParam debugParam; // 调试参数
|
||||
|
||||
BeltTearingProjectType projectType; // 项目类型
|
||||
|
||||
int serverPort = 5900; // 服务端端口
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -61,12 +61,11 @@ BeltTearingConfigResult VrBeltTearingConfig::LoadConfig(const std::string& fileP
|
||||
xml.readNext();
|
||||
|
||||
// 解析服务器配置
|
||||
if (xml.isStartElement() && xml.name() == "Servers") {
|
||||
if (xml.isStartElement() && xml.name() == "ClientServers") {
|
||||
while (xml.readNextStartElement()) {
|
||||
if (xml.name() == "Server") {
|
||||
ServerInfo server;
|
||||
server.name = xml.attributes().value("name").toString().toStdString();
|
||||
server.ip = xml.attributes().value("ip").toString().toStdString();
|
||||
server.name = xml.attributes().value("name").toString().toStdString(); server.ip = xml.attributes().value("ip").toString().toStdString();
|
||||
server.port = xml.attributes().value("port").toInt();
|
||||
result.servers.push_back(server);
|
||||
xml.skipCurrentElement();
|
||||
@ -134,6 +133,16 @@ BeltTearingConfigResult VrBeltTearingConfig::LoadConfig(const std::string& fileP
|
||||
}
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
|
||||
// 解析服务端配置
|
||||
else if (xml.isStartElement() && xml.name() == "LocalServerConfig") {
|
||||
while (xml.readNextStartElement()) {
|
||||
if (xml.name() == "ServerPort") {
|
||||
result.serverPort = xml.attributes().value("port").toInt();
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
@ -169,7 +178,7 @@ bool VrBeltTearingConfig::SaveConfig(const std::string& filePath, BeltTearingCon
|
||||
|
||||
// 保存服务器配置
|
||||
if (!configResult.servers.empty()) {
|
||||
xml.writeStartElement("Servers");
|
||||
xml.writeStartElement("ClientServers");
|
||||
for (const auto& server : configResult.servers) {
|
||||
xml.writeStartElement("Server");
|
||||
xml.writeAttribute("name", QString::fromStdString(server.name));
|
||||
@ -177,7 +186,7 @@ bool VrBeltTearingConfig::SaveConfig(const std::string& filePath, BeltTearingCon
|
||||
xml.writeAttribute("port", QString::number(server.port));
|
||||
xml.writeEndElement(); // Server
|
||||
}
|
||||
xml.writeEndElement(); // Servers
|
||||
xml.writeEndElement(); // ClientServers
|
||||
}
|
||||
|
||||
// 保存算法参数
|
||||
@ -221,6 +230,13 @@ bool VrBeltTearingConfig::SaveConfig(const std::string& filePath, BeltTearingCon
|
||||
xml.writeAttribute("type", typeStr);
|
||||
xml.writeEndElement(); // ProjectType
|
||||
|
||||
// 保存服务端配置
|
||||
xml.writeStartElement("LocalServerConfig");
|
||||
xml.writeStartElement("ServerPort");
|
||||
xml.writeAttribute("port", QString::number(configResult.serverPort));
|
||||
xml.writeEndElement(); // ServerPort
|
||||
xml.writeEndElement(); // LocalServerConfig
|
||||
|
||||
xml.writeEndElement(); // BeltTearingConfig
|
||||
xml.writeEndDocument();
|
||||
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<BeltTearingConfig>
|
||||
<!-- 网络服务器配置 -->
|
||||
<Servers>
|
||||
<!-- 客户端连接服务端的配置 -->
|
||||
<ClientServers>
|
||||
<Server name="主服务器" ip="192.168.1.100" port="8080" />
|
||||
<Server name="备用服务器1" ip="192.168.1.101" port="8081" />
|
||||
<Server name="备用服务器2" ip="192.168.1.102" port="8082" />
|
||||
</Servers>
|
||||
</ClientServers>
|
||||
|
||||
<!-- 本地服务端配置 -->
|
||||
<LocalServerConfig>
|
||||
<ServerPort port="5900" />
|
||||
</LocalServerConfig>
|
||||
|
||||
<!-- 算法参数 -->
|
||||
<AlgorithmParams>
|
||||
|
||||
@ -93,13 +93,7 @@ std::vector<SSG_beltTearingInfo> BeltTearingAlgo::Predit(std::vector<SVzNL3DLase
|
||||
beltTearings_unknown, //未判明,应用无需处理。
|
||||
algoParam);
|
||||
lineIndex += 1;
|
||||
// if (beltTearings_unknown.size() > 0) {
|
||||
// std::cout << "未知的撕裂数量: " << beltTearings_unknown.size() << std::endl;
|
||||
// }
|
||||
|
||||
// if (beltTearings_growing.size() > 0) {
|
||||
// std::cout << "进行中的撕裂数量: " << beltTearings_growing.size() << std::endl;
|
||||
// }
|
||||
|
||||
if (beltTearings_new.size() > 0) //收集撕裂点
|
||||
{
|
||||
@ -116,6 +110,5 @@ std::vector<SSG_beltTearingInfo> BeltTearingAlgo::Predit(std::vector<SVzNL3DLase
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 返回值有可能为空,也有可能为当前检测的撕裂
|
||||
return total_tearings;
|
||||
}
|
||||
|
||||
@ -1,29 +1,378 @@
|
||||
#include "BeltTearingPresenter.h"
|
||||
#include "PathManager.h"
|
||||
#include "version.h"
|
||||
#include <QUuid>
|
||||
#include <QDataStream>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <QDateTime>
|
||||
#include <iostream>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
#include "VrLog.h"
|
||||
|
||||
BeltTearingPresenter::BeltTearingPresenter(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_tcpServer(new QTcpServer(this))
|
||||
, m_dataTimer(new QTimer(this))
|
||||
, m_cameraInitTimer(new QTimer(this))
|
||||
, m_port(0)
|
||||
, m_config(nullptr)
|
||||
, m_eyeDevice(nullptr)
|
||||
, m_beltTearingAlgo(new BeltTearingAlgo())
|
||||
, m_cameraInitialized(false)
|
||||
, m_cameraDetecting(false)
|
||||
{
|
||||
// 打印版本信息
|
||||
LOG_INFO("Initializing %s %s\n", getProductName().toStdString().c_str(), getVersionString().toStdString().c_str());
|
||||
LOG_INFO("Build: %s\n", getBuildInfo().toStdString().c_str());
|
||||
|
||||
// 连接信号槽
|
||||
connect(m_tcpServer, &QTcpServer::newConnection, this, &BeltTearingPresenter::onNewConnection);
|
||||
connect(m_dataTimer, &QTimer::timeout, this, &BeltTearingPresenter::onSendSimulatedData);
|
||||
connect(m_cameraInitTimer, &QTimer::timeout, this, &BeltTearingPresenter::onCameraInitTimer);
|
||||
|
||||
// 创建配置实例
|
||||
IVrBeltTearingConfig::CreateInstance(&m_config);
|
||||
if (m_config) {
|
||||
m_config->SetConfigChangeNotify(this);
|
||||
}
|
||||
|
||||
// 初始化相机
|
||||
initializeCamera();
|
||||
}
|
||||
|
||||
BeltTearingPresenter::~BeltTearingPresenter()
|
||||
{
|
||||
stopServer();
|
||||
stopCamera();
|
||||
|
||||
if (m_beltTearingAlgo) {
|
||||
delete m_beltTearingAlgo;
|
||||
m_beltTearingAlgo = nullptr;
|
||||
}
|
||||
|
||||
if (m_config) {
|
||||
delete m_config;
|
||||
m_config = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool BeltTearingPresenter::loadConfiguration(const QString& configFilePath)
|
||||
{
|
||||
if (!m_config) {
|
||||
LOG_WARNING("Config instance not created\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_configFilePath = configFilePath;
|
||||
|
||||
try {
|
||||
// 加载配置文件
|
||||
m_configResult = m_config->LoadConfig(configFilePath.toStdString());
|
||||
|
||||
LOG_INFO("Configuration loaded successfully:\n");
|
||||
LOG_INFO(" Server Port: %d\n", m_configResult.serverPort);
|
||||
LOG_INFO(" Project Type: %d\n", static_cast<int>(m_configResult.projectType));
|
||||
LOG_INFO(" Servers count: %d\n", m_configResult.servers.size());
|
||||
|
||||
// 应用算法参数
|
||||
applyAlgorithmParameters(m_configResult.algorithmParams);
|
||||
|
||||
// 输出算法参数信息
|
||||
const auto& params = m_configResult.algorithmParams;
|
||||
LOG_INFO("Algorithm Parameters:\n");
|
||||
LOG_INFO(" Tear Threshold: %f\n", params.beltTearingParam.tearThreshold);
|
||||
LOG_INFO(" Min Tear Length: %f\n", params.beltTearingParam.minTearLength);
|
||||
LOG_INFO(" Max Tear Width: %f\n", params.beltTearingParam.maxTearWidth);
|
||||
LOG_INFO(" Blur Size: %d\n", params.imageProcessingParam.blurSize);
|
||||
LOG_INFO(" Check Interval: %d\n", params.monitoringParam.checkInterval);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("Error loading configuration: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::applyAlgorithmParameters(const BeltTearingAlgorithmParams& params)
|
||||
{
|
||||
if (!m_beltTearingAlgo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 重置算法参数
|
||||
m_beltTearingAlgo->ResetParameter();
|
||||
|
||||
// 应用算法参数
|
||||
LOG_DEBUG("Applying algorithm parameters...\n");
|
||||
LOG_DEBUG(" Tear Threshold: %f\n", params.beltTearingParam.tearThreshold);
|
||||
LOG_DEBUG(" Min Tear Length: %f\n", params.beltTearingParam.minTearLength);
|
||||
LOG_DEBUG(" Max Tear Width: %f\n", params.beltTearingParam.maxTearWidth);
|
||||
LOG_DEBUG(" Blur Size: %d\n", params.imageProcessingParam.blurSize);
|
||||
LOG_DEBUG(" Canny Threshold 1: %f\n", params.imageProcessingParam.cannyThreshold1);
|
||||
LOG_DEBUG(" Canny Threshold 2: %f\n", params.imageProcessingParam.cannyThreshold2);
|
||||
LOG_DEBUG(" Check Interval: %d ms\n", params.monitoringParam.checkInterval);
|
||||
LOG_DEBUG(" Alert Threshold: %f\n", params.monitoringParam.alertThreshold);
|
||||
|
||||
// 调试参数
|
||||
if (m_configResult.debugParam.enableDebug) {
|
||||
LOG_DEBUG("Debug mode enabled:\n");
|
||||
LOG_DEBUG(" Save debug images: %s\n", (m_configResult.debugParam.saveDebugImage ? "Yes" : "No"));
|
||||
LOG_DEBUG(" Print detail log: %s\n", (m_configResult.debugParam.printDetailLog ? "Yes" : "No"));
|
||||
}
|
||||
|
||||
// TODO: 根据BeltTearingAlgo的实际接口设置参数
|
||||
// 例如:m_beltTearingAlgo->SetTearThreshold(params.beltTearingParam.tearThreshold);
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::OnConfigChanged(const BeltTearingConfigResult& configResult)
|
||||
{
|
||||
LOG_INFO("Configuration changed notification received\n");
|
||||
|
||||
// 更新配置结果
|
||||
m_configResult = configResult;
|
||||
|
||||
// 重新应用算法参数
|
||||
applyAlgorithmParameters(configResult.algorithmParams);
|
||||
|
||||
// 如果服务器端口改变,可能需要重启服务器
|
||||
if (m_tcpServer->isListening() && m_tcpServer->serverPort() != configResult.serverPort) {
|
||||
LOG_INFO("Server port changed, restarting server...\n");
|
||||
stopServer();
|
||||
startServer(configResult.serverPort);
|
||||
}
|
||||
}
|
||||
|
||||
bool BeltTearingPresenter::initializeCamera()
|
||||
{
|
||||
if (m_eyeDevice) {
|
||||
return true; // 已经初始化过
|
||||
}
|
||||
|
||||
int result = IVrEyeDevice::CreateObject(&m_eyeDevice);
|
||||
if (result != 0 || !m_eyeDevice) {
|
||||
LOG_ERROR("Failed to create VrEyeDevice object, error code: %d\n", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = m_eyeDevice->InitDevice();
|
||||
if (result != 0) {
|
||||
LOG_ERROR("Failed to initialize VrEyeDevice, error code: %d\n", result);
|
||||
delete m_eyeDevice;
|
||||
m_eyeDevice = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置状态回调
|
||||
result = m_eyeDevice->SetStatusCallback(OnStatusCallback, this);
|
||||
if (result != 0) {
|
||||
LOG_WARNING("Failed to set status callback, error code: %d\n", result);
|
||||
}
|
||||
|
||||
LOG_INFO("VrEyeDevice initialized successfully\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::startCamera()
|
||||
{
|
||||
if (!m_eyeDevice) {
|
||||
if (!initializeCamera()) {
|
||||
// 启动定时器持续重试初始化
|
||||
LOG_WARNING("Camera initialization failed, starting retry timer...\n");
|
||||
m_cameraInitTimer->start(5000); // 每5秒重试一次
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试打开设备
|
||||
int result = m_eyeDevice->OpenDevice(nullptr);
|
||||
if (result != 0) {
|
||||
LOG_WARNING("Failed to open camera device, error code: %d, retrying...\n", result);
|
||||
|
||||
// 启动定时器持续重试连接
|
||||
m_cameraInitTimer->start(3000); // 每3秒重试一次
|
||||
return;
|
||||
}
|
||||
|
||||
// 停止重试定时器
|
||||
m_cameraInitTimer->stop();
|
||||
m_cameraInitialized = true;
|
||||
|
||||
// 开始检测
|
||||
result = m_eyeDevice->StartDetect(OnPointCloudCallback, keResultDataType_Position, this);
|
||||
if (result != 0) {
|
||||
LOG_ERROR("Failed to start detection, error code: %d\n", result);
|
||||
return;
|
||||
}
|
||||
|
||||
m_cameraDetecting = true;
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::stopCamera()
|
||||
{
|
||||
m_cameraInitTimer->stop();
|
||||
|
||||
if (m_eyeDevice) {
|
||||
if (m_cameraDetecting) {
|
||||
m_eyeDevice->StopDetect();
|
||||
m_cameraDetecting = false;
|
||||
}
|
||||
|
||||
if (m_cameraInitialized) {
|
||||
m_eyeDevice->CloseDevice();
|
||||
m_cameraInitialized = false;
|
||||
}
|
||||
|
||||
delete m_eyeDevice;
|
||||
m_eyeDevice = nullptr;
|
||||
}
|
||||
|
||||
LOG_INFO("Camera stopped\n");
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::onCameraInitTimer()
|
||||
{
|
||||
LOG_DEBUG("Retrying camera initialization...\n");
|
||||
|
||||
// 尝试重新初始化和连接相机
|
||||
if (!m_eyeDevice) {
|
||||
if (!initializeCamera()) {
|
||||
return; // 继续重试
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试连接相机
|
||||
int result = m_eyeDevice->OpenDevice(nullptr);
|
||||
if (result == 0) {
|
||||
// 连接成功,开始检测
|
||||
m_cameraInitTimer->stop();
|
||||
m_cameraInitialized = true;
|
||||
|
||||
result = m_eyeDevice->StartDetect(OnPointCloudCallback, keResultDataType_Position, this);
|
||||
if (result == 0) {
|
||||
m_cameraDetecting = true;
|
||||
LOG_INFO("Camera connection restored successfully!\n");
|
||||
} else {
|
||||
LOG_ERROR("Failed to start detection after reconnection, error code: %d\n", result);
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING("Still unable to connect to camera, continuing retry...\n");
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::OnStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
|
||||
{
|
||||
BeltTearingPresenter* presenter = static_cast<BeltTearingPresenter*>(pInfoParam);
|
||||
if (!presenter) return;
|
||||
|
||||
LOG_DEBUG("Camera status changed: %d\n", static_cast<int>(eStatus));
|
||||
|
||||
// 处理相机状态变化
|
||||
switch (eStatus) {
|
||||
case keDeviceWorkStatus_Eye_Comming:
|
||||
LOG_INFO("Camera connected\n");
|
||||
break;
|
||||
case keDeviceWorkStatus_Offline:
|
||||
LOG_WARNING("Camera disconnected, attempting to reconnect...\n");
|
||||
presenter->m_cameraInitialized = false;
|
||||
presenter->m_cameraDetecting = false;
|
||||
// 开始重连尝试
|
||||
if (!presenter->m_cameraInitTimer->isActive()) {
|
||||
presenter->m_cameraInitTimer->start(3000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::OnPointCloudCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pParam)
|
||||
{
|
||||
if(keResultDataType_Position != eDataType) return;
|
||||
|
||||
BeltTearingPresenter* presenter = static_cast<BeltTearingPresenter*>(pParam);
|
||||
if (!presenter || !pLaserLinePoint) return;
|
||||
|
||||
// 处理点云数据
|
||||
presenter->processPointCloudData(pLaserLinePoint);
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::processPointCloudData(const SVzLaserLineData* pLaserLine)
|
||||
{
|
||||
if (!m_beltTearingAlgo || !pLaserLine) return;
|
||||
|
||||
try {
|
||||
|
||||
SVzNL3DLaserLine sNL3DLaserLine;
|
||||
sNL3DLaserLine.nTimeStamp = pLaserLine->llTimeStamp;
|
||||
sNL3DLaserLine.p3DPosition = static_cast<SVzNL3DPosition*>(pLaserLine->p3DPoint);
|
||||
sNL3DLaserLine.nPositionCnt = pLaserLine->nPointCount;
|
||||
// 调用算法进行检测
|
||||
std::vector<SSG_beltTearingInfo> results = m_beltTearingAlgo->Predit(&sNL3DLaserLine, pLaserLine->llFrameIdx);
|
||||
|
||||
// 如果有检测结果,发送到网络客户端
|
||||
if (!results.empty()) {
|
||||
LOG_INFO("Detected %d belt tearing(s)\n", results.size());
|
||||
sendTearingResults(results);
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("Error in algorithm processing: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::sendTearingResults(const std::vector<SSG_beltTearingInfo>& results)
|
||||
{
|
||||
if (results.empty() || m_clients.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 将检测结果转换为JSON格式
|
||||
QJsonArray tearingArray;
|
||||
|
||||
for (const auto& result : results) {
|
||||
QJsonObject tearingObj;
|
||||
// tearingObj["level"] = QString::number(result.level);
|
||||
tearingObj["id"] = QString::number(result.tearID);
|
||||
tearingObj["tearStatus"] = QString::number(static_cast<int>(result.tearStatus));
|
||||
tearingObj["tearType"] = QString::number(result.tearType);
|
||||
tearingObj["statLineIdx"] = QString::number(result.statLineIdx);
|
||||
tearingObj["endLineIdx"] = QString::number(result.endLineIdx);
|
||||
tearingObj["tearDepth"] = QString::number(result.tearDepth);
|
||||
tearingObj["tearWidth"] = QString::number(result.tearWidth);
|
||||
// tearingObj["tearLength"] = QString::number(result.tearLength);
|
||||
tearingObj["roiLeft"] = QString::number(result.roi.left);
|
||||
tearingObj["roiRight"] = QString::number(result.roi.right);
|
||||
tearingObj["roiTop"] = QString::number(result.roi.top);
|
||||
tearingObj["roiBottom"] = QString::number(result.roi.bottom);
|
||||
// tearingObj["imageFile"] = QString::fromStdString(result.imageFile);
|
||||
// tearingObj["older"] = QString::fromStdString(result.older);
|
||||
tearingObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
|
||||
tearingArray.append(tearingObj);
|
||||
}
|
||||
|
||||
// 转换为JSON字符串
|
||||
QJsonDocument doc(tearingArray);
|
||||
QByteArray message = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
// 创建数据包
|
||||
QByteArray package;
|
||||
QDataStream stream(&package, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
stream << quint8(static_cast<quint8>(ByteDataType::Text)) << quint32(message.size());
|
||||
package.append(message);
|
||||
package.append("___END___\r\n");
|
||||
|
||||
// 发送到所有连接的客户端
|
||||
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
|
||||
QTcpSocket *socket = it.value();
|
||||
if (socket->state() == QAbstractSocket::ConnectedState) {
|
||||
socket->write(package);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Sent tearing detection results to %d client(s)\n", m_clients.size());
|
||||
}
|
||||
|
||||
bool BeltTearingPresenter::startServer(quint16 port)
|
||||
@ -36,9 +385,9 @@ bool BeltTearingPresenter::startServer(quint16 port)
|
||||
bool result = m_tcpServer->listen(QHostAddress::Any, port);
|
||||
|
||||
if (result) {
|
||||
std::cout << "TCP server started on port " << port << std::endl;
|
||||
LOG_INFO("TCP server started on port %d\n", port);
|
||||
} else {
|
||||
std::cout << "Failed to start TCP server: " << m_tcpServer->errorString().toStdString() << std::endl;
|
||||
LOG_ERROR("Failed to start TCP server: %s\n", m_tcpServer->errorString().toStdString().c_str());
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -57,25 +406,9 @@ void BeltTearingPresenter::stopServer()
|
||||
m_tcpServer->close();
|
||||
}
|
||||
|
||||
// 停止数据发送定时器
|
||||
stopSendingSimulatedData();
|
||||
|
||||
m_port = 0;
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::startSendingSimulatedData()
|
||||
{
|
||||
// 启动定时器,每2秒发送一次模拟数据
|
||||
m_dataTimer->start(1000);
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::stopSendingSimulatedData()
|
||||
{
|
||||
if (m_dataTimer->isActive()) {
|
||||
m_dataTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::onNewConnection()
|
||||
{
|
||||
while (m_tcpServer->hasPendingConnections()) {
|
||||
@ -90,7 +423,7 @@ void BeltTearingPresenter::onNewConnection()
|
||||
// 连接客户端信号
|
||||
connect(socket, &QTcpSocket::disconnected, this, &BeltTearingPresenter::onClientDisconnected);
|
||||
|
||||
std::cout << "Client connected: " << clientId.toStdString() << std::endl;
|
||||
LOG_INFO("Client connected: %s\n", clientId.toStdString().c_str());
|
||||
|
||||
// 发送欢迎消息
|
||||
QByteArray welcomeMsg = "Welcome to BeltTearing Server!";
|
||||
@ -116,164 +449,34 @@ void BeltTearingPresenter::onClientDisconnected()
|
||||
|
||||
if (!clientId.isEmpty()) {
|
||||
m_clients.remove(clientId);
|
||||
std::cout << "Client disconnected: " << clientId.toStdString() << std::endl;
|
||||
LOG_INFO("Client disconnected: %s\n", clientId.toStdString().c_str());
|
||||
}
|
||||
|
||||
socket->deleteLater();
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::onSendSimulatedData()
|
||||
{
|
||||
static unsigned int nCount = 0;
|
||||
nCount++;
|
||||
// 向所有连接的客户端发送模拟数据
|
||||
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
|
||||
QTcpSocket *socket = it.value();
|
||||
if (socket->state() == QAbstractSocket::ConnectedState) {
|
||||
if(nCount % 2 == 0){
|
||||
sendSimulatedImage(socket);
|
||||
}else{
|
||||
sendSimulatedTearingData(socket);
|
||||
}
|
||||
// 随机选择发送图像或日志记录
|
||||
// sendSimulatedImage(socket);
|
||||
// sendSimulatedLogRecords(socket);
|
||||
// sendSimulatedTearingData(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::sendSimulatedImage(QTcpSocket *socket)
|
||||
{
|
||||
// 创建一个模拟的图像
|
||||
cv::Mat image(480, 640, CV_8UC3, cv::Scalar(128, 128, 128));
|
||||
|
||||
// 在图像上绘制一些随机内容
|
||||
cv::circle(image, cv::Point(320, 240), 50, cv::Scalar(0, 0, 255), -1);
|
||||
cv::rectangle(image, cv::Rect(100, 100, 200, 150), cv::Scalar(0, 255, 0), 2);
|
||||
|
||||
static unsigned int s_imageCount = 0;
|
||||
// 在图像上叠加数字
|
||||
QString numberText = QString::number(++s_imageCount); // 生成一个随机数
|
||||
cv::putText(image, numberText.toStdString(), cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2);
|
||||
|
||||
// 编码图像
|
||||
std::vector<uchar> imgBuffer;
|
||||
std::vector<int> params = {cv::IMWRITE_PNG_COMPRESSION, 3};
|
||||
cv::imencode(".png", image, imgBuffer, params);
|
||||
|
||||
QByteArray byteArray(reinterpret_cast<const char*>(imgBuffer.data()), imgBuffer.size());
|
||||
|
||||
// 创建数据包
|
||||
QByteArray package;
|
||||
QDataStream stream(&package, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
stream << quint8(static_cast<quint8>(ByteDataType::Image)) << quint32(byteArray.size());
|
||||
package.append(byteArray);
|
||||
package.append("___END___\r\n");
|
||||
|
||||
// 发送数据
|
||||
socket->write(package);
|
||||
|
||||
std::cout << "Sent simulated image data to client" << std::endl;
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::sendSimulatedLogRecords(QTcpSocket *socket)
|
||||
{
|
||||
// 创建模拟日志记录
|
||||
QJsonArray logRecords;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
QJsonObject record;
|
||||
record["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
record["level"] = QString("INFO");
|
||||
record["message"] = QString("Simulated log message %1").arg(i + 1);
|
||||
record["source"] = QString("BeltTearingDetector");
|
||||
|
||||
logRecords.append(record);
|
||||
}
|
||||
|
||||
// 将日志记录转换为JSON字符串
|
||||
QJsonDocument doc(logRecords);
|
||||
QByteArray message = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
// 创建数据包
|
||||
QByteArray package;
|
||||
QDataStream stream(&package, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
stream << quint8(static_cast<quint8>(ByteDataType::Text)) << quint32(message.size());
|
||||
package.append(message);
|
||||
package.append("___END___\r\n");
|
||||
|
||||
// 发送数据
|
||||
socket->write(package);
|
||||
|
||||
std::cout << "Sent simulated log records to client" << std::endl;
|
||||
}
|
||||
|
||||
void BeltTearingPresenter::sendSimulatedTearingData(QTcpSocket *socket)
|
||||
{
|
||||
// 创建模拟撕裂数据
|
||||
QJsonArray tearingDataArray;
|
||||
|
||||
// 生成随机数量的撕裂数据(1-3个)
|
||||
int tearingCount = QRandomGenerator::global()->bounded(1, 4);
|
||||
|
||||
for (int i = 0; i < tearingCount; i++) {
|
||||
QJsonObject tearingInfo;
|
||||
|
||||
// 随机生成撕裂数据
|
||||
int level = QRandomGenerator::global()->bounded(1, 4); // 1-3级
|
||||
int tearStatus = QRandomGenerator::global()->bounded(1, 4); // 1-3状态
|
||||
|
||||
QString statusStr;
|
||||
switch (tearStatus) {
|
||||
case 1: statusStr = "新的撕裂"; break;
|
||||
case 2: statusStr = "进行中"; break;
|
||||
case 3: statusStr = "已完成"; break;
|
||||
default: statusStr = "无效撕裂"; break;
|
||||
}
|
||||
|
||||
// 填充撕裂信息
|
||||
tearingInfo.insert("level", QString::number(level));
|
||||
tearingInfo.insert("id", QString::number(QRandomGenerator::global()->bounded(1000, 9999)));
|
||||
tearingInfo.insert("tearStatus", statusStr);
|
||||
tearingInfo.insert("tearType", QString::number(QRandomGenerator::global()->bounded(1, 5)));
|
||||
tearingInfo.insert("statLineIdx", QString::number(QRandomGenerator::global()->bounded(1, 100)));
|
||||
tearingInfo.insert("endLineIdx", QString::number(QRandomGenerator::global()->bounded(1, 100)));
|
||||
tearingInfo.insert("tearDepth", QString::number(QRandomGenerator::global()->bounded(1, 1000)));
|
||||
tearingInfo.insert("tearWidth", QString::number(QRandomGenerator::global()->bounded(1, 500)));
|
||||
tearingInfo.insert("tearLength", QString::number(QRandomGenerator::global()->bounded(1, 1000)));
|
||||
tearingInfo.insert("roiLeft", QString::number(QRandomGenerator::global()->bounded(1, 200)));
|
||||
tearingInfo.insert("roiRight", QString::number(QRandomGenerator::global()->bounded(200, 400)));
|
||||
tearingInfo.insert("roiTop", QString::number(QRandomGenerator::global()->bounded(1, 100)));
|
||||
tearingInfo.insert("roiBottom", QString::number(QRandomGenerator::global()->bounded(100, 300)));
|
||||
tearingInfo.insert("imageFile", QString("/Image/Tearing/image_%1__.jpg").arg(QRandomGenerator::global()->bounded(1, 100)));
|
||||
tearingInfo.insert("older", (QRandomGenerator::global()->bounded(0, 2) == 0) ? "-" : "旧伤");
|
||||
|
||||
tearingDataArray.append(tearingInfo);
|
||||
}
|
||||
|
||||
// 将撕裂数据转换为JSON字符串
|
||||
QJsonDocument doc(tearingDataArray);
|
||||
QByteArray message = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
// 创建数据包
|
||||
QByteArray package;
|
||||
QDataStream stream(&package, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
stream << quint8(static_cast<quint8>(ByteDataType::Text)) << quint32(message.size());
|
||||
package.append(message);
|
||||
package.append("___END___\r\n");
|
||||
|
||||
// 发送数据
|
||||
socket->write(package);
|
||||
|
||||
std::cout << "Sent simulated tearing data to client" << std::endl;
|
||||
}
|
||||
|
||||
QString BeltTearingPresenter::generateClientId(QTcpSocket *socket)
|
||||
{
|
||||
// 使用UUID生成唯一的客户端ID
|
||||
return QUuid::createUuid().toString();
|
||||
}
|
||||
|
||||
QString BeltTearingPresenter::getVersionString()
|
||||
{
|
||||
return QString(BELT_TEARING_SERVER_VERSION_STRING);
|
||||
}
|
||||
|
||||
QString BeltTearingPresenter::getProductName()
|
||||
{
|
||||
return QString(BELT_TEARING_SERVER_PRODUCT_NAME);
|
||||
}
|
||||
|
||||
QString BeltTearingPresenter::getBuildInfo()
|
||||
{
|
||||
return QString("%1 %2 built on %3 %4 for %5")
|
||||
.arg(BELT_TEARING_SERVER_BUILD_TYPE)
|
||||
.arg(BELT_TEARING_SERVER_VERSION_STRING)
|
||||
.arg(BELT_TEARING_SERVER_BUILD_DATE)
|
||||
.arg(BELT_TEARING_SERVER_BUILD_TIME)
|
||||
.arg(BELT_TEARING_SERVER_PLATFORM);
|
||||
}
|
||||
|
||||
@ -7,6 +7,13 @@
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "IVrEyeDevice.h"
|
||||
#include "BeltTearingAlgo.h"
|
||||
#include "beltTearingDetection_Export.h"
|
||||
#include "IVrBeltTearingConfig.h"
|
||||
#include "VZNL_Common.h"
|
||||
#include "VZNL_Types.h"
|
||||
#include "VrLog.h"
|
||||
|
||||
// 假设ByteDataType枚举定义
|
||||
enum class ByteDataType : quint8 {
|
||||
@ -14,7 +21,7 @@ enum class ByteDataType : quint8 {
|
||||
Image = 2
|
||||
};
|
||||
|
||||
class BeltTearingPresenter : public QObject
|
||||
class BeltTearingPresenter : public QObject, public IVrBeltTearingConfigChangeNotify
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -22,29 +29,70 @@ public:
|
||||
explicit BeltTearingPresenter(QObject *parent = nullptr);
|
||||
~BeltTearingPresenter();
|
||||
|
||||
// 配置相关方法
|
||||
bool loadConfiguration(const QString& configFilePath);
|
||||
void applyAlgorithmParameters(const BeltTearingAlgorithmParams& params);
|
||||
|
||||
// 初始化TCP服务器
|
||||
bool startServer(quint16 port);
|
||||
bool startServer(quint16 port = 0); // port = 0 表示使用配置文件中的端口
|
||||
void stopServer();
|
||||
|
||||
// 模拟数据发送
|
||||
void startSendingSimulatedData();
|
||||
void stopSendingSimulatedData();
|
||||
// 相机相关方法
|
||||
bool initializeCamera();
|
||||
void startCamera();
|
||||
void stopCamera();
|
||||
|
||||
// 获取配置信息
|
||||
quint16 getServerPort() const { return m_configResult.serverPort; }
|
||||
const BeltTearingConfigResult& getConfig() const { return m_configResult; }
|
||||
|
||||
// 获取版本信息
|
||||
static QString getVersionString();
|
||||
static QString getProductName();
|
||||
static QString getBuildInfo();
|
||||
|
||||
// IVrBeltTearingConfigChangeNotify接口实现
|
||||
void OnConfigChanged(const BeltTearingConfigResult& configResult) override;
|
||||
|
||||
private slots:
|
||||
void onNewConnection();
|
||||
void onClientDisconnected();
|
||||
void onSendSimulatedData();
|
||||
void onCameraInitTimer();
|
||||
|
||||
private:
|
||||
// TCP服务器相关
|
||||
QTcpServer *m_tcpServer;
|
||||
QMap<QString, QTcpSocket*> m_clients;
|
||||
QTimer *m_dataTimer;
|
||||
quint16 m_port;
|
||||
|
||||
// 模拟数据发送方法
|
||||
void sendSimulatedImage(QTcpSocket *socket);
|
||||
void sendSimulatedLogRecords(QTcpSocket *socket);
|
||||
void sendSimulatedTearingData(QTcpSocket *socket);
|
||||
// 配置相关
|
||||
IVrBeltTearingConfig *m_config;
|
||||
BeltTearingConfigResult m_configResult;
|
||||
QString m_configFilePath;
|
||||
|
||||
// 相机相关
|
||||
IVrEyeDevice *m_eyeDevice;
|
||||
QTimer *m_cameraInitTimer;
|
||||
QString m_cameraIP;
|
||||
bool m_cameraInitialized;
|
||||
bool m_cameraDetecting;
|
||||
|
||||
// 算法相关
|
||||
BeltTearingAlgo *m_beltTearingAlgo;
|
||||
|
||||
// 相机状态回调函数
|
||||
static void OnStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
|
||||
|
||||
// 点云数据回调函数
|
||||
static void OnPointCloudCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pParam);
|
||||
|
||||
// 处理点云数据
|
||||
void processPointCloudData(const SVzLaserLineData* pLaserLine);
|
||||
|
||||
// 发送算法结果
|
||||
void sendTearingResults(const std::vector<SSG_beltTearingInfo>& results);
|
||||
|
||||
// 工具方法
|
||||
QString generateClientId(QTcpSocket *socket);
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
QT += core gui
|
||||
QT += serialport
|
||||
QT += core
|
||||
QT += network
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
@ -7,7 +6,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += c++11 console
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
@ -20,12 +22,14 @@ INCLUDEPATH += $$PWD/Utils/Inc
|
||||
|
||||
INCLUDEPATH += $$PWD/../VrConfig/Inc
|
||||
INCLUDEPATH += $$PWD/../VrEyeDevice/Inc
|
||||
INCLUDEPATH += $$PWD/../BeltTearingConfig/Inc
|
||||
|
||||
SOURCES += \
|
||||
BeltTearingAlgo.cpp \
|
||||
beltTearingDetection.cpp \
|
||||
main.cpp \
|
||||
BeltTearingPresenter.cpp
|
||||
BeltTearingPresenter.cpp \
|
||||
PathManager.cpp
|
||||
|
||||
HEADERS += \
|
||||
SG_baseAlgo_Export.h \
|
||||
@ -33,20 +37,25 @@ HEADERS += \
|
||||
SG_errCode.h \
|
||||
beltTearingDetection_Export.h \
|
||||
BeltTearingAlgo.h \
|
||||
BeltTearingPresenter.h
|
||||
BeltTearingPresenter.h \
|
||||
PathManager.h \
|
||||
Version.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
win32:CONFIG(debug, debug|release) {
|
||||
LIBS += -L../VrUtils/debug -lVrUtils
|
||||
LIBS += -L../VrEyeDevice/debug -lVrEyeDevice
|
||||
LIBS += -L../BeltTearingConfig/debug -lBeltTearingConfig
|
||||
LIBS += -L../VrEyeDevice/debug -lVrEyeDevice
|
||||
LIBS += -L../VrUtils/debug -lVrUtils
|
||||
}else:win32:CONFIG(release, debug|release){
|
||||
LIBS += -L../VrUtils/release -lVrUtils
|
||||
LIBS += -L../VrEyeDevice/release -lVrEyeDevice
|
||||
LIBS += -L../BeltTearingConfig/release -lBeltTearingConfig
|
||||
LIBS += -L../VrEyeDevice/release -lVrEyeDevice
|
||||
LIBS += -L../VrUtils/release -lVrUtils
|
||||
}else:unix:!macx {
|
||||
# Unix/Linux平台库链接(包括交叉编译)
|
||||
# 注意链接顺序:依赖关系从高到低
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
LIBS += -L../BeltTearingConfig -lBeltTearingConfig
|
||||
LIBS += -L../VrEyeDevice -lVrEyeDevice
|
||||
|
||||
# 添加系统库依赖
|
||||
@ -84,22 +93,10 @@ else:unix:!macx: {
|
||||
LIBS += -L$$PWD/../SDK/OpenCV320/Arm/aarch64 -lopencv_core -lopencv_imgproc -lopencv_highgui
|
||||
}
|
||||
|
||||
# 添加libmodbus依赖
|
||||
|
||||
# 添加Windows系统库依赖
|
||||
win32 {
|
||||
LIBS += -lshell32
|
||||
LIBS += -lws2_32
|
||||
LIBS += Advapi32.lib
|
||||
LIBS += -lAdvapi32
|
||||
}
|
||||
|
||||
# Default rules for deployment.
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
# Link real-time library for POSIX shared memory functions
|
||||
LIBS += -lrt
|
||||
}
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
59
BeltTearingServer/PathManager.cpp
Normal file
59
BeltTearingServer/PathManager.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "PathManager.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QFile>
|
||||
#include <iostream>
|
||||
|
||||
QString PathManager::GetConfigFilePath()
|
||||
{
|
||||
// 确保目标目录存在
|
||||
EnsureConfigDirectoryExists();
|
||||
return GetAppConfigDirectory() + "/config.xml";
|
||||
}
|
||||
|
||||
|
||||
QString PathManager::GetAppConfigDirectory()
|
||||
{
|
||||
QString configDir = "";
|
||||
#ifdef _WIN32
|
||||
// Windows系统:使用程序目录
|
||||
configDir = GetProgramDirectory() + "/BeltTearingServer/Config";
|
||||
#else
|
||||
// Linux系统:使用用户配置目录
|
||||
configDir = GetUserConfigDirectory() + "/../BeltTearingServer/Config";
|
||||
#endif
|
||||
return configDir;
|
||||
}
|
||||
|
||||
bool PathManager::EnsureConfigDirectoryExists()
|
||||
{
|
||||
QString configDir = GetAppConfigDirectory();
|
||||
|
||||
if (QDir().exists(configDir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cout << "Creating configuration directory: " << configDir.toStdString() << std::endl;
|
||||
|
||||
bool success = QDir().mkpath(configDir);
|
||||
if (success) {
|
||||
std::cout << "Configuration directory created successfully" << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to create configuration directory: " << configDir.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QString PathManager::GetProgramDirectory()
|
||||
{
|
||||
QString exePath = QCoreApplication::applicationFilePath();
|
||||
return QFileInfo(exePath).absoluteDir().path();
|
||||
}
|
||||
|
||||
QString PathManager::GetUserConfigDirectory()
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
}
|
||||
48
BeltTearingServer/PathManager.h
Normal file
48
BeltTearingServer/PathManager.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef PATHMANAGER_H
|
||||
#define PATHMANAGER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
* @brief 路径管理器类,统一管理皮带撕裂服务器的配置文件路径
|
||||
*
|
||||
* 该类负责根据不同操作系统提供合适的配置文件存储路径:
|
||||
* - Windows: 程序目录
|
||||
* - Linux: 用户配置目录 (~/.config/BeltTearingServer/)
|
||||
*/
|
||||
class PathManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 获取配置文件(BeltTearingConfig.xml)的完整路径
|
||||
* @return 配置文件的完整路径
|
||||
*/
|
||||
static QString GetConfigFilePath();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 确保配置目录存在,如果不存在则创建
|
||||
* @return 成功创建或目录已存在返回true,失败返回false
|
||||
*/
|
||||
static bool EnsureConfigDirectoryExists();
|
||||
|
||||
/**
|
||||
* @brief 获取应用程序配置目录路径
|
||||
* @return 配置目录的完整路径
|
||||
*/
|
||||
static QString GetAppConfigDirectory();
|
||||
|
||||
/**
|
||||
* @brief 获取程序目录路径
|
||||
* @return 程序目录的完整路径
|
||||
*/
|
||||
static QString GetProgramDirectory();
|
||||
|
||||
/**
|
||||
* @brief 获取用户配置目录路径(仅Linux系统)
|
||||
* @return 用户配置目录的完整路径
|
||||
*/
|
||||
static QString GetUserConfigDirectory();
|
||||
};
|
||||
|
||||
#endif // PATHMANAGER_H
|
||||
29
BeltTearingServer/Version.h
Normal file
29
BeltTearingServer/Version.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define BELT_TEARING_SERVER_VERSION_STRING "1.0.0"
|
||||
#define BELT_TEARING_SERVER_VERSION_BUILD "1"
|
||||
#define BELT_TEARING_SERVER_PRODUCT_NAME "BeltTearingServer"
|
||||
#define BELT_TEARING_SERVER_COMPANY_NAME "VisionRobot"
|
||||
#define BELT_TEARING_SERVER_COPYRIGHT "Copyright (C) 2024 VisionRobot. All rights reserved."
|
||||
#define BELT_TEARING_SERVER_DESCRIPTION "Belt Tearing Detection Server with Camera Integration"
|
||||
|
||||
// 构建信息
|
||||
#define BELT_TEARING_SERVER_BUILD_DATE __DATE__
|
||||
#define BELT_TEARING_SERVER_BUILD_TIME __TIME__
|
||||
|
||||
#ifdef _WIN32
|
||||
#define BELT_TEARING_SERVER_PLATFORM "Windows"
|
||||
#elif __linux__
|
||||
#define BELT_TEARING_SERVER_PLATFORM "Linux"
|
||||
#else
|
||||
#define BELT_TEARING_SERVER_PLATFORM "Unknown"
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BELT_TEARING_SERVER_BUILD_TYPE "Debug"
|
||||
#else
|
||||
#define BELT_TEARING_SERVER_BUILD_TYPE "Release"
|
||||
#endif
|
||||
|
||||
#endif // VERSION_H
|
||||
@ -1,25 +1,60 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include "BeltTearingPresenter.h"
|
||||
#include "PathManager.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "VrLog.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
// 设置应用程序信息
|
||||
app.setApplicationName(BELT_TEARING_SERVER_PRODUCT_NAME);
|
||||
app.setApplicationVersion(BELT_TEARING_SERVER_VERSION_STRING);
|
||||
app.setOrganizationName(BELT_TEARING_SERVER_COMPANY_NAME);
|
||||
|
||||
// 打印启动横幅
|
||||
LOG_DEBUG("===========================================\n");
|
||||
LOG_INFO(" %s\n", BELT_TEARING_SERVER_PRODUCT_NAME);
|
||||
LOG_INFO(" %s\n", BELT_TEARING_SERVER_DESCRIPTION);
|
||||
LOG_INFO(" %s\n", BELT_TEARING_SERVER_COPYRIGHT);
|
||||
LOG_DEBUG("===========================================\n");
|
||||
|
||||
// 创建并初始化Presenter
|
||||
BeltTearingPresenter presenter;
|
||||
|
||||
// 启动TCP服务器,监听端口12345
|
||||
if (!presenter.startServer(12345)) {
|
||||
std::cout << "Failed to start server" << std::endl;
|
||||
// 获取配置文件路径
|
||||
QString configFilePath = PathManager::GetConfigFilePath();
|
||||
|
||||
// 加载配置文件
|
||||
if (!presenter.loadConfiguration(configFilePath)) {
|
||||
LOG_WARN("Warning: Failed to load configuration file. Using default settings.\n");
|
||||
LOG_INFO("Config file location: %s\n", configFilePath.toStdString().c_str());
|
||||
}
|
||||
|
||||
// 启动TCP服务器(使用配置文件中的端口,如果配置加载失败则使用默认端口)
|
||||
quint16 serverPort = presenter.getServerPort();
|
||||
if (serverPort == 0) {
|
||||
serverPort = 5900; // 默认端口
|
||||
}
|
||||
|
||||
if (!presenter.startServer(serverPort)) {
|
||||
LOG_ERROR("Failed to start server on port %d\n", serverPort);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 开始发送模拟数据
|
||||
presenter.startSendingSimulatedData();
|
||||
// 启动相机
|
||||
presenter.startCamera();
|
||||
|
||||
std::cout << "BeltTearing Server started. Press Ctrl+C to exit." << std::endl;
|
||||
// 输出系统信息
|
||||
LOG_INFO("=== BeltTearing Server Started ===\n");
|
||||
LOG_DEBUG("===================================\n");
|
||||
LOG_INFO("Server is running. Press Ctrl+C to exit.\n");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@ -6,6 +6,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += c++17
|
||||
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
@ -91,12 +95,12 @@ win32:CONFIG(debug, debug|release) {
|
||||
}else:unix:!macx {
|
||||
# Unix/Linux平台库链接(包括交叉编译)
|
||||
# 注意链接顺序:依赖关系从高到低
|
||||
LIBS += -L../GrabBagConfig -lGrabBagConfig
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
LIBS += -L../VrEyeDevice -lVrEyeDevice
|
||||
LIBS += -L../GrabBagConfig -lGrabBagConfig
|
||||
LIBS += -L../VrEyeDevice -lVrEyeDevice
|
||||
LIBS += -L../Module/ModbusTCPServer -lModbusTCPServer
|
||||
LIBS += -L../Module/ShareMem -lShareMem
|
||||
LIBS += -L../VrNets -lVrNets
|
||||
LIBS += -L../VrNets -lVrModbus
|
||||
LIBS += -L../Module/ShareMem -lShareMem
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
|
||||
# 添加系统库依赖
|
||||
LIBS += -lpthread
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#include "ui_dialogcamera.h"
|
||||
#include <QMessageBox>
|
||||
#include "VrLog.h"
|
||||
#include "StyledMessageBox.h"
|
||||
|
||||
DialogCamera::DialogCamera(const std::vector<std::pair<std::string, IVrEyeDevice*>>& deviceList,
|
||||
QWidget *parent) :
|
||||
@ -72,16 +71,16 @@ void DialogCamera::on_camera_selection_changed(int index)
|
||||
void DialogCamera::on_btn_camer_ok_clicked()
|
||||
{
|
||||
if (!m_currentDevice) {
|
||||
StyledMessageBox::warning(this, "错误", "设备未初始化");
|
||||
QMessageBox::warning(this, "错误", "设备未初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
// 应用参数配置
|
||||
if (ApplyCameraParameters()) {
|
||||
StyledMessageBox::information(this, "成功", "相机参数配置成功!");
|
||||
QMessageBox::information(this, "成功", "相机参数配置成功!");
|
||||
accept(); // 关闭对话框并返回Accepted
|
||||
} else {
|
||||
StyledMessageBox::warning(this, "失败", "相机参数配置失败,请检查设备连接!");
|
||||
QMessageBox::warning(this, "失败", "相机参数配置失败,请检查设备连接!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +132,7 @@ void DialogCamera::InitCameraParameters()
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
StyledMessageBox::critical(this, "错误", "读取相机参数时发生异常");
|
||||
QMessageBox::critical(this, "错误", "读取相机参数时发生异常");
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +192,7 @@ bool DialogCamera::ApplyCameraParameters()
|
||||
return success;
|
||||
|
||||
} catch (...) {
|
||||
StyledMessageBox::critical(this, "错误", "应用相机参数时发生异常");
|
||||
QMessageBox::critical(this, "错误", "应用相机参数时发生异常");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,6 @@
|
||||
#include <QtCore/QFile>
|
||||
#include "VrLog.h"
|
||||
#include "PathManager.h"
|
||||
#include "StyledMessageBox.h"
|
||||
|
||||
DialogConfig::DialogConfig(IVrConfig* devConfig, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@ -71,7 +70,7 @@ void DialogConfig::LoadConfigToUI()
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("Failed to load configuration: %s\n", e.what());
|
||||
|
||||
StyledMessageBox::critical(this, "错误", "加载配置文件失败!");
|
||||
QMessageBox::critical(this, "错误", "加载配置文件失败!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,10 +126,10 @@ bool DialogConfig::SaveConfigFromUI()
|
||||
void DialogConfig::on_btn_apply_clicked()
|
||||
{
|
||||
if (SaveConfigFromUI()) {
|
||||
StyledMessageBox::information(this, "成功", "配置保存成功!");
|
||||
QMessageBox::information(this, "成功", "配置保存成功!");
|
||||
accept(); // 关闭对话框并返回Accepted
|
||||
} else {
|
||||
StyledMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限!");
|
||||
QMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ win32:CONFIG(debug, debug|release) {
|
||||
}else:win32:CONFIG(release, debug|release){
|
||||
LIBS += -L../VrUtils/release -lVrUtils
|
||||
}else:unix:!macx {
|
||||
# Unix/Linux平台库链接(包括交叉编译)
|
||||
# Unix/Linux平台库链接(including cross-compilation)
|
||||
LIBS += -L../VrUtils -lVrUtils
|
||||
}
|
||||
|
||||
@ -36,4 +36,4 @@ win32:CONFIG(debug, debug|release) {
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
}
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
@ -1,339 +1,339 @@
|
||||
#ifndef IVRCONFIG_H
|
||||
#define IVRCONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief 项目类型枚举
|
||||
*/
|
||||
enum class ProjectType
|
||||
{
|
||||
GrabBag = 0, // 抓包
|
||||
DirectBag = 1, // 带方向的编织袋
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 项目类型字符串转换函数
|
||||
*/
|
||||
inline std::string ProjectTypeToString(ProjectType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ProjectType::GrabBag:
|
||||
return "GrabBag";
|
||||
case ProjectType::DirectBag:
|
||||
return "DirectBag";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 字符串转项目类型函数
|
||||
*/
|
||||
inline ProjectType StringToProjectType(const std::string& str)
|
||||
{
|
||||
if (str == "GrabBag" || str == "0") {
|
||||
return ProjectType::GrabBag;
|
||||
} else if (str == "DirectBag" || str == "1") {
|
||||
return ProjectType::DirectBag;
|
||||
} else {
|
||||
return ProjectType::GrabBag; // 默认返回抓包
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string ip;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 串口配置信息
|
||||
*/
|
||||
struct SerialConfig
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string portName = "COM6"; // 串口名称
|
||||
#else
|
||||
std::string portName = "/dev/ttyS3"; // 串口名称
|
||||
#endif
|
||||
int baudRate = 115200; // 波特率
|
||||
int dataBits = 8; // 数据位
|
||||
int stopBits = 1; // 停止位
|
||||
int parity = 0; // 校验位 (0-无校验, 1-奇校验, 2-偶校验)
|
||||
int flowControl = 0; // 流控制 (0-无, 1-硬件, 2-软件)
|
||||
bool enabled = true; // 是否启用串口通信
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 编织袋参数
|
||||
*/
|
||||
struct VrBagParam
|
||||
{
|
||||
double bagL = 650.0; // 长
|
||||
double bagW = 450.0; // 宽
|
||||
double bagH = 160.0; // 高
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 垛参数
|
||||
*/
|
||||
struct VrPileParam
|
||||
{
|
||||
double pileL = 1300.0; // 垛长
|
||||
double pileW = 900.0; // 垛宽
|
||||
double pileH = 800.0; // 垛高
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 离群点滤波参数
|
||||
*/
|
||||
struct VrOutlierFilterParam
|
||||
{
|
||||
double continuityTh = 20.0; // 连续性阈值
|
||||
int outlierTh = 5; // 离群点判断阈值
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 角点参数
|
||||
*/
|
||||
struct VrCornerParam
|
||||
{
|
||||
double minEndingGap = 20.0; // 最小结束间隙
|
||||
double minEndingGap_z = 20.0; // z方向最小结束间隙
|
||||
double scale = 15.0; // 计算方向角的窗口比例因子
|
||||
double cornerTh = 30.0; // 角点阈值
|
||||
double jumpCornerTh_1 = 60.0; // 判断角点是否为跳跃的第一阈值
|
||||
double jumpCornerTh_2 = 15.0; // 判断角点是否为跳跃的第二阈值
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 斜率参数
|
||||
*/
|
||||
struct VrSlopeParam
|
||||
{
|
||||
double LSlopeZWin = 10.0; // 计算L型Slope特征高度计算的窗口长度
|
||||
double validSlopeH = 10.0; // 有效斜率高度
|
||||
double minLJumpH = 20.0; // 最小L跳跃高度
|
||||
double minEndingGap = 20.0; // 最小结束间隙
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief V特征参数
|
||||
*/
|
||||
struct VrVFeatureParam
|
||||
{
|
||||
double valleyMinH = 10.0; // 山谷最小高度
|
||||
double valleyMaxW = 80.0; // 山谷最大宽度
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 树生长参数
|
||||
*/
|
||||
struct VrTreeGrowParam
|
||||
{
|
||||
double yDeviation_max = 20.0; // 生长时允许的最大Y偏差
|
||||
double zDeviation_max = 80.0; // 生长时允许的最大Z偏差
|
||||
int maxLineSkipNum = 5; // 生长时允许跳过的最大线条数
|
||||
double maxSkipDistance = 20.0; // 最大跳跃距离
|
||||
double minLTypeTreeLen = 50.0; // L型树的最小长度
|
||||
double minVTypeTreeLen = 50.0; // V型树的最小长度
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HSV颜色比较参数
|
||||
*/
|
||||
struct VrHsvCmpParam
|
||||
{
|
||||
double hueTh = 15.0; // 色度阈值,小于门限为同一颜色
|
||||
double saturateTh = 120.0; // 色饱和度阈值
|
||||
double FBVldPtRatioTh = 0.075; // 正反两面有效颜色点的比例门限
|
||||
bool frontVldPtGreater = true; // true:有效颜色比例高的点的是正面;false:有效颜色比例高的点的是反面
|
||||
bool front_upVldPtGreater = false; // true:有效颜色比例高的点的是正面朝上;false:有效颜色比例高的点的是正面朝下
|
||||
bool back_upVldPtGreater = true; // true:有效颜色比例高的点的是反面朝上;false:有效颜色比例高的点的是反面朝下
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RGB颜色模式
|
||||
*/
|
||||
struct VrRgbColorPattern
|
||||
{
|
||||
int r = 36; // 红色分量
|
||||
int g = 165; // 绿色分量
|
||||
int b = 208; // 蓝色分量
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 颜色模板参数
|
||||
*/
|
||||
#define RGN_HIST_SIZE 16
|
||||
struct VrColorTemplateParam
|
||||
{
|
||||
double frontColorTemplate[RGN_HIST_SIZE] = {0.0}; // 正面颜色模板
|
||||
double backColorTemplate[RGN_HIST_SIZE] = {0.0}; // 反面颜色模板
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 单个相机的平面校准参数
|
||||
*/
|
||||
struct VrCameraPlaneCalibParam
|
||||
{
|
||||
int cameraIndex = 1; // 相机索引(1-based)
|
||||
std::string cameraName = ""; // 相机名称
|
||||
double planeCalib[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // 旋转矩阵,将数据调平(默认单位矩阵)
|
||||
double planeHeight = -1.0; // 参考平面的高度,用于去除地面数据
|
||||
double invRMatrix[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // 逆旋转矩阵,回到原坐标系(默认单位矩阵)
|
||||
bool isCalibrated = false; // 是否已经校准
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 平面校准参数(支持多相机)
|
||||
*/
|
||||
struct VrPlaneCalibParam
|
||||
{
|
||||
std::vector<VrCameraPlaneCalibParam> cameraCalibParams; // 各个相机的校准参数
|
||||
|
||||
// 获取指定相机的校准参数
|
||||
VrCameraPlaneCalibParam* GetCameraCalibParam(int cameraIndex) {
|
||||
for (auto& param : cameraCalibParams) {
|
||||
if (param.cameraIndex == cameraIndex) {
|
||||
return ¶m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 获取指定相机的校准参数(const版本)
|
||||
const VrCameraPlaneCalibParam* GetCameraCalibParam(int cameraIndex) const {
|
||||
for (const auto& param : cameraCalibParams) {
|
||||
if (param.cameraIndex == cameraIndex) {
|
||||
return ¶m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 设置或更新指定相机的校准参数
|
||||
void SetCameraCalibParam(const VrCameraPlaneCalibParam& param) {
|
||||
for (auto& existingParam : cameraCalibParams) {
|
||||
if (existingParam.cameraIndex == param.cameraIndex) {
|
||||
existingParam = param;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 如果不存在,则添加新的
|
||||
cameraCalibParams.push_back(param);
|
||||
}
|
||||
|
||||
// 移除指定相机的校准参数
|
||||
void RemoveCameraCalibParam(int cameraIndex) {
|
||||
cameraCalibParams.erase(
|
||||
std::remove_if(cameraCalibParams.begin(), cameraCalibParams.end(),
|
||||
[cameraIndex](const VrCameraPlaneCalibParam& param) {
|
||||
return param.cameraIndex == cameraIndex;
|
||||
}),
|
||||
cameraCalibParams.end());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调试参数
|
||||
*/
|
||||
struct VrDebugParam
|
||||
{
|
||||
bool enableDebug = false; // 是否开启调试模式
|
||||
bool savePointCloud = false; // 是否保存点云数据
|
||||
bool saveDebugImage = false; // 是否保存调试图像
|
||||
bool printDetailLog = false; // 是否打印详细日志
|
||||
std::string debugOutputPath = ""; // 调试输出路径
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 算法参数配置结构
|
||||
*/
|
||||
struct VrAlgorithmParams
|
||||
{
|
||||
VrBagParam bagParam; // 编织袋参数
|
||||
VrPileParam pileParam; // 垛参数
|
||||
VrOutlierFilterParam filterParam; // 滤波参数
|
||||
VrCornerParam cornerParam; // 角点特征参数
|
||||
VrSlopeParam slopeParam; // 斜率参数
|
||||
VrVFeatureParam valleyParam; // 山谷参数
|
||||
VrTreeGrowParam growParam; // 增长参数
|
||||
VrPlaneCalibParam planeCalibParam; // 平面校准参数
|
||||
VrHsvCmpParam hsvCmpParam; // HSV颜色比较参数
|
||||
VrRgbColorPattern rgbColorPattern; // RGB颜色模式
|
||||
VrColorTemplateParam colorTemplateParam; // 颜色模板参数
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 配置加载结果
|
||||
*/
|
||||
struct ConfigResult
|
||||
{
|
||||
std::vector<DeviceInfo> cameraList;
|
||||
std::vector<DeviceInfo> deviceList;
|
||||
VrAlgorithmParams algorithmParams; // 算法参数
|
||||
VrDebugParam debugParam; // 调试参数
|
||||
SerialConfig serialConfig; // 串口配置
|
||||
ProjectType projectType; // 项目类型
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 配置改变通知接口
|
||||
*/
|
||||
class IVrConfigChangeNotify
|
||||
{
|
||||
public:
|
||||
virtual ~IVrConfigChangeNotify() {}
|
||||
|
||||
/**
|
||||
* @brief 配置数据改变通知
|
||||
* @param configResult 新的配置数据
|
||||
*/
|
||||
virtual void OnConfigChanged(const ConfigResult& configResult) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief VrConfig接口类
|
||||
*/
|
||||
class IVrConfig
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 虚析构函数
|
||||
*/
|
||||
virtual ~IVrConfig() {}
|
||||
|
||||
/**
|
||||
* @brief 创建实例
|
||||
* @return 实例
|
||||
*/
|
||||
static bool CreateInstance(IVrConfig** ppVrConfig);
|
||||
|
||||
/**
|
||||
* @brief 加载配置文件
|
||||
* @param filePath 配置文件路径
|
||||
* @return 加载的配置结果
|
||||
*/
|
||||
virtual ConfigResult LoadConfig(const std::string& filePath) = 0;
|
||||
|
||||
/**
|
||||
* @brief 保存配置文件
|
||||
* @param filePath 配置文件路径
|
||||
* @param configResult 配置结果
|
||||
* @return 是否保存成功
|
||||
*/
|
||||
virtual bool SaveConfig(const std::string& filePath, ConfigResult& configResult) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置配置改变通知回调
|
||||
* @param notify 通知接口指针
|
||||
*/
|
||||
virtual void SetConfigChangeNotify(IVrConfigChangeNotify* notify) = 0;
|
||||
};
|
||||
|
||||
#endif // IVRCONFIG_H
|
||||
#ifndef IVRCONFIG_H
|
||||
#define IVRCONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief 项目类型枚举
|
||||
*/
|
||||
enum class ProjectType
|
||||
{
|
||||
GrabBag = 0, // 抓包
|
||||
DirectBag = 1, // 带方向的编织袋
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 项目类型字符串转换函数
|
||||
*/
|
||||
inline std::string ProjectTypeToString(ProjectType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ProjectType::GrabBag:
|
||||
return "GrabBag";
|
||||
case ProjectType::DirectBag:
|
||||
return "DirectBag";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 字符串转项目类型函数
|
||||
*/
|
||||
inline ProjectType StringToProjectType(const std::string& str)
|
||||
{
|
||||
if (str == "GrabBag" || str == "0") {
|
||||
return ProjectType::GrabBag;
|
||||
} else if (str == "DirectBag" || str == "1") {
|
||||
return ProjectType::DirectBag;
|
||||
} else {
|
||||
return ProjectType::GrabBag; // 默认返回抓包
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string ip;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 串口配置信息
|
||||
*/
|
||||
struct SerialConfig
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string portName = "COM6"; // 串口名称
|
||||
#else
|
||||
std::string portName = "/dev/ttyS3"; // 串口名称
|
||||
#endif
|
||||
int baudRate = 115200; // 波特率
|
||||
int dataBits = 8; // 数据位
|
||||
int stopBits = 1; // 停止位
|
||||
int parity = 0; // 校验位 (0-无校验, 1-奇校验, 2-偶校验)
|
||||
int flowControl = 0; // 流控制 (0-无, 1-硬件, 2-软件)
|
||||
bool enabled = true; // 是否启用串口通信
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 编织袋参数
|
||||
*/
|
||||
struct VrBagParam
|
||||
{
|
||||
double bagL = 650.0; // 长
|
||||
double bagW = 450.0; // 宽
|
||||
double bagH = 160.0; // 高
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 垛参数
|
||||
*/
|
||||
struct VrPileParam
|
||||
{
|
||||
double pileL = 1300.0; // 垛长
|
||||
double pileW = 900.0; // 垛宽
|
||||
double pileH = 800.0; // 垛高
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 离群点滤波参数
|
||||
*/
|
||||
struct VrOutlierFilterParam
|
||||
{
|
||||
double continuityTh = 20.0; // 连续性阈值
|
||||
int outlierTh = 5; // 离群点判断阈值
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 角点参数
|
||||
*/
|
||||
struct VrCornerParam
|
||||
{
|
||||
double minEndingGap = 20.0; // 最小结束间隙
|
||||
double minEndingGap_z = 20.0; // z方向最小结束间隙
|
||||
double scale = 15.0; // 计算方向角的窗口比例因子
|
||||
double cornerTh = 30.0; // 角点阈值
|
||||
double jumpCornerTh_1 = 60.0; // 判断角点是否为跳跃的第一阈值
|
||||
double jumpCornerTh_2 = 15.0; // 判断角点是否为跳跃的第二阈值
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 斜率参数
|
||||
*/
|
||||
struct VrSlopeParam
|
||||
{
|
||||
double LSlopeZWin = 10.0; // 计算L型Slope特征高度计算的窗口长度
|
||||
double validSlopeH = 10.0; // 有效斜率高度
|
||||
double minLJumpH = 20.0; // 最小L跳跃高度
|
||||
double minEndingGap = 20.0; // 最小结束间隙
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief V特征参数
|
||||
*/
|
||||
struct VrVFeatureParam
|
||||
{
|
||||
double valleyMinH = 10.0; // 山谷最小高度
|
||||
double valleyMaxW = 80.0; // 山谷最大宽度
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 树生长参数
|
||||
*/
|
||||
struct VrTreeGrowParam
|
||||
{
|
||||
double yDeviation_max = 20.0; // 生长时允许的最大Y偏差
|
||||
double zDeviation_max = 80.0; // 生长时允许的最大Z偏差
|
||||
int maxLineSkipNum = 5; // 生长时允许跳过的最大线条数
|
||||
double maxSkipDistance = 20.0; // 最大跳跃距离
|
||||
double minLTypeTreeLen = 50.0; // L型树的最小长度
|
||||
double minVTypeTreeLen = 50.0; // V型树的最小长度
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HSV颜色比较参数
|
||||
*/
|
||||
struct VrHsvCmpParam
|
||||
{
|
||||
double hueTh = 15.0; // 色度阈值,小于门限为同一颜色
|
||||
double saturateTh = 120.0; // 色饱和度阈值
|
||||
double FBVldPtRatioTh = 0.075; // 正反两面有效颜色点的比例门限
|
||||
bool frontVldPtGreater = true; // true:有效颜色比例高的点的是正面;false:有效颜色比例高的点的是反面
|
||||
bool front_upVldPtGreater = false; // true:有效颜色比例高的点的是正面朝上;false:有效颜色比例高的点的是正面朝下
|
||||
bool back_upVldPtGreater = true; // true:有效颜色比例高的点的是反面朝上;false:有效颜色比例高的点的是反面朝下
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RGB颜色模式
|
||||
*/
|
||||
struct VrRgbColorPattern
|
||||
{
|
||||
int r = 36; // 红色分量
|
||||
int g = 165; // 绿色分量
|
||||
int b = 208; // 蓝色分量
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 颜色模板参数
|
||||
*/
|
||||
#define RGN_HIST_SIZE 16
|
||||
struct VrColorTemplateParam
|
||||
{
|
||||
double frontColorTemplate[RGN_HIST_SIZE] = {0.0}; // 正面颜色模板
|
||||
double backColorTemplate[RGN_HIST_SIZE] = {0.0}; // 反面颜色模板
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 单个相机的平面校准参数
|
||||
*/
|
||||
struct VrCameraPlaneCalibParam
|
||||
{
|
||||
int cameraIndex = 1; // 相机索引(1-based)
|
||||
std::string cameraName = ""; // 相机名称
|
||||
double planeCalib[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // 旋转矩阵,将数据调平(默认单位矩阵)
|
||||
double planeHeight = -1.0; // 参考平面的高度,用于去除地面数据
|
||||
double invRMatrix[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // 逆旋转矩阵,回到原坐标系(默认单位矩阵)
|
||||
bool isCalibrated = false; // 是否已经校准
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 平面校准参数(支持多相机)
|
||||
*/
|
||||
struct VrPlaneCalibParam
|
||||
{
|
||||
std::vector<VrCameraPlaneCalibParam> cameraCalibParams; // 各个相机的校准参数
|
||||
|
||||
// 获取指定相机的校准参数
|
||||
VrCameraPlaneCalibParam* GetCameraCalibParam(int cameraIndex) {
|
||||
for (auto& param : cameraCalibParams) {
|
||||
if (param.cameraIndex == cameraIndex) {
|
||||
return ¶m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 获取指定相机的校准参数(const版本)
|
||||
const VrCameraPlaneCalibParam* GetCameraCalibParam(int cameraIndex) const {
|
||||
for (const auto& param : cameraCalibParams) {
|
||||
if (param.cameraIndex == cameraIndex) {
|
||||
return ¶m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 设置或更新指定相机的校准参数
|
||||
void SetCameraCalibParam(const VrCameraPlaneCalibParam& param) {
|
||||
for (auto& existingParam : cameraCalibParams) {
|
||||
if (existingParam.cameraIndex == param.cameraIndex) {
|
||||
existingParam = param;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 如果不存在,则添加新的
|
||||
cameraCalibParams.push_back(param);
|
||||
}
|
||||
|
||||
// 移除指定相机的校准参数
|
||||
void RemoveCameraCalibParam(int cameraIndex) {
|
||||
cameraCalibParams.erase(
|
||||
std::remove_if(cameraCalibParams.begin(), cameraCalibParams.end(),
|
||||
[cameraIndex](const VrCameraPlaneCalibParam& param) {
|
||||
return param.cameraIndex == cameraIndex;
|
||||
}),
|
||||
cameraCalibParams.end());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调试参数
|
||||
*/
|
||||
struct VrDebugParam
|
||||
{
|
||||
bool enableDebug = false; // 是否开启调试模式
|
||||
bool savePointCloud = false; // 是否保存点云数据
|
||||
bool saveDebugImage = false; // 是否保存调试图像
|
||||
bool printDetailLog = false; // 是否打印详细日志
|
||||
std::string debugOutputPath = ""; // 调试输出路径
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 算法参数配置结构
|
||||
*/
|
||||
struct VrAlgorithmParams
|
||||
{
|
||||
VrBagParam bagParam; // 编织袋参数
|
||||
VrPileParam pileParam; // 垛参数
|
||||
VrOutlierFilterParam filterParam; // 滤波参数
|
||||
VrCornerParam cornerParam; // 角点特征参数
|
||||
VrSlopeParam slopeParam; // 斜率参数
|
||||
VrVFeatureParam valleyParam; // 山谷参数
|
||||
VrTreeGrowParam growParam; // 增长参数
|
||||
VrPlaneCalibParam planeCalibParam; // 平面校准参数
|
||||
VrHsvCmpParam hsvCmpParam; // HSV颜色比较参数
|
||||
VrRgbColorPattern rgbColorPattern; // RGB颜色模式
|
||||
VrColorTemplateParam colorTemplateParam; // 颜色模板参数
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 配置加载结果
|
||||
*/
|
||||
struct ConfigResult
|
||||
{
|
||||
std::vector<DeviceInfo> cameraList;
|
||||
std::vector<DeviceInfo> deviceList;
|
||||
VrAlgorithmParams algorithmParams; // 算法参数
|
||||
VrDebugParam debugParam; // 调试参数
|
||||
SerialConfig serialConfig; // 串口配置
|
||||
ProjectType projectType; // 项目类型
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 配置改变通知接口
|
||||
*/
|
||||
class IVrConfigChangeNotify
|
||||
{
|
||||
public:
|
||||
virtual ~IVrConfigChangeNotify() {}
|
||||
|
||||
/**
|
||||
* @brief 配置数据改变通知
|
||||
* @param configResult 新的配置数据
|
||||
*/
|
||||
virtual void OnConfigChanged(const ConfigResult& configResult) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief VrConfig接口类
|
||||
*/
|
||||
class IVrConfig
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 虚析构函数
|
||||
*/
|
||||
virtual ~IVrConfig() {}
|
||||
|
||||
/**
|
||||
* @brief 创建实例
|
||||
* @return 实例
|
||||
*/
|
||||
static bool CreateInstance(IVrConfig** ppVrConfig);
|
||||
|
||||
/**
|
||||
* @brief 加载配置文件
|
||||
* @param filePath 配置文件路径
|
||||
* @return 加载的配置结果
|
||||
*/
|
||||
virtual ConfigResult LoadConfig(const std::string& filePath) = 0;
|
||||
|
||||
/**
|
||||
* @brief 保存配置文件
|
||||
* @param filePath 配置文件路径
|
||||
* @param configResult 配置结果
|
||||
* @return 是否保存成功
|
||||
*/
|
||||
virtual bool SaveConfig(const std::string& filePath, ConfigResult& configResult) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置配置改变通知回调
|
||||
* @param notify 通知接口指针
|
||||
*/
|
||||
virtual void SetConfigChangeNotify(IVrConfigChangeNotify* notify) = 0;
|
||||
};
|
||||
|
||||
#endif // IVRCONFIG_H
|
||||
|
||||
@ -4,9 +4,37 @@
|
||||
PKG_NAME="BeltTearingServer"
|
||||
PKG_ARCH="arm64"
|
||||
|
||||
# 默认版本信息
|
||||
PKG_VERSION="1.0.0"
|
||||
BUILD_NUMBER="1"
|
||||
# 从Version.h文件中读取版本信息
|
||||
VERSION_FILE="../BeltTearingServer/Version.h"
|
||||
|
||||
if [ -f "${VERSION_FILE}" ]; then
|
||||
# 读取版本号(从 BELT_TEARING_SERVER_VERSION_STRING 中提取)
|
||||
PKG_VERSION=$(grep '#define BELT_TEARING_SERVER_VERSION_STRING' ${VERSION_FILE} | sed 's/.*"\(.*\)".*/\1/')
|
||||
# 读取构建号(从 BELT_TEARING_SERVER_VERSION_BUILD 中提取)
|
||||
BUILD_NUMBER=$(grep '#define BELT_TEARING_SERVER_VERSION_BUILD' ${VERSION_FILE} | sed 's/.*"\(.*\)".*/\1/')
|
||||
|
||||
echo "从 ${VERSION_FILE} 读取版本信息:"
|
||||
echo " 版本号: ${PKG_VERSION}"
|
||||
echo " 构建号: ${BUILD_NUMBER}"
|
||||
|
||||
# 如果读取失败,使用默认值
|
||||
if [ -z "${PKG_VERSION}" ]; then
|
||||
PKG_VERSION="1.0.0"
|
||||
echo "警告: 无法读取版本号,使用默认值: ${PKG_VERSION}"
|
||||
fi
|
||||
|
||||
if [ -z "${BUILD_NUMBER}" ]; then
|
||||
BUILD_NUMBER="1"
|
||||
echo "警告: 无法读取构建号,使用默认值: ${BUILD_NUMBER}"
|
||||
fi
|
||||
else
|
||||
# Version.h文件不存在时的默认值
|
||||
PKG_VERSION="1.0.0"
|
||||
BUILD_NUMBER="1"
|
||||
echo "警告: ${VERSION_FILE} 文件不存在,使用默认版本信息"
|
||||
echo " 版本号: ${PKG_VERSION}"
|
||||
echo " 构建号: ${BUILD_NUMBER}"
|
||||
fi
|
||||
|
||||
PKG_PATH=$HOME/BeltTearingServerPkg
|
||||
CODE_PATH=../
|
||||
@ -23,12 +51,32 @@ fi
|
||||
|
||||
echo "创建打包目录结构..."
|
||||
mkdir -p ${PKG_PATH}/DEBIAN
|
||||
mkdir -p ${PKG_PATH}/opt/onvm
|
||||
mkdir -p ${PKG_PATH}/usr/lib
|
||||
mkdir -p ${PKG_PATH}/etc/profile.d
|
||||
mkdir -p ${PKG_PATH}/opt/belttearingserver
|
||||
|
||||
# 复制 BeltTearingServer/onvm 目录下的所有内容到 /opt
|
||||
BELT_TEARING_SERVER_PATH=${CODE_PATH}/GrabBagPrj/BeltTearingServer/onvm
|
||||
|
||||
echo "复制 Qt 运行时环境..."
|
||||
#QT depend
|
||||
QT_PKG_PATH=/opt/firefly_qt5.15_arm64_20.04
|
||||
cp -rfd ${QT_PKG_PATH}/ext ${PKG_PATH}/opt/firefly_qt5.15
|
||||
cp ${QT_PKG_PATH}/target_qtEnv.sh ${PKG_PATH}/etc/profile.d/
|
||||
|
||||
echo "复制依赖库文件..."
|
||||
#depend
|
||||
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_core*.so* ${PKG_PATH}/usr/lib/
|
||||
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_imgproc*.so* ${PKG_PATH}/usr/lib/
|
||||
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_highgui*.so* ${PKG_PATH}/usr/lib/
|
||||
|
||||
cp ${CODE_PATH}/SDK/bagPosition/Arm/aarch64/*.so ${PKG_PATH}/usr/lib/
|
||||
cp ${CODE_PATH}/SDK/VzNLSDK/Arm/aarch64/*.so ${PKG_PATH}/usr/lib/
|
||||
|
||||
|
||||
# 复制 BeltTearingServer 目录下的所有内容到 /opt
|
||||
echo "复制 BeltTearingServer 内容到 /opt/..."
|
||||
cp -r ${BELT_TEARING_SERVER_PATH}/* ${PKG_PATH}/opt/onvm
|
||||
|
||||
#APP
|
||||
cp ${CODE_PATH}/GrabBagPrj/buildarm/BeltTearingServer/BeltTearingServer ${PKG_PATH}/opt/belttearingserver/
|
||||
|
||||
echo "生成 control 文件..."
|
||||
#control
|
||||
@ -49,16 +97,16 @@ cat > ${POSTINST_PATH} << 'EOF'
|
||||
|
||||
echo "配置 BeltTearingServer 应用程序..."
|
||||
|
||||
# 安装并启用 onvm.service
|
||||
if [ -f /opt/onvm/onvm.service ]; then
|
||||
echo "安装 onvm.service..."
|
||||
cp /opt/onvm/onvm.service /etc/systemd/system/
|
||||
# 安装并启用 belttearingserver.service
|
||||
if [ -f /opt/belttearingserver/belttearingserver.service ]; then
|
||||
echo "安装 belttearingserver.service..."
|
||||
cp /opt/belttearingserver/belttearingserver.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable onvm.service
|
||||
systemctl start onvm.service
|
||||
echo "onvm.service 已安装并设置为开机自启"
|
||||
systemctl enable belttearingserver.service
|
||||
systemctl start belttearingserver.service
|
||||
echo "belttearingserver.service 已安装并设置为开机自启"
|
||||
else
|
||||
echo "错误: 未找到 onvm.service 文件"
|
||||
echo "错误: 未找到 belttearingserver.service 文件"
|
||||
fi
|
||||
|
||||
EOF
|
||||
@ -73,14 +121,17 @@ cat > ${POSTRM_PATH} << 'EOF'
|
||||
|
||||
echo "卸载 BeltTearingServer 应用程序..."
|
||||
|
||||
# 停止并禁用 onvm.service
|
||||
systemctl stop onvm.service 2>/dev/null || true
|
||||
systemctl disable onvm.service 2>/dev/null || true
|
||||
rm -f /etc/systemd/system/onvm.service
|
||||
# 停止并禁用 belttearingserver.service
|
||||
systemctl stop belttearingserver.service 2>/dev/null || true
|
||||
systemctl disable belttearingserver.service 2>/dev/null || true
|
||||
rm -f /etc/systemd/system/belttearingserver.service
|
||||
|
||||
# 重新加载systemd
|
||||
systemctl daemon-reload
|
||||
|
||||
# 清理 /opt/belttearingserver 目录
|
||||
rm -rf /opt/belttearingserver
|
||||
|
||||
echo "BeltTearingServer 应用程序卸载完成!"
|
||||
EOF
|
||||
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
QT -= gui
|
||||
|
||||
CONFIG += c++17 console
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
|
||||
@ -7,6 +7,11 @@ DEFINES += DLLBUILD
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
@ -34,4 +39,4 @@ SOURCES += \
|
||||
unix {
|
||||
target.path = $$[QT_INSTALL_PLUGINS]/generic
|
||||
}
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
@ -15,7 +15,11 @@
|
||||
#include "../crc/checksum.h"
|
||||
#include "../ini/SimpleIni.h"
|
||||
|
||||
// getopt只在Windows平台下包含,其他平台使用系统自带的getopt
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
// getopt只在Windows平台下包含,其他平台使用系统自带的getopt
|
||||
#ifdef _WIN32
|
||||
#include "getopt.h"
|
||||
#pragma comment(lib, "VrUtils.lib")
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#define LOG_DEBUG(...) VrLogUtils::EchoLog(KELOGLEVEL_Debug, logfilename(__FILE__), __LINE__, "APPD", ##__VA_ARGS__)
|
||||
#define LOG_INFO(...) VrLogUtils::EchoLog(KELOGLEVEL_Info, logfilename(__FILE__), __LINE__, "APPI", ##__VA_ARGS__)
|
||||
#define LOG_WARNING(...) VrLogUtils::EchoLog(KELOGLEVEL_Warning, logfilename(__FILE__), __LINE__, "APPW", ##__VA_ARGS__)
|
||||
#define LOG_WARN(...) VrLogUtils::EchoLog(KELOGLEVEL_Warning, logfilename(__FILE__), __LINE__, "APPW", ##__VA_ARGS__)
|
||||
#define LOG_ERROR(...) VrLogUtils::EchoLog(KELOGLEVEL_Error, logfilename(__FILE__), __LINE__, "APPE", ##__VA_ARGS__)
|
||||
#define LOG_ERRO(...) VrLogUtils::EchoLog(KELOGLEVEL_Error, logfilename(__FILE__), __LINE__, "APPE", ##__VA_ARGS__)
|
||||
#define LOG_ERR(...) VrLogUtils::EchoLog(KELOGLEVEL_Error, logfilename(__FILE__), __LINE__, "APPE", ##__VA_ARGS__)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user