feat 添加ng图片日志存储

main
liusiyang 3 weeks ago
parent 702a1556fe
commit cd95910651

@ -101,6 +101,8 @@ private:
// 插入相机日志
int InsertCameraLog();
int ngImgSave();
ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); // 获得 通道的检测功能
// 获取 检测核心库

@ -56,7 +56,8 @@ public:
static std::string GetRectString(cv::Rect rect);
// 创建目录
static int CreateDir(const std::string &dir);
// 删除目录
static int DeleteDir(const std::string &dir);
// 点的距离是否过小
static bool bcalDis(cv::Point p1, cv::Point p2, int disT);
static double calDis(cv::Point2f p1, cv::Point2f p2);

@ -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;

@ -20,6 +20,8 @@
#include <fstream>
#include <thread>
#include "snowflake.hpp"
#include <dirent.h>
#include <errno.h>
int _sysmkdir_2(const std::string &dir)
{
@ -39,6 +41,57 @@ int _sysmkdir_2(const std::string &dir)
}
return 0;
}
static int _remove_dir_recursive_(const std::string &dir_path) {
DIR *dir = opendir(dir_path.c_str());
if (!dir) {
// 如果目录不存在,视为成功(因为目标是不存在)
if (errno == ENOENT) return 0;
printf("opendir[%s] error: %s\n", dir_path.c_str(), strerror(errno));
return -1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr) {
std::string name = entry->d_name;
// 跳过 . 和 ..
if (name == "." || name == "..") {
continue;
}
std::string full_path = dir_path + "/" + name;
struct stat st;
// 获取文件状态,使用 lstat 以处理符号链接
if (lstat(full_path.c_str(), &st) == -1) {
printf("lstat[%s] error: %s\n", full_path.c_str(), strerror(errno));
continue;
}
// 如果是目录,递归删除
if (S_ISDIR(st.st_mode)) {
if (_remove_dir_recursive_(full_path) != 0) {
closedir(dir);
return -1;
}
// 删除空子目录
if (rmdir(full_path.c_str()) != 0) {
printf("rmdir[%s] error: %s\n", full_path.c_str(), strerror(errno));
closedir(dir);
return -1;
}
} else {
// 如果是文件(或符号链接等),直接删除
if (remove(full_path.c_str()) != 0) {
printf("remove[%s] error: %s\n", full_path.c_str(), strerror(errno));
closedir(dir);
return -1;
}
}
}
closedir(dir);
return 0;
}
std::string __getParentDir_2(const std::string &dir)
{
std::string pdir = dir;
@ -506,6 +559,45 @@ int CheckUtil::CreateDir(const std::string &dir)
return ret;
}
int CheckUtil::DeleteDir(const std::string &dir)
{
if (dir.empty()) {
return -1;
}
// 检查路径是否存在
struct stat st;
if (stat(dir.c_str(), &st) != 0) {
// 目录不存在,视为成功
return 0;
}
// 如果不是目录,可能是文件,尝试直接删除
if (!S_ISDIR(st.st_mode)) {
if (remove(dir.c_str()) == 0) {
return 0;
} else {
printf("remove file[%s] error: %s\n", dir.c_str(), strerror(errno));
return -1;
}
}
// 是目录,先递归清空内容
if (_remove_dir_recursive_(dir) != 0) {
return -1;
}
// 最后删除空目录本身
if (rmdir(dir.c_str()) != 0) {
printf("rmdir[%s] error: %s\n", dir.c_str(), strerror(errno));
return -1;
}
// printf("remove dir[%s] success.\n", dir.c_str());
return 0;
}
bool CheckUtil::bcalDis(cv::Point p1, cv::Point p2, int disT)
{
double dis = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));

Loading…
Cancel
Save