feat 添加传统检测相关参数配置

dev_lsy
liusiyang 4 weeks ago
parent e16100f205
commit 22dd824f94

@ -513,7 +513,8 @@ int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){
if(!b_update){
return 1;
}
if(cur_roi.width <= 0 || cur_roi.height <= 0){
int get_edge_roi = GetEdgeRoi(img, cur_roi, 20, 20);
if(get_edge_roi != 0){
return 2;
}
m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "-------------------start--------------");
@ -639,6 +640,9 @@ int ImgCheckAnalysisy::CheckRun()
m_CheckResult_shareP->basicResult.strChannel = m_CheckResult_shareP->in_shareImage->strChannel;
m_strCurDetChannel = m_CheckResult_shareP->basicResult.strChannel;
/*自适应更新参数*/
Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, m_pbaseCheckFunction->markLine.badapt_region);
// 2、参数检查
int rec = ConfigCheck(DetImgInfo_shareP->img);
if (rec != CHECK_OK)
@ -665,9 +669,6 @@ int ImgCheckAnalysisy::CheckRun()
m_pImageAllResult->pDetResult->CutRoi = m_CutRoi;
m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg;
/*自适应更新参数 — 基于AI边缘定位的精准ROI*/
Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, m_pbaseCheckFunction->markLine.badapt_region);
// 生成 检测的图片
cv::Mat image;
image = m_CheckResult_shareP->in_shareImage->img;
@ -1308,7 +1309,7 @@ int ImgCheckAnalysisy::AIMaskDet()
memset(m_ImgBlobHFlagData, 0, sizeof(unsigned char) * m_pImageAllResult->detImg.rows);
// 传统检测路径等待异步任务完成后计算HFlag
if(m_pBasicConfig->bTraditionalDetect)
if(m_pbaseCheckFunction->traditionDet.bOpen)
{
m_AItask->waitComplate();
int rec = m_AItask->nresult;
@ -1630,28 +1631,34 @@ int ImgCheckAnalysisy::Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &Re
std::string strBaseLog = "Traditional_Detect";
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect Start");
Base_Function_TraditionDet traditionParam = m_pbaseCheckFunction->traditionDet;
// 首次调用时初始化传统检测参数(从 m_AnalysisyConfig 映射)
static bool bTcsInited = false;
if (!bTcsInited)
{
CHECK_PARAM cp;
cp.nAreaLowFilter = 80;
cp.nBlockSize = 100;
cp.nDiscardTop = 170;
cp.nDiscardBottom = 170;
cp.nDiscardLeft = 180;
cp.nDiscardRight = 460;
cp.fZoomRatio = 0.25f;
cp.nBlockSize = traditionParam.nBlockSize;
cp.nDiscardTop = 0;
cp.nDiscardBottom = 0;
cp.nDiscardLeft = 0;
cp.nDiscardRight = 0;
cp.fZoomRatio = traditionParam.fZoomRatio;
cp.nFilterLow = 15;
cp.nFilterHigh = 15;
cp.nAreaFilter = 10;
cp.nCountFilter = 50;
cp.nAreaFilter = traditionParam.nAreaFilter;
cp.nCountFilter = traditionParam.nCountFilter;
m_tcsCheck.SetChecConfig(&cp);
bTcsInited = true;
}
// 调用传统检测:输出残点二值图(已内部完成 crop+resize 反向映射,与 img 同尺寸)
int ret = m_tcsCheck.TraditionalDetect(img, ResultImg);
cv::Rect detroi = traditionParam.detArea_ROI;
if(!traditionParam.bdetArea)
{
detroi = cv::Rect(0, 0, img.cols, img.rows);
}
// 调用传统检测:输出残点二值图
int ret = m_tcsCheck.TraditionalDetect(img, detroi, ResultImg);
if (ret != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect FAILED (no product)");
@ -1832,7 +1839,7 @@ int ImgCheckAnalysisy::Traditional_QX_Class_Thread()
{
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Start");
// 1. 调用传统分类:基于上次 TraditionalDetect 缓存的模糊图 + 当前 mask
// 1. 调用传统分类
if (m_pImageAllResult == nullptr || m_pImageAllResult->AIMaskImg.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " No mask image");
@ -1960,7 +1967,7 @@ void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr<TaskInfo> task)
t1 = CheckUtil::getcurTime();
int rec;
if(m_pBasicConfig->bTraditionalDetect)
if(m_pbaseCheckFunction->traditionDet.bOpen)
{
rec = Traditional_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg);
}
@ -1984,7 +1991,7 @@ void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr<TaskInfo> task)
t1 = CheckUtil::getcurTime();
int rec;
if(m_pBasicConfig->bTraditionalDetect)
if(m_pbaseCheckFunction->traditionDet.bOpen)
{
rec = Traditional_QX_Class_Thread();
}

@ -407,7 +407,6 @@ struct BasicConfig
float Product_Size_Height_mm; // 产品尺寸 高度 mm
float fImage_Scale_x; // 成像精度
float fImage_Scale_y; // 成像精度
bool bTraditionalDetect; // 使用传统算法检测
std::string strCamName; //
float density_R_mm; // 密度计算半径 像素
@ -428,7 +427,6 @@ struct BasicConfig
Product_Size_Height_mm = 1000;
fImage_Scale_x = 0.03;
fImage_Scale_y = 0.03;
bTraditionalDetect = false;
density_R_mm = 5;
strCamName = "";
strCamearName = EMPTY_CONFIG_NAME;
@ -452,7 +450,6 @@ struct BasicConfig
this->Product_Size_Height_mm = tem.Product_Size_Height_mm;
this->fImage_Scale_x = tem.fImage_Scale_x;
this->fImage_Scale_y = tem.fImage_Scale_y;
this->bTraditionalDetect = tem.bTraditionalDetect;
this->density_R_mm = tem.density_R_mm;
this->strCamearName = tem.strCamearName;
}
@ -461,7 +458,7 @@ struct BasicConfig
printf("============================↓↓↓↓↓↓%s↓↓ %s ↓↓↓↓↓=========================\n", str.c_str(), strCamearName.c_str());
printf("bCal_ImageScale %d Product_Size_Width =%f Product_Size_Height =%f \n", bCal_ImageScale, Product_Size_Width_mm, Product_Size_Height_mm);
printf("fImage_Scale_x =%f fImage_Scale_y=%f \n", fImage_Scale_x, fImage_Scale_y);
printf("bTraditionalDetect %d density_R_mm=%f \n", bTraditionalDetect, density_R_mm);
printf("density_R_mm=%f \n", density_R_mm);
// printf("height_min =%d height_max=%d \n", height_min, height_max);
printf("bDrawShieldRoi %d bShield_ZF %d DrawPreRoi %d fUP_IOU %f density_R_mm %f\n", bDrawShieldRoi, bShield_ZF, bDrawPreRoi, fUP_IOU, density_R_mm);
printf("============================↑↑↑↑↑↑%s↑↑↑↑↑↑=========================\n", str.c_str());
@ -1782,6 +1779,61 @@ struct Base_Function_SaveImg
}
};
//传统检测
struct Base_Function_TraditionDet
{
bool bOpen; // 是否开启
float nAreaLowFilter; // 定位阈值
int nBlockSize; // 分块大小
float fZoomRatio; // 缩放比例
float nAreaFilter; // 面积过滤
int nCountFilter; // 数量过滤
cv::Rect detArea_ROI;
std::vector<cv::Point> detArea;
bool bdetArea; // 是否使用区域
Base_Function_TraditionDet()
{
Init();
}
void Init()
{
bOpen = false;
nAreaLowFilter = 0;
nBlockSize = 0;
fZoomRatio = 0;
nAreaFilter = 0;
nCountFilter = 0;
bdetArea = false;
detArea_ROI = cv::Rect(0, 0, 0, 0);
detArea.clear();
}
void copy(Base_Function_TraditionDet tem)
{
this->bOpen = tem.bOpen;
this->nAreaLowFilter = tem.nAreaLowFilter;
this->nBlockSize = tem.nBlockSize;
this->fZoomRatio = tem.fZoomRatio;
this->nAreaFilter = tem.nAreaFilter;
this->nCountFilter = tem.nCountFilter;
this->bdetArea = tem.bdetArea;
this->detArea_ROI = tem.detArea_ROI;
this->detArea.assign(tem.detArea.begin(), tem.detArea.end());
}
void print(std::string str)
{
printf("%s>>bOpen %d nAreaLowFilter %f nBlockSize %d fZoomRatio %f nAreaFilter %f nCountFilter %d \n", str.c_str(),
bOpen, nAreaLowFilter, nBlockSize, fZoomRatio, nAreaFilter, nCountFilter);
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d nAreaLowFilter %f nBlockSize %d fZoomRatio %f nAreaFilter %f nCountFilter %d \n", str.c_str(),
bOpen, nAreaLowFilter, nBlockSize, fZoomRatio, nAreaFilter, nCountFilter);
std::string str123 = buffer;
return str123;
}
};
// 大缺陷 NG
struct Big_NG
{
@ -1970,6 +2022,7 @@ struct BaseCheckFunction
Base_Function_MarkLine markLine;
Base_Function_Edge_Det edgeDet;
Base_Function_SaveImg saveImg;
Base_Function_TraditionDet traditionDet;
Base_Function_BigNG bigNG;
BaseCheckFunction()
{
@ -1980,6 +2033,7 @@ struct BaseCheckFunction
markLine.Init();
edgeDet.Init();
saveImg.Init();
traditionDet.Init();
bigNG.Init();
}
void copy(BaseCheckFunction tem)
@ -1987,6 +2041,7 @@ struct BaseCheckFunction
this->markLine.copy(tem.markLine);
this->edgeDet.copy(tem.edgeDet);
this->saveImg.copy(tem.saveImg);
this->traditionDet.copy(tem.traditionDet);
this->bigNG.copy(tem.bigNG);
}
void print(std::string str)
@ -1995,6 +2050,7 @@ struct BaseCheckFunction
markLine.print("markLine");
edgeDet.print("edgeDet");
saveImg.print("saveImg");
traditionDet.print("traditionDet");
bigNG.print("bigNG");
}
std::string GetInfo(std::string str)
@ -2003,6 +2059,7 @@ struct BaseCheckFunction
str123 += markLine.GetInfo("markLine");
str123 += edgeDet.GetInfo("edgeDet");
str123 += saveImg.GetInfo("saveImg");
str123 += traditionDet.GetInfo("traditionDet");
str123 += bigNG.GetInfo("bigNG");
// str123 += "\n";
return str123;

@ -57,7 +57,6 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root)
_config.baseConfig.Product_Size_Height_mm = value["Product_Size_H"].asFloat();
_config.baseConfig.fImage_Scale_x = value["Image_Scale_X"].asFloat();
_config.baseConfig.fImage_Scale_y = value["Image_Scale_Y"].asFloat();
_config.baseConfig.bTraditionalDetect = value["bTraditionalDetect"].asFloat();
if (value["Density_R"])
{
_config.baseConfig.density_R_mm = value["Density_R"].asFloat();
@ -1309,6 +1308,62 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
// _config.edgeDet.print("edgeDet");
// getchar();
}
if ("Tradition_Detect" == strCode)
{
auto value_f = value;
// std::cout << value_f << std::endl;
// getchar();
_config.traditionDet.bOpen = value_f["isOpen"].asBool();
if (_config.traditionDet.bOpen)
{
if (value_f["form"]["Tradition_Param"]["nBlockSize"])
{
_config.traditionDet.nBlockSize = value_f["form"]["Tradition_Param"]["nBlockSize"].asInt();
}
if (value_f["form"]["Tradition_Param"]["fZoomRatio"])
{
_config.traditionDet.fZoomRatio = value_f["form"]["Tradition_Param"]["fZoomRatio"].asFloat();
}
if (value_f["form"]["Tradition_Param"]["nAreaFilter"])
{
_config.traditionDet.nAreaFilter = value_f["form"]["Tradition_Param"]["nAreaFilter"].asFloat();
}
if (value_f["form"]["Tradition_Param"]["nCountFilter"])
{
_config.traditionDet.nCountFilter = value_f["form"]["Tradition_Param"]["nCountFilter"].asInt();
}
// 2、读取区域点
{
auto value_region = value_f["form"]["Tradition_Param"]["detArea"];
if (value_region.isArray())
{
for (int idx = 0; idx < value_region.size(); idx++)
{
cv::Point p;
p.x = value_region[idx][0].asInt();
p.y = value_region[idx][1].asInt();
_config.traditionDet.detArea.emplace_back(p);
}
if (_config.traditionDet.detArea.size() > 0)
{
_config.traditionDet.detArea_ROI = boundingRect(_config.traditionDet.detArea);
}
}
}
if (value_f["form"]["Tradition_Param"]["bdetArea"])
{
_config.traditionDet.bdetArea = value_f["form"]["Tradition_Param"]["bdetArea"].asFloat();
}
}
else
{
_config.traditionDet.Init();
}
// _config.traditionDet.print("traditionDet");
// getchar();
}
if ("Big_NG" == strCode)
{
auto value_f = value;

@ -96,12 +96,9 @@ public:
void ProcessImages(bool bDrawResult);
// ========== 独立检测/分类接口 ==========
// 传统检测:对单张图做完整预处理+自适应二值化,输出残点二值图
// 返回: 0=成功, -1=无产品/输入为空
int TraditionalDetect(const cv::Mat& img, cv::Mat& blobImg);
// 传统分类:对残点二值图做连通域分析+缺陷分类,结果写入 m_vecDefectInfo
// 前提: 已调用 TraditionalDetect内部 m_matBlur 已就绪)
// 返回: 分类到的缺陷数量,<0 表示异常
// 传统检测,输出残点二值图 0=成功, -1=无产品/输入为空
int TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& blobImg);
// 传统分类,结果写入 m_vecDefectInfo
int TraditionalClassify(const cv::Mat& blobImg);
private:

@ -15,9 +15,10 @@ protected:
};
CTcsCheck::CTcsCheck()
: m_nInitStart(0)
, m_bSystemExit(0)
, m_nInitEnd(0)
{
memset(&m_nInitStart, 0, offsetof(CTcsCheck, m_nInitEnd) - offsetof(CTcsCheck, m_nInitStart) + sizeof(m_nInitEnd));
m_cpCfg.nAreaLowFilter = 80;
m_cpCfg.nBlockSize = 100;
m_cpCfg.nDiscardTop = 170;
@ -310,32 +311,37 @@ cv::Mat CTcsCheck::DrawBlobInfoImage(const cv::Mat& imgCrop, const cv::Mat& imgB
return cropColor;
}
// ============================================================
// TraditionalDetect — 独立检测接口
// 独立检测接口
// 对单张图做:阈值定位→裁剪→缩放→高斯模糊→自适应二值化
// 输出残点二值图 blobImg内部缓存 m_matBlur 供后续分类
// 返回: 0=成功, -1=无产品或输入异常
// ============================================================
int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Mat& blobImg)
int CTcsCheck::TraditionalDetect(const cv::Mat& img, cv::Rect detRoi, cv::Mat& blobImg)
{
if (img.empty()) return -1;
// if (img.empty()) return -1;
m_matLoad = img;
m_sizeImage = img.size();
cv::Rect rtCrop = detRoi;
if(detRoi.size() == img.size())
{
m_sizeImage = img.size();
// 1. 全局阈值 → 产品区域定位
cv::Mat matBinary;
cv::threshold(m_matLoad, matBinary, m_cpCfg.nAreaLowFilter, 255, cv::THRESH_BINARY);
// 1. 全局阈值 → 产品区域定位
cv::Mat matBinary;
cv::threshold(m_matLoad, matBinary, m_cpCfg.nAreaLowFilter, 255, cv::THRESH_BINARY);
// 2. 获取最大连通域外接矩形
cv::Rect rtValid = GetBoundingRect(matBinary);
if (rtValid == cv::Rect(0, 0, 0, 0))
{
blobImg = cv::Mat();
return -1;
}
// 2. 获取最大连通域外接矩形
cv::Rect rtValid = GetBoundingRect(matBinary);
if (rtValid == cv::Rect(0, 0, 0, 0))
{
blobImg = cv::Mat();
return -1;
}
// 3. 裁剪边缘
cv::Rect rtCrop = GetCropArea(rtValid);
// 3. 裁剪边缘
rtCrop = GetCropArea(rtValid);
}
cv::Mat matCrop = m_matLoad(rtCrop).clone();
// 4. 缩放

@ -5,6 +5,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include <filesystem>
#include "CheckUtil.hpp"
std::string ExtractFileNameWithoutExtension(const std::string &strImgPath)
{
@ -1083,10 +1084,6 @@ bool deal::ReadSystemConfig(const std::string &strPath)
}
m_system_param.Use_CPU_StartIdx = root["Use_CPU_StartIdx"].asInt();
// path
m_system_param.Analysis_Config_path = root["Analysis_Config_path"].asString();
m_system_param.Analysis_Config_path_Cam2 = root["Analysis_Config_path_Cam2"].asString();
m_system_param.Analysis_Config_path_Cam3 = root["Analysis_Config_path_Cam3"].asString();
m_system_param.Analysis_Config_path_Cam4 = root["Analysis_Config_path_Cam4"].asString();
m_system_param.config_Root_Path = root["Config_Root_Path"].asString();
m_system_param.Check_Config_path = root["Check_Config_path"].asString();
@ -1095,8 +1092,83 @@ bool deal::ReadSystemConfig(const std::string &strPath)
m_system_param.preCHeck_defect = root["preCHeck_defect"].asInt();
m_nCurUseCPUIDX = m_system_param.Use_CPU_StartIdx;
// 从 Config_Root_Path 目录下自动扫描匹配 param_*.json 文件,映射到各相机
ScanConfigPaths();
return m_system_param.valid();
}
int deal::ScanConfigPaths()
{
std::string configRoot = m_system_param.config_Root_Path;
if (configRoot.empty())
{
printf("ScanConfigPaths: Config_Root_Path is empty\n");
return -1;
}
// 确保路径以 / 结尾
if (configRoot.back() != '/')
{
configRoot += '/';
}
// 相机名称与对应存储指针的映射: Cam1=BCA, Cam2=BTA, Cam3=DCA, Cam4=DTA
struct CamPathMapping
{
std::string camName;
std::string *targetPath;
};
CamPathMapping mappings[] = {
{"BCA", &m_system_param.Analysis_Config_path},
{"BTA", &m_system_param.Analysis_Config_path_Cam2},
{"DCA", &m_system_param.Analysis_Config_path_Cam3},
{"DTA", &m_system_param.Analysis_Config_path_Cam4},
};
// 先清空所有路径
for (auto &m : mappings)
{
*m.targetPath = "";
}
if (!std::filesystem::exists(configRoot))
{
printf("ScanConfigPaths: directory does not exist: %s\n", configRoot.c_str());
return -1;
}
int foundCount = 0;
for (const auto &entry : std::filesystem::directory_iterator(configRoot))
{
if (!entry.is_regular_file())
continue;
std::string filename = entry.path().filename().string();
// 匹配 param_XXX.json 格式
if (filename.size() < 11) // "param_X.json" 最少 11 字符
continue;
if (filename.substr(0, 6) != "param_" || filename.substr(filename.size() - 5) != ".json")
continue;
// 提取相机名称: param_BCA.json → BCA
std::string camName = filename.substr(6, filename.size() - 11);
for (auto &m : mappings)
{
if (camName == m.camName)
{
*m.targetPath = entry.path().string();
printf("ScanConfigPaths: auto-discovered %s config → %s\n",
m.camName.c_str(), m.targetPath->c_str());
foundCount++;
break;
}
}
}
printf("ScanConfigPaths: found %d param config file(s) in %s\n", foundCount, configRoot.c_str());
return foundCount > 0 ? 0 : -1;
}
int deal::GetJcImageInfo(std::string strpath, std::vector<JC_IMAGE_INFO_> &jcImageInfoList)
{
LoadOfflineCheckImg(strpath);

@ -578,6 +578,8 @@ private:
void GetDealResultToQueu();
// 加载系统配置文件
bool ReadSystemConfig(const std::string &strPath);
// 从 Config_Root_Path 自动扫描匹配 param_*.json 文件
int ScanConfigPaths();
int GetJcImageInfo(std::string strpath, std::vector<JC_IMAGE_INFO_> &jcImageInfoList);
int ReadTestImgaData();

Loading…
Cancel
Save