357 lines
10 KiB
C++
357 lines
10 KiB
C++
#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 <img_utils.h>
|
|
#include <detectionworker.h>
|
|
|
|
using namespace std;
|
|
|
|
|
|
// 硬编码参数值
|
|
int file_delay = 1270; // 延迟时间(毫秒)
|
|
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<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_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);
|
|
}
|
|
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();
|
|
}
|
|
|
|
|