update 新增监控小图AI测试

dev_lsy
liusiyang 2 months ago
parent 85460ca7ac
commit c49bce980a

@ -1327,8 +1327,9 @@ int deal::DetImg()
return 0; return 0;
} }
/// @brief 监控模式:每 5 分钟执行一次模型推理,并把当前设备资源消耗(CPU 内存 / GPU 显存) /// @brief 监控模式:每 10 秒执行一次模型推理,并把当前设备资源消耗(CPU 内存 / GPU 显存)
/// 写入 monitor.log;当某次推理输出 out 图至少一个像素不为全黑时,保存该 out 图并退出监控。 /// 写入 monitor.log;out 图重复覆盖保存到输入图同名 out 文件(*_in.png -> *_out.png),
/// 当某次推理输出 out 图至少一个像素不为全黑时退出监控。
/// @return 0 表示成功,非 0 表示初始化失败 /// @return 0 表示成功,非 0 表示初始化失败
int deal::MonitorRun() int deal::MonitorRun()
{ {
@ -1397,9 +1398,25 @@ int deal::MonitorRun()
return 1; return 1;
} }
// 预处理成模型输入(只读一次,每轮复用) // 输出目录:输入目录去掉末尾 '/' 后追加 "_TEST/"(与 TestAIDet 保持一致)
std::string strDstRoot = strSrcRoot;
while (strDstRoot.size() > 1 && strDstRoot.back() == '/')
{
strDstRoot.pop_back();
}
strDstRoot += "_TEST/";
{
std::error_code ec;
fs::create_directories(strDstRoot, ec);
}
// 预处理成模型输入(只读一次,每轮复用),并计算对应输出路径(*_in.png -> *_out.png)
std::vector<std::string> okInList;
std::vector<cv::Mat> inImgs; std::vector<cv::Mat> inImgs;
std::vector<std::string> outList;
okInList.reserve(inList.size());
inImgs.reserve(inList.size()); inImgs.reserve(inList.size());
outList.reserve(inList.size());
for (size_t i = 0; i < inList.size(); i++) for (size_t i = 0; i < inList.size(); i++)
{ {
cv::Mat inImg = cv::imread(inList[i], cv::IMREAD_UNCHANGED); cv::Mat inImg = cv::imread(inList[i], cv::IMREAD_UNCHANGED);
@ -1429,7 +1446,18 @@ int deal::MonitorRun()
{ {
cv::resize(inImg, inImg, cv::Size(nModelInW, nModelInH)); cv::resize(inImg, inImg, cv::Size(nModelInW, nModelInH));
} }
okInList.push_back(inList[i]);
inImgs.push_back(inImg); inImgs.push_back(inImg);
std::string rel = inList[i].substr(strSrcRoot.size());
const std::string inSuffix = "_in.png";
const std::string outSuffix = "_out.png";
size_t pos = rel.rfind(inSuffix);
if (pos != std::string::npos)
{
rel.replace(pos, inSuffix.size(), outSuffix);
}
outList.push_back(strDstRoot + rel);
} }
if (inImgs.empty()) if (inImgs.empty())
{ {
@ -1437,28 +1465,8 @@ int deal::MonitorRun()
return 1; return 1;
} }
// 输出目录:输入目录去掉末尾 '/' 后追加 "_TEST/"(与 TestAIDet 保持一致)
std::string strDstRoot = strSrcRoot;
while (strDstRoot.size() > 1 && strDstRoot.back() == '/')
{
strDstRoot.pop_back();
}
strDstRoot += "_TEST/";
// 本次监控的时间戳输出目录(存图和 log 都放这里)
time_t startT = time(NULL);
struct tm stmv;
localtime_r(&startT, &stmv);
char dirTs[64] = {0};
strftime(dirTs, sizeof(dirTs), "monitor_%Y%m%d_%H%M%S", &stmv);
std::string strOutDir = strDstRoot + dirTs + "/";
{
std::error_code ec;
fs::create_directories(strOutDir, ec);
}
// 打开监控日志(追加写) // 打开监控日志(追加写)
std::string strLogPath = strOutDir + "monitor.log"; std::string strLogPath = strDstRoot + "monitor.log";
std::ofstream logFile(strLogPath, std::ios::app); std::ofstream logFile(strLogPath, std::ios::app);
if (!logFile) if (!logFile)
{ {
@ -1474,11 +1482,9 @@ int deal::MonitorRun()
logFile.flush(); logFile.flush();
}; };
const int nIntervalSec = 5 * 60; // 5 分钟 const int nIntervalSec = 1; // 1 秒
const int nMaxRunSec = 30 * 60; // 30 分钟
long nRound = 0; long nRound = 0;
auto monitorStart = std::chrono::steady_clock::now(); logLine("===== monitor start (every 10s, exit on first non-black out) =====");
logLine("===== monitor start (run max 30 min) =====");
// 初始化 CPU 采样基准(用于计算 CPU 使用率) // 初始化 CPU 采样基准(用于计算 CPU 使用率)
struct rusage usagePrev; struct rusage usagePrev;
@ -1489,16 +1495,6 @@ int deal::MonitorRun()
while (true) while (true)
{ {
// 0. 运行 30 分钟后停止
double elapsedSec = std::chrono::duration<double>(
std::chrono::steady_clock::now() - monitorStart)
.count();
if (elapsedSec >= nMaxRunSec)
{
logLine("===== monitor exit (timeout 30 min) =====");
break;
}
nRound++; nRound++;
// 1. 采集设备资源消耗 // 1. 采集设备资源消耗
@ -1557,8 +1553,8 @@ int deal::MonitorRun()
gpuUsedMB, gpuTotalMB); gpuUsedMB, gpuTotalMB);
logLine(buf); logLine(buf);
// 2. 逐图推理,遇到 out 非全黑则保存对应的输入图和输出图 // 2. 逐图推理,out 图重复覆盖保存;遇到非全黑则退出
int nHit = 0; bool bHit = false;
for (size_t i = 0; i < inImgs.size(); i++) for (size_t i = 0; i < inImgs.size(); i++)
{ {
cv::Mat outImg; cv::Mat outImg;
@ -1567,49 +1563,215 @@ int deal::MonitorRun()
{ {
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"[round %ld] infer fail(%d) on image %zu: %s", "[round %ld] infer fail(%d) on image %zu: %s",
nRound, re, i, inList[i].c_str()); nRound, re, i, okInList[i].c_str());
logLine(buf); logLine(buf);
continue; continue;
} }
// 输出图重复覆盖保存到 *_out.png
bool bSaved = false;
{
fs::path outParent = fs::path(outList[i]).parent_path();
if (!outParent.empty())
{
std::error_code ec;
fs::create_directories(outParent, ec);
}
bSaved = cv::imwrite(outList[i], outImg);
}
int nNonZero = cv::countNonZero(outImg); int nNonZero = cv::countNonZero(outImg);
if (nNonZero > 0) if (nNonZero > 0)
{ {
// 输出图不全黑 -> 保存对应的输入图和输出图
std::string saveInPath = strOutDir + "monitor_hit_round" +
std::to_string(nRound) + "_img" +
std::to_string(i) + "_in.png";
std::string saveOutPath = strOutDir + "monitor_hit_round" +
std::to_string(nRound) + "_img" +
std::to_string(i) + "_out.png";
cv::imwrite(saveInPath, inImgs[i]);
cv::imwrite(saveOutPath, outImg);
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"[round %ld] hit! out image %zu non-zero pixels: %d -> save %s / %s", "[round %ld] hit! out image %zu non-zero pixels: %d -> %s (saved=%d), exit monitor",
nRound, i, nNonZero, saveInPath.c_str(), saveOutPath.c_str()); nRound, i, nNonZero, outList[i].c_str(), bSaved ? 1 : 0);
logLine(buf); logLine(buf);
nHit++; bHit = true;
break;
} }
} }
snprintf(buf, sizeof(buf), "[round %ld] %d non-black out saved, sleep %d s ...", if (bHit)
nRound, nHit, nIntervalSec);
logLine(buf);
// 3. 休眠(不超过剩余运行时间)
double remainSec = nMaxRunSec - elapsedSec;
int sleepSec = (int)(remainSec < nIntervalSec ? remainSec : nIntervalSec);
if (sleepSec > 0)
{ {
std::this_thread::sleep_for(std::chrono::seconds(sleepSec)); break;
} }
snprintf(buf, sizeof(buf), "[round %ld] all out black, sleep %d s ...", nRound, nIntervalSec);
logLine(buf);
std::this_thread::sleep_for(std::chrono::seconds(nIntervalSec));
} }
logFile.close(); logFile.close();
return 0; return 0;
} }
/// @brief AI 检测独立测试:遍历 /home/aidlux/BOE/FOG/AI_Detect/ 下所有 *_in.png,
/// 送入 AI_defect_NF 模型推理,将输出 *_out.png 保存到 /home/aidlux/BOE/FOG/AI_Detect_TEST/
/// @return 0 表示成功
/*int deal::TestAIDet()
{
// 输入目录:优先使用命令行指定路径,否则使用默认路径
std::string strSrcRoot = runConfig.filePath;
if (strSrcRoot.empty())
{
strSrcRoot = "/home/aidlux/BOE/FOG/AI_Detect/";
}
else if (strSrcRoot.back() != '/')
{
strSrcRoot += "/";
}
// 输出目录:输入目录去掉末尾 '/' 后追加 "_TEST/"
// 默认输入 /home/aidlux/BOE/FOG/AI_Detect/ -> 输出 /home/aidlux/BOE/FOG/AI_Detect_TEST/
std::string strDstRoot = strSrcRoot;
while (strDstRoot.size() > 1 && strDstRoot.back() == '/')
{
strDstRoot.pop_back();
}
strDstRoot += "_TEST/";
if(runConfig.bmonitor)
{
// 监控模式:每 5 分钟执行一次模型推理,记录设备资源消耗到 log;
// 当某次推理输出 out 图至少一个像素不为全黑时退出监控。
return MonitorRun();
}
std::shared_ptr<AIFactory> pAIFactory = AIFactory::GetInstance();
std::shared_ptr<AIModel_Base> pAI_Model = pAIFactory->AI_defect_NF;
if (!pAI_Model || !pAI_Model->m_bInitSuccess)
{
printf("TestAIDet: AI model (AI_defect_NF) not ready!\n");
return 1;
}
printf("TestAIDet: model input [c=%d w=%d h=%d] output [c=%d w=%d h=%d]\n",
pAI_Model->input_0.channel, pAI_Model->input_0.width, pAI_Model->input_0.height,
pAI_Model->output_0.channel, pAI_Model->output_0.width, pAI_Model->output_0.height);
// 收集所有 *_in.png 文件
std::vector<std::string> inList;
try
{
if (!fs::exists(strSrcRoot))
{
printf("TestAIDet: src dir not exist: %s\n", strSrcRoot.c_str());
return 1;
}
for (const auto &entry : fs::recursive_directory_iterator(strSrcRoot))
{
if (!entry.is_regular_file())
{
continue;
}
std::string path = entry.path().string();
std::string name = entry.path().filename().string();
const std::string suffix = "_in.png";
if (name.size() >= suffix.size() &&
name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0)
{
inList.push_back(path);
}
}
}
catch (const std::exception &e)
{
printf("TestAIDet: traverse error %s\n", e.what());
return 1;
}
std::sort(inList.begin(), inList.end());
printf("TestAIDet: total %zu in images\n", inList.size());
const int nModelInCh = pAI_Model->input_0.channel;
const int nModelInW = pAI_Model->input_0.width;
const int nModelInH = pAI_Model->input_0.height;
int nOK = 0;
for (size_t i = 0; i < inList.size(); i++)
{
const std::string &inPath = inList[i];
cv::Mat inImg = cv::imread(inPath, cv::IMREAD_UNCHANGED);
if (inImg.empty())
{
printf("[%zu/%zu] read fail: %s\n", i + 1, inList.size(), inPath.c_str());
continue;
}
// 统一成模型要求的输入:单通道 8U、模型输入尺寸
if (inImg.channels() != nModelInCh)
{
cv::Mat tmp;
if (inImg.channels() >= 3)
{
cv::cvtColor(inImg, tmp, cv::COLOR_BGR2GRAY);
}
else
{
tmp = inImg.clone();
}
inImg = tmp;
}
if (inImg.type() != CV_8U)
{
inImg.convertTo(inImg, CV_8U);
}
if (inImg.cols != nModelInW || inImg.rows != nModelInH)
{
cv::resize(inImg, inImg, cv::Size(nModelInW, nModelInH));
}
cv::Mat outImg;
int re = pAI_Model->AIDet(inImg, outImg);
if (re != 0 || outImg.empty())
{
printf("[%zu/%zu] infer fail(%d): %s\n", i + 1, inList.size(), re, inPath.c_str());
continue;
}
// 输出 resize 回模型输入尺寸(与 AI_Detect_QX 保存的 out 图尺寸保持一致)
if (outImg.cols != nModelInW || outImg.rows != nModelInH)
{
cv::resize(outImg, outImg, cv::Size(nModelInW, nModelInH), 0, 0, 0);
}
// 相对路径,并保持子目录结构
std::string rel = inPath.substr(strSrcRoot.size());
std::string outRel = rel;
const std::string inSuffix = "_in.png";
const std::string outSuffix = "_out.png";
size_t pos = outRel.rfind(inSuffix);
if (pos != std::string::npos)
{
outRel.replace(pos, inSuffix.size(), outSuffix);
}
std::string outPath = strDstRoot + outRel;
// 创建输出父目录
fs::path outParent = fs::path(outPath).parent_path();
if (!outParent.empty())
{
std::error_code ec;
fs::create_directories(outParent, ec);
}
if (cv::imwrite(outPath, outImg))
{
nOK++;
printf("[%zu/%zu] ok: %s -> %s\n", i + 1, inList.size(), rel.c_str(), outRel.c_str());
}
else
{
printf("[%zu/%zu] save fail: %s\n", i + 1, inList.size(), outPath.c_str());
}
}
printf("TestAIDet: complete, success %d / %zu\n", nOK, inList.size());
return 0;
}*/
/// @brief AI 检测独立测试:遍历 /home/aidlux/BOE/FOG/AI_Detect/ 下所有 *_in.png, /// @brief AI 检测独立测试:遍历 /home/aidlux/BOE/FOG/AI_Detect/ 下所有 *_in.png,
/// 送入 AI_defect_NF 模型推理,将输出 *_out.png 保存到 /home/aidlux/BOE/FOG/AI_Detect_TEST/ /// 送入 AI_defect_NF 模型推理,将输出 *_out.png 保存到 /home/aidlux/BOE/FOG/AI_Detect_TEST/
/// @return 0 表示成功 /// @return 0 表示成功

Loading…
Cancel
Save