Compare commits

..

No commits in common. 'dev_offline' and 'main' have entirely different histories.

@ -26,7 +26,7 @@
// resize 图片的 宽度 // resize 图片的 宽度
#define RESIZE_IMAGE_WIDTH 1680 #define RESIZE_IMAGE_WIDTH 1680
#define AI_Time // #define AI_Time
enum TEM_IMG_IDX_ enum TEM_IMG_IDX_
{ {

@ -44,7 +44,6 @@ public:
static int SizeRect(cv::Rect &roi, int img_w, int img_h, int addw, int addh); static int SizeRect(cv::Rect &roi, int img_w, int img_h, int addw, int addh);
static int CalHj(const cv::Mat &img, const cv::Mat &mask, int b_value); static int CalHj(const cv::Mat &img, const cv::Mat &mask, int b_value);
static int CalHj(const cv::Mat &img, const cv::Mat &mask, const cv::Mat &backgroundimg); static int CalHj(const cv::Mat &img, const cv::Mat &mask, const cv::Mat &backgroundimg);
static int CalHjWeighted(const cv::Mat &img, const cv::Mat &mask, int b_value, float power = 2.0f);
static float CalRoi2RoiPre(cv::Rect rect1, cv::Rect rect2); static float CalRoi2RoiPre(cv::Rect rect1, cv::Rect rect2);
// 计算平均灰度 // 计算平均灰度
static float CalImgBrightness(cv::Mat imgRoi); static float CalImgBrightness(cv::Mat imgRoi);

@ -153,8 +153,6 @@ public:
void AddLog(std::string str); void AddLog(std::string str);
// 添加图片信息 // 添加图片信息
int AddDetImage(std::shared_ptr<shareImage> p); int AddDetImage(std::shared_ptr<shareImage> p);
// ✅ 处理完成后释放中间数据,减少内存占用
void ReleaseIntermediateData();
DetStep getStep(); DetStep getStep();
void setStep(DetStep step); void setStep(DetStep step);
bool IsNotDet(); bool IsNotDet();

@ -2,7 +2,7 @@
#define ImgCheckBase_H_ #define ImgCheckBase_H_
#include <string> #include <string>
#include <memory> #include <memory>
#define ALL_INTERFACE_VERSION 7 #define ALL_INTERFACE_VERSION 6
#define MAX_GPU_NUM 4 #define MAX_GPU_NUM 4
enum CHECK_THREAD_RUN_STATUS enum CHECK_THREAD_RUN_STATUS

@ -724,10 +724,6 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptr<I
for (int i = 0; i < m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_roiList.size(); i++) for (int i = 0; i < m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_roiList.size(); i++)
{ {
cv::Rect boundingRect = m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_roiList.at(i); cv::Rect boundingRect = m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_roiList.at(i);
boundingRect.x -= 5;
boundingRect.y -= 5;
boundingRect.width += 10;
boundingRect.height += 10;
detImg_mask(boundingRect).setTo(255); detImg_mask(boundingRect).setTo(255);
} }
if (L255->result->in_shareImage->bDebugsaveImg) if (L255->result->in_shareImage->bDebugsaveImg)

@ -457,32 +457,6 @@ int CheckUtil::CalHj(const cv::Mat &img, const cv::Mat &mask, const cv::Mat &bac
return meanValue123[0]; return meanValue123[0];
} }
int CheckUtil::CalHjWeighted(const cv::Mat &img, const cv::Mat &mask, int b_value, float power)
{
cv::Mat imgf;
if (img.type() != CV_32F)
img.convertTo(imgf, CV_32F);
else
imgf = img;
cv::Mat absDiff = cv::abs(imgf - b_value);
cv::Mat weight;
cv::pow(absDiff, power, weight);
cv::Mat maskedDiff, maskedWeight;
absDiff.copyTo(maskedDiff, mask);
weight.copyTo(maskedWeight, mask);
cv::Scalar weightedSum = cv::sum(maskedDiff.mul(weight));
cv::Scalar weightSum = cv::sum(maskedWeight);
if (weightSum[0] < 1e-6)
return 0;
return static_cast<int>(weightedSum[0] / weightSum[0]);
}
float CheckUtil::CalRoi2RoiPre(cv::Rect rect1, cv::Rect rect2) float CheckUtil::CalRoi2RoiPre(cv::Rect rect1, cv::Rect rect2)
{ {
// 计算交集区域 // 计算交集区域

@ -18,49 +18,6 @@ ImageAllResult::~ImageAllResult()
{ {
} }
// ✅ 处理完成后释放中间 cv::Mat 数据,减少内存占用
// 注意CheckResultresult中的图像数据必须保留
void ImageAllResult::ReleaseIntermediateData()
{
std::lock_guard<std::mutex> lock_cam(mtx_Det);
// ✅ 释放原始输入图像(处理完成后不再需要)
if (result && result->in_shareImage)
{
if (!result->in_shareImage->img.empty())
{
result->in_shareImage->img.release();
}
if (!result->in_shareImage->AI_maskImg.empty())
{
result->in_shareImage->AI_maskImg.release();
}
}
// ✅ AI_Time 开启时需要保留 detImg用于生成缺陷小图和 AI_Qx_MaskList用于 AI 调试图像)
// 其他中间数据可以安全释放
#ifndef AI_Time
if (!detImg.empty()) { detImg.release(); }
#endif
if (!AI_detImg.empty()) { AI_detImg.release(); }
if (!AIMaskImg.empty()) { AIMaskImg.release(); }
if (!AI_127CellMaskImg.empty()) { AI_127CellMaskImg.release(); }
if (!resultImg.empty()) { resultImg.release(); }
if (!shieldImg.empty()) { shieldImg.release(); }
if (!AI_shieldImg.empty()) { AI_shieldImg.release(); }
if (!YX_MaskImg.empty()) { YX_MaskImg.release(); }
if (!LcakPol_MaskImg.empty()) { LcakPol_MaskImg.release(); }
// 释放 AI 检测中间结果
if (qx_DetAIResult) { qx_DetAIResult->Init(); }
if (cell127_DetAIResult) { cell127_DetAIResult->Init(); }
// ✅ AI_Time 开启时需要保留 AI_Qx_MaskListGetAIDetImg 使用)
#ifndef AI_Time
AI_Qx_MaskList.clear();
#endif
}
void ImageAllResult::AddLog(std::string str) void ImageAllResult::AddLog(std::string str)
{ {
LogList.push_back(str); LogList.push_back(str);

@ -415,7 +415,6 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
Judge_Status = true; Judge_Status = true;
checkFlage = ANALYSIS_TYPE_TF; checkFlage = ANALYSIS_TYPE_TF;
nerrortype = 1; nerrortype = 1;
bNG_Status = true;
} }
} }
// 暗点 3S 分析 对 好品 或者 是 疑是的缺陷进行3S分析。S数量分析。 3S的暗点直接NG. // 暗点 3S 分析 对 好品 或者 是 疑是的缺陷进行3S分析。S数量分析。 3S的暗点直接NG.
@ -627,9 +626,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nresult = nqx_type; m_CheckResult_shareP->nresult = nqx_type;
} }
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->qxImageResult.push_back(tem); m_CheckResult_shareP->qxImageResult.push_back(tem);
} }
else else
@ -640,9 +637,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nYS_result = nqx_type; m_CheckResult_shareP->nYS_result = nqx_type;
} }
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->YS_ImageResult.push_back(tem); m_CheckResult_shareP->YS_ImageResult.push_back(tem);
} }
@ -890,9 +885,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
{ {
m_CheckResult_shareP->nresult = nqx_type; m_CheckResult_shareP->nresult = nqx_type;
} }
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->qxImageResult.push_back(tem); m_CheckResult_shareP->qxImageResult.push_back(tem);
} }
} }

@ -170,7 +170,7 @@ int ImgCheckAnalysisy::GetStatus()
std::string ImgCheckAnalysisy::GetVersion() std::string ImgCheckAnalysisy::GetVersion()
{ {
return std::string("BOE_1.2.3_" + std::string(__DATE__) + "_" + std::string(__TIME__)); return std::string("BOE_1.2.0");
} }
std::string ImgCheckAnalysisy::GetErrorInfo() std::string ImgCheckAnalysisy::GetErrorInfo()
@ -332,7 +332,7 @@ cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::M
// 计算 hj差异图像大于0的像素均值 // 计算 hj差异图像大于0的像素均值
// double hj = std::abs(fbk - fdet); // double hj = std::abs(fbk - fdet);
double hj = CheckUtil::CalHjWeighted(cimg, cmask, fbk, 2.0f); double hj = CheckUtil::CalHj(cimg, cmask, mean_bk.val[0]);
int worb = 0; int worb = 0;
if (fdet >= fbk) if (fdet >= fbk)
@ -381,7 +381,7 @@ double ImgCheckAnalysisy::CalBlobHJ(cv::Mat &img, const cv::Mat &mask, cv::Rect
// 计算 hj差异图像大于0的像素均值 // 计算 hj差异图像大于0的像素均值
// double hj = std::abs(fbk - fdet); // double hj = std::abs(fbk - fdet);
double hj = CheckUtil::CalHjWeighted(cimg, cmask, fbk, 2.0f); double hj = CheckUtil::CalHj(cimg, cmask, fbk);
static int kkk = 0; static int kkk = 0;
unsigned char *pErrordata = (unsigned char *)cimg.data; unsigned char *pErrordata = (unsigned char *)cimg.data;
@ -589,7 +589,6 @@ int ImgCheckAnalysisy::SetNewConfig()
m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0); m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0);
GetParamidx(); GetParamidx();
UpdateImgageScale(); UpdateImgageScale();
UPdateLDConfig();
if (true) if (true)
{ {
printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str()); printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str());
@ -667,8 +666,6 @@ int ImgCheckAnalysisy::Run(int nId)
CheckRun(); CheckRun();
m_nRun_Status = CHECK_THREAD_STATUS_COMPLETE; m_nRun_Status = CHECK_THREAD_STATUS_COMPLETE;
m_pImageAllResult->setStep(ImageAllResult::DetStep_Complet); m_pImageAllResult->setStep(ImageAllResult::DetStep_Complet);
// ✅ 处理完成后立即释放 ImageAllResult 的中间数据,减少内存占用
m_pImageAllResult->ReleaseIntermediateData();
m_nRun_Status = CHECK_THREAD_STATUS_IDLE; m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
// printf("*--------%d\n", m_nRun_Status); // printf("*--------%d\n", m_nRun_Status);
} }
@ -2485,11 +2482,6 @@ int ImgCheckAnalysisy::AI_Detect_QX()
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use Chess"); m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use Chess");
pAI_Model = AI_Factory->AI_defect_Chess; pAI_Model = AI_Factory->AI_defect_Chess;
} }
else if (m_pFuntion->function.f_BaseDet.strAIMode == "RGB-HGRAY")
{
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use RE_RGBHGRAY");
pAI_Model = AI_Factory->AI_defect_RE_RGBHGRAY;
}
else else
{ {
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use base"); m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use base");
@ -3364,17 +3356,17 @@ int ImgCheckAnalysisy::BLobToDetResult()
config_qx_type == CONFIG_QX_NAME_Other || config_qx_type == CONFIG_QX_NAME_Other ||
config_qx_type == CONFIG_QX_NAME_LD) config_qx_type == CONFIG_QX_NAME_LD)
{ {
qx_name = CONFIG_QX_NAME_Names[config_qx_type]; std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
// m_TemCheck.AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "LD", "stsrt config_qx_type %s ", qx_name.c_str()); // m_TemCheck.AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "LD", "stsrt config_qx_type %s ", qx_name.c_str());
int dbresult = LDJudge(config_qx_type, roi, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, pQxlog); int dbresult = LDJudge(config_qx_type, roi, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, pQxlog);
//int detre = 1; int detre = 1;
// 表示L0 和 DP 都有的 亮的 // 表示L0 和 DP 都有的 亮的
if (dbresult == 1) if (dbresult == 1)
{ {
config_qx_type = CONFIG_QX_NAME_LD; config_qx_type = CONFIG_QX_NAME_LD;
qx_name = CONFIG_QX_NAME_Names[config_qx_type]; qx_name = CONFIG_QX_NAME_Names[config_qx_type];
} }
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " LD Judge ", "%s qx %s ", Re_TO_STR_Pass_1(dbresult), qx_name.c_str()); pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " LD Judge ", "%s qx %s ", Re_TO_STR_False(detre), qx_name.c_str());
} }
// 如果是chess 画面缺陷类型直接是chess异常。 // 如果是chess 画面缺陷类型直接是chess异常。
if (m_pFuntion->function.f_AIQX.bAllToChess) if (m_pFuntion->function.f_AIQX.bAllToChess)
@ -3458,7 +3450,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
bool ban = JudgeQXAnalysis(config_qx_type, pQxlog); bool ban = JudgeQXAnalysis(config_qx_type, pQxlog);
if (!ban) if (!ban)
{ {
qx_name = CONFIG_QX_NAME_Names[config_qx_type]; std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Judge QX", "qx function close, config_qx_type %s Not Det", pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Judge QX", "qx function close, config_qx_type %s Not Det",
qx_name.c_str()); qx_name.c_str());
@ -3475,7 +3467,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
isMarksheildQX = Judge_MarkLine_QX(config_qx_type, roi, pQxlog); isMarksheildQX = Judge_MarkLine_QX(config_qx_type, roi, pQxlog);
if (isMarksheildQX) if (isMarksheildQX)
{ {
qx_name = CONFIG_QX_NAME_Names[config_qx_type]; std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkLine_QX", "MarkLine_QX close, config_qx_type %s Not Det", pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkLine_QX", "MarkLine_QX close, config_qx_type %s Not Det",
qx_name.c_str()); qx_name.c_str());

@ -972,7 +972,6 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
} }
A_2S_num += AD_list.at(ad_i).num_2s; A_2S_num += AD_list.at(ad_i).num_2s;
A_3S_num += AD_list.at(ad_i).num_3s; A_3S_num += AD_list.at(ad_i).num_3s;
if(AD_list.at(ad_i).num_1s >= 3) A_3S_num++;
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD_list %d %s", m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD_list %d %s",
ad_i, AD_list.at(ad_i).GetInfo().c_str()); ad_i, AD_list.at(ad_i).GetInfo().c_str());
} }
@ -1029,7 +1028,7 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
} }
else else
{ {
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result OK 3S %d < 1", m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result NG 3S %d < 1",
pQXChannelList->channel_name.c_str(), A_3S_num); pQXChannelList->channel_name.c_str(), A_3S_num);
} }
} }

@ -213,7 +213,6 @@ int ConfigInstance::Updata_Check(Json::Value json_value)
int ConfigInstance::SetStatus(int nConfigType) int ConfigInstance::SetStatus(int nConfigType)
{ {
std::lock_guard<std::mutex> lock(mutex_status);
for (int i = 0; i < MAX_USER_COUNT; i++) for (int i = 0; i < MAX_USER_COUNT; i++)
{ {
m_USER_ConfigUpdataStatusList[nConfigType][i] = true; m_USER_ConfigUpdataStatusList[nConfigType][i] = true;

@ -203,7 +203,6 @@ int ConfigManager::UpdateConfig()
if (!std::filesystem::exists(strConfigPath)) { if (!std::filesystem::exists(strConfigPath)) {
strConfigPath = m_strConfigRootPath + "/param.json"; strConfigPath = m_strConfigRootPath + "/param.json";
} }
printf("read param %s\n", strConfigPath.c_str());
std::shared_ptr<ConfigBase> temConfig = ConfigBase::GetInstance(); std::shared_ptr<ConfigBase> temConfig = ConfigBase::GetInstance();
re = LoadParamConfig(temConfig, strConfigPath); re = LoadParamConfig(temConfig, strConfigPath);
if (re != 0) if (re != 0)
@ -219,13 +218,8 @@ int ConfigManager::UpdateConfig()
printf("Error >>>> camear Name is empty \n"); printf("Error >>>> camear Name is empty \n");
continue; continue;
} }
auto it = Config_instances_.find(p.commonCheckConfig.baseConfig.strCamearName);
if (it != Config_instances_.end() && it->second) {
LoadParamConfig(it->second, strConfigPath);
} else {
Config_instances_[p.commonCheckConfig.baseConfig.strCamearName] = temConfig; Config_instances_[p.commonCheckConfig.baseConfig.strCamearName] = temConfig;
} }
}
// getchar(); // getchar();

@ -32,7 +32,7 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value rootvalue; Json::Value rootvalue;
std::string err; std::string err;
std::cout << strJson << std::endl; // std::cout << strJson << std::endl;
auto nSize = strJson.size(); auto nSize = strJson.size();
if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err)) if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err))
{ {
@ -49,7 +49,6 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
{ {
_config.baseConfig.strConfigVersion = "NULL"; _config.baseConfig.strConfigVersion = "NULL";
} }
_config.baseConfig.image_widht = value["image_widht"].asInt(); _config.baseConfig.image_widht = value["image_widht"].asInt();
_config.baseConfig.Image_height = value["Image_height"].asInt(); _config.baseConfig.Image_height = value["Image_height"].asInt();
_config.baseConfig.bDrawShieldRoi = value["bDrawShieldRoi"].asBool(); _config.baseConfig.bDrawShieldRoi = value["bDrawShieldRoi"].asBool();

@ -1,50 +0,0 @@
#ifndef _MEM_MONITOR_H_
#define _MEM_MONITOR_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
// 获取当前进程 RSS (物理内存) 使用量,单位 MB
static inline long getRSS_KB()
{
long rss = 0;
FILE *fp = fopen("/proc/self/status", "r");
if (!fp) return -1;
char line[256];
while (fgets(line, sizeof(line), fp))
{
if (strncmp(line, "VmRSS:", 6) == 0)
{
// 格式: "VmRSS: 12345 kB"
const char *p = line + 6;
while (*p == ' ' || *p == '\t') p++;
rss = atol(p);
break;
}
}
fclose(fp);
return rss;
}
// 获取当前进程内存使用,打印格式化日志
static inline void printMemUsage(const char *tag, const char *extra)
{
long rss = getRSS_KB();
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
printf("[MEM] %-30s | VmRSS: %6ld MB | maxRSS: %6ld MB | %s\n",
tag, rss / 1024, usage.ru_maxrss / 1024, extra ? extra : "");
}
// 获取产品检测 pipeline 队列深度信息快照
#define MEM_LOG(tag, fmt, ...) \
do { \
long _rss = getRSS_KB(); \
printf("[MEM] %-30s | VmRSS: %6ld MB | " fmt "\n", tag, _rss / 1024, ##__VA_ARGS__); \
} while(0)
#endif // _MEM_MONITOR_H_

@ -3,7 +3,6 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "MemMonitor.h"
#include <unistd.h> #include <unistd.h>
#include <string> #include <string>
#include "CheckUtil.hpp" #include "CheckUtil.hpp"
@ -901,7 +900,6 @@ void deal::GetDealResultToQueu()
mutex_Result_list.lock(); mutex_Result_list.lock();
m_Result_list.push(checkResult); m_Result_list.push(checkResult);
mutex_Result_list.unlock(); mutex_Result_list.unlock();
m_nTotalResultsDrained.fetch_add(1); // ✅ 更新计数器
} }
else else
{ {
@ -1343,65 +1341,11 @@ int deal::CheckFileImg()
products[i].print("产品" + std::to_string(i + 1)); products[i].print("产品" + std::to_string(i + 1));
} }
// getchar(); // getchar();
printMemUsage("CheckFileImg-开始处理", "");
for (size_t i = 0; i < products.size(); i++) for (size_t i = 0; i < products.size(); i++)
{ {
char buf[128];
snprintf(buf, sizeof(buf), "产品[%zu/%zu] %s 处理前", i+1, products.size(), products[i].product_id.c_str());
printMemUsage(buf, "");
CheckProduct(products[i]); // 处理单个产品 CheckProduct(products[i]); // 处理单个产品
snprintf(buf, sizeof(buf), "产品[%zu/%zu] %s 处理后", i+1, products.size(), products[i].product_id.c_str());
printMemUsage(buf, "");
}
// ✅ 修复:所有产品处理完成后,通知后台线程退出
printf("\n>>> 所有产品处理完成,正在停止后台线程...\n");
// 1. 通知产品读图线程退出
m_bProductReadExit = true;
m_productTaskCV.notify_all();
m_checkNotifyCV.notify_all();
// 2. 通知结果处理线程退出
m_bExit = true;
cv.notify_all();
// 3. 等待产品读图线程结束
for (auto &thread : m_productReadThreads)
{
if (thread && thread->joinable())
{
thread->join();
}
}
m_productReadThreads.clear();
// 4. 等待结果处理线程结束
for (auto &thread : ptr_ResultthreadList)
{
if (thread && thread->joinable())
{
thread->join();
}
}
ptr_ResultthreadList.clear();
// 5. 等待 GetResult 线程结束
if (ptr_GetResultthread && ptr_GetResultthread->joinable())
{
ptr_GetResultthread->join();
}
ptr_GetResultthread.reset();
// 6. 等待 DealImg 线程结束(如果存在)
if (ptr_DealImgthread && ptr_DealImgthread->joinable())
{
ptr_DealImgthread->join();
} }
ptr_DealImgthread.reset();
printf(">>> 所有后台线程已停止,程序退出.\n");
printf("\n"); printf("\n");
// TODO: 后续实现具体功能 // TODO: 后续实现具体功能
@ -1442,11 +1386,6 @@ int deal::CheckProduct(const LoadProductImages &product)
m_ProductFailedList.clear(); m_ProductFailedList.clear();
m_nCheckNotifiedCount = 0; m_nCheckNotifiedCount = 0;
// ✅ 修复内存泄漏清理上一个产品累积的原始图像数据cv::Mat
// 注意m_DetResult 是统计结果(轻量字符串/数字),不清除,跨产品累积
m_ImageInfoList.clear();
m_productIdList.clear();
// 3. 打印产品信息 // 3. 打印产品信息
printf("\n"); printf("\n");
printf("╔══════════════════════════════════════════════════════════\n"); printf("╔══════════════════════════════════════════════════════════\n");
@ -1498,53 +1437,6 @@ int deal::CheckProduct(const LoadProductImages &product)
SendCheckImg(info, IN_IMG_Status_End, true); SendCheckImg(info, IN_IMG_Status_End, true);
printf("\n"); printf("\n");
// ✅ 流控:等待 Run 线程处理完当前产品 + 结果全部保存完毕,再继续下一个产品
// 两步确认:
// 第1步 - 等 GetResultThread 把本产品所有结果从 m_CheckResultList 取出
// 第2步 - 等 ResultThread 把 m_Result_list 中的结果全部保存、释放内存
{
int startDrained = m_nTotalResultsDrained.load();
int expectedResults = (int)totalImgNum;
int maxWaitMs = 600000; // 最多等待10分钟
int waitedMs = 0;
// 第1步等结果被消费
printf("[流控-1] 等待产品 %s 的 %d 个检测结果被消费...\n", product.product_id.c_str(), expectedResults);
while (m_nTotalResultsDrained.load() - startDrained < expectedResults && waitedMs < maxWaitMs)
{
usleep(100000);
waitedMs += 100;
}
printf("[流控-1] 已完成,已消费 %d 个结果\n", m_nTotalResultsDrained.load() - startDrained);
// 第2步等结果全部保存完毕m_Result_list 排空)
printf("[流控-2] 等待结果保存完毕、内存释放...\n");
waitedMs = 0;
while (waitedMs < maxWaitMs)
{
bool queueEmpty;
{
std::lock_guard<std::mutex> lk(mutex_Result_list);
queueEmpty = m_Result_list.empty();
}
if (queueEmpty)
{
// 再等一小会确保最后一批 I/O 完成
usleep(500000);
break;
}
usleep(100000);
waitedMs += 100;
if (waitedMs % 10000 == 0)
{
size_t sz;
{ std::lock_guard<std::mutex> lk(mutex_Result_list); sz = m_Result_list.size(); }
printf("[流控-2] 等待中... 结果队列剩余 %zu 个\n", sz);
}
}
printf("[流控] 产品 %s 完全处理完毕,内存已释放,继续下一个产品\n\n", product.product_id.c_str());
}
// 6. 打印统计(不清理线程,继续下一个产品) // 6. 打印统计(不清理线程,继续下一个产品)
PrintProductStatistics(product); PrintProductStatistics(product);
// getchar(); // getchar();

@ -799,7 +799,6 @@ public:
std::mutex m_checkNotifyMutex; // 通知队列锁 std::mutex m_checkNotifyMutex; // 通知队列锁
std::condition_variable m_checkNotifyCV; // 通知条件变量 std::condition_variable m_checkNotifyCV; // 通知条件变量
std::atomic<int> m_nCheckNotifiedCount{0}; // 已通知数量 std::atomic<int> m_nCheckNotifiedCount{0}; // 已通知数量
std::atomic<int> m_nTotalResultsDrained{0}; // ✅ 已被消费的检测结果总数
std::set<std::string> m_productIdList; // 产品ID列表 std::set<std::string> m_productIdList; // 产品ID列表
}; };

@ -245,5 +245,10 @@ int main(int argc, char *argv[])
signal(SIGINT, handler); signal(SIGINT, handler);
test.start(); test.start();
while (true)
{
usleep(10 * 1000);
}
return 0; return 0;
} }

Loading…
Cancel
Save