feat 添加标签检测

main
liusiyang 3 weeks ago
parent 04246a9598
commit 02552b28d9

@ -52,8 +52,9 @@ public:
struct Edge_AI_Result
{
int nresult;
cv::RotatedRect bigroi;
cv::RotatedRect smallroi;
std::vector<cv::RotatedRect> bigroi; // 轮廓面积从大到小排序
std::vector<cv::RotatedRect> smallroi; // 轮廓面积从大到小排序
std::vector<cv::RotatedRect> tagroi; // 轮廓面积从大到小排序
bool buseOfft;
int offt_x;
int offt_y;
@ -71,8 +72,9 @@ public:
nresult = 0;
offt_x = 0;
offt_y = 0;
bigroi = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(0, 0), 0);
smallroi = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(0, 0), 0);
bigroi.clear();
smallroi.clear();
tagroi.clear();
markresulList.clear();
if (!H.empty())
{
@ -152,7 +154,7 @@ public:
private:
int InitModel_Big();
int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::RotatedRect &Roi);
int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector<cv::RotatedRect> &RoiList);
int creatsavedir();

@ -116,7 +116,7 @@ private:
cv::Scalar calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size = cv::Size(5, 5), int expand = 10, double threshold = 0.7);
// 检测
int CheckRun();
int AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi);
int AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi, std::vector<cv::RotatedRect> &tagroiList);
// 计算产品尺寸
int CalProductSize();
// 图片预处理
@ -141,7 +141,6 @@ private:
int CalBlob_Other();
// 分类
int GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight);
// 计算缺陷长度
@ -287,8 +286,9 @@ private:
// 模板信息
cv::RotatedRect m_tplOuterRect; // 模板外接矩形
cv::RotatedRect m_outer_rroi;
cv::RotatedRect m_outer_rroi;
cv::RotatedRect m_inner_rroi;
std::vector<cv::RotatedRect> m_tag_roiList;
};
#endif

@ -60,6 +60,7 @@ enum ERROR_TYPE_
ERROR_TYPE_shuizi, // 11 水渍
ERROR_TYPE_danban, // 12 淡斑
ERROR_TYPE_fuchen, // 13 浮尘
ERROR_TYPE_tag, // 14 标签
ERROR_TYPE_COUNT,
};
extern std::vector<std::string> QX_Result_Names;

@ -15,6 +15,7 @@
#include <opencv2/opencv.hpp> // OpenCV核心功能
#include <opencv2/imgproc.hpp> // 图像处理模块
#include <vector> // 向量容器
#include <algorithm> // std::sort
#include <iostream> // 输入输出流
/**
@ -233,8 +234,9 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared
// 1、初步定位 找到产品大致区域
int re = 0;
cv::RotatedRect Big_roi;
cv::RotatedRect Small_roi;
std::vector<cv::RotatedRect> Big_roi;
std::vector<cv::RotatedRect> Small_roi;
std::vector<cv::RotatedRect> Tag_roi;
re = Get_Edge(0, img, pDetConfig, m_pDetConfig->strChannel, Big_roi);
if (re != 0)
@ -256,9 +258,20 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared
}
return re;
}
re = Get_Edge(2, img, pDetConfig, m_pDetConfig->strChannel, Tag_roi);
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Tag----error %d ", re);
if (m_pDetConfig->IsSaveProcessImg())
{
cv::imwrite(str_error, img);
}
return re;
}
m_pCheckResult_Aling->bigroi = Big_roi;
m_pCheckResult_Aling->smallroi = Small_roi;
m_pCheckResult_Aling->tagroi = Tag_roi;
pCheckResult_Aling = m_pCheckResult_Aling;
// return 1;
@ -330,7 +343,7 @@ int AI_Edge_Algin::InitModel_ALL()
return 0;
}
int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::RotatedRect &Roi)
int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector<cv::RotatedRect> &RoiList)
{
std::shared_ptr<AIModel_Base> pBackPlate_Align;
switch (AIModel_type)
@ -341,6 +354,9 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe
case 1:
pBackPlate_Align = AI_Factory->Align_Inner;
break;
case 2:
pBackPlate_Align = AI_Factory->Tag_Loc;
break;
default:
pBackPlate_Align = AI_Factory->Align_Outer;
break;
@ -393,42 +409,73 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe
cv::imwrite(strChannel +"_edge_"+ to_string(AIModel_type) +"_out_mask.png", mask);
}
// 找到最大轮廓
bool found;
std::vector<cv::Point> boundingBox = CheckUtil::getLargestContourROI(mask, found);
if (!found)
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No contours found!----error ");
return 4;
}
// 边缘轮廓点集还原为原图坐标并计算得到RotateROI
// 检查模型输入尺寸
if (sz.width <= 0 || sz.height <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "invalid model input size!----error ");
return 5;
}
// 找到所有轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(mask.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No contours found!----error ");
return 4;
}
// 检测小图 到 原图 的缩放比例
const float scale_x = static_cast<float>(img.cols) / sz.width;
const float scale_y = static_cast<float>(img.rows) / sz.height;
// 轮廓点还原到原图坐标系
std::vector<cv::Point2f> srcContour;
srcContour.reserve(boundingBox.size());
for (const auto &pt : boundingBox)
RoiList.clear();
// 按轮廓面积从大到小排序(记录面积与轮廓索引)
std::vector<std::pair<double, size_t>> areaIdx;
areaIdx.reserve(contours.size());
for (size_t i = 0; i < contours.size(); i++)
{
double area = cv::contourArea(contours[i]);
if (area > 0)
{
areaIdx.emplace_back(area, i);
}
}
if (areaIdx.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No valid contours found!----error ");
return 4;
}
std::sort(areaIdx.begin(), areaIdx.end(),
[](const std::pair<double, size_t> &a, const std::pair<double, size_t> &b)
{ return a.first > b.first; });
// 按面积从大到小,将每个轮廓点还原到原图坐标系并计算 RotatedRect
RoiList.reserve(areaIdx.size());
for (const auto &ai : areaIdx)
{
srcContour.emplace_back(pt.x * scale_x, pt.y * scale_y);
const std::vector<cv::Point> &contour = contours[ai.second];
if (contour.size() < 3)
{
continue;
}
std::vector<cv::Point2f> srcContour;
srcContour.reserve(contour.size());
for (const auto &pt : contour)
{
srcContour.emplace_back(pt.x * scale_x, pt.y * scale_y);
}
RoiList.emplace_back(cv::minAreaRect(srcContour));
}
if (srcContour.size() < 3)
if (RoiList.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "contour points too few!----error ");
return 6;
}
Roi = cv::minAreaRect(srcContour);
return 0;
}

@ -29,6 +29,7 @@ std::vector<std::string> QX_Result_Names =
"shuizi",
"danban",
"fuchen",
"tag",
};
std::vector<std::string> QX_Result_Code =
{
@ -45,6 +46,7 @@ std::vector<std::string> QX_Result_Code =
"P0002",
"P0003",
"P0004",
"P0005",
};
int ReadFlawCodeConfig(std::string json_path)

@ -379,6 +379,13 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
}
}
// 标签缺陷:检测到标签直接判 NG
if (config_qx_type == CONFIG_QX_NAME_cell_tag)
{
bNG_Status = true;
Judge_Status = true;
}
std::string resultType = "OK";
if (!Judge_Status)
@ -1080,6 +1087,9 @@ int ImageResultJudge::ConfigTypeToResultType(int nconfigType)
case CONFIG_QX_NAME_cell_fuchen:
resultError_type = ERROR_TYPE_fuchen;
break;
case CONFIG_QX_NAME_cell_tag:
resultError_type = ERROR_TYPE_tag;
break;
default:
break;

@ -455,7 +455,7 @@ int ImgCheckAnalysisy::CheckRun()
/*AI 边缘定位(内外边缘)*/
// 模型定位内外边缘
int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi);
int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi, m_tag_roiList);
if (reedge != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge);
@ -502,10 +502,57 @@ int ImgCheckAnalysisy::CheckRun()
// 分析m_inner_rroi
/* Tag检测 */
{
for (const auto &tagRoi : m_tag_roiList)
{
// tag roi 在原图坐标系,转换为检测图(detImg)坐标系
cv::Rect roi = tagRoi.boundingRect();
roi.x -= m_outer_roi.x;
roi.y -= m_outer_roi.y;
roi &= cv::Rect(0, 0, m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows);
if (roi.width <= 0 || roi.height <= 0)
{
continue;
}
QX_ERROR_INFO_ temerror;
temerror.Idx = m_pDetResult->pQx_ErrorList->size();
temerror.roi = roi;
temerror.area = roi.width * roi.height;
temerror.JudgArea = roi.width * m_fImgage_Scale_X * roi.height * m_fImgage_Scale_Y;
temerror.JudgArea_second = temerror.JudgArea;
float tw = tagRoi.size.width;
float th = tagRoi.size.height;
temerror.flen = (tw > th ? tw : th) * m_fImgage_Scale_X;
temerror.fbreadth = (tw > th ? th : tw) * m_fImgage_Scale_Y;
temerror.nconfig_qx_type = CONFIG_QX_NAME_cell_tag;
temerror.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_tag];
temerror.result = QX_RESULT_TYPE_NG;
temerror.result_name = QX_RESULT_TYPE_Names[QX_RESULT_TYPE_NG];
// 计算标签中心所在的检测区域
cv::Point pCenter;
pCenter.x = roi.x + roi.width * 0.5;
pCenter.y = roi.y + roi.height * 0.5;
int nmaxregionIdx = 0;
for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++)
{
const std::vector<cv::Point> &polygon = m_DetRoiList.roiList_Src[iregion];
double result = cv::pointPolygonTest(polygon, pCenter, false);
if (result < 0)
{
continue;
}
nmaxregionIdx = iregion;
}
temerror.detRegionidxList.push_back(nmaxregionIdx);
m_pDetResult->pQx_ErrorList->push_back(temerror);
m_pdetlog->AddCheckstr(PrintLevel_0, "Tag检测", "tag %d roi [%d %d %d %d] -> NG", temerror.Idx, roi.x, roi.y, roi.width, roi.height);
}
}
m_CheckResult_shareP->nresult = 0;
/*把临时可以绘制的结果都绘制出来。*/
@ -1888,7 +1935,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
return 0;
}
int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi)
int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi, vector<cv::RotatedRect> &tagroiList)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "AI_Edge", "-------------------start--------------");
@ -1905,8 +1952,18 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv
{
printf("AI_Edge Is Error = %d \n", re);
}
outerRoi = m_pEdge_Align_Result->bigroi;
innerRoi = m_pEdge_Align_Result->smallroi;
if (!m_pEdge_Align_Result->bigroi.empty())
{
outerRoi = m_pEdge_Align_Result->bigroi[0];
}
if (!m_pEdge_Align_Result->smallroi.empty())
{
innerRoi = m_pEdge_Align_Result->smallroi[0];
}
if (!m_pEdge_Align_Result->tagroi.empty())
{
tagroiList = m_pEdge_Align_Result->tagroi;
}
// getchar();
return re;
}

@ -51,6 +51,7 @@ enum CONFIG_QX_NAME_
CONFIG_QX_NAME_cell_shuizi, // 分类 水渍
CONFIG_QX_NAME_cell_danban, // 分类 淡斑
CONFIG_QX_NAME_cell_fuchen, // 分类 浮尘
CONFIG_QX_NAME_cell_tag, // 分类 标签
CONFIG_QX_NAME_count,
};
// 缺陷项对应在参数中的名称
@ -68,6 +69,7 @@ static std::vector<std::string> CONFIG_QX_NAME_Names =
"shuizi",
"danban",
"fuchen",
"tag",
};
// 分析类型

@ -35,6 +35,7 @@ std::vector<std::string> QX_Result_Names =
"shuizi",
"danban",
"fuchen",
"tag",
};
std::vector<std::string> QX_Result_Code =
{
@ -51,6 +52,7 @@ std::vector<std::string> QX_Result_Code =
"P0002",
"P0003",
"P0004",
"P0005",
};
int ReadFlawCodeConfig(std::string json_path)

Loading…
Cancel
Save