diff --git a/example/deal.cpp b/example/deal.cpp index 2f4b804..fef6d9d 100644 --- a/example/deal.cpp +++ b/example/deal.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "CheckUtil.hpp" std::string ExtractFileNameWithoutExtension(const std::string &strImgPath) { @@ -101,6 +102,7 @@ deal::deal() m_nCurUseCPUIDX = 0; m_nSaveDetprocessImg = 0; m_nPushImgCount = 0; + m_nResultRecvCount = 0; m_DetResult.Init(); for (int i = 0; i < READ_IMG_THREAD_NUM; i++) { @@ -814,6 +816,8 @@ void deal::ResultThread(int id) { strlog += "/result"; } + // 确保日志目录存在(否则 writeLog 报 Failed to open file) + _sysmkdirs_1(strlog.substr(0, strlog.find_last_of('/'))); writeLog(strlog, m_DetResult.strlist); mutex_DetResult_.unlock(); @@ -861,6 +865,7 @@ void deal::GetDealResultToQueu() { mutex_Result_list.lock(); m_Result_list.push(checkResult); + m_nResultRecvCount++; mutex_Result_list.unlock(); } else @@ -903,6 +908,30 @@ bool deal::ReadSystemConfig(const std::string &strPath) } int deal::GetDetImageInfo(std::string strProductID, std::string strSearchImg, std::vector &jcImageInfoList) { + // -f 批量跑新格式: 产品目录下 input 子目录, 只取 _src 原图 + // (如 1M10121544R3B2_t_face_bright_src.jpg, 从图片名解析产品ID和相机名) + if (fs::is_directory(strSearchImg + "/input")) + { + jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end()); + std::vector srcImgPaths; + cv::glob(strSearchImg + "/input/*.jpg", srcImgPaths, false); + for (int idx = 0; idx < srcImgPaths.size(); idx++) + { + JC_IMAGE_INFO_ tem; + int re = GetImgInfo_BACKPLATE_SRC(srcImgPaths.at(idx), &tem); + if (re != 0) + { + continue; + } + if (tem.strProductID == "") + { + tem.strProductID = strProductID; + } + jcImageInfoList.push_back(tem); + } + return 0; + } + // 1、获取图片路径 std::vector img_paths; std::string strs1 = strSearchImg + "/*.jpg"; @@ -1000,6 +1029,63 @@ int deal::GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageIn } return 0; } +// -f 批量跑新格式: 解析图片名组装产品信息 +// 图片名示例: 1M10121544R3B2_t_face_bright_src.jpg +// 产品ID: 第一个 '_' 之前的部分 (1M10121544R3B2) +// 相机名: 直接匹配文件名中的相机名(t_face_bright / t_face_dark), 只处理后缀为 _src 的原图 +// 通道名: 统一用 t_face +int deal::GetImgInfo_BACKPLATE_SRC(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo) +{ + if (pImageInfo == NULL) + { + return 1; + } + + std::string strName = ExtractFileNameWithoutExtension(strImgPath); + + // 只处理后缀为 _src 的原图, 跳过 _roi 等其它图 + const std::string strSrcSuffix = "_src"; + if (strName.size() <= strSrcSuffix.size() || + strName.compare(strName.size() - strSrcSuffix.size(), strSrcSuffix.size(), strSrcSuffix) != 0) + { + return 1; + } + + // 直接匹配文件名中的相机名(t_face_bright / t_face_dark) + std::string strCamName = ""; + if (strName.find("t_face_bright") != std::string::npos) + { + strCamName = "t_face_bright"; + } + else if (strName.find("t_face_dark") != std::string::npos) + { + strCamName = "t_face_dark"; + } + if (strCamName == "") + { + printf("GetImgInfo_BACKPLATE_SRC: no camera match, skip %s\n", strImgPath.c_str()); + return 1; + } + + // 产品ID = 文件名第一个 '_' 之前的部分 + std::string strProductID = strName; + size_t nPos = strName.find('_'); + if (nPos != std::string::npos) + { + strProductID = strName.substr(0, nPos); + } + + pImageInfo->strProductID = strProductID; + pImageInfo->strCamID = strCamName; + pImageInfo->strchannelName = "t_face"; // 通道名统一用 t_face + pImageInfo->strName = strName; + pImageInfo->strPath = strImgPath; + + printf("strImgPath %s strName %s strProductID %s strCam %s strChannel %s\n", + strImgPath.c_str(), strName.c_str(), strProductID.c_str(), strCamName.c_str(), pImageInfo->strchannelName.c_str()); + + return 0; +} int deal::InsertDetResult(ReadImgInfo tem) { std::lock_guard lock(mtx_List[Mutex_Type_DetResult]); @@ -1203,6 +1289,36 @@ int deal::DetImg() // getchar(); m_nSystemCheckType = CHECK_TYPE_OFFLING; StartThread(THREAD_RUN_ALL); + + // -8 循环执行:保持常驻,重复处理同一批产品 + if (runConfig.bLoop) + { + while (true) + { + usleep(1000 * 1000); + } + } + + // -f 批量(不加 -8 只执行一次):等待全部产品处理完成后退出 + // DealImg 线程处理完一批后会清空 m_product_ID_List 并等待结果队列清空 + while (true) + { + usleep(200 * 1000); + size_t nResultSize = 0; + { + std::lock_guard lock(mutex_Result_list); + nResultSize = m_Result_list.size(); + } + if (m_product_ID_List.empty() && nResultSize <= 0) + { + break; + } + } + // 留时间给结果线程把最后一组结果写完 + usleep(2 * 1000 * 1000); + printf(">>> -f batch complete, exit \n"); + fflush(NULL); + _exit(0); return 0; } int deal::ReJson_product(std::vector &jsonList, std::string strProductName) @@ -1552,6 +1668,55 @@ int deal::LoadProductID(std::string strImgPath) m_product_ID_List.erase(m_product_ID_List.begin(), m_product_ID_List.end()); std::vector img_paths; + // -f 批量跑新格式适配(参考 data/img/test-2 结构): + // /<产品ID>_<时间戳>/input/<产品ID>_<相机名>_<位置>_src.jpg + // 也支持直接传入单个产品目录或产品目录下的 input 目录 + { + std::string strPath = strImgPath; + while (!strPath.empty() && strPath[strPath.size() - 1] == '/') + { + strPath.erase(strPath.size() - 1); + } + fs::path rootPath(strPath); + if (!strPath.empty() && fs::is_directory(rootPath)) + { + // 兼容直接传入 input 目录: 使用其上一级产品目录 + if (rootPath.filename() == "input" && rootPath.has_parent_path()) + { + rootPath = rootPath.parent_path(); + } + + std::vector productDirList; + if (fs::is_directory(rootPath / "input")) + { + // 直接传入单个产品目录 + productDirList.push_back(rootPath.string()); + } + else + { + // 批量根目录: 含 input 子目录的子目录视为一个产品 + for (const auto &entry : fs::directory_iterator(rootPath)) + { + if (entry.is_directory() && fs::is_directory(entry.path() / "input")) + { + productDirList.push_back(entry.path().string()); + } + } + } + + if (!productDirList.empty()) + { + std::sort(productDirList.begin(), productDirList.end()); + for (const auto &strProductDir : productDirList) + { + m_product_ID_List.push_back(strProductDir); + std::cout << "new format product dir: " << strProductDir << std::endl; + } + return 0; + } + } + } + // tif 格式 { std::string str_bmp = strImgPath + "/*.jpg"; @@ -1600,6 +1765,11 @@ int deal::LoadProductID(std::string strImgPath) } } + if (m_product_ID_List.empty()) + { + printf("warning: no product dir/image found under %s\n", strImgPath.c_str()); + } + return 0; } int deal::DelImg_Cell_ET() @@ -1650,6 +1820,13 @@ int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx) { std::string strProductID = GetFileName(strProductName); + // -f 批量跑新格式: 产品目录名为 <产品ID>_<时间戳>(如 1M10121544R3B2_20261012.151444.066219) + // 取第一个 '_' 之前的部分作为产品ID; 旧格式目录名本身即产品ID(无 '_')不受影响 + size_t nProductIDPos = strProductID.find('_'); + if (nProductIDPos != std::string::npos) + { + strProductID = strProductID.substr(0, nProductIDPos); + } // 获取图片路径 std::vector detImgInfoList; @@ -1739,6 +1916,33 @@ int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx) } } + // -f 批量逐个产品处理:等待本产品的检测结果全部返回后,再处理下一个产品, + // 避免多个产品同时积压在检测队列中(内存/检测器压力过大导致卡死) + if (AllImgNum > 0) + { + int nWaitCnt = 0; + while (true) + { + int nRecv = 0; + int nPush = 0; + { + std::lock_guard lock(mutex_Result_list); + nRecv = m_nResultRecvCount; + nPush = m_nPushImgCount; + } + if (nRecv >= nPush) + { + break; + } + if (nWaitCnt % 250 == 0) + { + printf(">>> waiting %s check result %d/%d ...\n", strProductID.c_str(), nRecv, nPush); + } + nWaitCnt++; + usleep(20 * 1000); + } + } + m_DetResult.one_result_list.push_back(tem_one); m_DetResult.det_num_all++; // if (m_DetResult.det_num_all == 1) diff --git a/example/deal.h b/example/deal.h index 6294cf7..c4f7681 100644 --- a/example/deal.h +++ b/example/deal.h @@ -551,6 +551,9 @@ private: int GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + // -f 批量跑新格式: 解析 <产品ID>_<相机名>_<位置>_src.jpg 图片名组装产品信息(相机名 t_face_bright/t_face_dark, 通道名统一 t_face) + int GetImgInfo_BACKPLATE_SRC(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + // 功能测试 int Det_Funtion_Test(); // 边缘测试 @@ -649,6 +652,7 @@ public: int m_nSaveDetprocessImg; int m_nPushImgCount; // 送检图片总数(拆分后) + int m_nResultRecvCount; // 已收到检测结果总数(-f 逐个产品处理:等当前产品结果返回后再跑下一个) cv::Rect m_CutRoi; Det_File_Result_Info m_DetResult; diff --git a/example/test_example.cpp b/example/test_example.cpp index d1731ef..1f930e5 100644 --- a/example/test_example.cpp +++ b/example/test_example.cpp @@ -85,6 +85,8 @@ int main(int argc, char *argv[]) cout << "*** 5、./test_JBL_Check -falign filepath num : 批量测试定位算法,num 至多处理张数,结果:/home/aidlux/BOE/Align" << endl; cout << "*** 6、./test_JBL_Check -rjson filepath: 单张复测,filepath xx/xx/3A3K380001B1DK_20240408_152157_Main_0_2_L255" << endl; cout << "*** 6、./test_JBL_Check -rjsonall filepath: 一套图复测,filepath xx/xx/" << endl; + cout << "*** 7、./test_BACKPLATE -8: 循环执行程序(常驻),不加 -8 只执行一次" << endl; + cout << "*** 8、./test_BACKPLATE -f filepath: 批量执行 filepath 下的套图(新格式: <产品ID>_<时间戳>/input/<产品ID>_<相机名>_xxx_src.jpg, 相机名 t_face_bright/t_face_dark, 通道名统一 t_face)" << endl; cout << "******************************************************" << endl; return 0;