cotton_double/widget.cpp

1166 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "widget.h"
#include "ui_widget.h"
#include <iostream>
#include <QTcpSocket>
#include <QPushButton>
#include <QTimer>
#include <QEventLoop>
#include <QElapsedTimer>
// #include <windows.h>
#include <QApplication>
#include <QLabel>
#include <QImage>
#include <QPixmap>
#include <QDateTime>
#include <QTabBar>
#include <img_utils.h>
#include <detection_worker.h>
#include <QString>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <algorithm>
#include <cctype>
#include <warning.h>
#include <QMessageBox>
using namespace std;
// 硬编码参数值
int file_delay = 1100; // 延迟时间(毫秒)
int file_encoder = 12000; // 行频
int file_valve = 200; // 喷阀触发频率
//下位机参数
int lowmac_dp = 350; //偏振延迟时间
int lowmac_sm = 1800; //吹气量 valve/12 = 吹气时间ms
int lowmac_ts = 10; //模板匹配阈值
int lowmac_sg = 65; //偏振绿色通道大小阈值
int lowmac_td = 7; //偏振红色通道差值
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
this->isCamRunning = false;
ui->setupUi(this);
// 确认 tabWidget 是 QTabWidget 类型并隐藏tab
QTabWidget* tab = qobject_cast<QTabWidget*>(ui->tabWidget);
if (tab) {
QTabBar* tabBar = tab->tabBar();
if (tabBar) {
tabBar->hide(); // 隐藏 TabBar
} else {
qWarning() << "tabBar() 返回 nullptr";
}
} else {
qWarning() << "ui->tabWidget 不是 QTabWidget 类型!";
}
ui->camera_0_img->setScaledContents(false);
ui->camera_1_img->setScaledContents(false);
iniOnnx();
// iniColor();
loadConfig(getConfigDirectory()+"/color_range_config.txt"); // 读取配置文件
iniCamera();
// 更新界面
update_main_settings(); // 更新主要设定
update_colorlist(); // 更新色彩列表
update_polar(); // 更新偏振相机界面
// 初始化存储工作者和线程
storageWorker = new StorageWorker();
storageWorker->moveToThread(&storageThread);
connect(&storageThread, &QThread::started, storageWorker, &StorageWorker::process);
connect(this, &Widget::destroyed, &storageThread, &QThread::quit);
connect(&storageThread, &QThread::finished, storageWorker, &QObject::deleteLater);
storageThread.start();
// 启动显示定时器,每秒检查一次
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Widget::refreshImage);
timer->start(40); // 每40毫秒秒刷新一次界面
// 启动PLC定时器每秒检查一次
plc_connector = std::make_unique<PLCConnector>(params["machine_num"]);
QTimer* timer_plc = new QTimer(this);
connect(timer_plc, &QTimer::timeout, this, &Widget::heart_beat);
heart_beat();
timer_plc->start(30000); // 每30秒发送一次心跳包
// 启动PLC定时器每秒检查一次
QTimer* timer_lower = new QTimer(this);
connect(timer_lower, &QTimer::timeout, this, &Widget::check_lower_machine);
check_lower_machine(); // 先尝试一次连接
timer_lower->start(10000); // 每10秒检查一次FPGA的状态
ui->tabWidget->setCurrentIndex(1);
showStartupCountdown();
}
void Widget::check_lower_machine(){
if(g_lower_machine_connected.load()){
return;
}
bool temp_status = iniLowMac();
g_lower_machine_connected.store(temp_status);
if(temp_status)
{ this->ui->lab_fpga->setStyleSheet(
"QLabel{"
"background-color: green;"
"color: white;"
"border: 1px solid black;"
"padding: 5px;"
"border-radius: 5px;"
"font: 20pt \"Microsoft YaHei UI\";"
"}"
);
}
else
{
this->ui->lab_fpga->setStyleSheet(
"QLabel{"
"background-color: red;"
"color: white;"
"border: 1px solid black;"
"padding: 5px;"
"border-radius: 5px;"
"font: 20pt \"Microsoft YaHei UI\";"
"}"
);
qWarning() << "FPGA Disconnected!";
}
}
void Widget::heart_beat()
{
QMutexLocker locker(&plc_mutex); // 锁住互斥锁,自动解锁
if(this->plc_connector == nullptr)
{
qDebug() << "plc_connector is null!";
return;
}
if(!this->plc_connector->is_connected())
{
if(!this->plc_connector->try_connect()){
// 未连接的情况下尝试连接失败,设置 lab_plc 为红色
qDebug() << "Try to connect to the PLC";
this->ui->lab_plc->setStyleSheet(
"QLabel{"
"background-color: red;"
"color: white;"
"border: 1px solid black;"
"padding: 5px;"
"border-radius: 5px;"
"font: 20pt \"Microsoft YaHei UI\";"
"}"
);
return;
}
}
if(this->plc_connector->send_heart_beat())
{
// 心跳发送成功,保持绿色
this->ui->lab_plc->setStyleSheet(
"QLabel{"
"background-color: green;"
"color: white;"
"border: 1px solid black;"
"padding: 5px;"
"border-radius: 5px;"
"font: 20pt \"Microsoft YaHei UI\";"
"}"
);
}
else
{
// 心跳发送失败,设置为红色
this->ui->lab_plc->setStyleSheet(
"QLabel{"
"background-color: red;"
"color: white;"
"border: 1px solid black;"
"padding: 5px;"
"border-radius: 5px;"
"font: 20pt \"Microsoft YaHei UI\";"
"}"
);
qWarning() << "Connection established but write to PLC Failed!";
}
}
void Widget::showStartupCountdown()
{
CountdownDialog* countdown = new CountdownDialog(10, this);
countdown->setAttribute(Qt::WA_DeleteOnClose); // 对话框关闭后自动删除
// 连接倒计时完成信号
connect(countdown, &CountdownDialog::countdownFinished, this, &Widget::onCountdownFinished);
// 连接对话框的关闭事件,以处理用户提前关闭
connect(countdown, &QDialog::rejected, this, &Widget::onCountdownCancelled);
countdown->show(); // 非模态显示,允许用户在倒计时期间与主窗口交互
}
void Widget::onCountdownCancelled()
{
qDebug() << "用户取消了启动倒计时。";
// 根据需求处理取消后的操作,例如不启动识别任务
// 可以选择什么都不做,或者提供提示
}
void Widget::onCountdownFinished()
{
qDebug() << "启动倒计时结束,继续执行开机操作。";
on_btn_start_clicked();
}
Widget::~Widget()
{
// 停止检测工作者线程
for(int i = 0; i < 2; ++i)
{
g_recognitionRunning[i]->store(false);
g_img_Queue[i]->stop(); // 停止队列以唤醒线程
}
// 等待检测工作者线程结束
for(int i = 0; i < 2; ++i)
{
if(g_recognitionThread[i] && g_recognitionThread[i]->joinable())
{
g_recognitionThread[i]->join();
delete g_recognitionThread[i];
g_recognitionThread[i] = nullptr;
}
if(g_recognitionRunning[i])
{
delete g_recognitionRunning[i];
g_recognitionRunning[i] = nullptr;
}
}
// 停止存储线程
g_storageQueue.stop();
storageThread.quit();
storageThread.wait();
// 现有清理代码...
DestoryCamera();
DestoryLowMac();
delete ui;
// 重启电脑
QProcess::startDetached("shutdown", QStringList() << "/r" << "/f" << "/t" << "0");
}
void Widget::refreshImage()
{
// refresh Image 1 and image 0
refreshSingleImage(0, this->ui->mtx_0_overlay->isChecked(), this->ui->dl_0_overlay->isChecked(), this->ui->img_0_mirror->isChecked());
refreshSingleImage(1, this->ui->mtx_1_overlay->isChecked(), this->ui->dl_1_overlay->isChecked(), this->ui->img_1_mirror->isChecked());
// refresh buttons
this->ui->btn_start->setEnabled(!this->isCamRunning);
this->ui->btn_stop->setEnabled(this->isCamRunning);
this->ui->btn_take_photos->setEnabled(this->isCamRunning);
// refresh checkouts
this->ui->dl_enable_0->setEnabled(!this->isCamRunning);
this->ui->dl_enable_1->setEnabled(!this->isCamRunning);
this->ui->tra_enable_0->setEnabled(!this->isCamRunning);
this->ui->tra_enable_1->setEnabled(!this->isCamRunning);
this->ui->btn_quit->setEnabled(!this->isCamRunning);
// refresh settings buttons
this->ui->btn_setColor->setEnabled(!this->isCamRunning);
this->ui->btn_reset_color->setEnabled(!this->isCamRunning);
this->ui->btn_del_color->setEnabled(!this->isCamRunning);
this->ui->btn_add_color->setEnabled(!this->isCamRunning);
this->ui->btn_reset_polar->setEnabled(!this->isCamRunning);
this->ui->btn_save_polar->setEnabled(!this->isCamRunning);
this->ui->btn_set_lower->setEnabled(!this->isCamRunning);
//
QDateTime now = QDateTime::currentDateTime();
ui->label_currentDateTime->setText(now.toString("yyyy-MM-dd hh:mm:ss"));
if (this->isCamRunning)
{
// 计算启动至今的秒数差
qint64 elapsedSeconds = this->startTime.secsTo(now);
// 转化为小时、分钟、秒
qint64 hours = elapsedSeconds / 3600;
qint64 minutes = (elapsedSeconds % 3600) / 60;
qint64 seconds = elapsedSeconds % 60;
// 将“总运行时间”的小时/分钟分别更新到 UI
ui->label_totalHours->setText(QString::number(hours)); // e.g. "482"
ui->label_totalMinutes->setText(QString::number(minutes)); // e.g. "52"
// 拼接“今日运行时长”一句话 (根据实际需求,可直接使用上面 hours、minutes、seconds)
QString todayRunStr = QString("今日运行时长:%1小时%2分钟%3秒")
.arg(hours)
.arg(minutes)
.arg(seconds);
ui->label_todayRunningTime->setText(todayRunStr);
}
else
{
// 如果设备没在运行UI可以显示默认内容或保持不变
// 下面示例:将运行时长重置为 0
ui->label_totalHours->setText("0");
ui->label_totalMinutes->setText("0");
ui->label_todayRunningTime->setText("今日运行时长:0小时0分钟0秒");
}
// refresh info
QString info;
if(this->isCamRunning)
{
if(SaveImg_Flag==1)
{
info = "存图中!!";
}
else
{
if(g_camera_error.load()){
info = "图像问题!!!";
} else {
info = "运行";
}
};
}else {
info = "停止";
};
this->ui->lab_info->setText(info);
ui->label_valve_actions->setText(QLocale(QLocale::English).toString(g_valveActionCount));
}
void Widget::refreshSingleImage(int camera_id, bool overlay_traditional_result, bool overlay_dl_result, bool mirror)
{
// 验证摄像头ID的有效性
if (camera_id < 0 || camera_id >= 2) { // 假设只有两个摄像头
qWarning() << "Invalid Camera ID:" << camera_id;
return;
}
// 定义每个摄像头对应的 QLabel
QLabel* cameraLabels[2] = { ui->camera_0_img, ui->camera_1_img };
// 定义每个摄像头对应的变量数组
QMutex* dispPicMutexes[2] = { &gDispPicMutex0, &gDispPicMutex1 };
MIL_ID dispCurrentPicIds[2] = { gDispCurrentPicId0, gDispCurrentPicId1 };
// 获取当前摄像头的数据
QMutex* currentDispMutex = dispPicMutexes[camera_id];
MIL_ID current_id;
{
QMutexLocker locker(currentDispMutex);
current_id = dispCurrentPicIds[camera_id];
}
if (current_id == 0)
return;
// 将MIL图像转换为OpenCV Mat
cv::Mat img = ImageUtils::mil2Mat(current_id);
if (img.empty())
{
qWarning() << "Failed to convert MIL image to Mat for Camera ID:" << camera_id;
return;
}
if (current_id == 0)
return;
std::vector<std::vector<uint8_t>> dl_mask;
std::vector<std::vector<uint8_t>> traditional_mask;
{
QMutexLocker locker(&g_detection_result[camera_id].mutex);
dl_mask = g_detection_result[camera_id].dl_mask;
traditional_mask = g_detection_result[camera_id].traditional_mask;
}
// 如果需要叠加结果,处理掩码
if (overlay_dl_result && g_dl_enable[camera_id])
{
if (!dl_mask.empty() && !dl_mask[0].empty())
{
// 将二维 vector 转换为 cv::Mat
int rows = dl_mask.size();
int cols = dl_mask[0].size();
cv::Mat dl_mask_mat(rows, cols, CV_8U);
for (int i = 0; i < rows; ++i)
{
if (dl_mask[i].size() != cols) {
qWarning() << "Inconsistent mask row size for dl_mask in Camera ID:" << camera_id;
dl_mask_mat.release();
break;
}
memcpy(dl_mask_mat.ptr(i), dl_mask[i].data(), cols);
}
if (!dl_mask_mat.empty())
{
// 调整掩膜尺寸以匹配图像尺寸
if (dl_mask_mat.size() != img.size()) {
cv::resize(dl_mask_mat, dl_mask_mat, img.size(), 0, 0, cv::INTER_NEAREST);
}
// 确保掩膜为二值图像
cv::threshold(dl_mask_mat, dl_mask_mat, 128, 255, cv::THRESH_BINARY);
// 创建绿色掩膜
cv::Mat green_overlay(img.size(), img.type(), cv::Scalar(0, 255, 0));
green_overlay.setTo(cv::Scalar(0, 255, 0), dl_mask_mat);
// 叠加掩膜到图像
cv::addWeighted(green_overlay, 0.5, img, 1.0, 0, img);
}
}
}
if (overlay_traditional_result & g_traditional_enable[camera_id])
{
if (!traditional_mask.empty() && !traditional_mask[0].empty())
{
// 将二维 vector 转换为 cv::Mat
int rows = traditional_mask.size();
int cols = traditional_mask[0].size();
cv::Mat traditional_mask_mat(rows, cols, CV_8U);
for (int i = 0; i < rows; ++i)
{
if (traditional_mask[i].size() != cols) {
qWarning() << "Inconsistent mask row size for traditional_mask in Camera ID:" << camera_id;
traditional_mask_mat.release();
break;
}
memcpy(traditional_mask_mat.ptr(i), traditional_mask[i].data(), cols);
}
if (!traditional_mask_mat.empty())
{
// 调整掩膜尺寸以匹配图像尺寸
if (traditional_mask_mat.size() != img.size()) {
cv::resize(traditional_mask_mat, traditional_mask_mat, img.size(), 0, 0, cv::INTER_NEAREST);
}
// 确保掩膜为二值图像
cv::threshold(traditional_mask_mat, traditional_mask_mat, 128, 255, cv::THRESH_BINARY);
// 创建红色掩膜
cv::Mat red_overlay(img.size(), img.type(), cv::Scalar(0, 0, 255));
red_overlay.setTo(cv::Scalar(0, 0, 255), traditional_mask_mat);
// 叠加掩膜到图像
cv::addWeighted(red_overlay, 0.5, img, 1.0, 0, img);
}
}
}
// 如果需要镜像处理
if (mirror)
{
cv::flip(img, img, 1); // 水平翻转
}
// 将OpenCV Mat转换为QPixmap
QPixmap pixmap = ImageUtils::mat2QPixmap(img);
if (pixmap.isNull()) {
qWarning() << "Failed to convert Mat to QPixmap for Camera ID:" << camera_id;
return;
}
// 缩放图像
QSize labelSize = cameraLabels[camera_id]->size();
QPixmap scaledPixmap = pixmap.scaled(labelSize);
// 更新UI标签
cameraLabels[camera_id]->setPixmap(scaledPixmap);
}
void Widget::on_btn_stop_clicked()
{
stop_grab();
DestoryLowMac();
this->isCamRunning = false;
// 恢复显示的图片
{
QMutexLocker locker(&gDispPicMutex0);
gDispCurrentPicId0 = 0;
}
ui->camera_0_img->clear();
{
QMutexLocker locker(&gDispPicMutex1);
gDispCurrentPicId1 = 0;
}
ui->camera_1_img->clear();
}
void Widget::on_btn_start_clicked()
{
// 设置相机参数
setLowMacParam();
g_dl_enable[0] = !this->ui->dl_enable_0->isChecked();
g_dl_enable[1] = !this->ui->dl_enable_0->isChecked();
g_traditional_enable[0] = !this->ui->tra_enable_0->isChecked();
g_traditional_enable[1] = !this->ui->tra_enable_1->isChecked();
this->isCamRunning = true;
this->startTime = QDateTime::currentDateTime(); // 从这里开始计算设备运行时间
// 热身两个工作者
for(int i = 0; i < 2; ++i)
{
g_runner_array[i]->warm_up();
}
// 启动检测工作者线程
for(int i = 0; i < 2; ++i)
{
g_recognitionRunning[i]->store(true);
g_recognitionThread[i] = new std::thread(detectionWorker, i);
// 获取线程的本地句柄
HANDLE hThread = static_cast<HANDLE>(g_recognitionThread[i]->native_handle());
// 设置线程优先级为最高
if(!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST))
{
std::cerr << "SET thread " << i << " failed, error code" << GetLastError() << std::endl;
}
}
start_camera();
}
void Widget::on_btn_take_photos_pressed()
{
SaveImg_Flag = true;
}
void Widget::on_btn_take_photos_released()
{
SaveImg_Flag = false;
}
void Widget::on_btn_quit_clicked()
{
qApp->quit();
}
void Widget::on_btn_set_lower_clicked()
{
// 硬编码参数值
lowmac_sm = ui->spinbox_maintime->value();
params["lowmac_sm"]=lowmac_sm;
params["machine_num"] = ui->spinbox_machine_code->value();
params["max_valves_together"] = ui->spinbox_max_valves_together->value();
params["screen_left_0"] = ui->spb_screen_left_0->value();
params["screen_right_0"] = ui->spb_screen_right_0->value();
params["screen_left_1"] = ui->spb_screen_left_1->value();
params["screen_right_1"] = ui->spb_screen_right_1->value();
saveConfig(getConfigDirectory()+"/color_range_config.txt", params, colors);
// 两个过去的参量不支持读取配置文件
file_encoder = ui->spinbox_encoder->text().toInt(); // 编码器值++
file_valve = ui->spinbox_valve->text().toInt(); // 阀门通道
// 重新初始化 PLCConnector
{
QMutexLocker locker(&plc_mutex);
plc_connector = std::make_unique<PLCConnector>(params["machine_num"]);
}
heart_beat();
}
void Widget::update_main_settings()
{
ui->lab_machine_num->setText(QString("%1号机").arg(params["machine_num"]));
ui->spinbox_machine_code->setValue(params["machine_num"]);
ui->spinbox_maintime->setValue(params["lowmac_sm"]);
ui->spinbox_max_valves_together->setValue(params["max_valves_together"]);
ui->spb_screen_left_0->setValue(params["screen_left_0"]);
ui->spb_screen_left_1->setValue(params["screen_left_1"]);
ui->spb_screen_right_0->setValue(params["screen_right_0"]);
ui->spb_screen_right_1->setValue(params["screen_right_1"]);
}
void Widget::on_btn_set_valve_clicked()
{
ui->tabWidget->setCurrentIndex(2);
}
void Widget::on_btn_tab3_backtab2_clicked()
{
ui->tabWidget->setCurrentIndex(1);
}
void Widget::on_btn_live_clicked()
{
ui->tabWidget->setCurrentIndex(1);
}
void Widget::on_btn_tab3_backtab2_2_clicked()
{
ui->tabWidget->setCurrentIndex(5);
}
void Widget::on_btn_settings_clicked()
{
ui->tabWidget->setCurrentIndex(2);
}
bool Widget::saveConfig(const QString &filePath, const std::map<std::string, int>& params_to_set, const std::vector<std::string>& color_vector_to_set)
{
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
qWarning() << "无法打开配置文件进行写入:" << filePath;
return false;
}
QTextStream out(&file);
// Qt 6 默认使用 UTF-8 编码,无需设置编码
// 保存每种颜色的参数
for (const auto &color : color_vector_to_set)
{
std::string color_lower = color;
// 将颜色名称首字母小写以匹配键名
if (!color_lower.empty())
{
color_lower[0] = static_cast<char>(std::tolower(color_lower[0]));
}
try {
// 使用 at() 方法访问元素
out << QString::fromStdString(color_lower) << "_L_min = " << QString::number(params_to_set.at(color_lower + "_L_min")) << "\n";
out << QString::fromStdString(color_lower) << "_L_max = " << QString::number(params_to_set.at(color_lower + "_L_max")) << "\n";
out << QString::fromStdString(color_lower) << "_a_min = " << QString::number(params_to_set.at(color_lower + "_a_min")) << "\n";
out << QString::fromStdString(color_lower) << "_a_max = " << QString::number(params_to_set.at(color_lower + "_a_max")) << "\n";
out << QString::fromStdString(color_lower) << "_b_min = " << QString::number(params_to_set.at(color_lower + "_b_min")) << "\n";
out << QString::fromStdString(color_lower) << "_b_max = " << QString::number(params_to_set.at(color_lower + "_b_max")) << "\n\n";
}
catch (const std::out_of_range& e) {
qWarning() << "缺少参数:" << QString::fromStdString(color_lower + "_L_min") << "等在颜色" << QString::fromStdString(color_lower);
// 根据需要,您可以决定如何处理缺少的参数,例如设置默认值或跳过
continue;
}
}
// 保存其他参数(不涉及颜色参数)
for (const auto &param : params_to_set)
{
std::string key = param.first;
// 如果不是颜色参数,则保存
if (key.find("_L_min") == std::string::npos &&
key.find("_L_max") == std::string::npos &&
key.find("_a_min") == std::string::npos &&
key.find("_a_max") == std::string::npos &&
key.find("_b_min") == std::string::npos &&
key.find("_b_max") == std::string::npos)
{
out << QString::fromStdString(key) << " = " << QString::number(param.second) << "\n";
}
}
file.close();
qDebug() << "配置已成功保存到" << filePath;
return true;
}
bool Widget::loadConfig(const QString &filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qWarning() << "无法打开配置文件进行读取:" << filePath;
return false;
}
QTextStream in(&file);
// Qt 6 默认使用 UTF-8 编码,无需设置编码
// 清空当前配置
colors.clear();
params.clear();
while (!in.atEnd())
{
QString line = in.readLine().trimmed();
// 跳过空行和注释行
if (line.isEmpty() || line.startsWith("#"))
continue;
// 处理键值对
QStringList keyValue = line.split("=");
if (keyValue.size() != 2)
continue; // 无效行
QString key = keyValue[0].trimmed();
QString valueStr = keyValue[1].trimmed();
bool ok;
int value = valueStr.toInt(&ok);
if (!ok)
{
qWarning() << "无效的数值:" << valueStr << "在行:" << line;
continue;
}
std::string key_std = key.toStdString();
params[key_std] = value;
// 检查是否为颜色参数(格式为 color_property例如 green_L_min
size_t underscorePos = key_std.find('_');
if (underscorePos != std::string::npos)
{
std::string colorName = key_std.substr(0, underscorePos);
size_t second_underscore = key_std.find('_', underscorePos + 1);
if (second_underscore != std::string::npos)
{
// 提取第二个部分,例如 "L"、"a"、"b"
std::string param_type = key_std.substr(underscorePos + 1, second_underscore - underscorePos - 1);
// 过滤不需要的参数类型
if ((param_type != "L") && (param_type != "a") && (param_type != "b"))
continue;
// 避免重复添加颜色
if (std::find(colors.begin(), colors.end(), colorName) == colors.end())
{
colors.push_back(colorName);
}
}
}
}
file.close();
lowmac_dp = params["lowmac_dp"]; //偏振延迟时间
lowmac_ts = params["lowmac_ts"]; //模板匹配阈值
lowmac_sg = params["lowmac_sg"]; //偏振绿色通道大小阈值
lowmac_td = params["lowmac_td"]; //偏振红色通道差值
file_delay = params["file_delay"]; // 延迟时间
expansionRaidus = params["expansionRaidus"]; // 扩展半径
sizeThreshold = params["sizeThreshold"]; // 大小过滤
qDebug() << "配置已成功从" << filePath << "加载";
// qDebug()<<colors;
return true;
}
void Widget::initDefaultConfig()
{
// 定义默认颜色和参数
colors = {"green", "blue", "orange", "black", "red", "purple", "yellow"};
params = {
// Green
{"green_L_min", 16}, {"green_L_max", 56},
{"green_a_min", -33}, {"green_a_max", -11},
{"green_b_min", -7}, {"green_b_max", 24},
// Blue
{"blue_L_min", 20}, {"blue_L_max", 43},
{"blue_a_min", -13}, {"blue_a_max", 22},
{"blue_b_min", -48}, {"blue_b_max", -8},
// Orange
{"orange_L_min", 67}, {"orange_L_max", 93},
{"orange_a_min", -8}, {"orange_a_max", 8},
{"orange_b_min", 36}, {"orange_b_max", 58},
// Black
{"black_L_min", 0}, {"black_L_max", 30},
{"black_a_min", -5}, {"black_a_max", 3},
{"black_b_min", -3}, {"black_b_max", 4},
// Red
{"red_L_min", 23}, {"red_L_max", 48},
{"red_a_min", 12}, {"red_a_max", 55},
{"red_b_min", -80}, {"red_b_max", 37},
// Purple
{"purple_L_min", 38}, {"purple_L_max", 60},
{"purple_a_min", 10}, {"purple_a_max", 25},
{"purple_b_min", -45}, {"purple_b_max", 1},
// Yellow
{"yellow_L_min", 45}, {"yellow_L_max", 56},
{"yellow_a_min", -4}, {"yellow_a_max", 7},
{"yellow_b_min", 20}, {"yellow_b_max", 21},
// Other parameters
{"lab_denoising", 1},
{"saturation_threshold", 165},
{"saturation_denoising", 1},
{"lowmac_sg",lowmac_sg},
{"lowmac_td",lowmac_td},
{"lowmac_ts",lowmac_ts},
{"lowmac_dp",lowmac_dp},
{"lowmac_sm", lowmac_sm},
{"machine_num", params["machine_num"]},
{"max_valves_together", params["max_valves_together"]},
{"screen_left_0", params["screen_left_0"]},
{"screen_left_1", params["screen_left_1"]},
{"screen_right_0", params["screen_right_0"]},
{"screen_right_1", params["screen_right_1"]},
{"sizeThreshold",4},
{"file_delay",1180},
{"expansionRaidus",1}
};
}
void Widget::on_btn_setColor_clicked()
{
std::string current_color=ui->comboBox_colorlist->currentText().toLocal8Bit().constData();
if (!(std::find(colors.begin(), colors.end(), current_color) != colors.end()))
return;
// 设置当前色彩
params[current_color+"_L_min"]=ui->spinBox_L_min->value();
params[current_color+"_L_max"]=ui->spinBox_L_max->value();
params[current_color+"_a_min"]=ui->spinBox_A_min->value();
params[current_color+"_a_max"]=ui->spinBox_A_max->value();
params[current_color+"_b_min"]=ui->spinBox_B_min->value();
params[current_color+"_b_max"]=ui->spinBox_B_max->value();
// 准备写入本地
params["file_delay"]=ui->spinbox_delaytime->value();
params["saturation_threshold"]=ui->spb_saturation->value(); // 这个参数会通过params直接被调用无需赋值给其他全局变量
params["sizeThreshold"]=ui->spinbox_msize_color->value();
params["expansionRaidus"]=ui->spb_expandsize->value();
// 写入内存进行使用
file_delay = params["file_delay"];
sizeThreshold = params["sizeThreshold"];
expansionRaidus = params["expansionRaidus"];
// 存入本地
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
}
void Widget::update_colorlist()
{
ui->comboBox_colorlist->clear();
for(auto color :colors)
{
ui->comboBox_colorlist->addItem(QString::fromStdString(color));
}
ui->spinbox_delaytime->setValue(params["file_delay"]);
ui->spb_saturation->setValue(params["saturation_threshold"]);
ui->spinbox_msize_color->setValue(params["sizeThreshold"]);
ui->spb_expandsize->setValue(params["expansionRaidus"]);
}
void Widget::on_comboBox_colorlist_currentIndexChanged(int index)
{
std::string current_color=ui->comboBox_colorlist->currentText().toLocal8Bit().constData();
if (!(std::find(colors.begin(), colors.end(), current_color) != colors.end()))
return;
int l_min = params[current_color+"_L_min"];
int l_max = params[current_color+"_L_max"];
int a_min = params[current_color+"_a_min"];
int a_max = params[current_color+"_a_max"];
int b_min = params[current_color+"_b_min"];
int b_max = params[current_color+"_b_max"];
ui->spinBox_L_max->setValue(l_max);
ui->spinBox_L_min->setValue(l_min);
ui->spinBox_A_max->setValue(a_max);
ui->spinBox_A_min->setValue(a_min);
ui->spinBox_B_max->setValue(b_max);
ui->spinBox_B_min->setValue(b_min);
}
void Widget::on_btn_add_color_clicked()
{
std::string current_color=ui->lineEdit_color->text().toLocal8Bit().constData();
// 空不添加
if(current_color== "")
{
QMessageBox::warning(this, "什么颜色?", "这名字起的不雅");
return;
}
// 必须跟之前所有颜色都不一致
if (!(std::find(colors.begin(), colors.end(), current_color) != colors.end()))
{
colors.push_back(current_color);
}
else
{
QMessageBox::warning(this, "已有名字", "这名字跟别的色撞了");
return;
}
// 存盘刷界面
params[current_color+"_L_min"]=ui->spinBox_L_min->value();
params[current_color+"_L_max"]=ui->spinBox_L_max->value();
params[current_color+"_a_min"]=ui->spinBox_A_min->value();
params[current_color+"_a_max"]=ui->spinBox_A_max->value();
params[current_color+"_b_min"]=ui->spinBox_B_min->value();
params[current_color+"_b_max"]=ui->spinBox_B_max->value();
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
update_colorlist();
ui->lineEdit_color->clear();
}
void Widget::on_btn_del_color_clicked()
{
// 获取当前选中的颜色文本
QString currentColorQStr = ui->comboBox_colorlist->currentText();
if (currentColorQStr.isEmpty())
{
QMessageBox::warning(this, "删除颜色", "当前没有选中的颜色。");
return;
}
std::string currentColor = currentColorQStr.toStdString();
std::string color_lower = currentColor;
if (!color_lower.empty())
{
color_lower[0] = static_cast<char>(std::tolower(color_lower[0]));
}
// 确认删除
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "删除颜色",
QString("确定要删除颜色 '%1' 吗?").arg(currentColorQStr),
QMessageBox::Yes | QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
// 查找颜色在 colors 向量中的位置
auto it = std::find(colors.begin(), colors.end(), currentColor);
if (it != colors.end())
{
// 计算索引
size_t index = std::distance(colors.begin(), it);
// 从 colors 向量中删除
colors.erase(it);
// 从 params 映射中删除相关参数
params.erase(color_lower + "_L_min");
params.erase(color_lower + "_L_max");
params.erase(color_lower + "_a_min");
params.erase(color_lower + "_a_max");
params.erase(color_lower + "_b_min");
params.erase(color_lower + "_b_max");
// 更新配置文件
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
// 更新 UI
update_colorlist();
// 如果还有颜色,选择被删除颜色后的第一个颜色
if (!colors.empty())
{
if (index >= colors.size())
index = colors.size() - 1;
ui->comboBox_colorlist->setCurrentIndex(static_cast<int>(index));
}
else
{
// 如果没有颜色,重置所有 spinBox
ui->spinBox_L_min->setValue(0);
ui->spinBox_L_max->setValue(0);
ui->spinBox_A_min->setValue(0);
ui->spinBox_A_max->setValue(0);
ui->spinBox_B_min->setValue(0);
ui->spinBox_B_max->setValue(0);
}
QMessageBox::information(this, "删除颜色", QString("颜色 '%1' 已成功删除。").arg(currentColorQStr));
}
else
{
QMessageBox::warning(this, "删除颜色", "未找到选中的颜色。");
}
}
void Widget::on_btn_reset_color_clicked()
{
// 确认重置
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "全部还原", "确定要将配置还原为默认设置吗?",
QMessageBox::Yes | QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
// 初始化默认配置
initDefaultConfig();
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
// 更新 UI
update_colorlist();
// 选择第一个颜色(如果有)
if (!colors.empty())
{
ui->comboBox_colorlist->setCurrentIndex(0);
}
else
{
// 如果没有颜色,重置所有 spinBox
ui->spinBox_L_min->setValue(0);
ui->spinBox_L_max->setValue(0);
ui->spinBox_A_min->setValue(0);
ui->spinBox_A_max->setValue(0);
ui->spinBox_B_min->setValue(0);
ui->spinBox_B_max->setValue(0);
}
QMessageBox::information(this, "全部还原", "配置已成功还原为默认设置。");
}
void Widget::on_btn_tab_color_clicked()
{
ui->tabWidget->setCurrentIndex(3);
}
void Widget::on_btn_tab3_backtab2_3_clicked()
{
ui->tabWidget->setCurrentIndex(5);
}
void Widget::on_btn_tab3_backtab2_5_clicked()
{
ui->tabWidget->setCurrentIndex(1);
}
void Widget::on_btn_tab_color_2_clicked()
{
ui->tabWidget->setCurrentIndex(3);
}
void Widget::on_btn_tab3_backtab2_6_clicked()
{
ui->tabWidget->setCurrentIndex(4);
}
void Widget::on_btn_tab3_backtab2_7_clicked()
{
ui->tabWidget->setCurrentIndex(5);
}
void Widget::on_btn_tab3_backtab2_8_clicked()
{
ui->tabWidget->setCurrentIndex(1);
}
void Widget::on_btn_tab_color_3_clicked()
{
ui->tabWidget->setCurrentIndex(3);
}
void Widget::on_btn_tab3_backtab2_9_clicked()
{
ui->tabWidget->setCurrentIndex(4);
}
void Widget::on_btn_tab3_backtab2_4_clicked()
{
ui->tabWidget->setCurrentIndex(4);
}
void Widget::on_btn_save_polar_clicked()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "确定保存", "确定要将偏振配置保存吗?",
QMessageBox::Yes | QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
params["lowmac_td"]=ui->spb_diff->value();
params["lowmac_sg"]=ui->spb_green->value();
params["lowmac_dp"]=ui->spb_delay_polar->value();
params["lowmac_ts"]=ui->spb_msize_polar->value();
lowmac_dp = params["lowmac_dp"]; //偏振延迟时间
lowmac_ts = params["lowmac_ts"]; //模板匹配阈值
lowmac_sg = params["lowmac_sg"]; //偏振绿色通道大小阈值
lowmac_td = params["lowmac_td"]; //偏振红色通道差值
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
}
void Widget::on_btn_reset_polar_clicked()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "确定重置", "确定要将偏振部分配置重置吗?",
QMessageBox::Yes | QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
params["lowmac_td"]= 2;
params["lowmac_sg"]= 60;
params["lowmac_dp"]= 350;
params["lowmac_ts"]= 13;
lowmac_dp = params["lowmac_dp"]; //偏振延迟时间
lowmac_ts = params["lowmac_ts"]; //模板匹配阈值
lowmac_sg = params["lowmac_sg"]; //偏振绿色通道大小阈值
lowmac_td = params["lowmac_td"]; //偏振红色通道差值
saveConfig(getConfigDirectory()+"/color_range_config.txt",params,colors);
update_polar();
}
void Widget::update_polar()
{
ui->spb_green->setValue(lowmac_sg);
ui->spb_diff->setValue(lowmac_td);
ui->spb_delay_polar->setValue(lowmac_dp);
ui->spb_msize_polar->setValue(lowmac_ts);
}
void Widget::on_tabWidget_currentChanged(int index)
{
update_main_settings();
update_colorlist(); // 更新色彩列表
update_polar(); // 更新偏振相机界面
}