#include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include // #include #include #include #include #include #include #include #include using namespace std; // 硬编码参数值 int file_delay = 1050; // 延迟时间(毫秒) int file_encoder = 12000; // 编码器值++ int file_valve = 200; // 阀门通道 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { this->isCamRunning = false; ui->setupUi(this); ui->camera_0_img->setScaledContents(false); ui->camera_1_img->setScaledContents(false); iniOnnx(); iniColor(); iniLowMac(); iniCamera(); // 初始化存储工作者和线程 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(50); // 每50毫秒秒刷新一次界面 } Widget::~Widget() { // 停止存储线程 g_storageQueue.stop(); storageThread.quit(); storageThread.wait(); // 现有清理代码... DestoryCamera(); DestoryLowMac(); delete ui; } 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); // refresh info QString info; if(this->isCamRunning) { if(SaveImg_Flag==1) { info = "存图中!!"; } else { info = "运行"; }; }else { info = "停止"; }; this->ui->lab_info->setText(info); } 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> dl_mask; std::vector> 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_pushButton_2_clicked() { SaveImg_Flag = 1; } void Widget::on_btn_goto_sort_clicked() { // 回复显示的图片 { QMutexLocker locker(&gDispPicMutex0); gDispCurrentPicId0 = 0; } ui->camera_0_img->clear(); { QMutexLocker locker(&gDispPicMutex1); gDispCurrentPicId1 = 0; } ui->camera_1_img->clear(); DestoryCamera(); DestoryLowMac(); } void Widget::on_btn_stop_clicked() { this->isCamRunning = false; // 恢复显示的图片 { QMutexLocker locker(&gDispPicMutex0); gDispCurrentPicId0 = 0; } ui->camera_0_img->clear(); { QMutexLocker locker(&gDispPicMutex1); gDispCurrentPicId1 = 0; } ui->camera_1_img->clear(); // 停止检测工作者线程 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; } } DestoryCamera(); DestoryLowMac(); } void Widget::on_btn_start_clicked() { 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; // 热身两个工作者 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(g_recognitionThread[i]->native_handle()); // 设置线程优先级为最高 if(SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST)) { std::cout << "DL Thread " << i << " set highest thread priority。" << std::endl; } else { 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(); }