|
|
|
|
@ -17,6 +17,17 @@
|
|
|
|
|
#include "CameraCheckAnalysisy.hpp"
|
|
|
|
|
#include "CheckUtil.hpp"
|
|
|
|
|
#include "Define.h"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <atomic>
|
|
|
|
|
#include <future>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
static std::mutex g_ngImgSave_mutex;
|
|
|
|
|
static std::vector<std::future<void>> g_ngImgSave_futures;
|
|
|
|
|
|
|
|
|
|
CameraCheckAnalysisy::CameraCheckAnalysisy()
|
|
|
|
|
{
|
|
|
|
|
@ -1033,6 +1044,7 @@ int CameraCheckAnalysisy::CheckImgRun()
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "========came %s Check ALL end time %ld ms %s",
|
|
|
|
|
m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), tend - m_pCheck_Result->time_start, strTimg.c_str());
|
|
|
|
|
InsertCameraLog();
|
|
|
|
|
ngImgSave();
|
|
|
|
|
std::lock_guard<std::mutex> lock(mtx_WaiteImg);
|
|
|
|
|
m_bHaveImgeDet = false;
|
|
|
|
|
|
|
|
|
|
@ -1173,6 +1185,193 @@ int CameraCheckAnalysisy::InsertCameraLog()
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int writeLog(std::string strSavePath, std::vector<std::string> logList)
|
|
|
|
|
{
|
|
|
|
|
std::string str = strSavePath + ".txt";
|
|
|
|
|
// 打开文件
|
|
|
|
|
std::ofstream outFile(str);
|
|
|
|
|
|
|
|
|
|
// 检查文件是否成功打开
|
|
|
|
|
if (!outFile)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Failed to open file." << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将vector中的内容写入文件
|
|
|
|
|
for (const auto &str : logList)
|
|
|
|
|
{
|
|
|
|
|
// printf("%s \n",str.c_str());
|
|
|
|
|
outFile << str << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 关闭文件
|
|
|
|
|
outFile.close();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string SanitizePathComponent(const std::string& input) {
|
|
|
|
|
std::string result;
|
|
|
|
|
result.reserve(input.size());
|
|
|
|
|
for (char ch : input) {
|
|
|
|
|
// 只允许字母、数字、下划线、点、短横线,其余替换为下划线
|
|
|
|
|
if (isalnum(static_cast<unsigned char>(ch)) || ch == '_' || ch == '.' || ch == '-') {
|
|
|
|
|
result.push_back(ch);
|
|
|
|
|
} else {
|
|
|
|
|
result.push_back('_');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 防止相对路径伪装(如 ".", "..")
|
|
|
|
|
if (result == "." || result == "..") {
|
|
|
|
|
result = "_";
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CameraCheckAnalysisy::ngImgSave() {
|
|
|
|
|
// 拷贝智能指针,保证在异步任务中引用计数有效
|
|
|
|
|
auto result_copy = m_pCheck_Result;
|
|
|
|
|
std::string save_path_root = "/home/aidlux/BOE/CELL_ET/cloud/";
|
|
|
|
|
|
|
|
|
|
auto task = std::async(std::launch::async, [result_copy, save_path_root]() {
|
|
|
|
|
try {
|
|
|
|
|
if (!result_copy) return;
|
|
|
|
|
|
|
|
|
|
// ---------- 目录清理(加锁防止并发删除)----------
|
|
|
|
|
{
|
|
|
|
|
static std::mutex cleanup_mutex; // 静态锁,所有实例共享
|
|
|
|
|
std::lock_guard<std::mutex> lock(cleanup_mutex);
|
|
|
|
|
|
|
|
|
|
DIR* dir = opendir(save_path_root.c_str());
|
|
|
|
|
if (dir) {
|
|
|
|
|
std::vector<std::pair<std::string, time_t>> dirs;
|
|
|
|
|
struct dirent* entry;
|
|
|
|
|
while ((entry = readdir(dir)) != nullptr) {
|
|
|
|
|
std::string name = entry->d_name;
|
|
|
|
|
if (name == "." || name == "..") continue;
|
|
|
|
|
std::string full_path = save_path_root + name;
|
|
|
|
|
struct stat st;
|
|
|
|
|
if (stat(full_path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
|
|
|
|
|
struct stat lst;
|
|
|
|
|
if (lstat(full_path.c_str(), &lst) == 0 && !S_ISLNK(lst.st_mode)) {
|
|
|
|
|
dirs.emplace_back(full_path, st.st_mtime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
closedir(dir);
|
|
|
|
|
|
|
|
|
|
if (dirs.size() > 100) {
|
|
|
|
|
std::sort(dirs.begin(), dirs.end(),
|
|
|
|
|
[](auto& a, auto& b) { return a.second < b.second; });
|
|
|
|
|
const std::string& oldest_dir = dirs.front().first;
|
|
|
|
|
if (!oldest_dir.empty() && oldest_dir != save_path_root) {
|
|
|
|
|
CheckUtil::DeleteDir(oldest_dir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cerr << ("ERROR: cannot open root directory for cleanup");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- 保存NG图像 ----------
|
|
|
|
|
int ImageNum = static_cast<int>(result_copy->ImageALLDetResultList.size());
|
|
|
|
|
for (int imgidx = 0; imgidx < ImageNum; ++imgidx) {
|
|
|
|
|
auto pImageResult = result_copy->ImageALLDetResultList.at(imgidx);
|
|
|
|
|
if (!pImageResult) continue;
|
|
|
|
|
auto m_CheckResult_shareP = pImageResult->result;
|
|
|
|
|
if (!m_CheckResult_shareP) continue;
|
|
|
|
|
|
|
|
|
|
// 提取并净化路径组件
|
|
|
|
|
std::string raw_product = result_copy->productBaseResult ?
|
|
|
|
|
result_copy->productBaseResult->strproductName : "unknown";
|
|
|
|
|
std::string raw_camera = result_copy->cameraBaseResult ?
|
|
|
|
|
result_copy->cameraBaseResult->strCameraName : "unknown";
|
|
|
|
|
std::string raw_channel = m_CheckResult_shareP->basicResult.strChannel;
|
|
|
|
|
|
|
|
|
|
std::string safe_product = SanitizePathComponent(raw_product);
|
|
|
|
|
std::string safe_camera = SanitizePathComponent(raw_camera);
|
|
|
|
|
std::string safe_channel = SanitizePathComponent(raw_channel);
|
|
|
|
|
|
|
|
|
|
// 只保存NG结果且图像数据非空
|
|
|
|
|
if ((m_CheckResult_shareP->nresult == 1 || safe_channel == "L255") &&
|
|
|
|
|
!m_CheckResult_shareP->resultMaskImg.empty() &&
|
|
|
|
|
!m_CheckResult_shareP->resultimg.empty() &&
|
|
|
|
|
!m_CheckResult_shareP->cutSrcimg.empty()) {
|
|
|
|
|
|
|
|
|
|
// 构建保存目录(使用净化后的组件)
|
|
|
|
|
std::string save_dir = save_path_root + "/" + safe_product + "/" + safe_camera + "/";
|
|
|
|
|
if (CheckUtil::CreateDir(save_dir) != 0) {
|
|
|
|
|
cerr << ("Failed to create directory: " + save_dir);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 深拷贝图像数据,避免原始数据被其他线程修改
|
|
|
|
|
cv::Mat mask_img = m_CheckResult_shareP->resultMaskImg.clone();
|
|
|
|
|
cv::Mat result_img = m_CheckResult_shareP->resultimg.clone();
|
|
|
|
|
cv::Mat cut_img = m_CheckResult_shareP->cutSrcimg.clone();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// cv::imwrite(save_dir + safe_channel + "_AIMask.png", mask_img);
|
|
|
|
|
// cv::imwrite(save_dir + safe_channel + "_Resultimg.png", result_img);
|
|
|
|
|
// cv::imwrite(save_dir + safe_channel + "_CutImg.png", cut_img);
|
|
|
|
|
writeLog(save_dir+ safe_channel + "log", m_CheckResult_shareP->det_LogList);
|
|
|
|
|
} catch (const cv::Exception& e) {
|
|
|
|
|
cerr << ("OpenCV exception: " + std::string(e.what()));
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
cerr << ("Standard exception: " + std::string(e.what()));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
cerr << ("Unknown exception during image save");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
cerr << ("Future get exception: " + std::string(e.what()));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
cerr << ("Future get unknown exception");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ---------- 管理 future 队列(清理已完成任务)----------
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_ngImgSave_mutex);
|
|
|
|
|
g_ngImgSave_futures.emplace_back(std::move(task));
|
|
|
|
|
|
|
|
|
|
size_t write_idx = 0;
|
|
|
|
|
for (size_t i = 0; i < g_ngImgSave_futures.size(); ++i) {
|
|
|
|
|
auto& f = g_ngImgSave_futures[i];
|
|
|
|
|
// 检查任务是否已就绪(非阻塞)
|
|
|
|
|
if (f.valid() && f.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
|
|
|
|
|
try {
|
|
|
|
|
f.get();
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
cerr << ("Future get exception: " + std::string(e.what()));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
cerr << ("Future get unknown exception");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 保留未完成的任务
|
|
|
|
|
if (i != write_idx) {
|
|
|
|
|
g_ngImgSave_futures[write_idx] = std::move(g_ngImgSave_futures[i]);
|
|
|
|
|
}
|
|
|
|
|
++write_idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_ngImgSave_futures.resize(write_idx);
|
|
|
|
|
|
|
|
|
|
// 限制队列最大长度,防止无限堆积(例如超过100则丢弃最老的任务)
|
|
|
|
|
const size_t MAX_PENDING_TASKS = 20;
|
|
|
|
|
if (g_ngImgSave_futures.size() > MAX_PENDING_TASKS) {
|
|
|
|
|
// 丢弃最早未完成的任务(注意:需要确保其可被销毁,不阻塞)
|
|
|
|
|
g_ngImgSave_futures.erase(g_ngImgSave_futures.begin());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ChannelCheckFunction *CameraCheckAnalysisy::GetChannelFuntion(std::string strChannelName)
|
|
|
|
|
{
|
|
|
|
|
ChannelCheckFunction *p = NULL;
|
|
|
|
|
|