|
|
|
|
@ -21,7 +21,7 @@
|
|
|
|
|
#define HANDLE_SIZE_MAX_RATIO 1.2f
|
|
|
|
|
// "附近"的搜索范围:把手区域外接矩形在宽/高方向各外扩该比例
|
|
|
|
|
#define HANDLE_NEAR_EXPAND_RATIO 5
|
|
|
|
|
// 凸起填充率下限等参数的默认值在 Handle_Check_Param(CheckConfigDefine.h)里
|
|
|
|
|
// 把手缺失检测开关见 Function_Support_Det::bDetHandle(CheckConfigDefine.h)
|
|
|
|
|
|
|
|
|
|
// 用于排序轮廓的比较函数
|
|
|
|
|
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
|
|
|
|
|
@ -811,7 +811,7 @@ int ImgCheckAnalysisy::CheckRun()
|
|
|
|
|
// 定位模型不跑,但把手检测仍要执行:暗场图像 + 明场 bigmask
|
|
|
|
|
{
|
|
|
|
|
long handle_s = CheckUtil::getcurTime();
|
|
|
|
|
CheckHandleByBigMask(m_CheckResult_shareP->in_shareImage->img, m_pEdge_Align_Result->bigmask);
|
|
|
|
|
CheckHandleByBigMask(m_pEdge_Align_Result->bigmask);
|
|
|
|
|
long handle_e = CheckUtil::getcurTime();
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle", "handle detect use time %ld", handle_e - handle_s);
|
|
|
|
|
}
|
|
|
|
|
@ -2552,7 +2552,7 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv
|
|
|
|
|
/*使用m_pEdge_Align_Result->bigmask检测把手是否缺失*/
|
|
|
|
|
{
|
|
|
|
|
long handle_s = CheckUtil::getcurTime();
|
|
|
|
|
CheckHandleByBigMask(img, m_pEdge_Align_Result->bigmask);
|
|
|
|
|
CheckHandleByBigMask(m_pEdge_Align_Result->bigmask);
|
|
|
|
|
long handle_e = CheckUtil::getcurTime();
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle", "handle detect use time %ld", handle_e - handle_s);
|
|
|
|
|
}
|
|
|
|
|
@ -2565,7 +2565,7 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv
|
|
|
|
|
// 3、参数里每个非空的"把手区域"附近都应该有一个把手:在区域附近找凸起,
|
|
|
|
|
// 凸起宽高与区域外接矩形宽高相近(HANDLE_SIZE_MIN_RATIO ~ HANDLE_SIZE_MAX_RATIO)才算匹配
|
|
|
|
|
// 4、凸起本身不算 NG,只有"某个把手区域附近找不到匹配的凸起"才算把手缺失(NG 由 CheckRun 上报)
|
|
|
|
|
int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &img, const cv::Mat &bigmask)
|
|
|
|
|
int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &bigmask)
|
|
|
|
|
{
|
|
|
|
|
m_bHandleDetSucc = false;
|
|
|
|
|
m_bHandleFound = false;
|
|
|
|
|
@ -2589,38 +2589,23 @@ int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &img, const cv::Mat &b
|
|
|
|
|
}
|
|
|
|
|
m_bHandleDetSucc = true;
|
|
|
|
|
|
|
|
|
|
// 2、把手判定参数 + 把手区域(最多4个,非空区域表示该处应该有一个把手)
|
|
|
|
|
Handle_Check_Param handleParam;
|
|
|
|
|
// 2、把手检测开关 + 把手区域(最多4个,非空区域表示该处应该有一个把手)
|
|
|
|
|
bool bDetHandle = false;
|
|
|
|
|
std::vector<cv::Rect> regionBoxList;
|
|
|
|
|
if (m_pFuntion != NULL)
|
|
|
|
|
{
|
|
|
|
|
const Function_Support_Det &supportDet = m_pFuntion->function.f_supportDet;
|
|
|
|
|
handleParam = supportDet.handleParam;
|
|
|
|
|
bDetHandle = supportDet.bDetHandle;
|
|
|
|
|
for (size_t i = 0; i < supportDet.handleBoxes.size() && i < HANDLE_REGION_MAX_NUM; i++)
|
|
|
|
|
{
|
|
|
|
|
regionBoxList.push_back(supportDet.handleBoxes[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_bHandleExpect = (handleParam.bOpen && !regionBoxList.empty());
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle", "protrusion num %ld handle region num %ld expect %s",
|
|
|
|
|
protrusionList.size(), regionBoxList.size(), BOOL_TO_STR(m_bHandleExpect));
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle", "%s", handleParam.GetInfo("judge").c_str());
|
|
|
|
|
m_bHandleExpect = (bDetHandle && !regionBoxList.empty());
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle", "protrusion num %ld handle region num %ld bDetHandle %s expect %s",
|
|
|
|
|
protrusionList.size(), regionBoxList.size(), BOOL_TO_STR(bDetHandle), BOOL_TO_STR(m_bHandleExpect));
|
|
|
|
|
|
|
|
|
|
// 灰阶判定是预留项:只有开启时才做灰度换算,避免无谓开销
|
|
|
|
|
cv::Mat grayImg;
|
|
|
|
|
if (handleParam.bJudgeGray && !img.empty())
|
|
|
|
|
{
|
|
|
|
|
if (img.channels() != 1)
|
|
|
|
|
{
|
|
|
|
|
cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
grayImg = img;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3、凸起候选实测特征(面积/填充率/灰度差,供日志与后续判定用)
|
|
|
|
|
// 3、凸起候选实测特征(面积/填充率,仅用于日志排查)
|
|
|
|
|
for (size_t i = 0; i < protrusionList.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Handle_Candidate_ cand;
|
|
|
|
|
@ -2629,17 +2614,11 @@ int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &img, const cv::Mat &b
|
|
|
|
|
bool bHorz = (cand.protr.nSide == 0 || cand.protr.nSide == 1);
|
|
|
|
|
cand.nLen = bHorz ? cand.protr.roi.height : cand.protr.roi.width;
|
|
|
|
|
cand.nDepth = bHorz ? cand.protr.roi.width : cand.protr.roi.height;
|
|
|
|
|
if (!grayImg.empty())
|
|
|
|
|
{
|
|
|
|
|
cand.fGrayDiff = CalProtrusionGrayDiff(grayImg, cand.protr.roi);
|
|
|
|
|
}
|
|
|
|
|
m_HandleCandList.push_back(cand);
|
|
|
|
|
// grayDiff 打印 -1 表示本次未开启灰阶判定(未计算)
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Handle",
|
|
|
|
|
"protrusion %ld side %d roi [%d %d %d %d] len %d depth %d area %0.0f fill %0.2f grayDiff %0.1f",
|
|
|
|
|
"protrusion %ld side %d roi [%d %d %d %d] len %d depth %d area %0.0f fill %0.2f",
|
|
|
|
|
i, cand.protr.nSide, cand.protr.roi.x, cand.protr.roi.y, cand.protr.roi.width, cand.protr.roi.height,
|
|
|
|
|
cand.nLen, cand.nDepth, cand.protr.fArea, cand.protr.fFillRatio,
|
|
|
|
|
grayImg.empty() ? -1.0f : cand.fGrayDiff);
|
|
|
|
|
cand.nLen, cand.nDepth, cand.protr.fArea, cand.protr.fFillRatio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4、逐个把手区域:在区域附近找宽高匹配的凸起(同一个凸起只匹配给一个区域)
|
|
|
|
|
@ -2650,7 +2629,7 @@ int ImgCheckAnalysisy::CheckHandleByBigMask(const cv::Mat &img, const cv::Mat &b
|
|
|
|
|
Handle_Region_Result_ result;
|
|
|
|
|
result.nIdx = (int)ir + 1;
|
|
|
|
|
result.boxRegion = regionBoxList[ir];
|
|
|
|
|
int nMatchIdx = MatchHandleRegion(m_HandleCandList, usedList, result.boxRegion, handleParam, result.roiHandle);
|
|
|
|
|
int nMatchIdx = MatchHandleRegion(m_HandleCandList, usedList, result.boxRegion, result.roiHandle);
|
|
|
|
|
result.bFound = (nMatchIdx >= 0);
|
|
|
|
|
if (result.bFound)
|
|
|
|
|
{
|
|
|
|
|
@ -2844,10 +2823,9 @@ int ImgCheckAnalysisy::CheckTagByBigMask(const cv::Mat &img, const cv::Mat &bigm
|
|
|
|
|
// 在某个把手区域附近找宽高匹配的凸起
|
|
|
|
|
// 匹配条件:1、凸起中心落在把手区域附近(区域宽/高各外扩 HANDLE_NEAR_EXPAND_RATIO)
|
|
|
|
|
// 2、凸起宽高与该区域外接矩形宽高的比值都在 [HANDLE_SIZE_MIN_RATIO, HANDLE_SIZE_MAX_RATIO](允许横竖互换)
|
|
|
|
|
// 3、填充率、预留的面积/灰阶等开关条件都满足
|
|
|
|
|
// 返回凸起在 candList 中的下标,-1 表示没找到
|
|
|
|
|
int ImgCheckAnalysisy::MatchHandleRegion(const std::vector<Handle_Candidate_> &candList, const std::vector<bool> &usedList,
|
|
|
|
|
const cv::Rect &boxRegion, const Handle_Check_Param ¶m, cv::Rect &roiHandle)
|
|
|
|
|
const cv::Rect &boxRegion, cv::Rect &roiHandle)
|
|
|
|
|
{
|
|
|
|
|
if (boxRegion.width <= 0 || boxRegion.height <= 0)
|
|
|
|
|
{
|
|
|
|
|
@ -2890,24 +2868,6 @@ int ImgCheckAnalysisy::MatchHandleRegion(const std::vector<Handle_Candidate_> &c
|
|
|
|
|
nNearIdx = (int)i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 类似矩形块:凸起区域内掩膜填充率要高
|
|
|
|
|
if (param.bJudgeFill && cand.protr.fFillRatio < param.fFillMin)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 预留:凸起面积
|
|
|
|
|
if (param.bJudgeArea && param.fAreaMax > param.fAreaMin &&
|
|
|
|
|
(cand.protr.fArea < param.fAreaMin || cand.protr.fArea > param.fAreaMax))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 预留:凸起与背景的灰度差
|
|
|
|
|
if (param.bJudgeGray && param.fGrayMax > param.fGrayMin &&
|
|
|
|
|
(cand.fGrayDiff < param.fGrayMin || cand.fGrayDiff > param.fGrayMax))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 宽高:与把手区域外接矩形的宽高相近(允许横竖互换)
|
|
|
|
|
float fw = (float)roi.width;
|
|
|
|
|
float fh = (float)roi.height;
|
|
|
|
|
@ -2948,39 +2908,6 @@ int ImgCheckAnalysisy::MatchHandleRegion(const std::vector<Handle_Candidate_> &c
|
|
|
|
|
return nBestIdx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算凸起区域与周边背景的平均灰度差(灰阶判定的预留量测值,grayImg 需为单通道)
|
|
|
|
|
float ImgCheckAnalysisy::CalProtrusionGrayDiff(const cv::Mat &grayImg, const cv::Rect &roi)
|
|
|
|
|
{
|
|
|
|
|
if (grayImg.empty() || grayImg.channels() != 1 || roi.width <= 0 || roi.height <= 0)
|
|
|
|
|
{
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
// 凸起区域通常整个都在掩膜内,向外扩一圈才能取到背景
|
|
|
|
|
int nExpand = std::max(20, std::min(roi.width, roi.height) / 2);
|
|
|
|
|
cv::Rect roiBg(roi.x - nExpand, roi.y - nExpand, roi.width + 2 * nExpand, roi.height + 2 * nExpand);
|
|
|
|
|
roiBg &= cv::Rect(0, 0, grayImg.cols, grayImg.rows);
|
|
|
|
|
if (roiBg.width <= 0 || roiBg.height <= 0)
|
|
|
|
|
{
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat grayRoi = grayImg(roiBg);
|
|
|
|
|
cv::Mat maskIn = cv::Mat::zeros(roiBg.size(), CV_8UC1);
|
|
|
|
|
cv::Rect inter = roi & roiBg;
|
|
|
|
|
cv::rectangle(maskIn, inter - roiBg.tl(), cv::Scalar(255), cv::FILLED);
|
|
|
|
|
cv::Mat maskOut;
|
|
|
|
|
cv::bitwise_not(maskIn, maskOut);
|
|
|
|
|
if (cv::countNonZero(maskIn) <= 0 || cv::countNonZero(maskOut) <= 0)
|
|
|
|
|
{
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double fMeanIn = cv::mean(grayRoi, maskIn)[0];
|
|
|
|
|
double fMeanOut = cv::mean(grayRoi, maskOut)[0];
|
|
|
|
|
double fDiff = fMeanIn - fMeanOut;
|
|
|
|
|
return (float)(fDiff >= 0 ? fDiff : -fDiff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ImgCheckAnalysisy::CalProductSize()
|
|
|
|
|
{
|
|
|
|
|
float fw = m_outer_roi.width * m_fImgage_Scale_X;
|
|
|
|
|
|