Compare commits

...

45 Commits

Author SHA1 Message Date
liusiyang 3dc0f73a34 feat 同步云平台部分修改
2 months ago
liusiyang f60ad3e379 feat 二次分割添加日志
2 months ago
liusiyang 68e5ead24b feat 二次分割长度添加日志
2 months ago
liusiyang 287abd7fe7 update energy改为double
3 months ago
liusiyang 479f62af40 feat 脏污添加数量距离分析
3 months ago
liusiyang 7c0dea2fac update 读图强制读取灰度图
3 months ago
liusiyang a2adff60e8 feat 添加边缘和主检测存图
3 months ago
liusiyang 84bd257567 test
4 months ago
liusiyang d83e77139a fix 图片宽高不一崩溃
4 months ago
liusiyang b09480d885 fix 对齐打开但roi没设置对会崩溃
4 months ago
liusiyang 026060fa5f update area和hj添加上限
4 months ago
liusiyang 6125aa5dad delete 去掉AI_Time
4 months ago
liusiyang 0b420a8476 v1.3.0
4 months ago
liusiyang c1b8cda63e update 批量跑同步执行,避免内存溢出
4 months ago
liusiyang 8274481bd6 update 日志文件分小时存储
4 months ago
liusiyang 61bd08fdf6 update 改为全部日志存储
4 months ago
liusiyang 548fa6f472 v1.2.9
4 months ago
liusiyang 5b8e4b7999 feat AD_YX添加HJ计算
4 months ago
liusiyang c1c6115c8a fix Detect可能越界崩溃
4 months ago
liusiyang 0dfbca8934 feat 添加AI_defect_Tag检测模型
4 months ago
liusiyang 768a227910 feat 初步添加BQ模型检测
4 months ago
liusiyang eb2cf825ce feat 开放标签扩/缩参数
4 months ago
liusiyang 8610481adb fix 异物范围过滤
4 months ago
liusiyang 63385495a1 feat LD新增检测(v1.2.7)
4 months ago
liusiyang 2f5f0e1589 update 更改线的二次判断,异物添加范围
4 months ago
liusiyang 9996b5a228 feat 开放暗点同位置判断IOU(v1.2.6)
4 months ago
liusiyang 49390e31bb fix 分类输入图片resize(v1.2.5)
4 months ago
liusiyang a9f6d659bd fix 删除重复定义
5 months ago
liusiyang f3ebf08fd6 Merge branch 'dev_lsy' of https://gitea.aidlux.getcharzp.cn/liusiyang/BOE_FOG_DETECT into dev_lsy
5 months ago
liusiyang 74f604ca65 update ngimg日志存储添加日期
5 months ago
liusiyang 8c5bcd7c9f feat density计算
5 months ago
liusiyang 4c36c7534c update 标签外扩5pix
5 months ago
liusiyang aaac47868f Revert "update 云平台改为单显卡" fog使用双显卡
5 months ago
liusiyang e47a221978 update 云平台改为单显卡
5 months ago
liusiyang c321a118d5 update 更新版本号
5 months ago
liusiyang eba708f32a fix 3s暗点漏检
5 months ago
liusiyang b535bc481e fix 异物漏检
5 months ago
liusiyang 8728bbdb68 update 标签外扩2pix
5 months ago
liusiyang 29086815bc fix 同位置3s暗点报出
5 months ago
liusiyang 036d19bbe6 Merge branch 'dev_lsy' of https://gitea.aidlux.getcharzp.cn/liusiyang/BOE_FOG_DETECT into dev_lsy
5 months ago
liusiyang 0857847444 fix 更改灰阶计算
5 months ago
liusiyang c1f4a2b451 update 同步cell参数延迟更改
5 months ago
liusiyang 0afe6c80a6 fix LD漏检
5 months ago
liusiyang 18a1394759 feat 添加RGB-HGRAY检测
5 months ago
liusiyang 546ce62fe6 fix AI_Time限制绘图
5 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_L127.engine";
boe_config.strName = "tag";
boe_config.inputType = AIModel_Base::Input_CHW;
AI_defect_Tag->Init(boe_config);
}
// 字符 127cell
if (!AI_defect_127Cell)
{

@ -44,7 +44,7 @@ typedef struct ERROR_DOTS_BLOB_DATA
unsigned short minx, miny;
unsigned short maxx, maxy;
int area;
int energy;
double energy;
float JudgArea;
float len;
int macro[_MAX_MACRO_COUNT];

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

@ -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;

@ -29,7 +29,7 @@ struct QX_ERROR_INFO_
std::string result_name;
cv::Rect roi;
int area;
int energy;
double energy;
float JudgArea;
float JudgArea_second;
float flen;
@ -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

@ -15,6 +15,7 @@ enum QX_ANALYSIS_NAME
QX_ANALYSIS_Scratch, // 划伤
QX_ANALYSIS_LINE, // 线类
QX_ANALYSIS_MTX, // MTX
QX_ANALYSIS_Dirty, // 脏污
QX_ANALYSIS_ALL, // MTX&异物
QX_ANALYSIS_COUNT,
};
@ -26,6 +27,7 @@ static const std::string QX_ANALYSIS_NAME_Names[] =
"Scratch",
"LINE",
"MTX",
"Dirty",
"POL_Cell&MTX"};
// 预处理参数

@ -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;
@ -206,6 +206,26 @@ int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDet
continue;
}
if (bdege || nRuntype != 0)
{
std::string res_dir = "ok";
if (cv::countNonZero(outMask) > 0)
{
res_dir = "ng";
}
if (!detimg.empty() && !outMask.empty())
{
std::string strSaveDir = "/home/aidlux/BOE/FOG/AI_Edge_Detect/" + res_dir + "/";
CheckUtil::CreateDir(strSaveDir);
std::string roi_ext = "[" + std::to_string(r.x) + "," + std::to_string(r.y) + "]";
std::string strSavePath_in = strSaveDir + pDetConfig->strCamChannel + "_" + roi_ext + "_edge_in.png";
std::string strSavePath_out = strSaveDir + pDetConfig->strCamChannel + "_" + roi_ext + "_edge_out.png";
cv::imwrite(strSavePath_in, detimg);
cv::imwrite(strSavePath_out, outMask);
}
}
// 边缘检测存图
bool isAllZero = true;
if (cv::countNonZero(outMask) > 0)
{

@ -490,10 +490,14 @@ int AI_SecondDet::Analysisy(const cv::Mat &maskImg, DetConfigResult *pDetConfig)
if (new_len > 0 && new_len < oldLen)
{
pDetConfig->new_len = new_len;
}
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AICheck_RE Len", "Use New Len :old Len %f (mm) new %f", oldLen, pDetConfig->new_len);
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AICheck_RE Len", "Not Use Len :old Len %f (mm) new %f", oldLen, new_len);
}
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AICheck_RE Len", " Not Use Len :old Len %f (mm) new %f", oldLen, new_len);
}

@ -476,6 +476,8 @@ int ALLImgCheckAnalysisy::InitData()
int ALLImgCheckAnalysisy::Det_Product(std::shared_ptr<Product> &product)
{
string cur_times = CheckUtil::getCurTimeHMS();
printf("[%s]>>>>>>>>>>>>>>>Det_Product****************det Start************\n", cur_times.c_str());
// m_pQX_Merge_Analysis->InitData();
// 处理每个相机
while (true)
@ -505,7 +507,8 @@ int ALLImgCheckAnalysisy::Det_Product(std::shared_ptr<Product> &product)
// AnalysiyAll(0);
MergeShowImg(product);
SetProductResult(product);
// printf(">>>>>>>>>>>>>>>Det_Product****************det End************\n");
string cur_timee = CheckUtil::getCurTimeHMS();
printf("[%s]>>>>>>>>>>>>>>>Det_Product****************det End************\n", cur_timee.c_str());
return 0;
}

@ -227,7 +227,7 @@ void MergeBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_BLOB_PARAM *param)
int miny = blob->miny;
int maxx = blob->maxx;
int maxy = blob->maxy;
int energy = blob->energy;
double energy = blob->energy;
int left = minx - pace, right = maxx + pace;
int top = miny - 1, bottom = maxy + 1;

@ -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;
@ -360,9 +361,7 @@ int CameraCheckAnalysisy::ResultParamJudge()
long t1 = CheckUtil::getcurTime();
int re = m_imageResultJudge.MergeResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx), ptemre);
long t2 = CheckUtil::getcurTime();
#ifdef AI_Time
m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx));
#endif
long t3 = CheckUtil::getcurTime();
// m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2);
@ -695,7 +694,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 +721,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 +1251,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 +1323,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 +1345,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) {

@ -103,7 +103,7 @@ void CheckResultJson::toObjectFromValue(Json::Value root)
tem.roi.width = errorJson["roi"]["width"].asInt();
tem.roi.height = errorJson["roi"]["height"].asInt();
tem.area = errorJson["area"].asInt();
tem.energy = errorJson["energy"].asInt();
tem.energy = errorJson["energy"].asDouble();
tem.JudgArea = errorJson["JudgArea"].asFloat();
if (errorJson["JudgArea_second"])
{

@ -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)
{
// 计算交集区域

@ -191,7 +191,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
float JudgArea_second = QX_info->JudgArea_second;
float flen = QX_info->flen;
float grayDis = QX_info->grayDis;
int energy = QX_info->energy;
double energy = QX_info->energy;
float fupS = QX_info->fUpIou;
int maxValue = QX_info->maxValue;
float density = QX_info->density;
@ -208,7 +208,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
}
pQxLog->AddCheckstr(PrintLevel_1,
"ResultJudge", "qxidx: %d/%d qx_status %d roi[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f energy %d region %s",
"ResultJudge", "qxidx: %d/%d qx_status %d roi[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f energy %.0f region %s",
qxidx, qxNum, qx_status, roi.x, roi.y, roi.width, roi.height, config_qx_type, qx_name.c_str(), qx_wb.c_str(),
JudgArea, grayDis, flen, energy, strdetRegionidxList.c_str());
@ -325,8 +325,10 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
float At = pParam->paramArr[j].area;
float Et = pParam->paramArr[j].energy;
float hj = pParam->paramArr[j].hj;
float hj_max = pParam->paramArr[j].hj_max;
float Len = pParam->paramArr[j].length;
float md = pParam->paramArr[j].density;
float area_max = pParam->paramArr[j].area_max;
Judge_Status = true;
@ -371,7 +373,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
}
if (energy < Et)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %d %s %f ",
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %.0f %s %f ",
BOOL_TO_STR(energy >= Et), energy, BOOL_TO_ThanLess(energy >= Et), Et);
}
if (grayDis < hj)
@ -385,6 +387,32 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
BOOL_TO_STR(flen >= Len), flen, BOOL_TO_ThanLess(flen > Len), Len);
}
if(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(hj_max > 0)
{
if(grayDis > hj_max)
{
nerrortype = 0;
result = true;
bNG_Status = false;
bYS_Status = false;
}
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "PolCell_HJ_Max", "%s -> %f %s %f ",
BOOL_TO_STR(grayDis > hj_max), grayDis, BOOL_TO_ThanLess(grayDis > hj_max), hj_max);
}
if (!result)
{
break;
@ -415,36 +443,32 @@ 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.
// if ((nerrortype == 0 || checkFlage != ANALYSIS_TYPE_TF) &&
// config_qx_type == CONFIG_QX_NAME_AD && pFuntion &&
// pFuntion->function.f_AD_Check.bOpen &&
// 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)
{
Judge_Status = true;
int det_s_Vale = 0;
if (JudgArea >= pFuntion->function.f_AD_Check.S_standard_3s.area &&
flen >= pFuntion->function.f_AD_Check.S_standard_3s.len)
if (JudgArea >= m_pbaseCheckFunction->ad_check.S_standard_3s.area &&
flen >= m_pbaseCheckFunction->ad_check.S_standard_3s.len && (strChannel == "L127" || strChannel == "L255"))
{
nerrortype = 1;
checkFlage = ANALYSIS_TYPE_TF;
bNG_Status = true;
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " AD 3S result NG, det area %f len %f >=3s param area %f len %f ",
JudgArea, flen, pFuntion->function.f_AD_Check.S_standard_3s.area, pFuntion->function.f_AD_Check.S_standard_3s.len);
JudgArea, flen, m_pbaseCheckFunction->ad_check.S_standard_3s.area, m_pbaseCheckFunction->ad_check.S_standard_3s.len);
}
else
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " AD 3S result OK, det area %f len %f < 3s param area %f len %f ",
JudgArea, flen, pFuntion->function.f_AD_Check.S_standard_3s.area, pFuntion->function.f_AD_Check.S_standard_3s.len);
JudgArea, flen, m_pbaseCheckFunction->ad_check.S_standard_3s.area, m_pbaseCheckFunction->ad_check.S_standard_3s.len);
}
}
@ -571,7 +595,6 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
// CheckUtil::printROI(CutRoi, "CutRoi");
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
#ifdef AI_Time
if (pImageResult->detImg.channels() == 1)
{
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
@ -581,7 +604,6 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
tem.srcImg = pImageResult->detImg(CutRoi).clone();
}
cv::resize(tem.srcImg, tem.resizeImg, sz);
#endif
int nqx_type = ConfigTypeToResultType(config_qx_type);
tem.type = nqx_type;
@ -796,7 +818,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
float JudgArea = QX_info->JudgArea;
float flen = QX_info->flen;
float grayDis = QX_info->grayDis;
int energy = QX_info->energy;
double energy = QX_info->energy;
float fupS = QX_info->fUpIou;
int maxValue = QX_info->maxValue;
float density = QX_info->density;
@ -814,7 +836,6 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg);
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
#ifdef AI_Time
if (pImageResult->detImg.channels() == 1)
{
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
@ -824,7 +845,6 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
tem.srcImg = pImageResult->detImg(CutRoi).clone();
}
cv::resize(tem.srcImg, tem.resizeImg, sz);
#endif
int nerrortype = 1;
int checkFlage = ANALYSIS_TYPE_TF;
@ -832,7 +852,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
float fmaxScore = 0;
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3,
"qx", "roi[%d %d %d %d] qx %d %s JudgArea %f hj %f len %f energy %d,",
"qx", "roi[%d %d %d %d] qx %d %s JudgArea %f hj %f len %f energy %.0f,",
roi.x, roi.y, roi.width, roi.height, config_qx_type, qx_name.c_str(),
JudgArea, grayDis, flen, energy);
// 生成缺陷小图
@ -1526,7 +1546,7 @@ int ImageResultJudge::AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info)
float JudgArea_second = QX_info->JudgArea_second;
float flen = QX_info->flen;
float grayDis = QX_info->grayDis;
int energy = QX_info->energy;
double energy = QX_info->energy;
float fupS = QX_info->fUpIou;
int maxValue = QX_info->maxValue;
float density = QX_info->density;
@ -1644,7 +1664,7 @@ int ImageResultJudge::AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info)
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "result", "%s param idx %d / %d", BOOL_TO_STR(bjudge), j + 1, pParam->useNum);
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Area", "%s -> %f %s %f ",
BOOL_TO_STR(JudgArea >= At), JudgArea, BOOL_TO_ThanLess(JudgArea >= At), At);
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %d %s %f ",
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %.0f %s %f ",
BOOL_TO_STR(energy >= Et), energy, BOOL_TO_ThanLess(energy >= Et), Et);
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "HJ", "%s -> %f %s %f ",
BOOL_TO_STR(grayDis > hj), grayDis, BOOL_TO_ThanLess(grayDis > hj), hj);
@ -1727,6 +1747,11 @@ int ImageResultJudge::ConfigTypeToQXAnalysis(int nconfigType)
case CONFIG_QX_NAME_MTX:
QXAnalysis_type = QX_ANALYSIS_MTX; // MTX
break;
case CONFIG_QX_NAME_Dirty_L0:
case CONFIG_QX_NAME_Dirty_L1:
case CONFIG_QX_NAME_Dirty_L2:
QXAnalysis_type = QX_ANALYSIS_Dirty; // 脏污
break;
// case CONFIG_QX_NAME_Broken_line:
// QXAnalysis_type = QX_ANALYSIS_ALL, // MTX&异物
// break;

@ -170,7 +170,7 @@ int ImgCheckAnalysisy::GetStatus()
std::string ImgCheckAnalysisy::GetVersion()
{
return std::string("BOE_1.2.0");
return std::string("BOE_1.3.0_" + 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,6 +518,14 @@ 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;
// cv::imwrite("dddddddd.png", m_pImageAllResult->qx_DetAIResult->AI_MaskImg);
@ -589,6 +597,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());
@ -1448,6 +1457,9 @@ int ImgCheckAnalysisy::GetCheckResultBLob()
BLobToDetResult();
// 计算缺陷密度
CalBlobDensity_QX();
return 0;
}
@ -1691,6 +1703,8 @@ int ImgCheckAnalysisy::GetALLBlob()
re = GetBlob_QX();
long t4 = CheckUtil::getcurTime();
re = GetBlob_127cell();
long t5 = CheckUtil::getcurTime();
re = GetBlob_BQ();
if (blobs.blobCount > 100)
{
@ -1700,8 +1714,8 @@ int ImgCheckAnalysisy::GetALLBlob()
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 +1771,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 +1792,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 +1810,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 +2165,302 @@ 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;
// 资源控制:限制最大并发数和最大待处理数
const int MAX_CONCURRENT = 5;
const int MAX_PENDING = 5;
long t2 = CheckUtil::getcurTime();
while (completed < totalTasks)
{
// 提交任务:满足并发限制和待处理限制
if (submitted < totalTasks
&& runner->GetProcessingCount() < MAX_CONCURRENT
&& (submitted - completed) < MAX_PENDING)
{
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_pImageAllResult->cameraBaseResult->pBQ_Result->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标签区域最小缺陷面积阈值
// 使用逐像素扫描方式提取blob(GetBlobs_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 +2804,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");
@ -2611,6 +2938,24 @@ int ImgCheckAnalysisy::AI_Detect_QX()
pDetAIResult->blobDetParam->AIMaskImgBLobQueue.push(temAIresult);
}
}
// AI检测残点图存图
if (DetImgInfo_shareP->bDebugsaveImg)
{
bool bNeedSave = false;
std::string roi_ext = "[" + std::to_string(result->roi.x) + "," + std::to_string(result->roi.y) + "]";
bNeedSave = true;
if (bNeedSave && !AIresult.empty())
{
std::string strSaveDir = "/home/aidlux/BOE/FOG/AI_Detect/" + 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, AIresult);
}
}
}
completed++;
}
@ -2621,7 +2966,9 @@ int ImgCheckAnalysisy::AI_Detect_QX()
}
te = CheckUtil::getcurTime();
float mean_AI = (te - t2) / SmallRoiList.size();
m_pdetlog->bPrintStr = true;
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, "============= End; AI Run Time: sum %ld pre %ld Run %ld mean One Small Img %f", te - ts, t2 - ts, te - t2, mean_AI);
m_pdetlog->bPrintStr = false;
// 临时存图
if (DetImgInfo_shareP->bDebugsaveImg)
@ -3351,23 +3698,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 +3792,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 +3805,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 +3818,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 +3835,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 +3864,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 +4107,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 +4127,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 +4261,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 +4278,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 +4824,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;
}

@ -139,6 +139,11 @@ int QX_Merge_Analysis::ConfigTypeToQXAnalysis(int nconfigType)
case CONFIG_QX_NAME_MTX:
QXAnalysis_type = QX_ANALYSIS_MTX; // MTX
break;
case CONFIG_QX_NAME_Dirty_L0:
case CONFIG_QX_NAME_Dirty_L1:
case CONFIG_QX_NAME_Dirty_L2:
QXAnalysis_type = QX_ANALYSIS_Dirty; // 脏污
break;
// case CONFIG_QX_NAME_Broken_line:
// QXAnalysis_type = QX_ANALYSIS_ALL, // MTX&异物
// break;
@ -378,7 +383,7 @@ int QX_Merge_Analysis::StartAnalysis()
// 分析每一个缺陷类型
for (int i = 0; i < QX_ANALYSIS_COUNT; i++)
{
if (QX_ANALYSIS_POL_CELL != i && QX_ANALYSIS_AD != i && QX_ANALYSIS_MTX != i && QX_ANALYSIS_Scratch != i && QX_ANALYSIS_LINE != i)
if (QX_ANALYSIS_POL_CELL != i && QX_ANALYSIS_AD != i && QX_ANALYSIS_MTX != i && QX_ANALYSIS_Scratch != i && QX_ANALYSIS_LINE != i && QX_ANALYSIS_Dirty != i)
{
m_pMergedetlog->AddCheckstr(PrintLevel_0, 3, "Num And Dis Judge", "== %d 11", i);
continue;
@ -485,7 +490,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 +598,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 +617,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 +857,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 +991,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 +1048,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);
}
}

@ -328,6 +328,7 @@ struct AandEParam
float area_max; // 面积上限
float energy; // 能量
float hj; // 灰阶
float hj_max; // 灰阶上限
float length; // 长度
int num; // 数量
float dis; // 距离
@ -340,6 +341,7 @@ struct AandEParam
area_max = -1;
energy = -1;
hj = -1;
hj_max = -1;
length = -1;
num = -1;
dis = -1;
@ -357,6 +359,7 @@ struct AandEParam
this->area_max = tem.area_max;
this->energy = tem.energy;
this->hj = tem.hj;
this->hj_max = tem.hj_max;
this->length = tem.length;
this->num = tem.num;
this->dis = tem.dis;
@ -466,6 +469,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 +798,7 @@ struct Function_YXDet
{
bool bOpen; // 是否开启
std::string strModle;
int minArea;
Function_YXDet()
{
Init();
@ -802,20 +807,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 +876,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 +893,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 +906,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)
{
@ -1271,7 +1294,19 @@ struct Function_Image_Align
{
printf("pointArry1 == 0 \n\n\n");
}
feature_Mask = tem_feature_Mask(feature_Roi).clone();
// 防御:feature_Roi 相对图像尺寸 img_W x img_H 可能越界,
// 越界会导致 cv::Mat(Mat, Rect) 断言失败并抛 cv::Exception,进而 abort。
cv::Rect roi = feature_Roi & cv::Rect(0, 0, img_W, img_H);
if (roi.width <= 0 || roi.height <= 0)
{
printf("[ToMaskImg] WARNING feature_Roi (%d,%d,%d,%d) out of range, img %dx%d\n",
feature_Roi.x, feature_Roi.y, feature_Roi.width, feature_Roi.height, img_W, img_H);
feature_Mask = tem_feature_Mask.clone();
}
else
{
feature_Mask = tem_feature_Mask(roi).clone();
}
}
}
void print(std::string str)
@ -1519,69 +1554,108 @@ struct AD_Analysisy_S
return str123;
}
};
// 暗点检测功能
struct Function_AD_Check
// 暗点同位置判断(IOU)
struct AD_Analysisy_IOU
{
bool bOpen; // 是否开启
AD_S_Standard S_standard_3s; // 3s 标准
AD_S_Standard S_standard_2s; // 2s 标准
AD_S_Standard S_standard_1s; // 1s 标准
AD_Analysisy_Num analysis_num; // 数量分析
AD_Analysisy_Dis analysis_dis; // 距离分析
AD_Analysisy_S analysis_s; // s 标准分析
Function_AD_Check()
float AD_IOU; // IOU 阈值
float AD_Expand; // 扩张阈值
AD_Analysisy_IOU()
{
Init();
}
void Init()
{
bOpen = false;
S_standard_3s.Init();
S_standard_2s.Init();
S_standard_1s.Init();
analysis_num.Init();
analysis_dis.Init();
analysis_s.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 AD_Analysisy_Bind
{
bool bUse;
std::vector<std::string> main_channel_2s;
std::vector<std::string> second_channel_2s;
std::vector<std::string> main_channel_3s;
std::vector<std::string> second_channel_3s;
std::vector<std::string> correlated_channels;
void copy(Function_AD_Check tem)
AD_Analysisy_Bind()
{
this->bOpen = tem.bOpen;
this->S_standard_3s.copy(tem.S_standard_3s);
this->S_standard_2s.copy(tem.S_standard_2s);
this->S_standard_1s.copy(tem.S_standard_1s);
this->analysis_num.copy(tem.analysis_num);
this->analysis_dis.copy(tem.analysis_dis);
this->analysis_s.copy(tem.analysis_s);
Init();
}
void print(std::string str)
void Init()
{
printf("%s>>bOpen %d %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());
bUse = false;
main_channel_2s.clear();
second_channel_2s.clear();
main_channel_3s.clear();
second_channel_3s.clear();
correlated_channels.clear();
}
void copy (AD_Analysisy_Bind tem)
{
this->bUse = tem.bUse;
this->main_channel_2s = tem.main_channel_2s;
this->second_channel_2s = tem.second_channel_2s;
this->main_channel_3s = tem.main_channel_3s;
this->second_channel_3s = tem.second_channel_3s;
this->correlated_channels = tem.correlated_channels;
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d ", str.c_str(), bOpen);
sprintf(buffer, "%s:bUse %d;", str.c_str(),
bUse);
std::string str123 = buffer;
str123 += S_standard_3s.GetInfo("3S");
str123 += S_standard_2s.GetInfo("2S");
str123 += S_standard_1s.GetInfo("1S");
str123 += analysis_num.GetInfo("analysis_num");
str123 += analysis_dis.GetInfo("analysis_dis");
str123 += analysis_s.GetInfo("analysis_s");
return str123;
}
};
struct AD_Analysisy_SF
{
std::vector<std::string> s_sf;
std::vector<std::string> region_sf;
AD_Analysisy_SF()
{
Init();
}
void Init()
{
s_sf.clear();
region_sf.clear();
}
void copy (AD_Analysisy_SF tem)
{
this->s_sf = tem.s_sf;
this->region_sf = tem.region_sf;
}
std::string GetInfo(std::string str)
{
std::string str123;
for (int i = 0; i < s_sf.size(); i++)
{
str123 += str + ":s_sf " + s_sf[i] + ";";
}
for (int i = 0; i < region_sf.size(); i++)
{
str123 += str + ":region_sf " + region_sf[i] + ";";
}
return str123;
}
};
// 异物检测功能
struct Function_POL_Check
{
@ -1670,6 +1744,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
{
@ -1686,9 +1798,9 @@ struct CheckFunction
Function_Image_Align f_Image_Align; // 图片特征对齐
Function_Detect_LackPol f_Dectect_LackPol; // 缺失POL检测
Function_SecondDet f_SecondDetect; // 二次检测分析
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();
@ -1708,9 +1820,9 @@ struct CheckFunction
f_Image_Align.Init();
f_Dectect_LackPol.Init();
f_SecondDetect.Init();
f_AD_Check.Init();
f_POL_Check.Init();
f_dege_Det.Init();
f_Det_BQ.Init();
}
void copy(CheckFunction tem)
{
@ -1728,9 +1840,9 @@ struct CheckFunction
this->f_Image_Align.copy(tem.f_Image_Align);
this->f_Dectect_LackPol.copy(tem.f_Dectect_LackPol);
this->f_SecondDetect.copy(tem.f_SecondDetect);
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)
{
@ -1748,9 +1860,9 @@ struct CheckFunction
f_Image_Align.print("Image_Align");
f_Dectect_LackPol.print("Dectect_LackPol");
f_SecondDetect.print("SecondDetect");
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)
{
@ -1769,9 +1881,9 @@ struct CheckFunction
str123 += f_Image_Align.GetInfo("Image_Align");
str123 += f_Dectect_LackPol.GetInfo("Dectect_LackPol");
str123 += f_SecondDetect.GetInfo("SecondDetect");
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 +2267,10 @@ 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 分析
AD_Analysisy_Bind analysis_bind; // 绑定分析
AD_Analysisy_SF analysis_sf; // 同画面参数分析
Base_Function_AD_Check()
{
@ -2169,6 +2285,9 @@ struct Base_Function_AD_Check
analysis_num.Init();
analysis_dis.Init();
analysis_s.Init();
analysis_iou.Init();
analysis_bind.Init();
analysis_sf.Init();
}
void copy(Base_Function_AD_Check tem)
@ -2180,16 +2299,22 @@ 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);
this->analysis_bind.copy(tem.analysis_bind);
this->analysis_sf.copy(tem.analysis_sf);
}
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 %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(),
analysis_bind.GetInfo("analysis_bind").c_str(),
analysis_sf.GetInfo("analysis_sf").c_str());
}
std::string GetInfo(std::string str)
{
@ -2202,6 +2327,9 @@ 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");
str123 += analysis_bind.GetInfo("analysis_time");
str123 += analysis_sf.GetInfo("analysis_sf");
return str123;
}

@ -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();

@ -32,7 +32,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 +49,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();
@ -225,6 +226,11 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
temparam.hj = value_node_imgs_region_Check_Param_value[idx]["hj"].asFloat();
}
if (value_node_imgs_region_Check_Param_value[idx]["hj_max"])
{
temparam.hj_max = value_node_imgs_region_Check_Param_value[idx]["hj_max"].asFloat();
}
if (value_node_imgs_region_Check_Param_value[idx]["length"])
{
temparam.length = value_node_imgs_region_Check_Param_value[idx]["length"].asFloat();
@ -530,6 +536,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 +569,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
{
@ -953,83 +984,6 @@ int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &funct
}
// getchar();
}
// 暗点检测
if ("AD_Check" == strCode)
{
auto value_f = value[i];
// std::cout << value_f << std::endl;
function.f_AD_Check.bOpen = value_f["isOpen"].asBool();
if (function.f_AD_Check.bOpen)
{
if (value_f["form"]["AD_S_Standard"]["AD_3S_Area"])
{
function.f_AD_Check.S_standard_3s.area = value_f["form"]["AD_S_Standard"]["AD_3S_Area"].asFloat();
}
if (value_f["form"]["AD_S_Standard"]["AD_3S_Len"])
{
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();
}
if (value_f["form"]["AD_S_Standard"]["AD_2S_Len"])
{
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();
}
if (value_f["form"]["AD_S_Standard"]["AD_1S_Len"])
{
function.f_AD_Check.S_standard_1s.len = value_f["form"]["AD_S_Standard"]["AD_1S_Len"].asFloat();
}
if (value_f["form"]["AD_Check_Num"]["Open"])
{
function.f_AD_Check.analysis_num.bOpen = value_f["form"]["AD_Check_Num"]["Open"].asBool();
}
if (value_f["form"]["AD_Check_Num"]["Num"])
{
function.f_AD_Check.analysis_num.numT = value_f["form"]["AD_Check_Num"]["Num"].asInt();
}
if (value_f["form"]["AD_Check_Dis"]["Open"])
{
function.f_AD_Check.analysis_dis.bOpen = value_f["form"]["AD_Check_Dis"]["Open"].asBool();
}
if (value_f["form"]["AD_Check_Dis"]["Dis"])
{
function.f_AD_Check.analysis_dis.disT = value_f["form"]["AD_Check_Dis"]["Dis"].asFloat();
}
if (value_f["form"]["AD_Check_S"]["Open"])
{
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();
}
if (value_f["form"]["AD_Check_S"]["NG_3s"])
{
function.f_AD_Check.analysis_s.NG_3s = value_f["form"]["AD_Check_S"]["NG_3s"].asBool();
}
if (value_f["form"]["AD_Check_S"]["Num"])
{
function.f_AD_Check.analysis_s.Check_s_Num = value_f["form"]["AD_Check_S"]["Num"].asInt();
}
}
else
{
function.f_AD_Check.Init();
}
// getchar();
}
// 异物检测
if ("POL_Cam" == strCode)
{
@ -1083,6 +1037,24 @@ 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();
}
}
}
}
}
return 0;
@ -1375,6 +1347,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.bOpen = value_f["isOpen"].asBool();
if (_config.ad_check.bOpen)
{
// S标准
if (value_f["form"]["AD_S_Standard"]["AD_3S_Area"])
{
_config.ad_check.S_standard_3s.area = value_f["form"]["AD_S_Standard"]["AD_3S_Area"].asFloat();
@ -1402,6 +1375,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.S_standard_1s.len = value_f["form"]["AD_S_Standard"]["AD_1S_Len"].asFloat();
}
// 数量分析
if (value_f["form"]["AD_Check_Num"]["Open"])
{
_config.ad_check.analysis_num.bOpen = value_f["form"]["AD_Check_Num"]["Open"].asBool();
@ -1411,6 +1385,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.analysis_num.numT = value_f["form"]["AD_Check_Num"]["Num"].asInt();
}
// S数量分析
if (value_f["form"]["AD_Check_Dis"]["Open"])
{
_config.ad_check.analysis_dis.bOpen = value_f["form"]["AD_Check_Dis"]["Open"].asBool();
@ -1420,6 +1395,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.analysis_dis.disT = value_f["form"]["AD_Check_Dis"]["Dis"].asFloat();
}
// 距离分析
if (value_f["form"]["AD_Check_S"]["Open"])
{
_config.ad_check.analysis_s.bOpen = value_f["form"]["AD_Check_S"]["Open"].asBool();
@ -1437,6 +1413,89 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
{
_config.ad_check.analysis_s.Check_s_Num = value_f["form"]["AD_Check_S"]["Num"].asInt();
}
// IOU分析
if (value_f["form"]["AD_Check_IOU"]["AD_IOU"])
{
_config.ad_check.analysis_iou.AD_IOU = value_f["form"]["AD_Check_IOU"]["AD_IOU"].asFloat();
}
if (value_f["form"]["AD_Check_IOU"]["AD_Expand"])
{
_config.ad_check.analysis_iou.AD_Expand = value_f["form"]["AD_Check_IOU"]["AD_Expand"].asFloat();
}
// 通道绑定
if (value_f["form"]["Bind_Channel"]["bUse_bind"])
{
_config.ad_check.analysis_bind.bUse = value_f["form"]["Bind_Channel"]["bUse_bind"].asBool();
}
auto value_qx = value_f["form"]["Bind_Channel"]["2s_main_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_bind.main_channel_2s.push_back(channel);
}
}
value_qx = value_f["form"]["Bind_Channel"]["2s_second_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_bind.second_channel_2s.push_back(channel);
}
}
value_qx = value_f["form"]["Bind_Channel"]["3s_main_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_bind.main_channel_3s.push_back(channel);
}
}
value_qx = value_f["form"]["Bind_Channel"]["3s_second_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_bind.second_channel_3s.push_back(channel);
}
}
value_qx = value_f["form"]["Bind_Channel"]["correlated_channels"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_bind.correlated_channels.push_back(channel);
}
}
// 同画面分析
value_qx = value_f["form"]["Single_Channel"]["s_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_sf.s_sf.push_back(channel);
}
}
value_qx = value_f["form"]["Single_Channel"]["region1_channel"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ad_check.analysis_sf.region_sf.push_back(channel);
}
}
}
else
{

@ -225,7 +225,7 @@ bool LoadImage::matchesExtension(
cv::Mat LoadImage::loadImageFile(const fs::path &path) const
{
// 使用 IMREAD_UNCHANGED 保留原图通道和位深信息
return cv::imread(path.string(), cv::IMREAD_UNCHANGED);
return cv::imread(path.string(), cv::IMREAD_GRAYSCALE);
}
/// @brief 加载指定目录下的所有图片(产品 - 图片对两层结构)

@ -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,6 +3,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "MemMonitor.h"
#include <unistd.h>
#include <string>
#include "CheckUtil.hpp"
@ -99,7 +100,7 @@ bool customSort(const AI_Det_Channel_ &a, const AI_Det_Channel_ &b)
// 定义图片读取函数
void readImage(const std::string &filename)
{
cv::Mat image = cv::imread(filename);
cv::Mat image = cv::imread(filename, cv::IMREAD_GRAYSCALE);
if (image.empty())
{
std::cerr << "Error: Unable to read image " << filename << std::endl;
@ -196,6 +197,10 @@ deal::deal()
m_nProductReadThreadNum = READ_PRODUCT_THREAD_NUM;
m_nProductQueueMaxSize = PRODUCT_QUEUE_MAX_SIZE;
m_nCheckNotifiedCount = 0;
// ✅ 图片尺寸一致性保护
m_nExpectedImgWidth = -1;
m_nExpectedImgHeight = -1;
}
deal::~deal()
@ -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,19 @@ int deal::CheckProduct(const LoadProductImages &product)
m_nProductPendingTasks = 0;
m_nProductSuccessCount = 0;
m_nProductFailCount = 0;
m_nProductSavedResultCount = 0; // 重置已保存结果计数
m_ProductFailedList.clear();
m_nCheckNotifiedCount = 0;
// ✅ 重置图片期望尺寸(每个产品批次独立)
m_nExpectedImgWidth = -1;
m_nExpectedImgHeight = -1;
// ✅ 修复内存泄漏:清理上一个产品累积的原始图像数据(cv::Mat)
// 注意:m_DetResult 是统计结果(轻量字符串/数字),不清除,跨产品累积
m_ImageInfoList.clear();
m_productIdList.clear();
// 3. 打印产品信息
printf("\n");
printf("╔══════════════════════════════════════════════════════════\n");
@ -1562,6 +1675,42 @@ int deal::SendCheckImg(const CheckImgNotifyInfo &info, IN_IMG_Status_ status, bo
m_nProductSuccessCount.fetch_add(1);
// ✅ 图片尺寸一致性保护:获取当前图片的有效图像
cv::Mat curImg;
if (!info.left_img.empty())
{
curImg = info.left_img;
}
else if (!info.right_img.empty())
{
curImg = info.right_img;
}
if (!curImg.empty())
{
// 首次设置期望尺寸
if (m_nExpectedImgWidth < 0 || m_nExpectedImgHeight < 0)
{
m_nExpectedImgWidth = curImg.cols;
m_nExpectedImgHeight = curImg.rows;
printf("[尺寸基准] 产品 %s 首张图片尺寸: %dx%d (channel: %s)\n",
info.productId.c_str(), m_nExpectedImgWidth, m_nExpectedImgHeight,
info.channelName.c_str());
}
// 尺寸不一致时,resize 到期望尺寸
else if (curImg.cols != m_nExpectedImgWidth || curImg.rows != m_nExpectedImgHeight)
{
printf("[尺寸修正] 产品 %s 图片尺寸不一致: 期望 %dx%d, 实际 %dx%d (channel: %s),正在resize...\n",
info.productId.c_str(),
m_nExpectedImgWidth, m_nExpectedImgHeight,
curImg.cols, curImg.rows,
info.channelName.c_str());
cv::Mat resizedImg;
cv::resize(curImg, resizedImg, cv::Size(m_nExpectedImgWidth, m_nExpectedImgHeight));
curImg = resizedImg;
}
}
std::shared_ptr<shareImage> tem = std::make_shared<shareImage>();
tem->strChannel = info.channelName;
@ -1596,13 +1745,9 @@ int deal::SendCheckImg(const CheckImgNotifyInfo &info, IN_IMG_Status_ status, bo
{
if (!info.left_img.empty())
{
tem->img = info.left_img;
}
else if (!info.right_img.empty())
if (!curImg.empty())
{
tem->img = info.right_img;
tem->img = curImg;
}
}
@ -1767,7 +1912,7 @@ void deal::ProductReadImgThreadFunc(int threadId)
// 读取左图
long startTime = getcurTime();
cv::Mat left_img;
cv::Mat img16 = cv::imread(task->left_path, cv::IMREAD_UNCHANGED);
cv::Mat img16 = cv::imread(task->left_path, cv::IMREAD_GRAYSCALE);
if (!img16.empty())
{
@ -1791,7 +1936,7 @@ void deal::ProductReadImgThreadFunc(int threadId)
// 读取右图
cv::Mat right_img;
img16 = cv::imread(task->right_path, cv::IMREAD_UNCHANGED);
img16 = cv::imread(task->right_path, cv::IMREAD_GRAYSCALE);
if (!img16.empty())
{
@ -1950,7 +2095,7 @@ int deal::ReJson_product(std::vector<Json_Det_Path> &jsonList, std::string strPr
std::string json_str = buffer.str(); // 获取 JSON 文件的内容作为字符串
// 显示读取到的 JSON 字符串
// std::cout << "JSON content: " << json_str << std::endl;
cv::Mat cutimg = cv::imread(strimg, 0);
cv::Mat cutimg = cv::imread(strimg, cv::IMREAD_GRAYSCALE);
int f0 = strJson.rfind('_');
int f1 = strJson.rfind('.');
int f2 = strJson.rfind('/');
@ -2275,7 +2420,7 @@ void deal::Thread_ReadImg(int id)
printf("pImageInfo == nullptr=================id %d=============\n", id);
return;
}
pImageInfo->img = cv::imread(pImageInfo->strPath, 0);
pImageInfo->img = cv::imread(pImageInfo->strPath, cv::IMREAD_GRAYSCALE);
m_ReadImgThread_Result[id] = pImageInfo;
// 线程完成读图,设置现场状态为 完成

@ -799,8 +799,14 @@ 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列表
// ============ 图片尺寸一致性保护 ============
int m_nExpectedImgWidth; // 当前产品批次期望的图片宽度(-1 表示未设置)
int m_nExpectedImgHeight; // 当前产品批次期望的图片高度(-1 表示未设置)
};
#endif //_CORELOGICFACTORY_HPP_

@ -245,10 +245,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