diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 0bfe64a..0fcb777 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -1378,38 +1378,11 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) long t1, t2, t3; t1 = CheckUtil::getcurTime(); - SmallRoiList.clear(); - SmallRoiList.erase(SmallRoiList.begin(), SmallRoiList.end()); - cv::Rect cutRoi; - cutRoi.x = 0; - cutRoi.y = 0; - cutRoi.width = img.cols - 0; - cutRoi.height = img.rows - 0; - - int deal_image_width = pAIDetList[0]->input_0.width; - int deal_image_height = pAIDetList[0]->input_0.height; - - int re = CheckUtil::cutSmallImg(img, SmallRoiList, cutRoi, deal_image_width, deal_image_height, 0, 0); - - m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg Num %d", SmallRoiList.size()); - if (re != 0 || SmallRoiList.size() <= 0) + if (img.empty()) { - m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg error %d", re); + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " input img empty error"); m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); - return re; - /* code */ - } - - // 临时存图 - if (DetImgInfo_shareP->bsaveProcessImg) - { - - cv::Mat imshow = img.clone(); // 保持输入通道,不再灰度转假彩 - for (int i = 0; i < SmallRoiList.size(); i++) - { - cv::rectangle(imshow, SmallRoiList.at(i), CheckUtil::GetDrawColor(imshow, cv::Scalar(0, 0, 255)), 3); - } - cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_Det_ROI.jpg", imshow); + return 1; } ResultImg = cv::Mat::zeros(img.size(), CV_8UC1); @@ -1422,105 +1395,108 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) modelMaskList[m] = cv::Mat::zeros(img.size(), CV_8UC1); } - const int totalTasks = SmallRoiList.size(); + // 整图检测模式下,所有模型的 ROI 都是整幅检测图 + const cv::Rect fullRoi(0, 0, img.cols, img.rows); - // std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_"; t2 = CheckUtil::getcurTime(); - // 依次用多个模型做检测,所有模型输出的 mask 取并集作为最终 outmask + // 模型实际输入图(整图 resize 到模型输入大小)缓存一份,供结果记录使用 + cv::Mat firstModelInput; + + // 依次用多个模型做检测:整图 resize 到模型输入大小 -> 推理 -> 输出 mask resize 回原图大小, + // 所有模型输出的 mask 取并集作为最终 outmask for (size_t m = 0; m < pAIDetList.size(); m++) { std::shared_ptr pAIDet = pAIDetList[m]; - int submitted = 0; - int completed = 0; - while (completed < totalTasks) + std::string strModelName = (m < pAIDetNameList.size()) ? pAIDetNameList[m] : std::string(AI_DET_MODEL_NAME_UnKnown); + + int deal_image_width = pAIDet->input_0.width; + int deal_image_height = pAIDet->input_0.height; + if (deal_image_width <= 0 || deal_image_height <= 0) { - // 如果任务还没提交完,且当前处理任务数 < 10,提交新任务 - if (submitted < totalTasks && runner->GetProcessingCount() < 10) - { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " %s model input size error [%d %d]", strModelName.c_str(), deal_image_width, deal_image_height); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); + return 2; + } - std::shared_ptr task = std::make_shared(); - task->id = submitted; - task->roi = SmallRoiList.at(submitted); - task->input = img(SmallRoiList.at(submitted)).clone(); - task->output = std::make_shared(); - task->engine = pAIDet; + // 1、整图 resize 到模型输入大小 + cv::Mat detInputImg; + cv::resize(img, detInputImg, cv::Size(deal_image_width, deal_image_height)); + // 模型输入要求单通道;原图为彩色时按 BGR 顺序转灰度(与 imread(path,0) 的亮度一致) + if (detInputImg.channels() == 3) + { + cv::cvtColor(detInputImg, detInputImg, cv::COLOR_BGR2GRAY); + } + else if (detInputImg.channels() == 4) + { + cv::cvtColor(detInputImg, detInputImg, cv::COLOR_BGRA2GRAY); + } - runner->SubmitTask(task); - submitted++; - } + if (m == 0) + { + firstModelInput = detInputImg; + } - // 尝试取结果 - std::shared_ptr result; - if (runner->PopResult(result)) - { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " %s input img [%d*%d] -> model [%d*%d]", + strModelName.c_str(), img.cols, img.rows, deal_image_width, deal_image_height); - { - std::lock_guard lock(mtx_AIMaskImgBLobQueue); - m_AIMaskImgBLobQueue.push(result); - } + // 临时存图:保存模型实际输入图 + if (DetImgInfo_shareP->bsaveProcessImg) + { + cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_Det_" + strModelName + "_in.jpg", detInputImg); + } - cv::Mat &outimg = *(result->output); - if (!outimg.empty()) - { - // 多个模型的结果取并集 - cv::Mat roiMat = ResultImg(result->roi); - cv::bitwise_or(roiMat, outimg, roiMat); + // 2、整图推理 + cv::Mat modelMask; + int re = pAIDet->AIDet(detInputImg, modelMask); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " %s AIDet error %d", strModelName.c_str(), re); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); + return re; + } - // 当前模型自己的 mask 单独记录一份 - if (m < modelMaskList.size() && !modelMaskList[m].empty()) - { - cv::Mat modelRoiMat = modelMaskList[m](result->roi); - cv::bitwise_or(modelRoiMat, outimg, modelRoiMat); - } + // 3、输出 mask resize 回原图大小(最近邻,保证 mask 像素值不被插值改变) + cv::Mat modelMaskFull; + if (!modelMask.empty()) + { + cv::resize(modelMask, modelMaskFull, img.size(), 0, 0, cv::INTER_NEAREST); - // AI 检测残点图存图:每个模型的结果都存,并增加一级 模型名称 目录, - // 用以区分该残点是由哪个模型检出的 - // 目录结构:/home/aidlux/BOE/ZB_SOCKET/AI_Detect/<模型名称>/<产品ID>/ - if (m_pbaseCheckFunction->saveImg.bSaveAIDetImg) - { - std::string strModelName = (m < pAIDetNameList.size()) ? pAIDetNameList[m] : std::string(AI_DET_MODEL_NAME_UnKnown); - std::string roi_ext = "[" + std::to_string(result->roi.x) + "," + std::to_string(result->roi.y) + "]"; - std::string strSaveDir = "/home/aidlux/BOE/ZB_SOCKET/AI_Detect/" + strModelName + "/" + DetImgInfo_shareP->strImgProductID + "/"; - CheckUtil::CreateDir(strSaveDir); - std::string strSavePath_in = strSaveDir + m_strCurDetChannel + "_" + roi_ext + "_in.png"; - std::string strSavePath_out = strSaveDir + m_strCurDetChannel + "_" + roi_ext + "_out.png"; - cv::imwrite(strSavePath_in, result->input); - cv::imwrite(strSavePath_out, outimg); - } - } + // 多个模型的 mask 取并集 + cv::bitwise_or(ResultImg, modelMaskFull, ResultImg); - // 同一 roi 的多个模型结果取并集后存入 AI_Qx_MaskList - bool bFind = false; - for (auto &item : m_pImageAllResult->AI_Qx_MaskList) - { - if (item->roi == result->roi) - { - cv::bitwise_or(item->AI_mask, outimg, item->AI_mask); - bFind = true; - break; - } - } - if (!bFind) - { - std::shared_ptr temAIresult = std::make_shared(); - temAIresult->roi = result->roi; - temAIresult->AI_inImg = result->input; - temAIresult->AI_mask = outimg.clone(); - m_pImageAllResult->AI_Qx_MaskList.push_back(temAIresult); - } - completed++; - } - else - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + // 当前模型自己的 mask 单独记录一份 + cv::bitwise_or(modelMaskList[m], modelMaskFull, modelMaskList[m]); + } + + // AI 检测残点图存图:每个模型的结果都存,并增加一级 模型名称 目录, + // 用以区分该残点是由哪个模型检出的 + // 目录结构:/home/aidlux/BOE/ZB_SOCKET/AI_Detect/<模型名称>/<产品ID>/ + if (m_pbaseCheckFunction->saveImg.bSaveAIDetImg && !modelMaskFull.empty()) + { + std::string strSaveDir = "/home/aidlux/BOE/ZB_SOCKET/AI_Detect/" + strModelName + "/" + DetImgInfo_shareP->strImgProductID + "/"; + CheckUtil::CreateDir(strSaveDir); + std::string strSavePath_in = strSaveDir + m_strCurDetChannel + "_in.png"; + std::string strSavePath_out = strSaveDir + m_strCurDetChannel + "_out.png"; + cv::imwrite(strSavePath_in, detInputImg); + cv::imwrite(strSavePath_out, modelMaskFull); + } + + // 4、mask 结果放入队列,用于 AIMaskDet 加速 blob 计算(整图 ROI) + if (!modelMaskFull.empty()) + { + std::shared_ptr maskTask = std::make_shared(); + maskTask->id = static_cast(m); + maskTask->roi = fullRoi; + maskTask->output = std::make_shared(modelMaskFull); + std::lock_guard lock(mtx_AIMaskImgBLobQueue); + m_AIMaskImgBLobQueue.push(maskTask); } } t3 = CheckUtil::getcurTime(); - float mean_AI = (t3 - t2) / (SmallRoiList.size() * pAIDetList.size()); - m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " AI Run Time: sum %ld pre %ld Run %ld mean One Small Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI); + float mean_AI = (t3 - t2) / (float)pAIDetList.size(); + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " AI Run Time: sum %ld pre %ld Run %ld mean One Full Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI); // 保存各模型的 全图 mask,并输出各模型检出的残点像素数量,便于追溯 for (size_t m = 0; m < modelMaskList.size(); m++) @@ -1534,6 +1510,27 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) temModelMask->strModelName.c_str(), cv::countNonZero(temModelMask->ModelMask)); } + // 整图检测模式下所有模型共用同一个 ROI(整幅检测图),多个模型的 mask 已取并集, + // 按整图 ROI 记录一条 AI 检测结果,供 GetAIDetImg 按缺陷中心点取到 AI 输入图与并集 mask + bool bFind = false; + for (auto &item : m_pImageAllResult->AI_Qx_MaskList) + { + if (item->roi == fullRoi) + { + cv::bitwise_or(item->AI_mask, ResultImg, item->AI_mask); + bFind = true; + break; + } + } + if (!bFind) + { + std::shared_ptr temAIresult = std::make_shared(); + temAIresult->roi = fullRoi; + temAIresult->AI_inImg = firstModelInput; + temAIresult->AI_mask = ResultImg.clone(); + m_pImageAllResult->AI_Qx_MaskList.push_back(temAIresult); + } + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); // 临时存图