皮带撕裂结果合并

This commit is contained in:
yiyi 2025-09-24 22:36:13 +08:00
parent 74a3e72534
commit 3932ec324d
9 changed files with 251 additions and 81 deletions

View File

@ -290,9 +290,6 @@ void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, cons
// 将新数据添加到缓存 // 将新数据添加到缓存
m_dataBuffers[serverName].append(pData, nLen); m_dataBuffers[serverName].append(pData, nLen);
LOG_DEBUG("Buffered data for %s: buffer_size=%d, new_data=%d\n",
serverName.toStdString().c_str(), m_dataBuffers[serverName].size(), nLen);
// 检查是否有完整的数据包 // 检查是否有完整的数据包
QByteArray &buffer = m_dataBuffers[serverName]; QByteArray &buffer = m_dataBuffers[serverName];
const QByteArray endMarker = "___END___\r\n"; const QByteArray endMarker = "___END___\r\n";
@ -301,8 +298,7 @@ void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, cons
while (endPos != -1) { while (endPos != -1) {
// 找到完整数据包 // 找到完整数据包
QByteArray completePacket = buffer.left(endPos); QByteArray completePacket = buffer.left(endPos);
LOG_DEBUG("Found complete packet for %s: size=%d\n", // LOG_DEBUG("Found complete packet for %s: size=%d\n", serverName.toStdString().c_str(), completePacket.size());
serverName.toStdString().c_str(), completePacket.size());
// 处理完整数据包 // 处理完整数据包
processCompletePacket(serverName, completePacket); processCompletePacket(serverName, completePacket);
@ -323,8 +319,7 @@ void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, cons
void BeltTearingPresenter::processCompletePacket(const QString &serverName, const QByteArray &completeData) void BeltTearingPresenter::processCompletePacket(const QString &serverName, const QByteArray &completeData)
{ {
LOG_DEBUG("Processing complete packet from %s: size=%d\n", // LOG_DEBUG("Processing complete packet from %s: size=%d\n", serverName.toStdString().c_str(), completeData.size());
serverName.toStdString().c_str(), completeData.size());
// 解析数据包协议头 // 解析数据包协议头
if (completeData.size() < 5) { if (completeData.size() < 5) {
@ -347,8 +342,7 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
QByteArray payloadData = completeData.mid(5, dataSize); QByteArray payloadData = completeData.mid(5, dataSize);
LOG_DEBUG("Parsed packet: dataType=%d, dataSize=%d, payload_size=%d\n", // LOG_DEBUG("Parsed packet: dataType=%d, dataSize=%d, payload_size=%d\n", dataType, dataSize, payloadData.size());
dataType, dataSize, payloadData.size());
BeltTearingResult tearResult; BeltTearingResult tearResult;
tearResult.bImageValid = false; tearResult.bImageValid = false;
@ -357,7 +351,6 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
{ {
// 处理文本数据 // 处理文本数据
QString textData = QString::fromUtf8(payloadData); QString textData = QString::fromUtf8(payloadData);
LOG_DEBUG("Received text data: %s\n", textData.left(100).toStdString().c_str());
// 解析JSON数据 // 解析JSON数据
QJsonDocument doc = QJsonDocument::fromJson(textData.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(textData.toUtf8());
@ -380,16 +373,12 @@ void BeltTearingPresenter::processCompletePacket(const QString &serverName, cons
} }
} }
} }
LOG_DEBUG("Processed text data from server %s\n", serverName.toStdString().c_str());
} }
else if (dataType == static_cast<int>(ByteDataType::Image)) else if (dataType == static_cast<int>(ByteDataType::Image))
{ {
// 处理图像数据 // 处理图像数据
LOG_DEBUG("Attempting to load image from %d bytes\n", payloadData.size());
if (tearResult.image.loadFromData(payloadData)) { if (tearResult.image.loadFromData(payloadData)) {
tearResult.bImageValid = true; tearResult.bImageValid = true;
LOG_DEBUG("Successfully loaded image: %dx%d\n",
tearResult.image.width(), tearResult.image.height());
} else { } else {
LOG_ERROR("Failed to load image from data\n"); LOG_ERROR("Failed to load image from data\n");
} }

View File

@ -1,10 +1,21 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QApplication> #include <QApplication>
#include <QMetaType>
#include <QVector>
#include <QList>
#include <QPersistentModelIndex>
#include <QAbstractItemModel>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
// Register meta types for signal-slot connections
qRegisterMetaType<QVector<int>>("QVector<int>");
qRegisterMetaType<QList<QPersistentModelIndex>>("QList<QPersistentModelIndex>");
qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>("QAbstractItemModel::LayoutChangeHint");
MainWindow w; MainWindow w;
w.show(); w.show();
return a.exec(); return a.exec();

View File

@ -162,7 +162,6 @@ void MainWindow::on_btn_test_clicked()
} }
void MainWindow::on_btn_camera_clicked() void MainWindow::on_btn_camera_clicked()
{ {
if(nullptr == ui_dialognetconfig){ if(nullptr == ui_dialognetconfig){

View File

@ -45,7 +45,7 @@ background-color: rgba(255, 255, 255, 0);</string>
<widget class="QPushButton" name="btn_test"> <widget class="QPushButton" name="btn_test">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>840</x> <x>960</x>
<y>21</y> <y>21</y>
<width>220</width> <width>220</width>
<height>80</height> <height>80</height>
@ -68,7 +68,7 @@ border: none;</string>
<widget class="QPushButton" name="btn_camera"> <widget class="QPushButton" name="btn_camera">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>555</x> <x>440</x>
<y>21</y> <y>21</y>
<width>220</width> <width>220</width>
<height>80</height> <height>80</height>
@ -165,7 +165,7 @@ background-color: rgba(255, 255, 255, 0);</string>
<widget class="QPushButton" name="btn_start"> <widget class="QPushButton" name="btn_start">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1220</x> <x>1260</x>
<y>21</y> <y>21</y>
<width>80</width> <width>80</width>
<height>80</height> <height>80</height>
@ -187,7 +187,7 @@ background-color: rgba(255, 255, 255, 0);</string>
<widget class="QPushButton" name="btn_stop"> <widget class="QPushButton" name="btn_stop">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1360</x> <x>1400</x>
<y>21</y> <y>21</y>
<width>80</width> <width>80</width>
<height>80</height> <height>80</height>
@ -206,6 +206,29 @@ background-color: rgba(255, 255, 255, 0);</string>
<string/> <string/>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="btn_algo_config">
<property name="geometry">
<rect>
<x>700</x>
<y>21</y>
<width>220</width>
<height>80</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_algo.png);
background-color: rgb(38, 40, 47);
border: none;</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget> </widget>
<widget class="QFrame" name="detect_result"> <widget class="QFrame" name="detect_result">
<property name="geometry"> <property name="geometry">

View File

@ -4,6 +4,9 @@
#include <QTableWidgetItem> #include <QTableWidgetItem>
#include <QBrush> #include <QBrush>
#include <QColor> #include <QColor>
#include <QApplication>
#include <QStyle>
#include <QRegExp>
TearingDataTableWidget::TearingDataTableWidget(QWidget *parent) TearingDataTableWidget::TearingDataTableWidget(QWidget *parent)
: QWidget(parent) : QWidget(parent)
@ -32,7 +35,8 @@ void TearingDataTableWidget::setupTable()
{ {
// 设置表头标签 // 设置表头标签
QStringList headers; QStringList headers;
headers << "ID" << "等级" << "状态" << "类型" /*<< "起始行" << "结束行" */<< "深度" << "宽度" << "长度" << "老化"; // headers << "ID" << "等级" << "状态" << "类型" /*<< "起始行" << "结束行" */<< "深度" << "宽度" << "长度" << "老化";
headers << "ID" << "状态" << "类型" << "深度(mm)" << "宽度(mm)" << "长度(mm)";
// 设置表格属性 // 设置表格属性
m_tableWidget->setColumnCount(headers.size()); m_tableWidget->setColumnCount(headers.size());
@ -50,14 +54,12 @@ void TearingDataTableWidget::setupTable()
m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
// 设置列宽 // 设置列宽
m_tableWidget->setColumnWidth(0, 52); // ID列 m_tableWidget->setColumnWidth(0, 62); // ID列
m_tableWidget->setColumnWidth(1, 45); // 等级列 m_tableWidget->setColumnWidth(1, 100); // 状态列
m_tableWidget->setColumnWidth(2, 80); // 状态列 m_tableWidget->setColumnWidth(2, 80); // 类型列
m_tableWidget->setColumnWidth(3, 45); // 类型列 m_tableWidget->setColumnWidth(3, 100); // 深度列
m_tableWidget->setColumnWidth(4, 80); // 深度列 m_tableWidget->setColumnWidth(4, 100); // 宽度列
m_tableWidget->setColumnWidth(5, 80); // 宽度列 m_tableWidget->setColumnWidth(5, 100); // 长度列
m_tableWidget->setColumnWidth(6, 80); // 长度列
m_tableWidget->setColumnWidth(7, 80); // 老化列
#endif #endif
// 设置样式表 // 设置样式表
m_tableWidget->setStyleSheet( m_tableWidget->setStyleSheet(
@ -75,25 +77,46 @@ void TearingDataTableWidget::setupTable()
" padding: 4px;" " padding: 4px;"
"}" "}"
); );
// 启用表格排序功能
m_tableWidget->setSortingEnabled(true);
// 设置默认按ID列升序排序
m_tableWidget->sortItems(0, Qt::AscendingOrder);
} }
void TearingDataTableWidget::addData(const TearingData &data) void TearingDataTableWidget::addData(const TearingData &data)
{ {
// 将数据显示到QTableWidget上 // 查找是否已存在相同ID的行
int row = m_tableWidget->rowCount(); int existingRow = findExistingRowById(data.id);
m_tableWidget->insertRow(row);
// 使用结构体数据填充表格 int row;
m_tableWidget->setItem(row, 0, new QTableWidgetItem(data.id)); if (existingRow >= 0) {
m_tableWidget->setItem(row, 1, new QTableWidgetItem(data.level)); // 如果存在相同ID更新该行
m_tableWidget->setItem(row, 2, new QTableWidgetItem(data.tearStatus)); row = existingRow;
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearType)); } else {
// m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.statLineIdx)); // 如果不存在,插入新行
// m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.endLineIdx)); row = m_tableWidget->rowCount();
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearDepth)); m_tableWidget->insertRow(row);
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearWidth)); }
m_tableWidget->setItem(row, 6, new QTableWidgetItem(data.tearLength));
m_tableWidget->setItem(row, 7, new QTableWidgetItem(data.older)); // 使用结构体数据填充表格,状态和类型显示中文,并设置居中对齐
NumericTableWidgetItem *idItem = new NumericTableWidgetItem(data.id);
idItem->setTextAlignment(Qt::AlignCenter); // ID列文字居中显示
m_tableWidget->setItem(row, 0, idItem);
QTableWidgetItem *statusItem = new QTableWidgetItem(getTearStatusText(data.tearStatus));
statusItem->setTextAlignment(Qt::AlignCenter); // 状态列文字居中显示
m_tableWidget->setItem(row, 1, statusItem);
QTableWidgetItem *typeItem = new QTableWidgetItem(getTearTypeText(data.tearType));
typeItem->setTextAlignment(Qt::AlignCenter); // 类型列文字居中显示
m_tableWidget->setItem(row, 2, typeItem);
m_tableWidget->setItem(row, 3, new QTableWidgetItem(data.tearDepth));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(data.tearWidth));
// m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.tearLength));
m_tableWidget->setItem(row, 5, new QTableWidgetItem(data.statLineIdx));
// 设置item的文本颜色 // 设置item的文本颜色
for (int i = 0; i < m_tableWidget->horizontalHeader()->count(); i++) { for (int i = 0; i < m_tableWidget->horizontalHeader()->count(); i++) {
@ -102,6 +125,9 @@ void TearingDataTableWidget::addData(const TearingData &data)
item->setForeground(QBrush(Qt::white)); item->setForeground(QBrush(Qt::white));
} }
} }
// 保持表格按ID列排序
m_tableWidget->sortItems(0, Qt::AscendingOrder);
} }
void TearingDataTableWidget::addData(const std::vector<TearingData> &dataList) void TearingDataTableWidget::addData(const std::vector<TearingData> &dataList)
@ -122,3 +148,85 @@ void TearingDataTableWidget::clearData()
{ {
m_tableWidget->setRowCount(0); m_tableWidget->setRowCount(0);
} }
QString TearingDataTableWidget::getTearStatusText(const QString &status)
{
// 将ESG_tearStatus枚举值转换为中文显示
if (status == "0" || status.contains("Uknown")) {
return "未知";
} else if (status == "1" || status.contains("New")) {
return "新发现";
} else if (status == "2" || status.contains("Growing")) {
return "正在增长";
} else if (status == "3" || status.contains("Ended")) {
return "撕裂结束";
} else if (status == "4" || status.contains("Invalid")) {
return "无效撕裂";
}
return status; // 如果无法识别,返回原值
}
QString TearingDataTableWidget::getTearTypeText(const QString &type)
{
// 将ESG_tearType枚举值转换为中文显示
if (type == "0" || type.contains("Uknown")) {
return "未知";
} else if (type == "1" || type.contains("MachineDir")) {
return "纵撕";
} else if (type == "2" || type.contains("CrossWise")) {
return "横撕";
}
return type; // 如果无法识别,返回原值
}
int TearingDataTableWidget::findExistingRowById(const QString &id)
{
// 在表格中查找具有相同ID的行
for (int row = 0; row < m_tableWidget->rowCount(); ++row) {
QTableWidgetItem *item = m_tableWidget->item(row, 0); // ID在第0列
if (item && item->text() == id) {
return row;
}
}
return -1; // 未找到
}
// NumericTableWidgetItem类的实现
NumericTableWidgetItem::NumericTableWidgetItem(const QString &text)
: QTableWidgetItem(text)
{
}
bool NumericTableWidgetItem::operator<(const QTableWidgetItem &other) const
{
// 尝试将文本转换为数字进行比较
double thisValue = toDouble();
double otherValue = static_cast<const NumericTableWidgetItem*>(&other)->toDouble();
// 如果两个值都有效,则按数字比较
if (thisValue != -1 && otherValue != -1) {
return thisValue < otherValue;
}
// 否则按默认的字符串比较
return QTableWidgetItem::operator<(other);
}
double NumericTableWidgetItem::toDouble() const
{
bool ok;
// 尝试直接转换为double
double value = text().toDouble(&ok);
if (ok) {
return value;
}
// 如果直接转换失败,尝试提取数字部分
QRegExp rx("(\\d+)");
if (rx.indexIn(text()) != -1) {
return rx.cap(1).toDouble(&ok);
}
// 如果所有方法都失败,返回-1表示无效值
return -1;
}

View File

@ -3,12 +3,25 @@
#include <QWidget> #include <QWidget>
#include <QTableWidget> #include <QTableWidget>
#include <QTableWidgetItem>
#include <QHeaderView> #include <QHeaderView>
#include <QJsonObject> #include <QJsonObject>
#include <QString> #include <QString>
#include <vector> #include <vector>
#include "IStatusUpdate.h" #include "IStatusUpdate.h"
// 自定义TableWidgetItem类支持按数字值排序
class NumericTableWidgetItem : public QTableWidgetItem
{
public:
NumericTableWidgetItem(const QString &text);
bool operator<(const QTableWidgetItem &other) const override;
private:
double toDouble() const;
};
class TearingDataTableWidget : public QWidget class TearingDataTableWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -25,6 +38,12 @@ public:
private: private:
void setupUI(); void setupUI();
void setupTable(); void setupTable();
QString getTearStatusText(const QString &status);
QString getTearTypeText(const QString &type);
int findExistingRowById(const QString &id);
// 排序相关的私有方法
void connectHeaderSignals();
QTableWidget *m_tableWidget; QTableWidget *m_tableWidget;
}; };

View File

@ -199,22 +199,22 @@ void BeltTearingPresenter::sendTestData(std::string fileName){
std::vector<SVzNL3DPosition> sVzNLPostion; std::vector<SVzNL3DPosition> sVzNLPostion;
sVzNLPostion.clear(); sVzNLPostion.clear();
bool bFindLineNum = true; int nIndex = 0;
int nLaserPointIdx = 0;
SVzLaserLineData pLaserLine; SVzLaserLineData pLaserLine;
while (std::getline(inputFile, line)) { while (std::getline(inputFile, line)) {
if (line.find("Line_") == 0) { if (line.find("Line_") == 0) {
if(!sVzNLPostion.empty()){ if(!sVzNLPostion.empty()){
pLaserLine.llFrameIdx = nLaserPointIdx;
pLaserLine.p3DPoint = sVzNLPostion.data(); pLaserLine.p3DPoint = sVzNLPostion.data();
pLaserLine.nPointCount = sVzNLPostion.size(); pLaserLine.nPointCount = sVzNLPostion.size();
processPointCloudData(&pLaserLine); processPointCloudData(&pLaserLine);
} }
sscanf(line.c_str(), "Line_%lld_%lld", &pLaserLine.llFrameIdx, &pLaserLine.llTimeStamp);
sVzNLPostion.clear(); sVzNLPostion.clear();
nIndex++;
} else if (line.find("{") == 0) { } else if (line.find("{") == 0) {
float lx, ly, rx, ry; float lx, ly, rx, ry;
SVzNL3DPosition pos; SVzNL3DPosition pos;
@ -226,6 +226,10 @@ void BeltTearingPresenter::sendTestData(std::string fileName){
sVzNLPostion.push_back(pos); sVzNLPostion.push_back(pos);
} }
// if(nIndex > 500){
// break;
// }
// std::this_thread::sleep_for(std::chrono::milliseconds(2)); // std::this_thread::sleep_for(std::chrono::milliseconds(2));
} }
@ -398,29 +402,32 @@ void BeltTearingPresenter::processPointCloudData(const SVzLaserLineData* pLaserL
// 将激光线数据添加到队列(用于图像生成) // 将激光线数据添加到队列(用于图像生成)
addLaserLineToQueue(pLaserLine); addLaserLineToQueue(pLaserLine);
// 调用SDK算法 // 调用SDK算法
int errorCode = 0; int errorCode = 0;
std::vector<SSG_beltTearingInfo> beltTearings_new;
std::vector<SSG_beltTearingInfo> beltTearings_growing;
std::vector<SSG_beltTearingInfo> beltTearings_ended;
std::vector<SSG_beltTearingInfo> beltTearings_unknown;
if(!m_bInitAlgo){ if(!m_bInitAlgo){
m_hLineWorkers.resize(pLaserLine->nPointCount); m_hLineWorkers.resize(pLaserLine->nPointCount);
m_beltTearings_new.clear();
m_beltTearings_new.shrink_to_fit();
m_beltTearings_growing.clear();
m_beltTearings_growing.shrink_to_fit();
m_beltTearings_ended.clear();
m_beltTearings_ended.shrink_to_fit();
m_beltTearings_unknown.clear();
m_beltTearings_unknown.shrink_to_fit();
sg_detectBeltTearing( sg_detectBeltTearing(
NULL, //空扫描线,用于复位内部静态变量 NULL, //空扫描线,用于复位内部静态变量
0, 0,
0, 0,
&errorCode, &errorCode,
m_hLineWorkers, m_hLineWorkers,
beltTearings_new, m_beltTearings_new,
beltTearings_growing, m_beltTearings_growing,
beltTearings_ended, m_beltTearings_ended,
beltTearings_unknown, //未判明,应用无需处理。 m_beltTearings_unknown, //未判明,应用无需处理。
m_algorithmParam); m_algorithmParam);
m_bInitAlgo = true; m_bInitAlgo = true;
} }
@ -437,27 +444,36 @@ void BeltTearingPresenter::processPointCloudData(const SVzLaserLineData* pLaserL
algorithmData.nPositionCnt, algorithmData.nPositionCnt,
&errorCode, &errorCode,
m_hLineWorkers, m_hLineWorkers,
beltTearings_new, m_beltTearings_new,
beltTearings_growing, m_beltTearings_growing,
beltTearings_ended, m_beltTearings_ended,
beltTearings_unknown, m_beltTearings_unknown,
m_algorithmParam m_algorithmParam
); );
// 合并所有检测结果 // 合并所有检测结果
std::vector<SSG_beltTearingInfo> allResults; std::vector<SSG_beltTearingInfo> allResults;
allResults.reserve(beltTearings_new.size() + beltTearings_growing.size() + allResults.reserve(m_beltTearings_new.size() + m_beltTearings_growing.size() + m_beltTearings_ended.size());
beltTearings_ended.size() + beltTearings_unknown.size());
allResults.insert(allResults.end(), beltTearings_new.begin(), beltTearings_new.end()); allResults.insert(allResults.end(), m_beltTearings_new.begin(), m_beltTearings_new.end());
// allResults.insert(allResults.end(), beltTearings_growing.begin(), beltTearings_growing.end()); allResults.insert(allResults.end(), m_beltTearings_growing.begin(), m_beltTearings_growing.end());
allResults.insert(allResults.end(), beltTearings_ended.begin(), beltTearings_ended.end()); allResults.insert(allResults.end(), m_beltTearings_ended.begin(), m_beltTearings_ended.end());
// allResults.insert(allResults.end(), beltTearings_unknown.begin(), beltTearings_unknown.end()); // allResults.insert(allResults.end(), m_beltTearings_unknown.begin(), m_beltTearings_unknown.end());
LOG_DEBUG("line count : %d algo detect count: %d (new:%d, growing:%d, ended:%d, unknown:%d)[%d]\n", LOG_DEBUG("line count : %d algo detect count: %d (new:%d, growing:%d, ended:%d, unknown:%d)[%d]\n",
algorithmData.nPositionCnt, algorithmData.nPositionCnt,
allResults.size(), beltTearings_new.size(), beltTearings_growing.size(), allResults.size(), m_beltTearings_new.size(), m_beltTearings_growing.size(),
beltTearings_ended.size(), beltTearings_unknown.size(), errorCode); m_beltTearings_ended.size(), m_beltTearings_unknown.size(), errorCode);
for(auto& item : m_beltTearings_new){
LOG_DEBUG("-----new %lld ID: %d st: %d depth: %f \n", pLaserLine->llFrameIdx, item.tearID, item.tearStatus, item.tearDepth);
}
#if 1
for(auto& item : m_beltTearings_ended){
LOG_DEBUG("-----end %lld ID: %d st: %d depth: %f \n", pLaserLine->llFrameIdx, item.tearID, item.tearStatus, item.tearDepth);
}
#endif
// 发送检测结果 // 发送检测结果
if (!allResults.empty()) { if (!allResults.empty()) {

View File

@ -86,14 +86,19 @@ private:
// SDK算法相关 // SDK算法相关
std::atomic<bool> m_bInitAlgo{false}; std::atomic<bool> m_bInitAlgo{false};
std::vector<SSG_hLineProInfo> m_hLineWorkers; std::vector<SSG_hLineProInfo> m_hLineWorkers;
SSG_beltTearingParam m_algorithmParam; SSG_beltTearingParam m_algorithmParam;
std::vector<SSG_beltTearingInfo> m_beltTearings_new;
std::vector<SSG_beltTearingInfo> m_beltTearings_growing;
std::vector<SSG_beltTearingInfo> m_beltTearings_ended;
std::vector<SSG_beltTearingInfo> m_beltTearings_unknown;
// 激光线队列管理 // 激光线队列管理
std::deque<SVzLaserLineData> m_laserLineQueue; // 激光线数据队列 std::deque<SVzLaserLineData> m_laserLineQueue; // 激光线数据队列
std::mutex m_queueMutex; // 队列访问互斥锁 std::mutex m_queueMutex; // 队列访问互斥锁
unsigned long long m_lineCounter; // 新增线条计数器 unsigned long long m_lineCounter; // 新增线条计数器
static const int MAX_QUEUE_SIZE = 200; // 最大队列大小 static const int MAX_QUEUE_SIZE = 200; // 最大队列大小
static const int IMAGE_GENERATION_INTERVAL = 10; // 每10条线生成一次图像 static const int IMAGE_GENERATION_INTERVAL = 20; // 每20条线生成一次图像
// 相机状态回调函数 // 相机状态回调函数
static void OnStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam); static void OnStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);