Compare commits

...

47 Commits

Author SHA1 Message Date
liusiyang e4436f7028 update 修改blod上限1000
3 days ago
liusiyang 38a9739b7d feat YX添加面积过滤YS
1 week ago
liusiyang 73193e70dd v1.3.5
2 weeks ago
liusiyang e5fb359e02 fix 使用参数配置BQ检测开关
2 weeks ago
liusiyang 857057166f fix -tag离线程序mask为空bug
3 weeks ago
liusiyang 9d3164ebcb v1.3.4
3 weeks ago
liusiyang 84da7c79cd feat AI_Mask合并BQ检测
3 weeks ago
liusiyang 085e06bb87 feat 离线程序添加-tag
3 weeks ago
liusiyang 530ba7b3bf update 整理标签存图路径
3 weeks ago
liusiyang a5bfe40bee update 标签检测存图添加参数配置
3 weeks ago
liusiyang 4092ade847 update 标签检测分块(v1.3.3)
3 weeks ago
liusiyang d3a93f9fbe fix 参数读取bug
3 weeks ago
liusiyang 6c5f6a9d55 fix 根据参数配置进行BQ检测(v1.3.2)
3 weeks ago
liusiyang 53878afe4f update 修改标签检测模型名,精简参数设置
3 weeks ago
liusiyang 0b420a8476 v1.3.0
4 weeks ago
liusiyang c1b8cda63e update 批量跑同步执行,避免内存溢出
4 weeks ago
liusiyang 8274481bd6 update 日志文件分小时存储
4 weeks ago
liusiyang 61bd08fdf6 update 改为全部日志存储
4 weeks ago
liusiyang 548fa6f472 v1.2.9
4 weeks ago
liusiyang 5b8e4b7999 feat AD_YX添加HJ计算
4 weeks ago
liusiyang c1c6115c8a fix Detect可能越界崩溃
4 weeks ago
liusiyang 0dfbca8934 feat 添加AI_defect_Tag检测模型
1 month ago
liusiyang 768a227910 feat 初步添加BQ模型检测
1 month ago
liusiyang eb2cf825ce feat 开放标签扩/缩参数
1 month ago
liusiyang 8610481adb fix 异物范围过滤
1 month ago
liusiyang 63385495a1 feat LD新增检测(v1.2.7)
1 month ago
liusiyang 2f5f0e1589 update 更改线的二次判断,异物添加范围
1 month ago
liusiyang 9996b5a228 feat 开放暗点同位置判断IOU(v1.2.6)
1 month ago
liusiyang 49390e31bb fix 分类输入图片resize(v1.2.5)
1 month ago
liusiyang a9f6d659bd fix 删除重复定义
2 months ago
liusiyang f3ebf08fd6 Merge branch 'dev_lsy' of https://gitea.aidlux.getcharzp.cn/liusiyang/BOE_FOG_DETECT into dev_lsy
2 months ago
liusiyang 74f604ca65 update ngimg日志存储添加日期
2 months ago
liusiyang 8c5bcd7c9f feat density计算
2 months ago
liusiyang 4c36c7534c update 标签外扩5pix
2 months ago
liusiyang aaac47868f Revert "update 云平台改为单显卡" fog使用双显卡
2 months ago
liusiyang e47a221978 update 云平台改为单显卡
2 months ago
liusiyang c321a118d5 update 更新版本号
2 months ago
liusiyang eba708f32a fix 3s暗点漏检
2 months ago
liusiyang b535bc481e fix 异物漏检
2 months ago
liusiyang 8728bbdb68 update 标签外扩2pix
2 months ago
liusiyang 29086815bc fix 同位置3s暗点报出
2 months ago
liusiyang 036d19bbe6 Merge branch 'dev_lsy' of https://gitea.aidlux.getcharzp.cn/liusiyang/BOE_FOG_DETECT into dev_lsy
2 months ago
liusiyang 0857847444 fix 更改灰阶计算
2 months ago
liusiyang c1f4a2b451 update 同步cell参数延迟更改
2 months ago
liusiyang 0afe6c80a6 fix LD漏检
2 months ago
liusiyang 18a1394759 feat 添加RGB-HGRAY检测
2 months ago
liusiyang 546ce62fe6 fix AI_Time限制绘图
2 months ago

@ -174,7 +174,8 @@ public:
std::shared_ptr<AIModel_Base> AI_defect_zf; // L127 L255
std::shared_ptr<AIModel_Base> AI_defect_bq; // L127 L255
std::shared_ptr<AIModel_Base> AI_defect_bq;
std::shared_ptr<AIModel_Base> AI_defect_Tag;
std::shared_ptr<AIModel_Base> AI_defect_127Cell; // L127 L255

@ -143,7 +143,7 @@ int AIFactory::InitALLAIModle(GPU_Config gupconfig)
boe_config.inputType = AIModel_Base::Input_CHW;
AI_defect_zf->Init(boe_config);
}
// 标签 检测
// 标签 定位
if (!AI_defect_bq)
{
AI_defect_bq = AIModel_Base::GetInstance();
@ -154,6 +154,17 @@ int AIFactory::InitALLAIModle(GPU_Config gupconfig)
boe_config.inputType = AIModel_Base::Input_CHW;
AI_defect_bq->Init(boe_config);
}
// 标签 检测
if (!AI_defect_Tag)
{
AI_defect_Tag = AIModel_Base::GetInstance();
AIModel_Base::AIModelRun_Config boe_config;
boe_config.gpuconfig.copy(gupconfig);
boe_config.strPath = "/home/aidlux/BOE/UseModel_FOG/defect_Tag.engine";
boe_config.strName = "tag";
boe_config.inputType = AIModel_Base::Input_CHW;
AI_defect_Tag->Init(boe_config);
}
// 字符 127cell
if (!AI_defect_127Cell)
{

@ -10,8 +10,8 @@ enum ERR_DOT_TYPE_ENUM
#define Value_ERR_TYPE_2 128
//-----------------------sxg added
#define _MAX_ERROR_SCAN_LINE_PER_ROW 300
#define _MAX_ERROR_DOT_BLOB 80
#define _MAX_ERROR_SCAN_LINE_PER_ROW 1000
#define _MAX_ERROR_DOT_BLOB 1000
#define _MAX_MACRO_COUNT 4
#define _MAX_ERR_CLASS ERR_TYPE_COUNT

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

@ -44,6 +44,7 @@ public:
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, 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 CalImgBrightness(cv::Mat imgRoi);

@ -173,6 +173,7 @@ public:
std::shared_ptr<Image_AI_Det_Result> qx_DetAIResult; // BLob 检测要用到的一些 参数 。
std::shared_ptr<Image_AI_Det_Result> cell127_DetAIResult; // 127 cell 检测要用到的一些 参数 。
std::shared_ptr<Image_AI_Det_Result> bq_DetAIResult; // BQ标签检测要用到的一些 参数 。
// 结果图片
cv::Mat resultImg;

@ -40,6 +40,7 @@ struct QX_ERROR_INFO_
float grayDis;
float fUpIou;
float density; // Blob- 密度
bool bIsStandardLD; // 是否通过LD标准判定跳过UP/DP的IOU检查
std::vector<std::string> detLogList; // 检测日志
std::shared_ptr<DetLog> detlog;
std::vector<int> detRegionidxList; // 对应检测区域的 idx.
@ -344,7 +345,11 @@ struct BQ_Result
{
int nresult = 1;
bool bShield_BQ = true; // 是否屏蔽标签
std::vector<cv::Rect> pBQ_roiList; // 标签的区域
bool bBQ_AI_Det = false; // 是否启用标签独立AI检测
bool bsaveAll = false; // 是否保存所有的检测结果
std::vector<cv::Rect> pBQ_roiList; // 标签的原始区域
std::vector<cv::Rect> pBQ_expandedRoiList; // 标签的扩展后区域用于AI检测
std::vector<cv::Mat> pBQ_cropImages; // 标签扩展区域图像
std::vector<cv::Point> BQ_centerPoint; // 标签的中心点位置
};
struct CameraBaseResult

@ -73,6 +73,9 @@ public:
// 获取检测库 状态信息 返回CHECK_THREAD_RUN_STATUS
int GetStatus();
// 计算blob的密度
int CalBlobDensity_QX();
// 更新参数 pconfig 参数指针nConfigType 需要更新的参数类型 返回0 成功 其他异常
int UpdateConfig(void *pconfig, int nConfigType);
@ -191,6 +194,12 @@ private:
// 获得 127cell blob
int GetBlob_127cell();
// 获得 BQ标签 blob
int GetBlob_BQ();
// BQ标签 AI 检测
int AI_Detect_BQ();
// 对AI mask图片进行 结果处理
int AIMaskDet();

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

@ -18,7 +18,7 @@
#include <unordered_map> // unordered_map
#define RESULT_VERSION 31
#define MAX_BLOB_NUM 200
#define MAX_BLOB_NUM 1000
// 输入模型图片尺寸
#define SRCIMG_WIDTH 14200

@ -123,7 +123,7 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared
return 7;
}
if (max_contour_index >= 0)
if (max_contour_index >= 0&& contours.size() > 0)
{
result_roi = boundingRect(contours[max_contour_index]);
}

@ -129,11 +129,11 @@ int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDet
m_pdetlog = pdetlog;
if (pDetConfig->ninstruct == 767)
{
// nRuntype = 1;
nRuntype = 1;
}
else if (pDetConfig->ninstruct == 768)
{
// nRuntype = 2;
nRuntype = 2;
}
bool bdege = false;

@ -25,6 +25,7 @@
#include <vector>
#include <mutex>
#include <algorithm>
#include <ctime>
static std::mutex g_ngImgSave_mutex;
static std::vector<std::future<void>> g_ngImgSave_futures;
@ -695,7 +696,13 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptr<I
{
long ts = CheckUtil::getcurTime();
m_pCheck_Result->cameraBaseResult->pBQ_Result = std::make_shared<BQ_Result>();
m_pCheck_Result->cameraBaseResult->pBQ_Result->bShield_BQ = m_AnalysisyConfig.commonCheckConfig.baseConfig.bShield_BQ;
ChannelCheckFunction *pChannelFuntion_BQ = GetChannelFuntion(L255->strChannel);
if (pChannelFuntion_BQ)
{
m_pCheck_Result->cameraBaseResult->pBQ_Result->bBQ_AI_Det = pChannelFuntion_BQ->function.f_Det_BQ.bBQ_AI_Det;
m_pCheck_Result->cameraBaseResult->pBQ_Result->bsaveAll = pChannelFuntion_BQ->function.f_Det_BQ.bsaveAll;
}
cv::Rect Det_CropRoi = m_pCheck_Result->cameraBaseResult->pEdgeDetResult->cutRoi;
@ -716,25 +723,36 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptr<I
return re;
}
// 如果要屏蔽标签
if (m_pCheck_Result->cameraBaseResult->pBQ_Result->bShield_BQ)
// 默认屏蔽标签
{
m_pdetlog->AddCheckstr(PrintLevel_2, "preDet_BQ", "shieldBQ is Open");
cv::Mat detImg_mask = m_pCheck_Result->cameraBaseResult->pEdgeDetResult->shieldMask;
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);
int BQ_expand = pChannelFuntion_BQ ? pChannelFuntion_BQ->function.f_Det_BQ.BQ_expand : 0;
boundingRect.x -= BQ_expand;
boundingRect.y -= BQ_expand;
boundingRect.width += 2 * BQ_expand;
boundingRect.height += 2 * BQ_expand;
boundingRect = boundingRect & cv::Rect(0, 0, detImg_mask.cols, detImg_mask.rows);
if (boundingRect.width > 0 && boundingRect.height > 0)
{
detImg_mask(boundingRect).setTo(255);
m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_expandedRoiList.push_back(boundingRect);
// 保存裁剪图像供独立BQ AI检测
if (pChannelFuntion_BQ && pChannelFuntion_BQ->function.f_Det_BQ.bBQ_AI_Det)
{
cv::Mat bqCrop = L255CutImg(boundingRect).clone();
m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_cropImages.push_back(bqCrop);
}
}
}
if (L255->result->in_shareImage->bDebugsaveImg)
{
cv::imwrite("sheildImg.png", m_pCheck_Result->cameraBaseResult->pEdgeDetResult->shieldMask);
}
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_2, "preDet_BQ", "shieldBQ is false");
}
std::shared_ptr<BQ_Result> pBQ_Result = m_pCheck_Result->cameraBaseResult->pBQ_Result; // BQ 检测结果
pBQ_Result->BQ_centerPoint.erase(pBQ_Result->BQ_centerPoint.begin(), pBQ_Result->BQ_centerPoint.end());
for (int i = 0; i < pBQ_Result->pBQ_roiList.size(); i++)
@ -1235,43 +1253,55 @@ int CameraCheckAnalysisy::ngImgSave() {
auto result_copy = m_pCheck_Result;
std::string save_path_root = "/home/aidlux/BOE/FOG/cloud/";
auto task = std::async(std::launch::async, [result_copy, save_path_root]() {
// 生成当天日期字符串和当前小时字符串,用于按天/小时组织存储目录
time_t now = time(nullptr);
struct tm tm_now;
localtime_r(&now, &tm_now);
char date_buf[16];
strftime(date_buf, sizeof(date_buf), "%Y-%m-%d", &tm_now);
std::string date_str(date_buf);
char hour_buf[4];
strftime(hour_buf, sizeof(hour_buf), "%H", &tm_now);
std::string hour_str(hour_buf);
auto task = std::async(std::launch::async, [result_copy, save_path_root, date_str, hour_str]() {
try {
if (!result_copy) return;
// ---------- 目录清理(加锁防止并发删除)----------
// 只保留最近 2 天的数据(今天 + 昨天),删除更早的日期目录
{
static std::mutex cleanup_mutex; // 静态锁,所有实例共享
std::lock_guard<std::mutex> lock(cleanup_mutex);
// 计算 1 天前的日期作为清理截止线(保留今天和昨天共 2 天)
time_t now_cleanup = time(nullptr);
time_t cutoff_time = now_cleanup - 1 * 24 * 3600;
struct tm tm_cutoff;
localtime_r(&cutoff_time, &tm_cutoff);
char cutoff_buf[16];
strftime(cutoff_buf, sizeof(cutoff_buf), "%Y-%m-%d", &tm_cutoff);
std::string cutoff_str(cutoff_buf);
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;
// 检查是否为日期格式目录 YYYY-MM-DD
if (name.length() == 10 && name[4] == '-' && name[7] == '-') {
// ISO 日期格式可按字典序直接比较
if (name < cutoff_str) {
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);
CheckUtil::DeleteDir(full_path);
}
}
}
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");
closedir(dir);
}
}
@ -1295,13 +1325,14 @@ int CameraCheckAnalysisy::ngImgSave() {
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()) {
// 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 + "/";
// 构建保存目录(使用净化后的组件,包含日期/小时子目录
std::string save_dir = save_path_root + date_str + "/" + hour_str + "/" + safe_product + "/" + safe_camera + "/";
if (CheckUtil::CreateDir(save_dir) != 0) {
cerr << ("Failed to create directory: " + save_dir);
continue;
@ -1316,7 +1347,7 @@ int CameraCheckAnalysisy::ngImgSave() {
// 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);
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) {

@ -457,6 +457,32 @@ int CheckUtil::CalHj(const cv::Mat &img, const cv::Mat &mask, const cv::Mat &bac
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)
{
// 计算交集区域

@ -327,6 +327,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
float hj = pParam->paramArr[j].hj;
float Len = pParam->paramArr[j].length;
float md = pParam->paramArr[j].density;
float area_max = pParam->paramArr[j].area_max;
Judge_Status = true;
@ -385,6 +386,19 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
BOOL_TO_STR(flen >= Len), flen, BOOL_TO_ThanLess(flen > Len), Len);
}
if( config_qx_type == CONFIG_QX_NAME_POL_Cell && area_max > 0)
{
if(detArea > area_max)
{
nerrortype = 0;
result = true;
bNG_Status = false;
bYS_Status = false;
}
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "PolCell_Area_Max", "%s -> %f %s %f ",
BOOL_TO_STR(detArea > area_max), detArea, BOOL_TO_ThanLess(detArea > area_max), area_max);
}
if (!result)
{
break;
@ -415,6 +429,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
Judge_Status = true;
checkFlage = ANALYSIS_TYPE_TF;
nerrortype = 1;
bNG_Status = true;
}
}
// 暗点 3S 分析 对 好品 或者 是 疑是的缺陷进行3S分析。S数量分析。 3S的暗点直接NG.
@ -424,7 +439,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
// pFuntion->function.f_AD_Check.analysis_s.bOpen &&
// pFuntion->function.f_AD_Check.analysis_s.NG_3s && bpreSucc)
if ((nerrortype == 0 || checkFlage != ANALYSIS_TYPE_TF) &&
config_qx_type == CONFIG_QX_NAME_AD && m_pbaseCheckFunction &&
config_qx_type == CONFIG_QX_NAME_AD && pFuntion != NULL && m_pbaseCheckFunction &&
m_pbaseCheckFunction->ad_check.bOpen &&
m_pbaseCheckFunction->ad_check.analysis_s.bOpen &&
m_pbaseCheckFunction->ad_check.analysis_s.NG_3s && bpreSucc)
@ -479,7 +494,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
{
// 目前为止判断是好品
if (!bNG_Status && pFuntion->function.f_Big_QX.bOpen)
if (!bNG_Status && pFuntion != NULL && pFuntion->function.f_Big_QX.bOpen)
{
Judge_Status = true;
bool berror = false;
@ -503,7 +518,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
}
// 总面积判断
if (!bNG_Status && pFuntion->function.f_Big_QX.bOpen)
if (!bNG_Status && pFuntion != NULL && pFuntion->function.f_Big_QX.bOpen)
{
if (nSumBLobNUm <= pFuntion->function.f_Big_QX.Sum_blob_Num)
{
@ -550,6 +565,17 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " big qx ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str());
}
// 对于 AD_YX 类型,面积小于设定值的 降级为NoJudge
if (config_qx_type == CONFIG_QX_NAME_AD_YX && bYS_Status && pFuntion != NULL &&
pFuntion->function.f_YXDet.bOpen && JudgArea < pFuntion->function.f_YXDet.minArea)
{
bYS_Status = false;
QX_info->result = QX_RESULT_TYPE_OK;
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
resultType = QX_info->result_name;
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AD_YX downgrade", "area %f < %d, YS -> OK", JudgArea, pFuntion->function.f_YXDet.minArea);
}
if (bNG_Status)
{
m_CheckResult_shareP->nresult = 1;
@ -626,7 +652,9 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nresult = nqx_type;
}
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->qxImageResult.push_back(tem);
}
else
@ -637,7 +665,9 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nYS_result = nqx_type;
}
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->YS_ImageResult.push_back(tem);
}
@ -885,7 +915,9 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
{
m_CheckResult_shareP->nresult = nqx_type;
}
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
m_CheckResult_shareP->qxImageResult.push_back(tem);
}
}

@ -170,7 +170,7 @@ int ImgCheckAnalysisy::GetStatus()
std::string ImgCheckAnalysisy::GetVersion()
{
return std::string("BOE_1.2.0");
return std::string("BOE_1.3.5_" + std::string(__DATE__) + "_" + std::string(__TIME__));
}
std::string ImgCheckAnalysisy::GetErrorInfo()
@ -332,7 +332,7 @@ cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::M
// 计算 hj差异图像大于0的像素均值
// double hj = std::abs(fbk - fdet);
double hj = CheckUtil::CalHj(cimg, cmask, mean_bk.val[0]);
double hj = CheckUtil::CalHjWeighted(cimg, cmask, fbk, 2.0f);
int worb = 0;
if (fdet >= fbk)
@ -381,7 +381,7 @@ double ImgCheckAnalysisy::CalBlobHJ(cv::Mat &img, const cv::Mat &mask, cv::Rect
// 计算 hj差异图像大于0的像素均值
// double hj = std::abs(fbk - fdet);
double hj = CheckUtil::CalHj(cimg, cmask, fbk);
double hj = CheckUtil::CalHjWeighted(cimg, cmask, fbk, 2.0f);
static int kkk = 0;
unsigned char *pErrordata = (unsigned char *)cimg.data;
@ -518,8 +518,26 @@ int ImgCheckAnalysisy::CheckRun()
Edge_Det();
// BQ标签AI检测
{
long t_BQ_s = CheckUtil::getcurTime();
int recBQ = AI_Detect_BQ();
long t_BQ_e = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_0, "4、BQ Detect", "-------------------------BQ AI Detect--------%ld ms-------\n", t_BQ_e - t_BQ_s);
}
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->qx_DetAIResult->AI_MaskImg;
// 将BQ标签的AI mask合并到结果mask中
if (m_pImageAllResult->bq_DetAIResult && !m_pImageAllResult->bq_DetAIResult->AI_MaskImg.empty())
{
cv::Mat &bqMask = m_pImageAllResult->bq_DetAIResult->AI_MaskImg;
if (bqMask.size() == m_CheckResult_shareP->resultMaskImg.size())
{
cv::bitwise_or(m_CheckResult_shareP->resultMaskImg, bqMask, m_CheckResult_shareP->resultMaskImg);
}
}
// cv::imwrite("dddddddd.png", m_pImageAllResult->qx_DetAIResult->AI_MaskImg);
// if (!m_pImageAllResult->qx_DetAIResult->AI_MaskImg.empty())
// {
@ -589,6 +607,7 @@ int ImgCheckAnalysisy::SetNewConfig()
m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0);
GetParamidx();
UpdateImgageScale();
UPdateLDConfig();
if (true)
{
printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str());
@ -732,6 +751,11 @@ int ImgCheckAnalysisy::CalBlob_Other()
}
cv::Mat maskImg = pDetAIResult->AI_MaskImg;
if (maskImg.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "CalBlob_Other", "AI_MaskImg is empty for qx_type=%d, skip blob %d", config_qx_type, i);
continue;
}
// 精确计算长度
float re_len = Cal_QXLen(maskImg(roi), config_qx_type, fs_x, fs_y);
@ -1068,6 +1092,11 @@ int ImgCheckAnalysisy::CalBLobMean_GrayDis()
}
cv::Mat maskImg = pDetAIResult->AI_MaskImg;
if (maskImg.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "CalBLobMean_GrayDis", "AI_MaskImg is empty for qx_type=%d, skip blob %d", config_qx_type, i);
continue;
}
CalBlobHJ(m_pImageAllResult->detImg, maskImg, det_roi, roi);
@ -1448,6 +1477,9 @@ int ImgCheckAnalysisy::GetCheckResultBLob()
BLobToDetResult();
// 计算缺陷密度
CalBlobDensity_QX();
return 0;
}
@ -1691,17 +1723,19 @@ int ImgCheckAnalysisy::GetALLBlob()
re = GetBlob_QX();
long t4 = CheckUtil::getcurTime();
re = GetBlob_127cell();
long t5 = CheckUtil::getcurTime();
re = GetBlob_BQ();
if (blobs.blobCount > 100)
if (blobs.blobCount > 1000)
{
blobs.blobCount = 100;
blobs.blobCount = 1000;
/* code */
}
long te = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_0, strBaseLog,
"---GetALLBlob End ;use time %ld ms yx %ld ms lack %ld ms qx %ld ms 127 %ld ms",
te - t1, t2 - t1, t3 - t2, t4 - t3, te - t4);
"---GetALLBlob End ;use time %ld ms yx %ld ms lack %ld ms qx %ld ms 127 %ld ms bq %ld ms",
te - t1, t2 - t1, t3 - t2, t4 - t3, t5 - t4, te - t5);
// getchar();
return 0;
@ -1757,6 +1791,10 @@ int ImgCheckAnalysisy::GetBLob_YX()
cv::findContours(erodedImage, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
int nresult = 0;
// 将 mask 一次性 resize 到 detImg 尺寸,避免循环内反复 resize
cv::Mat maskImg;
cv::resize(erodedImage, maskImg, cv::Size(m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows), 0, 0, cv::INTER_AREA);
for (size_t i = 0; i < contours.size(); ++i)
{
@ -1774,7 +1812,15 @@ int ImgCheckAnalysisy::GetBLob_YX()
roi.y *= fy_src;
roi.height *= fy_src;
float len = std::sqrt(roi.width * roi.width + roi.height * roi.height);
// 精确计算长度
float re_len = Cal_QXLen(maskImg(roi), config_qx_type, fx_src, fy_src);
cv::Scalar result = calc_blob_info_withstats(m_pImageAllResult->detImg, maskImg, roi);
double min_val, max_val;
cv::Point min_loc, max_loc;
cv::minMaxLoc(m_pImageAllResult->detImg(roi), &min_val, &max_val, &min_loc, &max_loc);
if (true)
{
@ -1784,12 +1830,12 @@ int ImgCheckAnalysisy::GetBLob_YX()
temerror.area = area;
temerror.JudgArea = judgeArea;
temerror.JudgArea_second = judgeArea;
temerror.energy = area * fx_src * fy_src;
temerror.flen = len;
temerror.energy = result[1];
temerror.flen = re_len;
temerror.nconfig_qx_type = config_qx_type;
temerror.qx_name = qx_name;
temerror.maxValue = 0;
temerror.grayDis = 0;
temerror.maxValue = max_val;
temerror.grayDis = result[2];
temerror.density = 0;
temerror.fUpIou = 0;
@ -2139,6 +2185,295 @@ int ImgCheckAnalysisy::GetBlob_127cell()
return 0;
}
// BQAI检测
int ImgCheckAnalysisy::AI_Detect_BQ()
{
std::string strBaseLog = "AI_Detect_BQ";
// 检查BQ标签AI检测是否启用
if (!m_pImageAllResult->cameraBaseResult->pBQ_Result)
{
return 0;
}
if (!m_pFuntion->function.f_Det_BQ.bBQ_AI_Det)
{
return 0;
}
int bqNum = static_cast<int>(m_pImageAllResult->cameraBaseResult->pBQ_Result->pBQ_cropImages.size());
if (bqNum <= 0)
{
return 0;
}
m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog, "============= Start, BQ num = %d", bqNum);
long ts = CheckUtil::getcurTime();
std::string BQ_save_path = "/home/aidlux/BOE/FOG/BQ_AI_Det/"+ m_pImageAllResult->productBaseResult->strproductName + "/";
CheckUtil::CreateDir(BQ_save_path);
// 初始化BQ AI检测结果
m_pImageAllResult->bq_DetAIResult = std::make_shared<ImageAllResult::Image_AI_Det_Result>();
std::shared_ptr<ImageAllResult::Image_AI_Det_Result> pDetAIResult = m_pImageAllResult->bq_DetAIResult;
// 使用BQ AI
std::shared_ptr<AIModel_Base> pAI_Model = AI_Factory->AI_defect_Tag;
int AIInputImg_width = pAI_Model->input_0.width;
int AIInputImg_height = pAI_Model->input_0.height;
int AIOutputImg_width = pAI_Model->output_0.width;
int AIOutputImg_height = pAI_Model->output_0.height;
// 是否需要 resize到输入图大小进行后续处理
bool bResizeToSrc = false;
if (AIOutputImg_width != AIInputImg_width || AIOutputImg_height != AIInputImg_height)
{
bResizeToSrc = true;
}
cv::Size src_sz;
src_sz.width = AIInputImg_width;
src_sz.height = AIInputImg_height;
// 创建全图大小的AI mask与主检测detImg同尺寸
cv::Mat AI_detImage = m_pImageAllResult->AI_detImg;
pDetAIResult->AI_MaskImg = cv::Mat::zeros(AI_detImage.size(), CV_8UC1);
cv::Mat AIresultMask = pDetAIResult->AI_MaskImg;
// 为每个BQ区域生成小ROI列表仿照AI_Detect_QX的裁剪小块方式
std::vector<cv::Rect> BQ_SmallRoiList;
for (int i = 0; i < bqNum; i++)
{
cv::Rect bqRoi = m_pImageAllResult->cameraBaseResult->pBQ_Result->pBQ_expandedRoiList.at(i);
cv::Rect validRoi = bqRoi & cv::Rect(0, 0, AI_detImage.cols, AI_detImage.rows);
if (validRoi.width <= 0 || validRoi.height <= 0) continue;
// 如果BQ区域大于等于模型输入尺寸切分成小块
if (validRoi.width >= AIInputImg_width && validRoi.height >= AIInputImg_height)
{
std::vector<cv::Rect> smallList;
int re = CheckUtil::cutSmallImg(AI_detImage, smallList, validRoi, AIInputImg_width, AIInputImg_height, 0, 0);
if (re == 0)
{
for (const auto& roi : smallList)
{
BQ_SmallRoiList.push_back(roi);
}
}
}
else
{
// BQ区域小于模型输入尺寸以BQ区域中心创建模型输入大小的ROI
int cx = validRoi.x + validRoi.width / 2;
int cy = validRoi.y + validRoi.height / 2;
cv::Rect newRoi;
newRoi.x = cx - AIInputImg_width / 2;
newRoi.y = cy - AIInputImg_height / 2;
newRoi.width = AIInputImg_width;
newRoi.height = AIInputImg_height;
// 裁剪到图像边界
if (newRoi.x < 0) newRoi.x = 0;
if (newRoi.y < 0) newRoi.y = 0;
if (newRoi.x + newRoi.width > AI_detImage.cols) newRoi.x = AI_detImage.cols - newRoi.width;
if (newRoi.y + newRoi.height > AI_detImage.rows) newRoi.y = AI_detImage.rows - newRoi.height;
if (newRoi.x < 0) { newRoi.x = 0; newRoi.width = AI_detImage.cols; }
if (newRoi.y < 0) { newRoi.y = 0; newRoi.height = AI_detImage.rows; }
BQ_SmallRoiList.push_back(newRoi);
}
}
const int totalTasks = BQ_SmallRoiList.size();
if (totalTasks <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "no valid small roi for BQ");
return 0;
}
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "BQ small roi num = %d", totalTasks);
// 调试存图:原图 + BQ小ROI框
if (m_pFuntion->function.f_Det_BQ.bsaveAll)
{
cv::Mat debugImg;
if (AI_detImage.channels() == 1)
{
cv::cvtColor(AI_detImage, debugImg, cv::COLOR_GRAY2BGR);
}
else
{
debugImg = AI_detImage.clone();
}
for (size_t i = 0; i < BQ_SmallRoiList.size(); i++)
{
cv::rectangle(debugImg, BQ_SmallRoiList.at(i), cv::Scalar(0, 0, 255), 2);
}
cv::imwrite(BQ_save_path + m_strCurDetCamChannel + "_BQ_original_with_rois.png", debugImg);
}
int submitted = 0;
int completed = 0;
long t2 = CheckUtil::getcurTime();
while (completed < totalTasks)
{
// 提交任务
if (submitted < totalTasks && runner->GetProcessingCount() < 10)
{
std::shared_ptr<AIMulThreadRunBase::AITask> task = std::make_shared<AIMulThreadRunBase::AITask>();
task->id = submitted;
task->roi = BQ_SmallRoiList.at(submitted);
task->input = AI_detImage(task->roi).clone();
task->output = std::make_shared<cv::Mat>();
task->engine = pAI_Model;
// 调试存图:保存每个小块
if (m_pFuntion->function.f_Det_BQ.bsaveAll)
{
cv::imwrite(BQ_save_path +m_strCurDetCamChannel + "_" + std::to_string(submitted) + "_BQ_crop_in.png", task->input);
}
runner->SubmitTask(task);
submitted++;
}
// 收集结果
std::shared_ptr<AIMulThreadRunBase::AITask> result;
if (runner->PopResult(result))
{
cv::Mat &outimg = *(result->output);
if (!outimg.empty())
{
// 调试存图保存模型原始输出mask
if (m_pFuntion->function.f_Det_BQ.bsaveAll)
{
cv::imwrite(BQ_save_path + m_strCurDetCamChannel+ "_" + std::to_string(result->id) + "_BQ_crop_out.png", outimg);
}
cv::Mat AIresult;
if (bResizeToSrc)
{
cv::resize(outimg, AIresult, src_sz, 0, 0, 0);
}
else
{
AIresult = outimg;
}
cv::Rect srcsize_roi = result->roi;
AIresult.copyTo(AIresultMask(srcsize_roi), AIresult);
// 调试存图保存resize后的mask
if (m_pFuntion->function.f_Det_BQ.bsaveAll && bResizeToSrc)
{
cv::imwrite(BQ_save_path + m_strCurDetCamChannel + "_BQ_mask_resized_" + std::to_string(result->id) + ".png", AIresult);
}
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "BQ[%d] AI done, roi=[%d,%d,%d,%d]",
result->id, srcsize_roi.x, srcsize_roi.y, srcsize_roi.width, srcsize_roi.height);
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "BQ[%d] AI output empty", result->id);
}
completed++;
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
long te = CheckUtil::getcurTime();
float mean_AI = (te - t2) / totalTasks;
m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog, "============= End; AI Run Time: sum %ld pre %ld Run %ld mean One Small Img %f", te - ts, t2 - ts, te - t2, mean_AI);
// 调试存图
if (m_pFuntion->function.f_Det_BQ.bsaveAll)
{
cv::imwrite(BQ_save_path + m_strCurDetCamChannel + "_AI_BQ_mask.png", pDetAIResult->AI_MaskImg);
}
return 0;
}
int ImgCheckAnalysisy::GetBlob_BQ()
{
std::string strBaseLog = "GetBlob_BQ";
// 检查BQ标签AI检测是否启用
if (!m_pImageAllResult->cameraBaseResult->pBQ_Result)
{
return 0;
}
if (!m_pFuntion->function.f_Det_BQ.bBQ_AI_Det)
{
return 0;
}
if (!m_pImageAllResult->bq_DetAIResult)
{
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "bq_DetAIResult is null, skip");
return 0;
}
std::shared_ptr<ImageAllResult::Image_AI_Det_Result> pDetAIResult = m_pImageAllResult->bq_DetAIResult;
cv::Mat maskimg = pDetAIResult->AI_MaskImg;
if (maskimg.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "AI_MaskImg is empty, skip");
return 0;
}
long t1 = CheckUtil::getcurTime();
// 使用与主流程相同的blob提取方式GetBlobs_V3
// BQ检测的mask中缺陷像素值为非零值
ERROR_DOTS_BLOBS blobs_bq;
memset(&blobs_bq, 0x00, sizeof(ERROR_DOTS_BLOBS));
unsigned char *pGrayErrordata = (unsigned char *)maskimg.data;
int width = maskimg.cols;
int height = maskimg.rows;
int minArea = 10; // BQ标签区域最小缺陷面积阈值
// 使用逐像素扫描方式提取blobGetBlobs_V3对mask中的非零值进行blob提取
GetBlobs_V3(&blobs_bq, pGrayErrordata, width, height, minArea);
// 设置BQ blob的默认缺陷类型后续分类会重新确定类型
// 使用非cell类型确保进入AI_Classify_New分类流程
for (int i = 0; i < blobs_bq.blobCount; i++)
{
blobs_bq.blobTab[i].ErrType = CONFIG_QX_NAME_LD; // 以亮点作为初始类型,后续分类修正
}
// 将BQ的blob汇入主blob列表
PushBlob(&blobs, &blobs_bq);
long te = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog,
"BQ blob num = %d, merged to main blobs (total=%d), time=%ld ms",
blobs_bq.blobCount, blobs.blobCount, te - t1);
// 调试存图
if (DetImgInfo_shareP->bDebugsaveImg && blobs_bq.blobCount > 0)
{
cv::Mat tm;
cv::cvtColor(maskimg, tm, cv::COLOR_GRAY2RGB);
for (int i = 0; i < blobs_bq.blobCount; i++)
{
cv::Rect roi;
roi.x = blobs_bq.blobTab[i].minx;
roi.y = blobs_bq.blobTab[i].miny;
roi.width = blobs_bq.blobTab[i].maxx - blobs_bq.blobTab[i].minx + 1;
roi.height = blobs_bq.blobTab[i].maxy - blobs_bq.blobTab[i].miny + 1;
cv::rectangle(tm, roi, cv::Scalar(0, 0, 255), 2);
}
cv::imwrite(m_strCurDetCamChannel + "_BQ_blob.png", tm);
}
return 0;
}
int ImgCheckAnalysisy::AIMaskDet()
{
m_pdetlog->AddCheckstr(PrintLevel_0, "AIMaskDet", "=======start");
@ -2482,6 +2817,11 @@ int ImgCheckAnalysisy::AI_Detect_QX()
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use 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
{
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, strBaseLog, "=======model use base");
@ -3351,23 +3691,40 @@ int ImgCheckAnalysisy::BLobToDetResult()
}
}
bool bLD_Standard = false; // 是否通过LD标准判定跳过UP/DP的IOU检查
if (config_qx_type == CONFIG_QX_NAME_MTX ||
config_qx_type == CONFIG_QX_NAME_POL_Cell ||
config_qx_type == CONFIG_QX_NAME_Other ||
config_qx_type == CONFIG_QX_NAME_LD)
{
std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
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());
int dbresult = LDJudge(config_qx_type, roi, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, pQxlog);
int detre = 1;
int dbresult = -1;
if(m_pFuntion->function.f_LDConfig.bOpen && m_pFuntion->function.f_LDConfig.bUseLD_Standard)
{
if(blobs.blobTab[i].JudgArea >= m_pFuntion->function.f_LDConfig.fLD_Area &&
blobs.blobTab[i].grayDis >= m_pFuntion->function.f_LDConfig.fLD_HJ &&
blobs.blobTab[i].energy >= m_pFuntion->function.f_LDConfig.fLD_En &&
blobs.blobTab[i].len >= m_pFuntion->function.f_LDConfig.fLD_Len)
{
dbresult = 1;
bLD_Standard = true;
}
pQxlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "LD Analysis", "Area %0.2f > %0.2f , hj %0.2f > %0.2f , Energy %0.2f > %0.2f , len %0.2f > %0.2f",
blobs.blobTab[i].JudgArea, m_pFuntion->function.f_LDConfig.fLD_Area, blobs.blobTab[i].grayDis, m_pFuntion->function.f_LDConfig.fLD_HJ, blobs.blobTab[i].energy, m_pFuntion->function.f_LDConfig.fLD_En, blobs.blobTab[i].len, m_pFuntion->function.f_LDConfig.fLD_Len);
}
if(dbresult != 1)
{
dbresult = LDJudge(config_qx_type, roi, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, pQxlog);
}
//int detre = 1;
// 表示L0 和 DP 都有的 亮的
if (dbresult == 1)
{
config_qx_type = CONFIG_QX_NAME_LD;
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_False(detre), qx_name.c_str());
}
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " LD Judge ", "%s qx %s ", Re_TO_STR_Pass_1(dbresult), qx_name.c_str()); }
// 如果是chess 画面缺陷类型直接是chess异常。
if (m_pFuntion->function.f_AIQX.bAllToChess)
{
@ -3428,8 +3785,8 @@ int ImgCheckAnalysisy::BLobToDetResult()
QX_Stauts qx_status = QX_Stauts_Analysis;
// 和UP画面进行IOU判断
if (m_pFuntion->function.f_UseUpQX.bOpen)
// 和UP画面进行IOU判断 (通过亮点标准的缺陷跳过此检查)
if (!bLD_Standard && m_pFuntion->function.f_UseUpQX.bOpen)
{
if (fupS >= m_pFuntion->function.f_UseUpQX.fIOU)
{
@ -3441,6 +3798,10 @@ int ImgCheckAnalysisy::BLobToDetResult()
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Up Mask judge", "UseUpQX.bOpen = true ;fupS = %0.2f < %02f ", fupS, m_pFuntion->function.f_UseUpQX.fIOU);
}
}
else if (bLD_Standard)
{
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Up Mask judge", "bLD_Standard = true, skip UP/DP IOU check ;fupS = %0.2f ", fupS);
}
else
{
pQxlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Up Mask judge", "UseUpQX.bOpen = false ;fupS = %0.2f ", fupS);
@ -3450,7 +3811,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
bool ban = JudgeQXAnalysis(config_qx_type, pQxlog);
if (!ban)
{
std::string 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, "Judge QX", "qx function close, config_qx_type %s Not Det",
qx_name.c_str());
@ -3467,7 +3828,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
isMarksheildQX = Judge_MarkLine_QX(config_qx_type, roi, pQxlog);
if (isMarksheildQX)
{
std::string 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, "MarkLine_QX", "MarkLine_QX close, config_qx_type %s Not Det",
qx_name.c_str());
@ -3496,6 +3857,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
temerror.grayDis = blobs.blobTab[i].grayDis;
temerror.density = blobs.blobTab[i].density;
temerror.fUpIou = fupS;
temerror.bIsStandardLD = bLD_Standard;
temerror.whiteOrBlack = blobs.blobTab[i].whiteOrblack;
temerror.qx_status = qx_status;
@ -3738,11 +4100,13 @@ int ImgCheckAnalysisy::AI_Classify_New(const cv::Mat &src_Img, cv::Rect qx_roi,
if (3 != AI_detImage.channels())
{
cv::cvtColor(AI_detImage(task->roi), task->input, cv::COLOR_GRAY2BGR);
cv::Mat temsizeimg;
cv::resize(AI_detImage(task->roi), temsizeimg, sz);
cv::cvtColor(temsizeimg, task->input, cv::COLOR_GRAY2BGR);
}
else
{
task->input = AI_detImage(task->roi).clone();
cv::resize(AI_detImage(task->roi), task->input, sz);
}
task->engine = pAIDet;
@ -3756,6 +4120,12 @@ int ImgCheckAnalysisy::AI_Classify_New(const cv::Mat &src_Img, cv::Rect qx_roi,
if (runner->PopResult(result))
{
// if (true)
// {
// printf("result->cls_score %f\n",result->cls_score);
// std::string classpath = std::to_string(result->cls_label) + "_" + std::to_string(result->cls_score) + ".png";
// cv::imwrite(classpath, result->input);
// }
int cls_num = result->cls_label;
if (cls_num >= 0 && cls_num < maxcls)
{
@ -3884,6 +4254,7 @@ int ImgCheckAnalysisy::AI_Classify_New(const cv::Mat &src_Img, cv::Rect qx_roi,
if (true)
{
// 长宽比
bool bIsLine = false;
float flenr = 1;
int len = 0;
int widt = 0;
@ -3900,29 +4271,42 @@ int ImgCheckAnalysisy::AI_Classify_New(const cv::Mat &src_Img, cv::Rect qx_roi,
len = qx_roi.height;
}
// 长宽比过大,判断成
if (flenr > 18 &&
len > 70 &&
widt < 220 &&
fjustarea < 800)
{
// printf("\n\n\n\n\n\n\n\n\n--------- flenr %f len %d,widt %d,fjustarea %f\n", flenr,len,widt,fjustarea);
// getchar();
cls_num = AI_CLass_QX_NAME_line;
strclassName = "line";
}
// 长宽比过小,判断成
else if (flenr > 4 &&
len > 180 &&
widt < 220 &&
fjustarea < 800 &&
fjustarea > 20)
// // 长宽比过大,判断成
// if (flenr > 18 &&
// len > 70 &&
// widt < 220 &&
// fjustarea < 800)
// {
// // printf("\n\n\n\n\n\n\n\n\n--------- flenr %f len %d,widt %d,fjustarea %f\n", flenr,len,widt,fjustarea);
// // getchar();
// cls_num = AI_CLass_QX_NAME_line;
// strclassName = "line";
// bIsLine = true;
// }
// // 长宽比过小,判断成
// else if (flenr > 4 &&
// len > 180 &&
// widt < 220 &&
// fjustarea < 800 &&
// fjustarea > 20)
// {
// // printf("\n\n\n\n\n\n\n\n\n--------- flenr %f len %d,widt %d,fjustarea %f\n", flenr,len,widt,fjustarea);
// // getchar();
// cls_num = AI_CLass_QX_NAME_line;
// strclassName = "line";
// bIsLine = true;
// }
//长宽比满足,判断为线
if (flenr > 10)
{
// printf("\n\n\n\n\n\n\n\n\n--------- flenr %f len %d,widt %d,fjustarea %f\n", flenr,len,widt,fjustarea);
// getchar();
cls_num = AI_CLass_QX_NAME_line;
strclassName = "line";
bIsLine = true;
}
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Classify_line", "bIsLine %d, flenr %f len %d,widt %d,fjustarea %f", bIsLine, flenr,len,widt,fjustarea);
}
}
@ -4433,3 +4817,104 @@ bool ImgCheckAnalysisy::JudgeQXAnalysis(int nqx_configType, std::shared_ptr<DetL
return re;
}
int ImgCheckAnalysisy::CalBlobDensity_QX()
{
float fs_x = m_fImgage_Scale_X;
float fs_y = m_fImgage_Scale_Y;
double dis_T = m_pBasicConfig->density_R_mm;
if (dis_T <= 0 || dis_T > 99999)
{
dis_T = 5;
}
if (!m_pDetResult || !m_pDetResult->pQx_ErrorList || m_pDetResult->pQx_ErrorList->size() <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Density_QX", "pQx_ErrorList is empty, skip density calc");
return 0;
}
m_pdetlog->AddCheckstr(PrintLevel_1, "Density_QX", "Start: dis_T=%.1fmm qx_count=%zu", dis_T, m_pDetResult->pQx_ErrorList->size());
for (int i = 0; i < m_pDetResult->pQx_ErrorList->size(); i++)
{
m_pDetResult->pQx_ErrorList->at(i).density = 1;
if (m_pDetResult->pQx_ErrorList->at(i).nconfig_qx_type == CONFIG_QX_NAME_MTX ||
m_pDetResult->pQx_ErrorList->at(i).nconfig_qx_type == CONFIG_QX_NAME_POL_Cell ||
m_pDetResult->pQx_ErrorList->at(i).nconfig_qx_type == CONFIG_QX_NAME_LD ||
m_pDetResult->pQx_ErrorList->at(i).nconfig_qx_type == CONFIG_QX_NAME_AD)
{
/* code */
}
else
{
continue;
}
cv::Rect roi = m_pDetResult->pQx_ErrorList->at(i).roi;
cv::Point p;
p.x = roi.x + roi.width * 0.5;
p.y = roi.y + roi.height * 0.5;
int num = 1;
double sum_dis = 0;
for (int j = 0; j < m_pDetResult->pQx_ErrorList->size(); j++)
{
if (i == j)
{
continue;
}
if (m_pDetResult->pQx_ErrorList->at(j).nconfig_qx_type == CONFIG_QX_NAME_MTX ||
m_pDetResult->pQx_ErrorList->at(j).nconfig_qx_type == CONFIG_QX_NAME_POL_Cell ||
m_pDetResult->pQx_ErrorList->at(j).nconfig_qx_type == CONFIG_QX_NAME_LD ||
m_pDetResult->pQx_ErrorList->at(j).nconfig_qx_type == CONFIG_QX_NAME_AD)
{
/* code */
}
else
{
continue;
}
cv::Rect roi123 = m_pDetResult->pQx_ErrorList->at(j).roi;
cv::Point p123;
p123.x = roi123.x + roi123.width * 0.5;
p123.y = roi123.y + roi123.height * 0.5;
double dis_x = std::abs(p123.x - p.x) * fs_x;
double dis_y = std::abs(p123.y - p.y) * fs_y;
double dis = std::sqrt(dis_x * dis_x + dis_y * dis_y);
if (dis > dis_T)
{
continue;
}
num++;
sum_dis += dis;
}
float avdis = dis_T;
if (num > 1)
{
avdis = sum_dis / (num - 1);
}
float fScore = (dis_T - avdis) / dis_T;
double fD = num + fScore;
m_pDetResult->pQx_ErrorList->at(i).density = fD;
m_pdetlog->AddCheckstr(PrintLevel_2, "Density_QX", " idx=%d type=%d(%s) roi[%d,%d,%d,%d] near_num=%d avgDis=%.2f score=%.3f density=%.2f",
i,
m_pDetResult->pQx_ErrorList->at(i).nconfig_qx_type,
m_pDetResult->pQx_ErrorList->at(i).qx_name.c_str(),
roi.x, roi.y, roi.width, roi.height,
num, avdis, fScore, fD);
}
m_pdetlog->AddCheckstr(PrintLevel_1, "Density_QX", "End: processed %zu defects", m_pDetResult->pQx_ErrorList->size());
return 0;
}

@ -485,7 +485,7 @@ int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_cha
fmaxLen = pqxList->qxList.at(i).length;
}
// 长度超过阈值
if (pqxList->qxList.at(i).length > pconfig->len)
if (pconfig->len > 0 && pqxList->qxList.at(i).length > pconfig->len)
{
blenerror = true;
pqxList->qxList.at(i).nqx_type = QX_ERROR_TYPE_Len;
@ -593,7 +593,7 @@ int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_cha
{
int minidx = -1;
bool bdis = true;
bool bdis = (pconfig->dis > 0);
double remindis = 0;
// 对距离有要求
if (pconfig->dis > 0)
@ -612,6 +612,11 @@ int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_cha
allmindis = pqxList->qxList.at(i).tem_dis;
}
}
else
{
// 无邻近缺陷,距离检查自动通过
bdis = false;
}
remindis = pqxList->qxList.at(i).tem_dis;
}
@ -847,11 +852,20 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
int list_idx = -1;
int channel_s = 0;
int roi_expand = (round)(pAd_checkParma->analysis_iou.AD_Expand);
bool bnew_add = true;
for (int idx = 0; idx < AD_list.size(); idx++)
{
cv::Rect tem_roi(AD_list.at(idx).roi.x-roi_expand, AD_list.at(idx).roi.y-roi_expand, AD_list.at(idx).roi.width+2*roi_expand, AD_list.at(idx).roi.height+2*roi_expand);
cv::Rect tem_roi2(roi.x-roi_expand, roi.y-roi_expand, roi.width+2*roi_expand, roi.height+2*roi_expand);
float fiou = CheckUtil::CalIoU(AD_list.at(idx).roi, roi);
if (fiou > 0.15)
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "CalIoU",
"roi1 %s roi2 %s expand %d iou %f",
CheckUtil::GetRectString(AD_list.at(idx).roi).c_str(),
CheckUtil::GetRectString(roi).c_str(),
roi_expand, fiou);
if (fiou > pAd_checkParma->analysis_iou.AD_IOU)
{
list_idx = idx;
}
@ -972,6 +986,7 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
}
A_2S_num += AD_list.at(ad_i).num_2s;
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",
ad_i, AD_list.at(ad_i).GetInfo().c_str());
}
@ -1028,7 +1043,7 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
}
else
{
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result NG 3S %d < 1",
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result OK 3S %d < 1",
pQXChannelList->channel_name.c_str(), A_3S_num);
}
}

@ -466,6 +466,7 @@ struct BasicConfig
height_max = 999999;
bDrawShieldRoi = false;
bShield_ZF = false;
bShield_BQ = true;
bDrawPreRoi = false;
fUP_IOU = 0.9;
bCal_ImageScale = false;
@ -794,6 +795,7 @@ struct Function_YXDet
{
bool bOpen; // 是否开启
std::string strModle;
int minArea;
Function_YXDet()
{
Init();
@ -802,20 +804,22 @@ struct Function_YXDet
{
bOpen = false;
strModle = "";
minArea = 0;
}
void copy(Function_YXDet tem)
{
this->bOpen = tem.bOpen;
this->strModle = tem.strModle;
this->minArea = tem.minArea;
}
void print(std::string str)
{
// printf("%s>>bOpen %d strModle %s\n", str.c_str(), bOpen, strModle.c_str());
// printf("%s>>bOpen %d strModle %s minArea %d\n", str.c_str(), bOpen, strModle.c_str(), minArea);
}
std::string GetInfo(std::string str)
{
char buffer[64];
sprintf(buffer, "%s>>bOpen %d strModle %s\n", str.c_str(), bOpen, strModle.c_str());
sprintf(buffer, "%s>>bOpen %d strModle %s minArea %d\n", str.c_str(), bOpen, strModle.c_str(), minArea);
std::string str123 = buffer;
return str123;
}
@ -869,6 +873,12 @@ struct Function_AI_LD
bool bWTBLD; // 是否是WTB亮点
bool bHSLD; // 黑闪类型的亮点
float fDP_IOU; // DP的IOU
bool bUseLD_Standard; // 是否使用亮点标准化参数
float fLD_Area; // 亮点面积
float fLD_En; // 亮点的能量
float fLD_HJ; // 亮点灰阶
float fLD_Len; // 亮点长度
Function_AI_LD()
{
Init();
@ -880,6 +890,11 @@ struct Function_AI_LD
bWTBLD = false;
bHSLD = false;
fDP_IOU = 0.1;
fLD_Area = -1;
fLD_En = -1;
fLD_HJ = -1;
fLD_Len = -1;
bUseLD_Standard = false;
}
void copy(Function_AI_LD tem)
{
@ -888,6 +903,11 @@ struct Function_AI_LD
this->bWTBLD = tem.bWTBLD;
this->bHSLD = tem.bHSLD;
this->fDP_IOU = tem.fDP_IOU;
this->fLD_Area = tem.fLD_Area;
this->fLD_En = tem.fLD_En;
this->fLD_HJ = tem.fLD_HJ;
this->fLD_Len = tem.fLD_Len;
this->bUseLD_Standard = tem.bUseLD_Standard;
}
void print(std::string str)
{
@ -1519,6 +1539,34 @@ struct AD_Analysisy_S
return str123;
}
};
// 暗点同位置判断(IOU)
struct AD_Analysisy_IOU
{
float AD_IOU; // IOU 阈值
float AD_Expand; // 扩张阈值
AD_Analysisy_IOU()
{
Init();
}
void Init()
{
AD_IOU = 0.15f;
AD_Expand = 0.0f;
}
void copy(AD_Analysisy_IOU tem)
{
this->AD_IOU = tem.AD_IOU;
this->AD_Expand = tem.AD_Expand;
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s:AD_IOU %f AD_Expand %f;", str.c_str(),
AD_IOU, AD_Expand);
std::string str123 = buffer;
return str123;
}
};
// 暗点检测功能
struct Function_AD_Check
{
@ -1530,6 +1578,7 @@ struct Function_AD_Check
AD_Analysisy_Num analysis_num; // 数量分析
AD_Analysisy_Dis analysis_dis; // 距离分析
AD_Analysisy_S analysis_s; // s 标准分析
AD_Analysisy_IOU analysis_iou; // IOU 分析
Function_AD_Check()
{
@ -1544,6 +1593,7 @@ struct Function_AD_Check
analysis_num.Init();
analysis_dis.Init();
analysis_s.Init();
analysis_iou.Init();
}
void copy(Function_AD_Check tem)
@ -1555,16 +1605,18 @@ struct Function_AD_Check
this->analysis_num.copy(tem.analysis_num);
this->analysis_dis.copy(tem.analysis_dis);
this->analysis_s.copy(tem.analysis_s);
this->analysis_iou.copy(tem.analysis_iou);
}
void print(std::string str)
{
printf("%s>>bOpen %d %s %s %s %s %s %s\n", str.c_str(),
printf("%s>>bOpen %d %s %s %s %s %s %s %s\n", str.c_str(),
bOpen, S_standard_3s.GetInfo("3S").c_str(),
S_standard_2s.GetInfo("2S").c_str(),
S_standard_1s.GetInfo("1S").c_str(),
analysis_num.GetInfo("analysis_num").c_str(),
analysis_dis.GetInfo("analysis_dis").c_str(),
analysis_s.GetInfo("analysis_s").c_str());
analysis_s.GetInfo("analysis_s").c_str(),
analysis_iou.GetInfo("analysis_iou").c_str());
}
std::string GetInfo(std::string str)
{
@ -1577,6 +1629,7 @@ struct Function_AD_Check
str123 += analysis_num.GetInfo("analysis_num");
str123 += analysis_dis.GetInfo("analysis_dis");
str123 += analysis_s.GetInfo("analysis_s");
str123 += analysis_iou.GetInfo("analysis_iou");
return str123;
}
@ -1670,6 +1723,44 @@ struct Function_Edge_Det
return str123;
}
};
struct Function_Det_BQ
{
bool bBQ_AI_Det; // 是否启用标签独立AI检测
int BQ_expand;
bool bsaveAll;
Function_Det_BQ()
{
Init();
}
void Init()
{
BQ_expand = 0;
bBQ_AI_Det = false;
bsaveAll = false;
}
void copy(Function_Det_BQ tem)
{
this->BQ_expand = tem.BQ_expand;
this->bBQ_AI_Det = tem.bBQ_AI_Det;
this->bsaveAll = tem.bsaveAll;
}
void print(std::string str)
{
printf("%d BQ_expand %d bBQ_AI_Det %d bsaveAll %d\n", str.c_str(),
BQ_expand, bBQ_AI_Det, bsaveAll);
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%d BQ_expand %d bBQ_AI_Det %d bsaveAll %d\n", str.c_str(),
BQ_expand, bBQ_AI_Det, bsaveAll);
std::string str123 = buffer;
return str123;
}
};
// 检测功能
struct CheckFunction
{
@ -1689,6 +1780,7 @@ struct CheckFunction
Function_AD_Check f_AD_Check; // 暗点的检测功能
Function_POL_Check f_POL_Check; // 异物的检测功能
Function_Edge_Det f_dege_Det;
Function_Det_BQ f_Det_BQ;
CheckFunction()
{
Init();
@ -1711,6 +1803,7 @@ struct CheckFunction
f_AD_Check.Init();
f_POL_Check.Init();
f_dege_Det.Init();
f_Det_BQ.Init();
}
void copy(CheckFunction tem)
{
@ -1731,6 +1824,7 @@ struct CheckFunction
this->f_AD_Check.copy(tem.f_AD_Check);
this->f_POL_Check.copy(tem.f_POL_Check);
this->f_dege_Det.copy(tem.f_dege_Det);
this->f_Det_BQ.copy(tem.f_Det_BQ);
}
void print(std::string str)
{
@ -1751,6 +1845,7 @@ struct CheckFunction
f_AD_Check.print("f_AD_Check");
f_POL_Check.print("f_POL_Check");
f_dege_Det.print("f_dege_Det");
f_Det_BQ.print("f_Det_BQ");
}
std::string GetInfo(std::string str)
{
@ -1772,6 +1867,7 @@ struct CheckFunction
str123 += f_AD_Check.GetInfo("f_AD_Check");
str123 += f_POL_Check.GetInfo("f_POL_Check");
str123 += f_dege_Det.GetInfo("f_dege_Det");
str123 += f_Det_BQ.GetInfo("f_Det_BQ");
return str123;
}
};
@ -2155,6 +2251,7 @@ struct Base_Function_AD_Check
AD_Analysisy_Num analysis_num; // 数量分析
AD_Analysisy_Dis analysis_dis; // 距离分析
AD_Analysisy_S analysis_s; // s 标准分析
AD_Analysisy_IOU analysis_iou; // IOU 分析
Base_Function_AD_Check()
{
@ -2169,6 +2266,7 @@ struct Base_Function_AD_Check
analysis_num.Init();
analysis_dis.Init();
analysis_s.Init();
analysis_iou.Init();
}
void copy(Base_Function_AD_Check tem)
@ -2180,6 +2278,7 @@ struct Base_Function_AD_Check
this->analysis_num.copy(tem.analysis_num);
this->analysis_dis.copy(tem.analysis_dis);
this->analysis_s.copy(tem.analysis_s);
this->analysis_iou.copy(tem.analysis_iou);
}
void print(std::string str)
{
@ -2189,7 +2288,8 @@ struct Base_Function_AD_Check
S_standard_1s.GetInfo("1S").c_str(),
analysis_num.GetInfo("analysis_num").c_str(),
analysis_dis.GetInfo("analysis_dis").c_str(),
analysis_s.GetInfo("analysis_s").c_str());
analysis_s.GetInfo("analysis_s").c_str(),
analysis_iou.GetInfo("analysis_iou").c_str());
}
std::string GetInfo(std::string str)
{
@ -2202,6 +2302,7 @@ struct Base_Function_AD_Check
str123 += analysis_num.GetInfo("analysis_num");
str123 += analysis_dis.GetInfo("analysis_dis");
str123 += analysis_s.GetInfo("analysis_s");
str123 += analysis_iou.GetInfo("analysis_iou");
return str123;
}

@ -64,6 +64,8 @@ public:
int GetConfig(ALLChannelCheckFunction &config);
int GetFunction(Json::Value value, CheckFunction &function);
static bool s_bDetTag; // 标签检测模式标志,由命令行 -tag 参数控制
private:
ALLChannelCheckFunction _config;
};

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

@ -22,62 +22,6 @@ ConfigManager::~ConfigManager()
{
}
std::vector <std::string> QX_Result_Names =
{
"OK",
"AD_YX",
"X_Line",
"Y_Line",
"fangge",
"Rubbing_Mura",
"Broken_line",
"ZARA",
"MTX",
"POL_Cell",
"Bright_Point",
"Dark_Point",
"BLack_Point",
"White_Point",
"Scratch",
"Weak_Bright_Mura",
"No_Label",
"Bright_Mura_Exe",
"Sweak_Line_Dark",
"STEAM_POCKET",
"Dirty",
"other",
"Cell_W",
"Cell_B",
"LackPol"};
std::vector <std::string> QX_Result_Code =
{
"P1153",
"P6873",
"P3351",
"P3452",
"P3453",
"P1550",
"P3379",
"P1153",
"P1164",
"P1101",
"P1112",
"P1111",
"P1104",
"P1103",
"P1557",
"P1654",
"P2833",
"P1549",
"P1204",
"P2534",
"P2534",
"P1101",
"P1103",
"P1104",
"P8001",
};
int ReadFlawCodeConfig(std::string json_path)
{
m_FlawCodeList.erase(m_FlawCodeList.begin(), m_FlawCodeList.end());
@ -203,6 +147,7 @@ int ConfigManager::UpdateConfig()
if (!std::filesystem::exists(strConfigPath)) {
strConfigPath = m_strConfigRootPath + "/param.json";
}
printf("read param %s\n", strConfigPath.c_str());
std::shared_ptr<ConfigBase> temConfig = ConfigBase::GetInstance();
re = LoadParamConfig(temConfig, strConfigPath);
if (re != 0)
@ -218,8 +163,13 @@ int ConfigManager::UpdateConfig()
printf("Error >>>> camear Name is empty \n");
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;
}
}
// getchar();

@ -1,5 +1,8 @@
#include "JsonConfig.h"
// 静态成员定义:标签检测模式标志
bool ChannelFuntonConfigJson::s_bDetTag = false;
Json::Value CommonParamJson::toJsonValue()
{
return Json::Value();
@ -32,7 +35,7 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value rootvalue;
std::string err;
// std::cout << strJson << std::endl;
std::cout << strJson << std::endl;
auto nSize = strJson.size();
if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err))
{
@ -49,6 +52,7 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
{
_config.baseConfig.strConfigVersion = "NULL";
}
_config.baseConfig.image_widht = value["image_widht"].asInt();
_config.baseConfig.Image_height = value["Image_height"].asInt();
_config.baseConfig.bDrawShieldRoi = value["bDrawShieldRoi"].asBool();
@ -530,6 +534,10 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_YXDet.strModle = value_f["form"]["YX_Det"]["AI_Model"].asString();
}
if (value_f["form"]["YX_Det"]["minArea"])
{
function.f_YXDet.minArea = value_f["form"]["YX_Det"]["minArea"].asInt();
}
// function.f_UseUpQX.print("UpQX");
}
@ -559,6 +567,27 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_LDConfig.fDP_IOU = value_f["form"]["LD_Det"]["DP_IOU"].asFloat();
}
if (value_f["form"]["LD_Standard"]["LD_Area"])
{
function.f_LDConfig.fLD_Area = value_f["form"]["LD_Standard"]["LD_Area"].asFloat();
}
if (value_f["form"]["LD_Standard"]["LD_En"])
{
function.f_LDConfig.fLD_En = value_f["form"]["LD_Standard"]["LD_En"].asFloat();
}
if (value_f["form"]["LD_Standard"]["LD_HJ"])
{
function.f_LDConfig.fLD_HJ = value_f["form"]["LD_Standard"]["LD_HJ"].asFloat();
}
if (value_f["form"]["LD_Standard"]["LD_Len"])
{
function.f_LDConfig.fLD_Len = value_f["form"]["LD_Standard"]["LD_Len"].asFloat();
}
if (value_f["form"]["LD_Standard"]["bUseLD_Standard"])
{
function.f_LDConfig.bUseLD_Standard = value_f["form"]["LD_Standard"]["bUseLD_Standard"].asBool();
}
}
else
{
@ -969,7 +998,6 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_AD_Check.S_standard_3s.len = value_f["form"]["AD_S_Standard"]["AD_3S_Len"].asFloat();
}
if (value_f["form"]["AD_S_Standard"]["AD_2S_Area"])
{
function.f_AD_Check.S_standard_2s.area = value_f["form"]["AD_S_Standard"]["AD_2S_Area"].asFloat();
@ -978,7 +1006,6 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_AD_Check.S_standard_2s.len = value_f["form"]["AD_S_Standard"]["AD_2S_Len"].asFloat();
}
if (value_f["form"]["AD_S_Standard"]["AD_1S_Area"])
{
function.f_AD_Check.S_standard_1s.area = value_f["form"]["AD_S_Standard"]["AD_1S_Area"].asFloat();
@ -1010,7 +1037,6 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_AD_Check.analysis_s.bOpen = value_f["form"]["AD_Check_S"]["Open"].asBool();
}
if (value_f["form"]["AD_Check_S"]["S_value"])
{
function.f_AD_Check.analysis_s.Check_s_Value = value_f["form"]["AD_Check_S"]["S_value"].asInt();
@ -1023,6 +1049,15 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
{
function.f_AD_Check.analysis_s.Check_s_Num = value_f["form"]["AD_Check_S"]["Num"].asInt();
}
if (value_f["form"]["AD_Check_IOU"]["AD_IOU"])
{
function.f_AD_Check.analysis_iou.AD_IOU = value_f["form"]["AD_Check_IOU"]["AD_IOU"].asFloat();
}
if (value_f["form"]["AD_Check_IOU"]["AD_Expand"])
{
function.f_AD_Check.analysis_iou.AD_Expand = value_f["form"]["AD_Check_IOU"]["AD_Expand"].asFloat();
}
}
else
{
@ -1083,6 +1118,31 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
// function.f_markDet.print("UpQX");
// getchar();
}
// 标签配置参数
if ("Det_BQ" == strCode)
{
auto value_f = value[i];
// std::cout << value_f << std::endl;
// getchar();
function.f_Det_BQ.bBQ_AI_Det = value_f["isOpen"].asBool();
{
if (value_f["form"]["BQ_Param"]["BQ_expand"])
{
function.f_Det_BQ.BQ_expand = value_f["form"]["BQ_Param"]["BQ_expand"].asInt();
}
if (value_f["form"]["BQ_Param"]["bsaveAll"])
{
function.f_Det_BQ.bsaveAll = value_f["form"]["BQ_Param"]["bsaveAll"].asBool();
}
}
// 当 -tag 参数启用时,强制开启标签 AI 检测和保存所有中间结果
if (s_bDetTag)
{
function.f_Det_BQ.bBQ_AI_Det = true;
function.f_Det_BQ.bsaveAll = true;
}
}
}
}
return 0;
@ -1443,6 +1503,5 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.Init();
}
}
return 0;
}

@ -0,0 +1,50 @@
#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,10 +3,12 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "MemMonitor.h"
#include <unistd.h>
#include <string>
#include "CheckUtil.hpp"
#include "LoadImage.hpp" // #include "LoadImage.h"
#include "JsonConfig.h"
bool check_strChannel(string strChannel){
if(strChannel == "XD" || strChannel == "XON") return false;
@ -260,6 +262,9 @@ int deal::Init()
// 初始化参数模块
InitConfig();
// 设置标签检测模式标志,供 ChannelFuntonConfigJson 在解析 JSON 时使用
ChannelFuntonConfigJson::s_bDetTag = runConfig.det_Tag;
printf("\n\n\n\n\n\n\n\n\n\n\n**********************************************************LoadCheckImgConfig\n");
// 载入参数
re = LoadCheckImgConfig();
@ -856,6 +861,10 @@ void deal::ResultThread(int id)
writeLog(strlog, m_DetResult.strlist);
mutex_DetResult_.unlock();
}
// ✅ 递增已保存结果计数,并通知等待线程,立刻唤醒检查
m_nProductSavedResultCount.fetch_add(1);
m_productResultCV.notify_all();
}
usleep(5 * 1000);
@ -1341,11 +1350,105 @@ int deal::CheckFileImg()
products[i].print("产品" + std::to_string(i + 1));
}
// getchar();
printMemUsage("CheckFileImg-开始处理", "");
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]); // 处理单个产品
// ✅ 等待当前产品的所有检测结果保存完成,再处理下一个产品
// 使用条件变量ResultThread 每保存完一个结果就 notify_all立刻唤醒检查
printf("\n[同步] 等待产品 %s 检测结果保存完成...\n", products[i].product_id.c_str());
{
std::unique_lock<std::mutex> lock(mutex_Result_list);
int waitCount = 0;
while (true)
{
bool done = m_productResultCV.wait_for(lock, std::chrono::milliseconds(5000), [this]() {
return m_nProductSavedResultCount.load() >= m_nProductSuccessCount.load()
&& m_Result_list.empty();
});
if (done) break;
waitCount++;
printf("[同步] 等待中... 已保存: %d/%d (成功:%d 失败:%d), 结果队列: %s\n",
m_nProductSavedResultCount.load(),
m_nProductSuccessCount.load() + m_nProductFailCount.load(),
m_nProductSuccessCount.load(), m_nProductFailCount.load(),
m_Result_list.empty() ? "" : "非空");
}
}
printf("[同步] 产品 %s 所有结果已保存完成 (saved=%d, success=%d)\n",
products[i].product_id.c_str(),
m_nProductSavedResultCount.load(),
m_nProductSuccessCount.load());
// ✅ 释放资源:清理图像数据,释放内存
{
// 清理图像信息列表(已在 CheckProduct 开头清理过,这里做双重保障)
for (auto &info : m_ImageInfoList)
{
if (!info.img.empty())
{
info.img.release();
}
}
m_ImageInfoList.clear();
std::vector<JC_IMAGE_INFO_>().swap(m_ImageInfoList); // 强制释放 vector 内存
}
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");
// TODO: 后续实现具体功能
@ -1383,9 +1486,15 @@ int deal::CheckProduct(const LoadProductImages &product)
m_nProductPendingTasks = 0;
m_nProductSuccessCount = 0;
m_nProductFailCount = 0;
m_nProductSavedResultCount = 0; // 重置已保存结果计数
m_ProductFailedList.clear();
m_nCheckNotifiedCount = 0;
// ✅ 修复内存泄漏清理上一个产品累积的原始图像数据cv::Mat
// 注意m_DetResult 是统计结果(轻量字符串/数字),不清除,跨产品累积
m_ImageInfoList.clear();
m_productIdList.clear();
// 3. 打印产品信息
printf("\n");
printf("╔══════════════════════════════════════════════════════════\n");

@ -545,6 +545,7 @@ struct DealRunConfig
Process_Run_Type run_Type = Process_Run_Detect; // 运行模式
RUNTYPE_ det_Type = RUNTYPE_RUN_Pre; // 处理
std::string filePath = ""; // 处理文件路径 如果为空 处理当前的单张图片
bool det_Tag = false; // 是否检测标签
bool bDebugSaveImg = false; // 是否中间图片图片
int m_nTestNum = 999999;
void print(std::string str)
@ -799,6 +800,8 @@ public:
std::mutex m_checkNotifyMutex; // 通知队列锁
std::condition_variable m_checkNotifyCV; // 通知条件变量
std::atomic<int> m_nCheckNotifiedCount{0}; // 已通知数量
std::atomic<int> m_nProductSavedResultCount{0}; // 已保存结果数量(用于产品间同步等待)
std::condition_variable m_productResultCV; // 产品结果保存通知CV每次save后notify
std::set<std::string> m_productIdList; // 产品ID列表
};

@ -228,7 +228,12 @@ int main(int argc, char *argv[])
return 0;
}
}
else if (string(argv[i]) == "-tag" && i + 1 < argc)
{
test.runConfig.det_Type = RUNTYPE_RUN_File;
test.runConfig.filePath = string(argv[i + 1]);
test.runConfig.det_Tag = true;
}
if (string(argv[i]) == "-s")
{
test.runConfig.bDebugSaveImg = true;
@ -245,10 +250,10 @@ int main(int argc, char *argv[])
signal(SIGINT, handler);
test.start();
while (true)
{
usleep(10 * 1000);
}
// while (true)
// {
// usleep(10 * 1000);
// }
return 0;
}

Loading…
Cancel
Save