feat 适配hard存图文件名

dev_lsy
liusiyang 6 days ago
parent 2a5404c6b1
commit de04f149f8

@ -1652,7 +1652,7 @@ int CameraCheckAnalysisy::GetProductFirstRow(const cv::Mat &img, int &outRow)
} }
const uchar brightThreshold = 35; // 亮像素灰度阈值(与背景判断阈值保持一致) const uchar brightThreshold = 35; // 亮像素灰度阈值(与背景判断阈值保持一致)
const int needBrightCount = std::max(1, (int)(gray.cols * 0.2)); // 该行亮像素数量占比超过 20% 认为是产品所在行 const int needBrightCount = std::max(1, (int)(gray.cols * 0.02)); // 该行亮像素数量占比超过 20% 认为是产品所在行
const int rowStep = 16; // 跳行扫描步长 const int rowStep = 16; // 跳行扫描步长
// 判断某一行是否为产品所在行(亮像素数量达到阈值) // 判断某一行是否为产品所在行(亮像素数量达到阈值)

@ -8,6 +8,65 @@ std::string toLower(const std::string &str)
return lower; return lower;
} }
// 4 相机代码, 顺序与原有实现保持一致
static const std::string g_strCameraCodes[] = {"BCA", "DCA", "BTA", "DTA"};
// 解析文件名中的 相机代码 与 半幅(左右)
// 支持两种命名:
// 1) {前缀}_{相机}_{0|1}_{后缀} 如 3ABD670013A8BG1_BCA_0_src (0=左半, 1=右半)
// 2) {前缀}{相机}{A|B} 如 BCAA / A_BCAB (A=左半, B=右半)
// 对应关系: BCA_0 <=> BCAA(左半), BCA_1 <=> BCAB(右半)
std::string Extract_Camera_And_Half(const std::string &strStem, std::string &strHalf)
{
strHalf = "";
// 方式1: {前缀}_{相机}_{0|1}_{后缀} (merg 目录下的命名)
// 形如 3ABD670013A8BG1_BCA_0_src.jpg, 其中 0 对应 BCAA, 1 对应 BCAB
for (const auto &strCam : g_strCameraCodes)
{
const std::string strKey = "_" + strCam + "_";
size_t pos = strStem.find(strKey);
while (pos != std::string::npos)
{
const size_t nHalfPos = pos + strKey.size();
if (nHalfPos < strStem.size() &&
(strStem[nHalfPos] == '0' || strStem[nHalfPos] == '1') &&
(nHalfPos + 1 >= strStem.size() || strStem[nHalfPos + 1] == '_' || strStem[nHalfPos + 1] == '.'))
{
strHalf = (strStem[nHalfPos] == '0') ? "A" : "B";
return strCam;
}
pos = strStem.find(strKey, pos + 1);
}
}
// 方式2: {前缀}{相机}{A|B} (原有的 4 相机命名)
for (const auto &strCam : g_strCameraCodes)
{
const size_t pos = strStem.find(strCam);
if (pos != std::string::npos && pos + strCam.size() < strStem.size())
{
const char cHalf = strStem[pos + strCam.size()];
if (cHalf == 'A' || cHalf == 'B')
{
strHalf = std::string(1, cHalf);
return strCam;
}
}
}
// 兜底: 文件名中只包含相机代码, 无法判定左右
for (const auto &strCam : g_strCameraCodes)
{
if (strStem.find(strCam) != std::string::npos)
{
return strCam;
}
}
return "";
}
int Extract_Name_Base::Read_Product_Image(std::string strPath) int Extract_Name_Base::Read_Product_Image(std::string strPath)
{ {
@ -189,12 +248,17 @@ int Extract_ALL::Extract_Info(std::string strPath, std::string strproduct, int u
fs::path p = fs::path(strPath); fs::path p = fs::path(strPath);
std::string filenameWithoutExt = p.stem().string(); std::string filenameWithoutExt = p.stem().string();
// 记录半幅信息: 左半(A/BCAA/…_0_) / 右半(B/BCAB/…_1_), 用于配对时确定左右图
std::string strHalf;
Extract_Camera_And_Half(filenameWithoutExt, strHalf);
std::shared_ptr<Image_Info> pImage = std::make_shared<Image_Info>(); std::shared_ptr<Image_Info> pImage = std::make_shared<Image_Info>();
pImage->strProductID = strProductName; pImage->strProductID = strProductName;
pImage->strCamID = strCameraName; pImage->strCamID = strCameraName;
pImage->strchannelName = strChannelName; pImage->strchannelName = strChannelName;
pImage->strName = filenameWithoutExt; pImage->strName = filenameWithoutExt;
pImage->strHalf = strHalf;
pImage->strPath = strPath; pImage->strPath = strPath;
pCamera->image_list.push_back(pImage); pCamera->image_list.push_back(pImage);
@ -207,17 +271,10 @@ std::string Extract_ALL::Extract_Camera_Name(std::string strPath, int userflag)
fs::path p = fs::path(strPath); fs::path p = fs::path(strPath);
std::string filename = p.stem(); std::string filename = p.stem();
// 文件名包含 BCA/BTA/DCA/DTA/CA/TA 即判定对应相机 // 相机名从统一的命名解析中获取:
if (filename.find("BCA") != std::string::npos) // {相机}{A|B} 形式(BCAA/BCAB) 与 {相机}_{0|1} 形式(BCA_0/BCA_1) 均支持
return "BCA"; std::string strHalf;
else if (filename.find("DCA") != std::string::npos) return Extract_Camera_And_Half(filename, strHalf);
return "DCA";
else if (filename.find("BTA") != std::string::npos)
return "BTA";
else if (filename.find("DTA") != std::string::npos)
return "DTA";
return "";
} }
std::string Extract_ALL::Extract_Product_Name(std::string strPath, int userflag) std::string Extract_ALL::Extract_Product_Name(std::string strPath, int userflag)
@ -252,6 +309,7 @@ std::string Extract_ALL::Extract_Channel_Name(std::string strPath, int userflag)
// 新格式: {Prefix}_{Camera}{AB}, 如 A_BCAA, M_DTAB, A_BCAB // 新格式: {Prefix}_{Camera}{AB}, 如 A_BCAA, M_DTAB, A_BCAB
// 通道名 = 前缀 (A/M), 表示不同打光方式 // 通道名 = 前缀 (A/M), 表示不同打光方式
// 支持4相机: BCAA, BCAB, BTAA, BTAB, DCAA, DCAB, DTAA, DTAB // 支持4相机: BCAA, BCAB, BTAA, BTAB, DCAA, DCAB, DTAA, DTAB
// 兼容 {Camera}_{0|1} 命名(如 BCA_0 / BCA_1), 其 0/1 对应 A/B
size_t underscorePos = filename.find('_'); size_t underscorePos = filename.find('_');
if (underscorePos != std::string::npos) if (underscorePos != std::string::npos)
{ {
@ -259,7 +317,9 @@ std::string Extract_ALL::Extract_Channel_Name(std::string strPath, int userflag)
std::string rest = filename.substr(underscorePos + 1); std::string rest = filename.substr(underscorePos + 1);
// 4相机格式 // 4相机格式
if (rest == "BCAA" || rest == "BCAB" || rest == "BTAA" || rest == "BTAB" || if (rest == "BCAA" || rest == "BCAB" || rest == "BTAA" || rest == "BTAB" ||
rest == "DCAA" || rest == "DCAB" || rest == "DTAA" || rest == "DTAB" ) rest == "DCAA" || rest == "DCAB" || rest == "DTAA" || rest == "DTAB" ||
rest == "BCA_0" || rest == "BCA_1" || rest == "BTA_0" || rest == "BTA_1" ||
rest == "DCA_0" || rest == "DCA_1" || rest == "DTA_0" || rest == "DTA_1")
{ {
return prefix; // "A" or "M" return prefix; // "A" or "M"
} }

@ -15,6 +15,20 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace std; using namespace std;
// ==================== 图片命名解析 ====================
// 相机代码: BCA / BTA / DCA / DTA
// 目前支持两种图片命名方式:
// 1) {前缀}{相机}{A|B} 例: BCAA.jpg / A_BCAB.jpg / M_DTAB.jpg
// 末位 A = 左半, B = 右半
// 2) {前缀}_{相机}_{0|1}_{后缀} 例: 3ABD670013A8BG1_BCA_0_src.jpg
// 0 = 左半, 1 = 右半
// 两种命名的对应关系: BCA_0 等价于 BCAA, BCA_1 等价于 BCAB; BTA/DCA/DTA 同理。
//
// strStem : 去掉目录与扩展名的文件名
// strHalf : 输出半幅信息, "A"=左半, "B"=右半, 无法判定时为空
// 返回值 : 相机代码, 未识别到相机时返回空字符串
std::string Extract_Camera_And_Half(const std::string &strStem, std::string &strHalf);
// 图片信息 // 图片信息
struct Image_Info struct Image_Info
{ {
@ -23,6 +37,7 @@ struct Image_Info
std::string strchannelName; // 通道名称 std::string strchannelName; // 通道名称
std::string strPath; // 完整路径 std::string strPath; // 完整路径
std::string strName; // 图片名称 std::string strName; // 图片名称
std::string strHalf; // 半幅: "A"=左半(BCAA/…_0_), "B"=右半(BCAB/…_1_)
cv::Mat img; // 图像数据 cv::Mat img; // 图像数据
long readImg_start; // 读取开始时间 long readImg_start; // 读取开始时间
long readImg_end; // 读取结束时间 long readImg_end; // 读取结束时间
@ -41,6 +56,7 @@ struct Image_Info
strchannelName = ""; strchannelName = "";
strPath = ""; strPath = "";
strName = ""; strName = "";
strHalf = "";
img.release(); // 释放图像内存 img.release(); // 释放图像内存
readImg_start = 0; readImg_start = 0;
readImg_end = 0; readImg_end = 0;
@ -53,6 +69,7 @@ struct Image_Info
std::cout << "Channel Name: " << strchannelName << std::endl; std::cout << "Channel Name: " << strchannelName << std::endl;
std::cout << "Image Path: " << strPath << std::endl; std::cout << "Image Path: " << strPath << std::endl;
std::cout << "Image Name: " << strName << std::endl; std::cout << "Image Name: " << strName << std::endl;
std::cout << "Image Half: " << strHalf << std::endl;
std::cout << "Read Start Time: " << readImg_start << std::endl; std::cout << "Read Start Time: " << readImg_start << std::endl;
std::cout << "Read End Time: " << readImg_end << std::endl; std::cout << "Read End Time: " << readImg_end << std::endl;
} }

@ -556,19 +556,26 @@ int deal::preCheck()
for (const auto pcam : product->camera_list) for (const auto pcam : product->camera_list)
{ {
auto& imgList = pcam->image_list; auto& imgList = pcam->image_list;
// 同一camera内按配对处理每两张图一组 (CAA+CAB / TAA+TAB) // 同一camera内按配对处理每两张图一组 (左半 + 右半)
// cv::glob 返回字母序,确保 A_CAA 在 A_CAB 前M_CAA 在 M_CAB 前 // 支持 {相机}{A|B}(BCAA/BCAB) 与 {相机}_{0|1}(BCA_0/BCA_1, merg 目录) 两种命名
// 左半(A/…_0_)为左图, 右半(B/…_1_)为右图; 若读入顺序相反则交换
for (size_t i = 0; i < imgList.size(); i += 2) for (size_t i = 0; i < imgList.size(); i += 2)
{ {
std::shared_ptr<Image_Info> pLeft = imgList[i];
std::shared_ptr<Image_Info> pRight = (i + 1 < imgList.size()) ? imgList[i + 1] : nullptr;
if (pRight && pLeft->strHalf == "B" && pRight->strHalf == "A")
{
std::swap(pLeft, pRight);
}
std::shared_ptr<JC_IMAGE_INFO_> tem = std::make_shared<JC_IMAGE_INFO_>(); std::shared_ptr<JC_IMAGE_INFO_> tem = std::make_shared<JC_IMAGE_INFO_>();
tem->strCamID = pcam->strCamName; tem->strCamID = pcam->strCamName;
tem->strchannelName = imgList[i]->strchannelName; tem->strchannelName = pLeft->strchannelName;
tem->strName = imgList[i]->strName; tem->strName = pLeft->strName;
tem->strProductID = imgList[i]->strProductID; tem->strProductID = pLeft->strProductID;
tem->strPath = imgList[i]->strPath; tem->strPath = pLeft->strPath;
if (i + 1 < imgList.size()) if (pRight)
{ {
tem->strPath_B = imgList[i + 1]->strPath; tem->strPath_B = pRight->strPath;
} }
InsertReadImgInfo(tem); InsertReadImgInfo(tem);
AllImgNum++; AllImgNum++;
@ -1340,30 +1347,15 @@ int deal::GetImgInfo_POL_ET(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo)
strName = ExtractFileNameWithoutExtension(strImgPath); strName = ExtractFileNameWithoutExtension(strImgPath);
printf("strName %s \n", strName.c_str()); printf("strName %s \n", strName.c_str());
std::string strImageChannel; // 统一命名解析: 同时支持 {相机}{A|B}(BCAA/BCAB) 与 {相机}_{0|1}(BCA_0/BCA_1) 命名
// 对应关系: BCA_0 <=> BCAA, BCA_1 <=> BCAB; BTA/DCA/DTA 同理
// 使用 find 检查是否包含 4 个相机标识 (BCA, BTA, DCA, DTA) 及兼容旧 CA/TA std::string strHalf;
if (strName.find("BCA") != std::string::npos) std::string strImageChannel = Extract_Camera_And_Half(strName, strHalf);
{ if (strImageChannel.empty())
strImageChannel = "BCA";
}
else if (strName.find("BTA") != std::string::npos)
{
strImageChannel = "BTA";
}
else if (strName.find("DCA") != std::string::npos)
{
strImageChannel = "DCA";
}
else if (strName.find("DTA") != std::string::npos)
{
strImageChannel = "DTA";
}
else
{ {
return 1; return 1;
} }
printf("strImageChannel %s\n", strImageChannel.c_str()); printf("strImageChannel %s strHalf %s\n", strImageChannel.c_str(), strHalf.c_str());
pImageInfo->strchannelName = strImageChannel; pImageInfo->strchannelName = strImageChannel;
pImageInfo->strName = strName; pImageInfo->strName = strName;
pImageInfo->strPath = strImgPath; pImageInfo->strPath = strImgPath;
@ -2482,7 +2474,8 @@ int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx)
int AllImgNum = detImgInfoList.size(); int AllImgNum = detImgInfoList.size();
// 遍历所有图片 开始读图处理 // 遍历所有图片 开始读图处理
// 按相机分组,同相机内每两张配对 (BCAA+BCAB 拼接送检,与 preCheck 一致) // 按相机分组,同相机内每两张配对 (A半+ B半 拼接送检,与 preCheck 一致)
// 注: 除旧的 BCAA/BCAB 命名外,同时支持 merg 目录下的 xxx_BCA_0_src / xxx_BCA_1_src 命名
std::map<std::string, std::vector<int>> camGroups; std::map<std::string, std::vector<int>> camGroups;
for (int i = 0; i < (int)detImgInfoList.size(); i++) for (int i = 0; i < (int)detImgInfoList.size(); i++)
{ {
@ -2494,11 +2487,25 @@ int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx)
auto& indices = kv.second; auto& indices = kv.second;
for (size_t i = 0; i < indices.size(); i += 2) for (size_t i = 0; i < indices.size(); i += 2)
{ {
int nLeftIdx = indices[i];
int nRightIdx = (i + 1 < indices.size()) ? indices[i + 1] : -1;
// 左右图由文件名决定: A半(BCAA/…_0_)为左图, B半(BCAB/…_1_)为右图; 顺序相反时交换
if (nRightIdx >= 0)
{
std::string strHalfL;
std::string strHalfR;
Extract_Camera_And_Half(detImgInfoList.at(nLeftIdx).strName, strHalfL);
Extract_Camera_And_Half(detImgInfoList.at(nRightIdx).strName, strHalfR);
if (strHalfL == "B" && strHalfR == "A")
{
std::swap(nLeftIdx, nRightIdx);
}
}
std::shared_ptr<JC_IMAGE_INFO_> tem = std::make_shared<JC_IMAGE_INFO_>(); std::shared_ptr<JC_IMAGE_INFO_> tem = std::make_shared<JC_IMAGE_INFO_>();
tem->copy(detImgInfoList.at(indices[i])); tem->copy(detImgInfoList.at(nLeftIdx));
if (i + 1 < indices.size()) if (nRightIdx >= 0)
{ {
tem->strPath_B = detImgInfoList.at(indices[i + 1]).strPath; tem->strPath_B = detImgInfoList.at(nRightIdx).strPath;
} }
InsertReadImgInfo(tem); InsertReadImgInfo(tem);
AllImgNum++; AllImgNum++;

Loading…
Cancel
Save