You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2430 lines
69 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "deal.h"
#include "json/json.h"
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include "CheckUtil.hpp"
#include "LoadImage.hpp" // #include "LoadImage.h"
std::string ExtractFileNameWithoutExtension(const std::string &strImgPath)
{
// 查找最后一个斜杠 '/' 或 '\' 的位置
size_t lastSlashPos = strImgPath.find_last_of("/\\");
// 如果没有找到斜杠,默认整个字符串是文件名
std::string fileName = (lastSlashPos == std::string::npos)
? strImgPath
: strImgPath.substr(lastSlashPos + 1);
// 查找最后一个点 '.' 的位置
size_t lastDotPos = fileName.find_last_of('.');
// 如果没有找到点号,或者点号在第一个字符的位置,则返回完整文件名
if (lastDotPos == std::string::npos || lastDotPos == 0)
{
return fileName;
}
// 返回去掉扩展名的部分
return fileName.substr(0, lastDotPos);
}
std::string GetFileName(const std::string &strImgPath)
{
// 查找最后一个斜杠 '/' 或 '\' 的位置
size_t lastSlashPos = strImgPath.find_last_of("/\\");
// 如果没有找到斜杠,默认整个字符串是文件名
std::string fileName = (lastSlashPos == std::string::npos)
? strImgPath
: strImgPath.substr(lastSlashPos + 1);
// 查找最后一个点 '.' 的位置
return fileName;
}
bool customSort(const AI_Det_Channel_ &a, const AI_Det_Channel_ &b)
{
// 特定规则排序: "a" 排第一, "b" 排第二, "L" 排最后
if (a.strChannel == "Up-Particle" && b.strChannel != "Up-Particle")
{
return true; // "a" 排在前面
}
if (a.strChannel != "Up-Particle" && b.strChannel == "Up-Particle")
{
return false;
}
if (a.strChannel == "Down-Particle" && b.strChannel != "Down-Particle" && b.strChannel != "Up-Particle")
{
return true; // "b" 排第二
}
if (a.strChannel != "Down-Particle" && b.strChannel == "Down-Particle")
{
return false;
}
if (a.strChannel == "L0" && b.strChannel != "L0" && b.strChannel != "Up-Particle" && b.strChannel != "Down-Particle")
{
return false; // "L" 排最后
}
if (a.strChannel != "L0" && b.strChannel == "L0")
{
return true;
}
// 对其他情况使用字典顺序排序
return a.strChannel < b.strChannel;
}
// 定义图片读取函数
void readImage(const std::string &filename)
{
cv::Mat image = cv::imread(filename);
if (image.empty())
{
std::cerr << "Error: Unable to read image " << filename << std::endl;
return;
}
// // 在这里可以添加对图像的处理操作
// // 例如:显示图像、保存图像、进行其他处理等
// // 示例:显示图像
// cv::imshow(filename, image);
// cv::waitKey(0);
// cv::destroyWindow(filename);
}
int _sysmkdir_1(const std::string &dir)
{
int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (ret && errno == EEXIST)
{
// printf("dir[%s] already exist.\n", dir.c_str());
}
else if (ret)
{
printf("create dir[%s] error: %d %s\n", dir.c_str(), ret, strerror(errno));
return -1;
}
else
{
printf("create dir[%s] success.\n", dir.c_str());
}
return 0;
}
std::string __getParentDir_1(const std::string &dir)
{
std::string pdir = dir;
if (pdir.length() < 1 || (pdir[0] != '/'))
{
return "";
}
while (pdir.length() > 1 && (pdir[pdir.length() - 1] == '/'))
pdir = pdir.substr(0, pdir.length() - 1);
pdir = pdir.substr(0, pdir.find_last_of('/'));
return pdir;
}
int _sysmkdirs_1(const std::string &dir)
{
int ret = 0;
if (dir.empty())
return -1;
std::string pdir;
if ((ret = _sysmkdir_1(dir)) == -1)
{
pdir = __getParentDir_1(dir);
if ((ret = _sysmkdirs_1(pdir)) == 0)
{
ret = _sysmkdirs_1(dir);
}
}
return ret;
}
long getcurTime()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000;
}
deal::deal()
{
nLastCheckAnalysisyThreadIdx = 0;
m_nCamIdx = 0;
m_nCurUseCPUIDX = 0;
m_DetResult.Init();
for (int i = 0; i < READ_IMG_THREAD_NUM; i++)
{
m_nReadStausList[i] = ReadImg_Status_IDE;
}
m_nreadImg_Stop = false;
m_strCurDate = "";
m_nReadThread_type = READ_THREAD_TYPE_NULL;
for (int i = 0; i < Status_Type_Count; i++)
{
m_DetStatusList[i] = Thread_Status_IDE;
}
m_nTestNum = 9999999;
m_pALLImgCheckAnalysisy = NULL;
// ✅ 新增:初始化产品检测线程池
m_bProductReadExit = false;
m_nProductReadThreadNum = READ_PRODUCT_THREAD_NUM;
m_nProductQueueMaxSize = PRODUCT_QUEUE_MAX_SIZE;
m_nCheckNotifiedCount = 0;
}
deal::~deal()
{
// ✅ 新增:销毁产品检测线程池
DestroyProductReadThreadPool();
}
int deal::start()
{
std::string strdate = CheckUtil::getCurrentDate();
printf("===== %s\n", strdate.c_str());
int re = Init();
// getchar();
// 配置系统运行的cup核数。
if (re != 0)
{
return 1;
}
// 解析图片,并保存
if (Process_Run_SaveImg == runConfig.run_Type)
{
return 1;
}
else if (runConfig.run_Type == Process_Run_ReJson)
{
ReJson_ALL();
return 0;
}
else
{
DetImg();
}
return 0;
}
int deal::Init()
{
InitCPUIDX();
// 读取系统配置文件
int re = ReadSystemConfig(FILE_SYSTEM_RUN_CONFIG);
if (re == false)
{
printf("ReadSystemConfig error\n");
return 1;
}
// 加载 检测 的通道 图片名称
std::string strchannlePath = m_system_param.config_Root_Path + "surface_list.json";
m_image_ReadChannel.ReadJsonConfig(strchannlePath);
// getchar();
if (Process_Run_SaveImg == runConfig.run_Type)
{
return 0;
}
// getchar();
// 初始化参数模块
InitConfig();
printf("\n\n\n\n\n\n\n\n\n\n\n**********************************************************LoadCheckImgConfig\n");
// 载入参数
re = LoadCheckImgConfig();
if (re != 0)
{
printf("read config error\n");
return 2;
}
printf("\n\n**********************************************************InitCheckAnalysisy\n");
// 初始化检测库
InitCheckAnalysisy();
printf("\n\n\n\n\n\n\n\n\n\n\n**********************************************************Check\n");
return 0;
}
int deal::LoadCheckImgConfig()
{
int re = LoadAnalysisConfig();
if (re != 0)
{
return re;
}
return 0;
}
int deal::InitCheckAnalysisy()
{
int re = 0;
int m_nMAX_GPU_NUM = MAX_GPU_NUM;
if (m_nMAX_GPU_NUM <= 0)
{
printf(">>>>error GPU error %d \n", m_nMAX_GPU_NUM);
return 2;
}
int startidx = m_CPUInfo[THREAD_CPU_CheckSo].startIdx;
int cpunum = m_CPUInfo[THREAD_CPU_CheckSo].num;
m_RunConfig.nCpu_start_Idx = startidx;
m_RunConfig.nCpu_num = cpunum;
m_RunConfig.nWorkIdx = m_system_param.nWorkIdx;
for (int i = 0; i < MAX_GPU_NUM; i++)
{
m_RunConfig.UseGPUList[i] = m_system_param.GPU_Device_ID_List[i];
printf("gpu %d %d\n", i, m_RunConfig.UseGPUList[i]);
}
m_pALLImgCheckAnalysisy = ALLImgCheckBase::GetInstance();
re = m_pALLImgCheckAnalysisy->UpdateConfig((void *)&m_RunConfig, CHECK_CONFIG_Run);
re = m_pALLImgCheckAnalysisy->UpdateConfig((void *)m_pConfigManager, CHECK_CONFIG_Module);
VERSION_INFO tm;
tm.InterfaceVersion = ALL_INTERFACE_VERSION;
tm.ConfigVersion = CONFIGBASE_VERSION;
tm.ResultVersion = RESULT_VERSION;
re = m_pALLImgCheckAnalysisy->RunStart(&tm);
if (re != 0)
{
printf("RunStart Fail %d\n", re);
return re;
}
printf(">>>> ImgCheckThread Start Succ \n");
return 0;
}
int deal::InitConfig()
{
m_pConfigManager = ConfigManagerBase::GetInstance();
return 0;
}
int deal::InitSaveImgPath()
{
return 0;
}
int deal::LoadCheckConfig()
{
return 0;
}
int deal::LoadAnalysisConfig()
{
if (!m_pConfigManager)
{
return 1;
}
std::string folder = m_system_param.config_Root_Path;
int re = m_pConfigManager->LoadAnalysisConfig(folder);
for (const auto &pair : m_pConfigManager->Config_instances_)
{
std::cout << "cam: " << pair.first << std::endl;
}
// getchar();
return re;
}
int deal::StartThread(THREAD_RUN_TYPE type)
{
m_bExit = false;
// 只读图线程
if (type == THREAD_RUN_ALL)
{
// 开启检测线程
ptr_DealImgthread = std::make_shared<std::thread>(&deal::DealImg, this);
// 结果处理线程
// ptr_Resultthread = std::make_shared<std::thread>(&deal::ResultThread, this);
for (int i = 0; i < Save_IMG_THREAD_NUM; ++i)
{
// 创建线程,并使用 std::make_shared 创建 shared_ptr
std::shared_ptr<std::thread> threadPtr = std::make_shared<std::thread>(&deal::ResultThread, this, i);
// 将 shared_ptr 添加到 vector 中
ptr_ResultthreadList.push_back(threadPtr);
}
// 结果拷贝线程
ptr_GetResultthread = std::make_shared<std::thread>(&deal::GetResultThread, this);
}
InitProductReadThreadPool();
// for (int i = 0; i < READ_IMG_THREAD_NUM; ++i)
// {
// // 创建线程,并使用 std::make_shared 创建 shared_ptr
// std::shared_ptr<std::thread> threadPtr = std::make_shared<std::thread>(&deal::ReadImgThread, this, i);
// // 将 shared_ptr 添加到 vector 中
// threadArray.push_back(threadPtr);
// }
return 0;
}
int deal::StopThread()
{
return 0;
}
int deal::preCheck()
{
printf(">>> preCheck start \n");
std::string strRoot = "../data/img/t1";
std::string strProductID = "";
{
READ_IMG_INFO read;
readTestImg(read);
strRoot = read.strpath;
strProductID = read.strproduct;
printf("strSearchImg strRoot %s\n", strRoot.c_str());
std::ifstream file123(strRoot);
bool bhave = file123.good();
if (!bhave)
{
printf("read img path error %d %s\n", bhave, strRoot.c_str());
return 1;
}
}
// 获取图片路径
std::string strSearchImg = strRoot;
LoadImage loader;
LoadConfig config;
config.Init();
printf("开始加载图片...\n\n");
std::vector<LoadProductImages> products = loader.LoadALLImg(strSearchImg, config, &m_image_ReadChannel, strProductID);
if (products.empty())
{
printf("未找到任何图片!\n");
printf("错误信息:%s\n", loader.getLastError().c_str());
return 1;
}
printf("加载完成!\n");
printf("产品数量:%zu\n", products.size());
printf("图片总数:%zu\n\n", loader.getTotalLoaded());
for (size_t i = 0; i < products.size(); i++)
{
products[i].print("产品" + std::to_string(i + 1));
}
long t1 = getcurTime();
for (size_t i = 0; i < products.size(); i++)
{
CheckProduct(products[i]); // 处理单个产品
int getresultNum = 0;
// getchar();
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟消费过程
// 处理结果
std::shared_ptr<CheckResult> checkResult;
int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult);
saveImg("/home/aidlux/BOE/FOG/testresult/", checkResult);
getresultNum++;
if (getresultNum == m_nProductSuccessCount)
{
break;
}
}
}
// }
printf(">>> ALL preCheck complete \n");
return 0;
}
std::string deal::readTestImg()
{
std::string strRoot = "../data/img/TestImg.json";
printf("Reading Img config %s\n", strRoot.c_str());
Json::CharReaderBuilder builder;
builder["collectComments"] = true;
Json::Value root;
std::string err;
std::ifstream ifs(strRoot);
if (!ifs.is_open())
{
printf("error:file is open\n");
return "";
}
if (!Json::parseFromStream(builder, ifs, &root, &err))
{
printf("error:parseFromStream\n");
return "";
}
std::string imgpath = "";
imgpath = root["TestImg_Path"].asString();
return imgpath;
}
int deal::readTestImg(READ_IMG_INFO &read)
{
std::string strRoot = "../data/img/TestImg.json";
printf("Reading Img config %s\n", strRoot.c_str());
Json::CharReaderBuilder builder;
builder["collectComments"] = true;
Json::Value root;
std::string err;
std::ifstream ifs(strRoot);
if (!ifs.is_open())
{
printf("error:file is open\n");
return 1;
}
if (!Json::parseFromStream(builder, ifs, &root, &err))
{
printf("error:parseFromStream\n");
return 1;
}
std::string imgpath = "";
read.strpath = root["TestImg_Path"].asString();
read.strproduct = root["ProductID"].asString();
return 0;
}
int deal::repeatCheck()
{
return 0;
}
int deal::saveImg(std::string strpath, std::shared_ptr<CheckResult> result)
{
std::string strroot = strpath;
std::string strroot_qx = strpath;
if (result->in_shareImage->imgstr != "")
{
strroot += result->in_shareImage->imgstr;
strroot += "/";
strroot_qx += result->in_shareImage->imgstr;
strroot_qx += "/";
}
if (strpath != "")
{
strroot_qx += "qx/";
if (result->nProductResult != 0)
{
strroot += "NG/";
}
else
{
strroot += "OK/";
}
if (result->in_shareImage->strImgProductID != "")
{
strroot += result->in_shareImage->strImgProductID + "/";
}
if (result->nresult != 0)
{
strroot += "NG/";
}
else
{
if (result->nYS_result != 0)
{
strroot += "OK/YS/";
}
else
{
strroot += "OK/OK/";
}
}
}
printf("result->nresult %d %d \n", result->nresult, result->nYS_result);
printf("%s\n", strroot.c_str());
_sysmkdirs_1(strroot);
std::string str_saveName = "";
// getchar();
if (result->in_shareImage->strImgProductID != "")
{
strroot += result->in_shareImage->strImgProductID;
str_saveName += result->in_shareImage->strImgProductID;
}
if (result->in_shareImage->strImgName != "")
{
strroot += "_" + result->in_shareImage->strImgName;
str_saveName += "_" + result->in_shareImage->strImgName;
}
{
strroot += "_" + result->in_shareImage->strCameraName;
str_saveName += "_" + result->in_shareImage->strCameraName;
strroot += "_" + result->in_shareImage->strChannel;
str_saveName += "_" + result->in_shareImage->strChannel;
}
writeLog(strroot, result->det_LogList);
WriteJsonString(strroot, result->strResultJson);
// printf("%s \n", strroot.c_str());
std::string str = strroot + "_RE_Resultimg.png";
if (!result->resultimg.empty())
{
cv::imwrite(str, result->resultimg);
}
std::string str123 = strroot + "_RE_CutImg.png";
if (!result->cutSrcimg.empty())
{
cv::imwrite(str123, result->cutSrcimg);
}
std::string str123r = strroot + "_RE_CutDrawImg.png";
if (!result->SrcResultImg.empty())
{
cv::imwrite(str123r, result->SrcResultImg);
}
std::string strMask = strroot + "_RE_AIMask.png";
if (!result->resultMaskImg.empty())
{
cv::imwrite(strMask, result->resultMaskImg);
}
std::string str_qx;
printf("result->qxImageResult.size() %ld \n", result->qxImageResult.size());
for (int i = 0; i < result->qxImageResult.size(); i++)
{
std::string str = strroot + "_RE_" + std::to_string(i) + "_Src.png";
if (!result->qxImageResult.at(i).srcImg.empty())
{
cv::imwrite(str, result->qxImageResult.at(i).srcImg);
}
str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/";
printf("-1-- %s\n", str_qx.c_str());
_sysmkdirs_1(str_qx);
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_Src.png";
// printf("-2-- %s\n", str_qx.c_str());
if (!result->qxImageResult.at(i).srcImg.empty())
{
cv::imwrite(str_qx, result->qxImageResult.at(i).srcImg);
}
str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_Small.png";
if (!result->qxImageResult.at(i).resizeImg.empty())
{
cv::imwrite(str_qx, result->qxImageResult.at(i).resizeImg);
}
{
str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_AI_In.png";
if (!result->qxImageResult.at(i).AI_in_Img.empty())
{
cv::imwrite(str_qx, result->qxImageResult.at(i).AI_in_Img);
}
str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_AI_In_mask.png";
if (!result->qxImageResult.at(i).AI_out_img.empty())
{
cv::imwrite(str_qx, result->qxImageResult.at(i).AI_out_img);
}
}
// printf("-1111-- %s\n", str_qx.c_str());
std::string str1 = strroot + "_RE_" + std::to_string(i) + "_Small.png";
if (!result->qxImageResult.at(i).resizeImg.empty())
{
cv::imwrite(str1, result->qxImageResult.at(i).resizeImg);
}
}
printf("result->YS_ImageResult.size() %ld\n", result->YS_ImageResult.size());
for (int i = 0; i < result->YS_ImageResult.size(); i++)
{
std::string str = strroot + "_RE_" + std::to_string(i) + "_YS_Src.png";
if (result->YS_ImageResult.at(i).srcImg.empty())
{
printf("resqwwwwwwwwwwwwwwwult->YS_ImageResult.size() %ld \n", result->YS_ImageResult.size());
}
if (!result->YS_ImageResult.at(i).srcImg.empty())
{
cv::imwrite(str, result->YS_ImageResult.at(i).srcImg);
}
str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/";
// printf("-3-- %s\n", str_qx.c_str());
_sysmkdirs_1(str_qx);
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_Src.png";
// printf("-4-- %s\n", str_qx.c_str());
if (!result->YS_ImageResult.at(i).srcImg.empty())
{
cv::imwrite(str_qx, result->YS_ImageResult.at(i).srcImg);
}
str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_Small.png";
if (!result->YS_ImageResult.at(i).resizeImg.empty())
{
cv::imwrite(str_qx, result->YS_ImageResult.at(i).resizeImg);
}
{
str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_AI_In.png";
if (!result->YS_ImageResult.at(i).AI_in_Img.empty())
{
cv::imwrite(str_qx, result->YS_ImageResult.at(i).AI_in_Img);
}
str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/";
str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_AI_In_mask.png";
if (!result->YS_ImageResult.at(i).AI_out_img.empty())
{
cv::imwrite(str_qx, result->YS_ImageResult.at(i).AI_out_img);
}
}
// printf("-1111-- %s\n", str_qx.c_str());
std::string str1 = strroot + "_RE_" + std::to_string(i) + "_YS_Small.png";
if (!result->YS_ImageResult.at(i).resizeImg.empty())
{
cv::imwrite(str1, result->YS_ImageResult.at(i).resizeImg);
}
}
return 0;
}
int deal::writeLog(std::string strSavePath, std::vector<std::string> logList)
{
std::string str = strSavePath + ".txt";
// 打开文件
std::ofstream outFile(str);
// 检查文件是否成功打开
if (!outFile)
{
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 将vector中的内容写入文件
for (const auto &str : logList)
{
// printf("%s \n",str.c_str());
outFile << str << std::endl;
}
// 关闭文件
outFile.close();
return 0;
}
int deal::WriteJsonString(std::string strSavePath, std::string strjson)
{
std::string str = strSavePath + ".json";
// 打开文件
std::ofstream outFile(str);
// 检查文件是否成功打开
if (!outFile)
{
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 将vector中的内容写入文件
outFile << strjson << std::endl;
// 关闭文件
outFile.close();
return 0;
}
void deal::ResultThread(int id)
{
std::vector<int> vi;
int startidx = m_CPUInfo[THREAD_CPU_Main_saveImg].startIdx;
int cpunum = m_CPUInfo[THREAD_CPU_Main_saveImg].num;
// for (int i = 0; i < cpunum; i++)
// {
// vi.push_back(startidx + i);
// }
vi.push_back(startidx + id);
auto nRet = set_cpu_id(vi);
printf("THREAD_CPU_Main_saveImg %d bind cpu ret %d startidx %d num %d\n", id, nRet, startidx + id, 1);
int re = 0;
cv::Mat detImg;
int kkkkk = 0;
static int saveidx = 0;
while (!m_bExit)
{
std::shared_ptr<CheckResult> dealResult;
mutex_Result_list.lock();
if (m_Result_list.size() > 0)
{
dealResult = m_Result_list.front();
m_Result_list.pop();
if (m_Result_list.size() > 10)
{
printf("Result_list size %ld \n", m_Result_list.size());
}
mutex_Result_list.unlock();
}
else
{
mutex_Result_list.unlock();
usleep(10000);
continue;
}
{
updataResltInfo(dealResult);
}
{
if (true)
{
// 存图
std::string savepath = "/home/aidlux/BOE/FOG/Detsave/";
saveImg(savepath, dealResult);
// saveImg("/home/aidlux/BOE/ResultImg/", dealResult);
}
{
// 存 检测统计 日志
mutex_DetResult_.lock();
m_DetResult.print(false);
std::string strlog = "/home/aidlux/BOE/FOG/ResultImg/";
if (m_strCurDate != "")
{
strlog += m_strCurDate;
strlog += "/result";
}
else
{
strlog += "/result";
}
writeLog(strlog, m_DetResult.strlist);
mutex_DetResult_.unlock();
}
}
usleep(5 * 1000);
}
}
int deal::set_cpu_id(const std::vector<int> &cpu_set_vec)
{
// for cpu affinity
int nRet = 0;
#ifdef __linux
cpu_set_t _cur_cpu_set;
CPU_ZERO(&_cur_cpu_set);
for (auto _id : cpu_set_vec)
{
CPU_SET(_id, &_cur_cpu_set);
}
if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set))
{
perror("set cpu affinity failed: ");
printf("Warning: set cpu affinity failed ... ...\n");
nRet = -1;
}
#endif //__linux
return nRet;
}
void deal::GetDealResultToQueu()
{
// 处理结果
std::shared_ptr<CheckResult> checkResult;
if (!m_pALLImgCheckAnalysisy)
{
return;
}
int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult);
if (re == 0)
{
mutex_Result_list.lock();
m_Result_list.push(checkResult);
mutex_Result_list.unlock();
}
else
{
printf("Check error >>>>>>>>>>>>>>>>> \n");
}
return;
}
bool deal::ReadSystemConfig(const std::string &strPath)
{
printf("Reading system config %s\n", strPath.c_str());
Json::CharReaderBuilder builder;
builder["collectComments"] = true;
Json::Value root;
std::string err;
std::ifstream ifs(strPath);
if (!ifs.is_open())
{
printf("error:file is open\n");
return false;
}
if (!Json::parseFromStream(builder, ifs, &root, &err))
{
printf("error:parseFromStream\n");
return false;
}
m_system_param.Use_CPU_StartIdx = root["Use_CPU_StartIdx"].asInt();
m_system_param.nWorkIdx = root["Detect_Work_Idx"].asInt();
m_system_param.config_Root_Path = root["Config_Root_Path"].asString();
for (int i = 0; i < 4; i++)
m_system_param.GPU_Device_ID_List[i] = -1;
if (root.isMember("GPU_Device_ID_List"))
{
auto &arr = root["GPU_Device_ID_List"];
for (int i = 0; i < arr.size() && i < 4; i++)
{
m_system_param.GPU_Device_ID_List[i] = arr[i].asInt();
}
}
m_nCurUseCPUIDX = m_system_param.Use_CPU_StartIdx;
return m_system_param.valid();
}
int deal::GetJcImageInfo(std::string strpath, std::vector<JC_IMAGE_INFO_> &jcImageInfoList)
{
LoadOfflineCheckImg(strpath);
jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end());
// 遍历每一套图片
for (int idx = 0; idx < m_OffLineCheckImgNameList.size(); idx++)
{
std::string path = m_OffLineCheckImgNameList.at(idx);
JC_IMAGE_INFO_ tem;
int re = GetImgInfo_POL_ET(path, &tem);
}
// getchar();
return 0;
}
int deal::GetDetImageInfo(std::string strProductID, std::string strSearchImg, std::vector<JC_IMAGE_INFO_> &jcImageInfoList)
{
// 1、获取图片路径
std::vector<cv::String> img_paths;
std::string strs1 = strSearchImg + "/*.ytimage";
cv::glob(strs1, img_paths, true);
printf("%ld \n", img_paths.size());
jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end());
// 遍历每一套图片
for (int idx = 0; idx < img_paths.size(); idx++)
{
// printf("---- %d / %d %s----\n", idx, m_OffLineCheckImgNameList.size(), m_OffLineCheckImgNameList.at(idx).c_str());
std::string path = img_paths.at(idx);
JC_IMAGE_INFO_ tem;
int re = 0;
{
re = GetImgInfo_POL_ET(path, &tem);
if (re != 0)
{
continue;
}
}
tem.strProductID = strProductID;
jcImageInfoList.push_back(tem);
}
return 0;
}
int deal::GetImgInfo_POL_ET(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo)
{
if (pImageInfo == NULL)
{
return 1;
}
string strName = ExtractFileNameWithoutExtension(strImgPath);
printf("strName %s \n", strName.c_str());
size_t lastUnderscore = strName.rfind('_');
if (lastUnderscore == std::string::npos)
return 1; // 没有找到最后一个 '_'
std::string strImageChannel = strName.substr(0, lastUnderscore);
printf("strImageChannel %s\n", strImageChannel.c_str());
if (strImageChannel == "CA" || strImageChannel == "TA")
{
}
else
{
return 1;
}
pImageInfo->strchannelName = strImageChannel;
pImageInfo->strName = strName;
pImageInfo->strPath = strImgPath;
pImageInfo->strCamID = "0";
printf("strImgPath %s strName %s strChannel %s\n", strImgPath.c_str(), strName.c_str(), strImageChannel.c_str());
// 使用 find 函数检查是否包含 "_左"
return 0;
}
int deal::GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo)
{
if (pImageInfo == NULL)
{
return 1;
}
string strImageChannel = ExtractFileNameWithoutExtension(strImgPath);
printf("strImageChannel %s\n", strImageChannel.c_str());
std::string strChannle = m_image_ReadChannel.strDetName(strImageChannel);
if (strChannle == "")
{
return 1;
}
pImageInfo->strchannelName = strChannle;
pImageInfo->strName = strChannle;
pImageInfo->strPath = strImgPath;
pImageInfo->strCamID = "0";
// printf("strImgPath %s strChannel %s\n", strImgPath.c_str(), strChannle.c_str());
// 使用 find 函数检查是否包含 "_左"
if (strImgPath.find("_工位右") != std::string::npos)
{
pImageInfo->strCamID = "1";
;
}
return 0;
}
int deal::ReadTestImgaData()
{
std::string strPath = "../data/testImg.json";
printf("ReadTestImgaData config %s\n", strPath.c_str());
Json::CharReaderBuilder builder;
builder["collectComments"] = true;
Json::Value root;
std::string err;
std::ifstream ifs(strPath);
if (!ifs.is_open())
{
printf("error:file is open\n");
return false;
}
if (!Json::parseFromStream(builder, ifs, &root, &err))
{
printf("error:parseFromStream\n");
return false;
}
m_TestJC_ImageDate.erase(m_TestJC_ImageDate.begin(), m_TestJC_ImageDate.end());
{
auto value = root["img_date"];
if (value.isObject())
{
auto arr = value["date"];
std::cout << arr << std::endl;
if (arr.isArray())
{
// 遍历数组中的每个元素
for (int i = 0; i < arr.size(); i++)
{
// 读取对象中的属性值
std::string strdata = arr[i].asString();
m_TestJC_ImageDate.push_back(strdata);
// 输出属性值
std::cout << "date: " << strdata << std::endl;
}
}
}
}
// getchar();
return 0;
}
int deal::InitDetData()
{
m_read_ImgNum = 0;
return 0;
}
int deal::InsertDetResult(ReadImgInfo tem)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_DetResult]);
m_DetResultList.push_back(tem);
return 0;
}
int deal::GetUpMaskImg(cv::Mat inImg, cv::Rect roi, cv::Mat &maskimg)
{
// 定义滑动窗口的大小和步长
int windowWidth = 128;
int windowHeight = 128;
int stepX = 110; // 横向步长
int stepY = 110; // 纵向步长
maskimg = cv::Mat(roi.height, roi.width, CV_8U, cv::Scalar(0));
int sx = roi.x;
int ex = roi.x + roi.width;
int sy = roi.y;
int ey = roi.y + roi.height;
cv::Rect detroi;
detroi.width = windowWidth;
detroi.height = windowHeight;
cv::Rect maskroi;
maskroi.width = windowWidth;
maskroi.height = windowHeight;
cv::Mat temmask;
// 遍历图像,使用滑动窗口
for (int y = sy; y <= ey; y += stepY)
{
detroi.y = y;
if (detroi.y + windowHeight > ey)
{
detroi.y = ey - windowHeight;
}
maskroi.y = detroi.y - sy;
for (int x = sx; x <= ex; x += stepX)
{
detroi.x = x;
if (detroi.x + windowWidth > ex)
{
detroi.x = ex - windowWidth;
}
maskroi.x = detroi.x - sx;
int thresholdValue = 30; // 初始阈值OTSU将自动计算
int maxVal = 255; // 最大值
double otsuThreshold;
cv::Scalar mean, stddev;
cv::meanStdDev(inImg(detroi), mean, stddev);
int varianceImg;
varianceImg = mean[0] + 1 * mean[0];
if (mean[0] > 100)
{
continue;
}
// 使用 OTSU 阈值处理
otsuThreshold = cv::threshold(inImg(detroi), temmask, thresholdValue, maxVal, cv::THRESH_BINARY | cv::THRESH_OTSU);
thresholdValue = otsuThreshold;
if (thresholdValue < 30)
{
thresholdValue = 30;
}
if (thresholdValue < varianceImg)
{
thresholdValue = varianceImg;
}
if (thresholdValue > 100)
{
continue;
}
// std::cout << "varianceImg value is: " << varianceImg << std::endl;
// std::cout << "OTSU threshold value is: " << otsuThreshold << std::endl;
// std::cout << "stddev[0] value is: " << stddev[0] << std::endl;
otsuThreshold = cv::threshold(inImg(detroi), maskimg(maskroi), thresholdValue, maxVal, cv::THRESH_BINARY);
// cv::threshold(inImg(detroi), maskimg(maskroi), thresholdValue, maxVal, cv::THRESH_BINARY + cv::THRESH_OTSU);
// 提取当前窗口
// cv::rectangle(inImg, detroi, cv::Scalar(255, 0, 0));
}
}
// cv::imwrite("inImg1123.png", inImg);
// cv::imwrite("maskimg.png", maskimg);
// getchar();
return 0;
}
int deal::ReJson()
{
return 0;
}
int deal::ReJson_ALL()
{
printf(">>> ReJson ALL start \n");
// 1、获取所有的json
std::vector<cv::String> img_paths;
cv::glob(runConfig.filePath + "/*.json", img_paths, true);
if (img_paths.size() <= 0)
{
printf("json file is NULL \n");
return 1;
/* code */
}
// 用map存储每个id对应的vector
std::unordered_map<std::string, std::vector<cv::String>> ProductJsonList;
// 遍历路径并按照ID分组
for (const auto &path : img_paths)
{
// 获取路径中的 ID 部分(即文件夹名部分)
size_t start_pos = path.find_last_of("/") + 1;
size_t end_pos = path.find("_", start_pos);
std::string id = path.substr(start_pos, end_pos - start_pos);
// printf("id %s\n",id.c_str());
// 将文件路径加入对应 ID 的vector中
ProductJsonList[id].push_back(path);
}
for (const auto &product : ProductJsonList)
{
std::cout << product.first << " => " << product.second.size() << std::endl;
std::vector<Json_Det_Path> jsonList;
std::string strProductName = product.first;
for (const auto &str : product.second)
{
{
// 2、获取第一个 名称
std::string strPath = str;
size_t lastSlashPos = strPath.find_last_of('/');
// 提取文件名(从最后一个斜杠之后的部分)
std::string filename = strPath.substr(lastSlashPos + 1);
// 查找文件名中的第一个下划线位置
size_t firstUnderscorePos = filename.find('_');
// 提取文件名中的名称部分(下划线之前的字符串)
std::string strProduct = filename.substr(0, firstUnderscorePos);
// printf("strProduct %s \n", strProduct.c_str());
if (strProduct == strProductName)
{
Json_Det_Path tem;
tem.strPath_Json = str;
tem.strPath_CutImg = str;
size_t pos = tem.strPath_CutImg.rfind(".json");
if (pos != std::string::npos)
{
// 替换 ".json" 为 "_RE_CutImg.png"
tem.strPath_CutImg.replace(pos, 5, "_RE_CutImg.png");
}
std::cout << " Path: " << tem.strPath_Json << std::endl;
std::cout << " Path: " << tem.strPath_CutImg << std::endl;
jsonList.push_back(tem);
}
}
}
ReJson_product(jsonList, strProductName);
}
// 获取要检测的 json 图片 list
printf(">>>>>>>>>>>>>>>>>>>> rejson ALL is Complete \n");
return 0;
}
int deal::DetImg()
{
// 单张检测
if (runConfig.det_Type == RUNTYPE_RUN_Pre)
{
m_nReadThread_type = READ_THREAD_TYPE_READIMG;
StartThread(THREAD_RUN_Only_ReadImg);
preCheck();
return 0;
}
m_nReadThread_type = READ_THREAD_TYPE_READIMG;
m_nSystemCheckType = CHECK_TYPE_OFFLING;
StartThread(THREAD_RUN_ALL);
// 文件夹套图处理
if (RUNTYPE_RUN_File == runConfig.det_Type ||
runConfig.det_Type == RUNTYPE_RUN_File_AI_TEST ||
runConfig.det_Type == RUNTYPE_RUN_File_Edge_Test_Save_Qx ||
runConfig.det_Type == RUNTYPE_RUN_File_Edge_Test_Save_ALL)
{
CheckFileImg(); // 检查文件图片
}
// getchar();
return 0;
}
/// @brief 检查文件图片
/// @detail 后续实现具体功能
/// @return 0 表示成功
int deal::CheckFileImg()
{
std::string root_dir = runConfig.filePath;
printf("测试目录:%s\n\n", root_dir.c_str());
LoadImage loader;
LoadConfig config;
config.Init();
config.max_products = runConfig.m_nTestNum;
if (config.max_products <= 0)
{
config.max_products = 9999999;
}
printf("开始加载图片...\n\n");
std::vector<LoadProductImages> products = loader.LoadALLImg(root_dir, config, &m_image_ReadChannel);
if (products.empty())
{
printf("未找到任何图片!\n");
printf("错误信息:%s\n", loader.getLastError().c_str());
return 1;
}
printf("加载完成!\n");
printf("产品数量:%zu\n", products.size());
printf("图片总数:%zu\n\n", loader.getTotalLoaded());
for (size_t i = 0; i < products.size(); i++)
{
products[i].print("产品" + std::to_string(i + 1));
}
// getchar();
for (size_t i = 0; i < products.size(); i++)
{
CheckProduct(products[i]); // 处理单个产品
}
printf("\n");
// TODO: 后续实现具体功能
// getchar();
return 0;
}
/// @brief 检查单个产品
/// @param product 产品信息(包含图片对列表)
/// @return 0 表示成功
int deal::CheckProduct(const LoadProductImages &product)
{
// 1. 统计图片对总数
size_t totalImgNum = product.images.size();
if (runConfig.det_Type == RUNTYPE_RUN_File_AI_TEST)
{
totalImgNum = 0;
for (const auto &image : product.images)
{
if (image.channel_name == "L255")
{
totalImgNum++;
}
}
}
if (totalImgNum == 0)
{
printf("[产品] %s 没有图片对\n", product.product_id.c_str());
return 0;
}
// 2. 重置计数器(重要!每个产品独立计数)
m_nProductPendingTasks = 0;
m_nProductSuccessCount = 0;
m_nProductFailCount = 0;
m_ProductFailedList.clear();
m_nCheckNotifiedCount = 0;
// 3. 打印产品信息
printf("\n");
printf("╔══════════════════════════════════════════════════════════\n");
printf("║ 产品:%s\n", product.product_id.c_str());
printf("║ 图片对数:%zu\n", totalImgNum);
printf("╚══════════════════════════════════════════════════════════\n\n");
// 4. 分发读图任务
printf("[任务分发] 开始向读图线程分发 %zu 个任务...\n", totalImgNum);
DistributeProductTasks(product);
printf("[任务分发] 完成\n\n");
// 5. 使用条件变量等待并处理通知队列
int processed = 0;
{
IN_IMG_Status_ temstatus = IN_IMG_Status_Start;
std::unique_lock<std::mutex> lock(m_checkNotifyMutex);
while (processed < (int)totalImgNum)
{
// 等待通知:队列非空 或 所有任务已完成
m_checkNotifyCV.wait_for(lock, std::chrono::milliseconds(100),
[this, &processed, totalImgNum]()
{
return !m_checkNotifyQueue.empty() || m_nCheckNotifiedCount.load() >= (int)totalImgNum;
});
// 消费队列中的所有通知
while (!m_checkNotifyQueue.empty())
{
auto info = m_checkNotifyQueue.front();
m_checkNotifyQueue.pop();
// 处理图片对
SendCheckImg(info, temstatus, false);
processed++;
if (IN_IMG_Status_Start == temstatus)
{
temstatus = IN_IMG_Status_Other;
}
}
}
// 注:不需要第二个 while 清理,因为第一个 while 退出时 processed == totalImgNum
// 队列中不可能还有未处理的项目(内层 while 已经消费完)
}
CheckImgNotifyInfo info;
info.productId = product.product_id;
SendCheckImg(info, IN_IMG_Status_End, true);
printf("\n");
// 6. 打印统计(不清理线程,继续下一个产品)
PrintProductStatistics(product);
// getchar();
return 0;
}
int deal::SendCheckImg(const CheckImgNotifyInfo &info, IN_IMG_Status_ status, bool bComplete)
{
// 发送结束标志
if (bComplete)
{
std::shared_ptr<shareImage> tem = std::make_shared<shareImage>();
tem->strImgProductID = info.productId;
tem->Status = -1;
if (m_pALLImgCheckAnalysisy)
{
m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(tem);
}
return 0;
}
// 图片读取有异常,处理失败的图片对
if (!info.success)
{
// 记录失败
FailedImgRecord record;
record.left_path = info.left_path;
record.right_path = info.right_path;
record.productId = info.productId;
record.channelName = info.channelName;
record.errorReason = info.errorReason;
RecordFailedImg(record);
m_nProductFailCount.fetch_add(1);
printf("[失败-%3d] %s | %s | %s\n",
info.taskIndex,
info.productId.c_str(),
info.channelName.c_str(),
info.errorReason.c_str());
return -1;
}
// printf("[%3d] %s | %d | %s | %s | %s | 左:%dx%d 右:%dx%d | 耗时:%ldms\n",
// info.taskIndex,
// info.productId.c_str(),
// info.camera_Num,
// info.cameraSide.c_str(),
// info.channelName.c_str(),
// info.imageName.c_str(),
// info.left_img.cols, info.left_img.rows,
// info.right_img.cols, info.right_img.rows,
// info.readTimeMs);
m_nProductSuccessCount.fetch_add(1);
std::shared_ptr<shareImage> tem = std::make_shared<shareImage>();
tem->strChannel = info.channelName;
// cv::imwrite(tem->strChannel + "_new_debug.png", info.left_img);
// return 0;
// cv::imwrite(tem->strChannel+".png",pDetImageInfo->img);
tem->nImgBigIdx = 0;
tem->strImgName = info.imageName;
tem->strImgProductID = info.productId;
tem->imgstr = m_strCurDate;
if (runConfig.bDebugSaveImg == 1)
{
tem->otherValue = 9;
}
tem->getImgTimeMs = getcurTime();
tem->Status = status;
tem->Det_Mode = DET_MODE_Det;
if (runConfig.det_Type == RUNTYPE_RUN_File_AI_TEST)
{
tem->Det_Mode = DET_MODE_EDGE;
}
if (runConfig.det_Type == RUNTYPE_RUN_File_Edge_Test_Save_Qx || runConfig.det_Type == RUNTYPE_RUN_File_Edge_Test_Save_ALL)
{
tem->ninstruct = 767;
if (runConfig.det_Type == RUNTYPE_RUN_File_Edge_Test_Save_ALL)
{
tem->ninstruct = 768;
}
}
{
if (!info.left_img.empty())
{
tem->img = info.left_img;
}
else if (!info.right_img.empty())
{
tem->img = info.right_img;
}
}
tem->strCameraName = info.cameraSide;
tem->camera_ID = 0;
if (runConfig.bDebugSaveImg == 1)
{
tem->bDebugsaveImg = true;
}
int re = 0;
if (m_pALLImgCheckAnalysisy)
{
bool bcontinue = false;
do
{
re = m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(tem);
if (re == 8)
{
bcontinue = true;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
else
{
bcontinue = false;
}
} while (bcontinue);
}
return re;
}
// ============ 产品检测线程池相关函数 ============
void deal::InitProductReadThreadPool()
{
printf("[线程池] 初始化产品检测线程池...\n");
// 创建 8 个读图线程
for (int i = 0; i < m_nProductReadThreadNum; i++)
{
auto thread = std::make_shared<std::thread>(
&deal::ProductReadImgThreadFunc, this, i);
m_productReadThreads.push_back(thread);
}
printf("[线程池] 创建完成 (%d 读图线程)\n", m_nProductReadThreadNum);
}
void deal::DestroyProductReadThreadPool()
{
printf("[线程池] 销毁产品检测线程池...\n");
// 通知所有线程退出
m_bProductReadExit = true;
m_productTaskCV.notify_all();
m_checkNotifyCV.notify_all();
// 等待读图线程结束
for (auto &thread : m_productReadThreads)
{
if (thread && thread->joinable())
{
thread->join();
}
}
m_productReadThreads.clear();
printf("[线程池] 销毁完成\n");
}
void deal::DistributeProductTasks(const LoadProductImages &product)
{
int taskIndex = 0;
for (const auto &image : product.images)
{
if (runConfig.det_Type == RUNTYPE_RUN_File_AI_TEST)
{
if (image.channel_name != "L255")
{
continue;
}
}
auto task = std::make_shared<ReadImgTask>();
task->productId = product.product_id;
task->channelName = image.channel_name;
task->imageName = image.image_name; // 图片名称
task->left_path = image.left_path;
task->right_path = image.right_path;
task->camera_Num = product.camera_Num;
task->cameraSide = image.camera_side;
task->taskIndex = taskIndex++;
// 如果队列满了,等待
{
std::unique_lock<std::mutex> lock(m_productTaskMutex);
m_productTaskCV.wait(lock, [this]()
{ return m_productTaskQueue.size() < (size_t)m_nProductQueueMaxSize || m_bProductReadExit; });
if (m_bProductReadExit)
{
break;
}
m_productTaskQueue.push(task);
m_nProductPendingTasks.fetch_add(1);
}
m_productTaskCV.notify_one();
}
}
std::shared_ptr<ReadImgTask> deal::GetProductTask()
{
std::shared_ptr<ReadImgTask> task;
std::unique_lock<std::mutex> lock(m_productTaskMutex);
if (m_productTaskCV.wait_for(lock, std::chrono::milliseconds(10),
[this]()
{ return !m_productTaskQueue.empty() || m_bProductReadExit; }))
{
if (m_productTaskQueue.empty())
{
return nullptr;
}
task = m_productTaskQueue.front();
m_productTaskQueue.pop();
}
return task;
}
void deal::ProductReadImgThreadFunc(int threadId)
{
while (!m_bProductReadExit)
{
auto task = GetProductTask();
if (task == nullptr)
{
continue;
}
CheckImgNotifyInfo info;
info.taskIndex = task->taskIndex;
info.productId = task->productId;
info.channelName = task->channelName;
info.imageName = task->imageName;
info.left_path = task->left_path;
info.right_path = task->right_path;
info.cameraSide = task->cameraSide; // 复制相机方位
info.camera_Num = task->camera_Num;
try
{
// 读取左图
long startTime = getcurTime();
cv::Mat left_img;
cv::Mat img16 = cv::imread(task->left_path, cv::IMREAD_UNCHANGED);
if (!img16.empty())
{
if (img16.type() != CV_8U)
{
// printf("=========== 1 %s\n", info.channelName.c_str());
cv::Mat img8;
cv::normalize(img16, img8, 0, 255, cv::NORM_MINMAX);
img8.convertTo(img8, CV_8U);
left_img = img8;
}
else if (img16.type() == CV_8U)
{
// printf("=========== 2%s\n", info.channelName.c_str());
left_img = img16;
}
}
// cv::imwrite(info.channelName+"_ddddd.png", left_img);
// getchar();
// 读取右图
cv::Mat right_img;
img16 = cv::imread(task->right_path, cv::IMREAD_UNCHANGED);
if (!img16.empty())
{
if (img16.type() != CV_8U)
{
// printf("=========== 1 %s\n", info.channelName.c_str());
cv::Mat img8;
cv::normalize(img16, img8, 0, 255, cv::NORM_MINMAX);
img8.convertTo(img8, CV_8U);
right_img = img8;
}
else if (img16.type() == CV_8U)
{
// printf("=========== 2%s\n", info.channelName.c_str());
right_img = img16;
}
}
long endTime = getcurTime();
info.width = left_img.cols;
info.height = left_img.rows;
info.readTimeMs = endTime - startTime;
info.left_img = left_img;
info.right_img = right_img;
// 检查是否成功读取
info.success = !left_img.empty() || !right_img.empty();
if (!info.success)
{
// 记录失败原因
if (left_img.empty() && right_img.empty())
{
info.errorReason = "左右图都读取失败";
}
else if (left_img.empty())
{
info.errorReason = "左图读取失败:" + task->left_path;
}
else
{
info.errorReason = "右图读取失败:" + task->right_path;
}
printf("[读图错误-%3d] %s\n", task->taskIndex, info.errorReason.c_str());
}
}
catch (const cv::Exception &e)
{
// OpenCV 异常处理
info.success = false;
info.errorReason = std::string("OpenCV 异常:") + e.what();
info.width = 0;
info.height = 0;
info.readTimeMs = 0;
printf("[读图异常-%3d] %s\n", task->taskIndex, e.what());
}
catch (const std::exception &e)
{
// 标准异常处理
info.success = false;
info.errorReason = std::string("异常:") + e.what();
info.width = 0;
info.height = 0;
info.readTimeMs = 0;
printf("[读图异常-%3d] %s\n", task->taskIndex, e.what());
}
catch (...)
{
// 未知异常处理
info.success = false;
info.errorReason = "未知异常";
info.width = 0;
info.height = 0;
info.readTimeMs = 0;
printf("[读图未知异常-%3d]\n", task->taskIndex);
}
// 推送到通知队列并通知主线程
{
std::lock_guard<std::mutex> lock(m_checkNotifyMutex);
m_checkNotifyQueue.push(info);
}
m_checkNotifyCV.notify_one(); // 立即唤醒主线程
// 更新计数器
m_nCheckNotifiedCount.fetch_add(1);
}
}
void deal::RecordFailedImg(const FailedImgRecord &record)
{
std::lock_guard<std::mutex> lock(m_productFailedMutex);
m_ProductFailedList.push_back(record);
}
void deal::PrintProductStatistics(const LoadProductImages &product)
{
printf("\n");
printf("╔══════════════════════════════════════════════════════════\n");
printf("║ 产品:%s - 处理完成\n", product.product_id.c_str());
printf("║ ─────────────────────────────────────────────────────── \n");
printf("║ 总计:%zu 对图片\n", product.images.size());
printf("║ 成功:%d 对\n", m_nProductSuccessCount.load());
printf("║ 失败:%d 对\n", m_nProductFailCount.load());
int totalProcessed = m_nProductSuccessCount.load() + m_nProductFailCount.load();
float successRate = (totalProcessed > 0) ? (m_nProductSuccessCount.load() * 100.0f / totalProcessed) : 0;
printf("║ 成功率:%.1f%%\n", successRate);
if (!m_ProductFailedList.empty())
{
printf("║ ─────────────────────────────────────────────────────── \n");
printf("║ 失败列表:\n");
for (size_t i = 0; i < m_ProductFailedList.size() && i < 10; i++)
{
const auto &record = m_ProductFailedList[i];
printf("║ [%zu] 左:%s\n", i, record.left_path.c_str());
printf("║ 右:%s\n", record.right_path.c_str());
printf("║ 错误:%s\n", record.errorReason.c_str());
}
if (m_ProductFailedList.size() > 10)
{
printf("║ ... 还有 %zu 条失败记录\n", m_ProductFailedList.size() - 10);
}
}
printf("╚══════════════════════════════════════════════════════════\n");
printf("\n");
}
int deal::ReJson_product(std::vector<Json_Det_Path> &jsonList, std::string strProductName)
{
// 获取要检测的 json 图片 list
int temstatus = IN_IMG_Status_Start;
int PushNum = 0;
// 开始逐一复测
for (int i = 0; i < jsonList.size(); i++)
{
std::string strJson = jsonList.at(i).strPath_Json;
std::string strimg = jsonList.at(i).strPath_CutImg;
std::ifstream file(strJson);
if (!file.is_open())
{
std::cerr << "Unable to open file!" << std::endl;
return -1;
}
// 读取文件内容到 std::string
std::stringstream buffer;
buffer << file.rdbuf();
std::string json_str = buffer.str(); // 获取 JSON 文件的内容作为字符串
// 显示读取到的 JSON 字符串
// std::cout << "JSON content: " << json_str << std::endl;
cv::Mat cutimg = cv::imread(strimg, 0);
int f0 = strJson.rfind('_');
int f1 = strJson.rfind('.');
int f2 = strJson.rfind('/');
std::string str1 = strJson.substr(f2 + 1, f1 - f2 - 1);
std::string str2 = strJson.substr(f0 + 1, f1 - f0 - 1);
// std::string str3 = strJson.substr(f2 + 1, strJson.size() - f2);
std::cout << str1 << std::endl;
std::cout << str2 << std::endl;
if (str1.find("CA") != std::string::npos)
{
str2 = "CA";
}
else if (str1.find("TA") != std::string::npos)
{
str2 = "TA";
}
else
{
continue;
}
std::cout << "start " << strJson << std::endl;
std::shared_ptr<CheckResult> result;
// 多线程 互斥 作用域
{
std::shared_ptr<shareImage> temdet = std::make_shared<shareImage>();
temdet->strCameraName = str2;
temdet->strImgProductID = strProductName;
temdet->strChannel = str2;
temdet->strImgName = str1;
std::cout << "strChannel " << temdet->strChannel << std::endl;
temdet->Det_Mode = DET_MODE_ReJson;
temdet->img = cutimg;
temdet->resultJson = json_str;
{
if (i == 0)
{
temdet->Status = IN_IMG_Status_Start;
}
else if (i == jsonList.size() - 1)
{
temdet->Status = IN_IMG_Status_End;
}
else
{
temdet->Status = IN_IMG_Status_Other;
}
}
int re = m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(temdet);
if (re != 0)
{
printf("reJson Error %d \n", re);
continue;
}
PushNum++;
// 结果异常
}
}
int getresultNum = 0;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟消费过程
// 处理结果
std::shared_ptr<CheckResult> checkResult;
int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult);
printf("********************** Get result %d -- %s \n", getresultNum, checkResult->in_shareImage->strChannel.c_str());
saveImg("/home/aidlux/BOE/ReJsonresult/", checkResult);
getresultNum++;
if (getresultNum == PushNum)
{
break;
}
}
return 0;
}
void deal::GetResultThread()
{
std::vector<int> vi;
vi.push_back(18);
auto nRet = set_cpu_id(vi);
printf("bind cpu ret %d, %d\n", nRet, 18);
int re = 0;
int nsleep1 = 2 * 1000;
while (!m_bExit)
{
// 1、拷贝检测结果到队列
GetDealResultToQueu();
usleep(nsleep1);
}
}
void deal::ReadImgThread(int id)
{
int nsleep1 = 200 * 1000;
int readThreadIdx = id;
while (!m_bExit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟消费过程
// 读图模式
if (READ_THREAD_TYPE_READIMG == m_nReadThread_type)
{
Thread_ReadImg(readThreadIdx);
}
else if (READ_THREAD_Detect == m_nReadThread_type)
{
}
}
}
void deal::testimg(cv::Mat img)
{
}
int deal::updataResltInfo(std::shared_ptr<CheckResult> result)
{
mutex_DetResult_.lock();
std::string productID = result->in_shareImage->strImgProductID;
std::string imgName = result->in_shareImage->strChannel;
// printf("add productID %s imgName %s %d\n", productID.c_str(), imgName.c_str(), result->nresult);
long t1 = getcurTime();
m_DetResult.updata(productID, imgName, result->nresult, t1);
for (int i = 0; i < ERROR_TYPE_COUNT; i++)
{
if (result->defectResultList[i].nresult == 1)
{
m_DetResult.update_qx(result->defectResultList[i].keyName, result->defectResultList[i].num);
}
}
mutex_DetResult_.unlock();
return 0;
}
// 滑动窗口二值化函数
void deal::slidingWindowAutoThreshold(const cv::Mat &src, cv::Mat &dst, int windowSize, int step, double C)
{
// 确保窗口大小为奇数
// if (windowSize % 2 == 0)
// {
// windowSize++;
// }
// 创建目标图像
dst = cv::Mat::zeros(src.size(), CV_8UC1);
// 获取源图像的尺寸
int rows = src.rows;
int cols = src.cols;
int xs = 0;
int xe = windowSize;
int ys = 0;
int ye = windowSize;
for (int y = ye; y < rows;)
{
int xs = 0;
int xe = windowSize;
for (int x = xe; x < cols;)
{
cv::Rect roi;
roi.x = xs;
roi.width = windowSize;
roi.y = ys;
roi.height = windowSize;
cv::Mat window = src(roi);
// 计算窗口中的平均值和标准差
cv::Scalar mean, stdDev;
cv::meanStdDev(window, mean, stdDev);
// printf(" x %d %d y %d %d %f %f \n", xs, xe, ys, ye, mean[0], stdDev[0]);
int T = mean[0] + 20 * stdDev[0];
cv::threshold(window, dst(roi), T, 255, cv::THRESH_BINARY);
// cv::rectangle(src, roi, cv::Scalar(255, 0, 255));
if (xe == cols)
{
break;
}
xs = xs + step;
xe = xs + windowSize;
if (xs < cols && xe > cols)
{
xe = cols;
xs = xe - windowSize;
}
}
if (ye == rows)
{
break;
}
ys = ys + step;
ye = ys + windowSize;
if (ys < rows && ye > rows)
{
ye = rows;
ys = ye - windowSize;
}
}
}
int deal::SetStatus(int type, int status)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_DetStatus]);
m_DetStatusList[type] = status;
return 0;
}
int deal::GetStatus(int type)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_DetStatus]);
return m_DetStatusList[type];
}
bool deal::IsStatus(int type, int status)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_DetStatus]);
if (m_DetStatusList[type] == status)
{
return true;
}
return false;
}
int deal::SetStatus_List(int idx, Thread_Status_ status)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_ReadImgThread]);
m_nReadStausList[idx] = status;
return 0;
}
int deal::GetStatus_List(int idx)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_ReadImgThread]);
return m_nReadStausList[idx];
}
bool deal::IsStatus_List(int idx, Thread_Status_ status)
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_ReadImgThread]);
if (idx < 0 || idx >= READ_IMG_THREAD_NUM)
{
}
else
{
if (m_nReadStausList[idx] == status)
{
return true;
}
}
return false;
}
int deal::setReadThreadStart()
{
for (int i = 0; i < READ_IMG_THREAD_NUM; i++)
{
SetStatus_List(i, Thread_Status_READY);
}
return 0;
}
int deal::GetReadImgCompleteThreadIdx()
{
for (int i = 0; i < READ_IMG_THREAD_NUM; i++)
{
if (IsStatus_List(i, Thread_Status_COMMPLET))
{
return i;
}
}
return -1;
}
bool deal::IsALLComplete()
{
std::lock_guard<std::mutex> lock(mtx_List[Mutex_Type_DetStatus]);
for (size_t i = 0; i < READ_IMG_THREAD_NUM; i++)
{
if (m_nReadStausList[i] == ReadImg_Status_COMMPLET)
{
return false;
}
}
return true;
}
int deal::InitCPUIDX()
{
int start = 3;
m_CPUInfo[THREAD_CPU_Main_Det].set(start, 4);
start += 4;
m_CPUInfo[THREAD_CPU_Main_readImg].set(start, READ_IMG_THREAD_NUM);
start += READ_IMG_THREAD_NUM;
m_CPUInfo[THREAD_CPU_Main_saveImg].set(start, Save_IMG_THREAD_NUM);
start += Save_IMG_THREAD_NUM;
m_CPUInfo[THREAD_CPU_CheckSo].set(start, 15);
return 0;
}
void deal::Thread_ReadImg(int id)
{
if (!IsStatus_List(id, Thread_Status_READY))
{
return;
}
int re = 0;
std::shared_ptr<JC_IMAGE_INFO_> pImageInfo = nullptr;
re = GetReadImgInfo(pImageInfo);
if (pImageInfo == nullptr)
{
printf("pImageInfo == nullptr=================id %d=============\n", id);
return;
}
pImageInfo->img = cv::imread(pImageInfo->strPath, 0);
m_ReadImgThread_Result[id] = pImageInfo;
// 线程完成读图,设置现场状态为 完成
SetStatus_List(id, Thread_Status_COMMPLET);
// printf("Thread_ReadImg=================id %d %s=============\n", id, pImageInfo->strPath.c_str());
}
int deal::InsertReadImgInfo(std::shared_ptr<JC_IMAGE_INFO_> pImageInfo)
{
std::lock_guard<std::mutex> lock(mutex_ReadImgList);
m_ReadImg_queue.push(pImageInfo);
cv_ReadImgList.notify_one(); // 唤醒等待的线程
return 0;
}
int deal::GetReadImgInfo(std::shared_ptr<JC_IMAGE_INFO_> &pImageInfo)
{
// printf("===============waite img info ===============\n");
std::unique_lock<std::mutex> lock(mutex_ReadImgList);
cv_ReadImgList.wait(lock, [this]()
{ return !m_ReadImg_queue.empty(); });
pImageInfo = m_ReadImg_queue.front(); // 获取队首数据
if (pImageInfo == NULL)
{
return 1;
}
m_ReadImg_queue.pop(); // 弹出队首数据
return 0;
}
int deal::LoadOfflineCheckImg(std::string strImgPath)
{
std::vector<cv::String> img_paths;
cv::glob(strImgPath, img_paths, true);
m_OffLineCheckImgList.erase(m_OffLineCheckImgList.begin(), m_OffLineCheckImgList.end());
m_OffLineCheckImgNameList.erase(m_OffLineCheckImgNameList.begin(), m_OffLineCheckImgNameList.end());
for (int i = 0; i < img_paths.size(); i++)
{
size_t found = img_paths[i].find_last_of("/\\");
// std::cout << img_paths[i] << std::endl;
std::string str = img_paths[i];
m_OffLineCheckImgNameList.push_back(str);
}
return 0;
}
int deal::LoadImgPath_JCSN(std::string strImgPath)
{
std::cout << strImgPath << std::endl;
std::vector<cv::String> img_paths;
cv::glob(strImgPath, img_paths, true);
m_OffImageSNPathList.erase(m_OffImageSNPathList.begin(), m_OffImageSNPathList.end());
for (int i = 0; i < img_paths.size(); i++)
{
std::string path = img_paths[i];
// std::cout << img_paths[i] << std::endl;
// 提取所有文件夹名称
std::vector<std::string> allDirectories = extractAllDirectories(path);
std::string strSN = "";
// 输出所有文件夹名称
std::string strAllPath = "/";
for (const auto &dir : allDirectories)
{
strAllPath += dir;
if (isValidString(dir))
{
strSN = dir;
// std::cout << strSN << std::endl;
break;
}
strAllPath += "/";
}
bool bh = false;
for (int j = 0; j < m_OffImageSNPathList.size(); j++)
{
if (m_OffImageSNPathList.at(j) == strAllPath)
{
bh = true;
break;
}
}
if (!bh)
{
if (m_OffImageSNPathList.size() < m_nTestNum)
{
m_OffImageSNPathList.push_back(strAllPath);
std::cout << strAllPath << std::endl;
}
// std::cout << strSN << std::endl;
}
}
return 0;
}
bool deal::isValidString(const std::string &str)
{
// 检查字符串长度是否为10
if (str.length() < 14 || str.length() > 19)
{
return false;
}
// 检查字符串中的每个字符是否都是字母或数字
for (char c : str)
{
if (!std::isalnum(c))
{ // 如果字符不是字母或数字
return false;
}
}
// 字符串满足条件
return true;
}
int deal::LoadProductID(std::string strImgPath)
{
m_product_ID_List.erase(m_product_ID_List.begin(), m_product_ID_List.end());
std::vector<cv::String> img_paths;
// tif 格式
{
std::string str_bmp = strImgPath + "/*.ytimage";
std::cout << str_bmp << std::endl;
cv::glob(str_bmp, img_paths, true);
for (int i = 0; i < img_paths.size(); i++)
{
std::string path = img_paths[i];
// 提取所有文件夹名称
std::vector<std::string> allDirectories = extractAllDirectories(path);
std::string strSN = "";
// 输出所有文件夹名称
std::string strAllPath = "/";
for (const auto &dir : allDirectories)
{
// std::cout << dir << std::endl;
strAllPath += dir;
if (isValidString(dir))
{
strSN = dir;
break;
}
strAllPath += "/";
}
bool bh = false;
for (int j = 0; j < m_product_ID_List.size(); j++)
{
if (m_product_ID_List.at(j) == strAllPath)
{
bh = true;
break;
}
}
if (!bh)
{
if (m_product_ID_List.size() < m_nTestNum)
{
m_product_ID_List.push_back(strAllPath);
std::cout << strAllPath << std::endl;
}
}
}
}
return 0;
}
int deal::RandDrawImg(cv::Mat srcimg, cv::Mat &randErrorImg)
{
randErrorImg = srcimg.clone();
cv::Rect roi;
roi.x = (rand() % (srcimg.cols - 20 - 20)) + 20;
roi.y = (rand() % (srcimg.rows - 20 - 20)) + 20;
roi.width = (rand() % (100 - 5)) + 5;
roi.height = roi.width;
if (roi.x + roi.width >= srcimg.cols)
{
roi.x = srcimg.cols - roi.width - 1;
/* code */
}
if (roi.y + roi.height >= srcimg.rows)
{
roi.y = srcimg.rows - roi.height - 1;
/* code */
}
randErrorImg(roi).setTo(30);
return 0;
}
void deal::DealImg()
{
}
// 提取所有文件夹名称函数
std::vector<std::string> deal::extractAllDirectories(const std::string &path)
{
std::vector<std::string> directories;
std::string directory;
// 遍历路径中的每个字符
for (char c : path)
{
// 如果遇到路径分隔符,则将当前文件夹名称存储起来
if (c == '/' || c == '\\')
{
if (!directory.empty())
{ // 确保文件夹名称不为空
directories.push_back(directory);
directory.clear(); // 清空当前文件夹名称
}
}
else
{
directory += c; // 将字符添加到当前文件夹名称中
}
}
// 将最后一个文件夹名称添加到列表中
if (!directory.empty())
{
directories.push_back(directory);
}
return directories;
}