|
|
|
@ -11,7 +11,9 @@
|
|
|
|
#include "Define.h"
|
|
|
|
#include "Define.h"
|
|
|
|
#include <omp.h>
|
|
|
|
#include <omp.h>
|
|
|
|
#include "AICommonDefine.h"
|
|
|
|
#include "AICommonDefine.h"
|
|
|
|
|
|
|
|
#include "AlignShare.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include <cctype>
|
|
|
|
|
|
|
|
|
|
|
|
// 把手判定参数:
|
|
|
|
// 把手判定参数:
|
|
|
|
// 每个非空的"把手区域"附近都应该有一个把手:凸起宽高与该区域外接矩形宽高的比值落在下面范围内才算匹配
|
|
|
|
// 每个非空的"把手区域"附近都应该有一个把手:凸起宽高与该区域外接矩形宽高的比值落在下面范围内才算匹配
|
|
|
|
@ -537,6 +539,193 @@ static void WarpAffineBandParallel(const cv::Mat &src, cv::Mat &dst, const cv::M
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 暗场复用明场定位:把字符串里的 "dark"(大小写不敏感)替换为 "bright";未命中返回空串
|
|
|
|
|
|
|
|
static std::string ReplaceDarkWithBright(const std::string &strIn)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const std::string strKey = ALIGN_REUSE_FOLLOWER_KEY; // "dark"
|
|
|
|
|
|
|
|
const std::string strSrc = ALIGN_REUSE_SOURCE_KEY; // "bright"
|
|
|
|
|
|
|
|
if (strIn.size() < strKey.size())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i + strKey.size() <= strIn.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
size_t k = 0;
|
|
|
|
|
|
|
|
for (; k < strKey.size(); k++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (::tolower((unsigned char)strIn[i + k]) != (unsigned char)strKey[k])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k == strKey.size())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::string strOut = strIn;
|
|
|
|
|
|
|
|
strOut.replace(i, strKey.size(), strSrc);
|
|
|
|
|
|
|
|
return strOut;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 暗场复用明场定位结果(ALIGN_REUSE_* 配置) =====
|
|
|
|
|
|
|
|
// 取当前图的产品ID/相机名:优先用 ImageAllResult 关联的基础结果,兕底用送图信息
|
|
|
|
|
|
|
|
void ImgCheckAnalysisy::GetProductCameraStr(std::string &strProduct, std::string &strCamera)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strProduct = "";
|
|
|
|
|
|
|
|
strCamera = "";
|
|
|
|
|
|
|
|
if (m_pImageAllResult)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (m_pImageAllResult->productBaseResult)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strProduct = m_pImageAllResult->productBaseResult->strproductName;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_pImageAllResult->cameraBaseResult)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strCamera = m_pImageAllResult->cameraBaseResult->strCameraName;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_CheckResult_shareP && m_CheckResult_shareP->in_shareImage)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (strProduct.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strProduct = m_CheckResult_shareP->in_shareImage->strImgProductID;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strCamera.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strCamera = m_CheckResult_shareP->in_shareImage->strCameraName;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 发布本图定位结果(成功)或失败标记(供同产品其它相机复用)
|
|
|
|
|
|
|
|
void ImgCheckAnalysisy::PublishAlignShare(bool bSucc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::string strProduct;
|
|
|
|
|
|
|
|
std::string strCamera;
|
|
|
|
|
|
|
|
GetProductCameraStr(strProduct, strCamera);
|
|
|
|
|
|
|
|
if (strProduct.empty() || strCamera.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bSucc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!m_pEdge_Align_Result)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cv::Size sz(0, 0);
|
|
|
|
|
|
|
|
if (m_CheckResult_shareP && m_CheckResult_shareP->in_shareImage)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sz = m_CheckResult_shareP->in_shareImage->img.size();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignShare::GetInstance().PublishSuccess(strProduct, strCamera, m_strCurDetChannel, m_pEdge_Align_Result, sz);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AlignShare::GetInstance().PublishFailed(strProduct, strCamera, m_strCurDetChannel);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 暗场相机不做定位模型:等待并复用明场相机的定位结果
|
|
|
|
|
|
|
|
// 返回 true 时:m_pEdge_Align_Result / m_outer_rroi / m_inner_rroi / m_tag_roiList 已用明场结果填充
|
|
|
|
|
|
|
|
// 返回 false:非复用相机,或复用失败(超时/源失败/无源图/尺寸不一致),调用方走自有定位
|
|
|
|
|
|
|
|
bool ImgCheckAnalysisy::TryReuseAlignFromSource(std::string &strSrcCamera, std::string &strSrcChannel, int &nWaitMs)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
nWaitMs = -1;
|
|
|
|
|
|
|
|
#if !ALIGN_REUSE_ENABLE
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
std::string strProduct;
|
|
|
|
|
|
|
|
std::string strCamera;
|
|
|
|
|
|
|
|
GetProductCameraStr(strProduct, strCamera);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 相机名/通道名都要能按 dark->bright 替换,否则本相机不在复用规则内
|
|
|
|
|
|
|
|
std::string strSrcCam = ReplaceDarkWithBright(strCamera);
|
|
|
|
|
|
|
|
std::string strSrcChn = ReplaceDarkWithBright(m_strCurDetChannel);
|
|
|
|
|
|
|
|
if (strSrcCam.empty() || strSrcChn.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
strSrcCamera = strSrcCam;
|
|
|
|
|
|
|
|
strSrcChannel = strSrcChn;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_pImageAllResult || !m_pImageAllResult->productBaseResult || !m_pImageAllResult->productBaseResult->alignPushState)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align reuse", "reuse from %s|%s failed(no push state), do align by self", strSrcCam.c_str(), strSrcChn.c_str());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align reuse", "wait %s|%s (timeout %d ms)", strSrcCam.c_str(), strSrcChn.c_str(), ALIGN_REUSE_WAIT_TIMEOUT_MS);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AlignShare &alignShare = AlignShare::GetInstance();
|
|
|
|
|
|
|
|
std::shared_ptr<AI_Edge_Algin::Edge_AI_Result> pSrc;
|
|
|
|
|
|
|
|
cv::Size srcSize;
|
|
|
|
|
|
|
|
const long t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
|
|
bool bGot = false;
|
|
|
|
|
|
|
|
bool bSucc = false;
|
|
|
|
|
|
|
|
std::string strFailReason = "timeout";
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (alignShare.TryGet(strProduct, strSrcCam, strSrcChn, bSucc, pSrc, srcSize))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bGot = true;
|
|
|
|
|
|
|
|
if (!bSucc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strFailReason = "source align failed";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 源图不会再来了(送图已结束,且源相机没有图):立即回退,不干等超时
|
|
|
|
|
|
|
|
if (!m_pImageAllResult->productBaseResult->alignPushState->MayStillCome(strSrcCam))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strFailReason = "no source image";
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CheckUtil::getcurTime() - t1 > ALIGN_REUSE_WAIT_TIMEOUT_MS)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(ALIGN_REUSE_POLL_MS));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
nWaitMs = (int)(CheckUtil::getcurTime() - t1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!bGot || !bSucc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align reuse", "reuse from %s|%s failed(wait %d ms, %s), do align by self",
|
|
|
|
|
|
|
|
strSrcCam.c_str(), strSrcChn.c_str(), nWaitMs, strFailReason.c_str());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pSrc || pSrc->bigroi.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align reuse", "reuse from %s|%s failed(wait %d ms, src roi empty), do align by self",
|
|
|
|
|
|
|
|
strSrcCam.c_str(), strSrcChn.c_str(), nWaitMs);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 图像尺寸必须与源图一致,否则源坐标系不可用
|
|
|
|
|
|
|
|
if (srcSize.width > 0 && srcSize.height > 0 && m_CheckResult_shareP && m_CheckResult_shareP->in_shareImage)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const cv::Mat &img = m_CheckResult_shareP->in_shareImage->img;
|
|
|
|
|
|
|
|
if (img.cols != srcSize.width || img.rows != srcSize.height)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align reuse", "reuse from %s|%s failed, size %dx%d != cur %dx%d, do align by self",
|
|
|
|
|
|
|
|
strSrcCam.c_str(), strSrcChn.c_str(), srcSize.width, srcSize.height, img.cols, img.rows);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 复用明场定位结果:ROI/掩码/映射都用明场的
|
|
|
|
|
|
|
|
m_pEdge_Align_Result = pSrc;
|
|
|
|
|
|
|
|
m_outer_rroi = pSrc->bigroi[0];
|
|
|
|
|
|
|
|
if (!pSrc->smallroi.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_inner_rroi = pSrc->smallroi[0];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tag_roiList = pSrc->tagroi; // 直接赋值:明场没有标签时清空(避免沿用上一张的标签)
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckRun()
|
|
|
|
int ImgCheckAnalysisy::CheckRun()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
@ -574,6 +763,7 @@ int ImgCheckAnalysisy::CheckRun()
|
|
|
|
if (rec != CHECK_OK)
|
|
|
|
if (rec != CHECK_OK)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "ConfigCheck is error type = %d", rec);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "ConfigCheck is error type = %d", rec);
|
|
|
|
|
|
|
|
PublishAlignShare(false); // 本图不会产出定位结果,通知可能的等待方(暗场复用)
|
|
|
|
m_nErrorCode = rec;
|
|
|
|
m_nErrorCode = rec;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
@ -591,23 +781,51 @@ int ImgCheckAnalysisy::CheckRun()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
nfunction = 1;
|
|
|
|
nfunction = 1;
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "m_pFuntion is NULL");
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "m_pFuntion is NULL");
|
|
|
|
|
|
|
|
PublishAlignShare(false); // 本图不会产出定位结果,通知可能的等待方(暗场复用)
|
|
|
|
m_nErrorCode = 22;
|
|
|
|
m_nErrorCode = 22;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*AI 边缘定位(内外边缘)*/
|
|
|
|
/*AI 边缘定位(内外边缘)*/
|
|
|
|
// 模型定位内外边缘
|
|
|
|
// 暗场相机不做定位模型,等待复用明场相机的定位结果(见 ALIGN_REUSE_* 配置);
|
|
|
|
int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi, m_tag_roiList);
|
|
|
|
// 非复用相机、或复用失败(源超时/源失败/无源图/尺寸不一致)时,仍走原有定位流程
|
|
|
|
|
|
|
|
int reedge = 0;
|
|
|
|
|
|
|
|
int nAlignReuseWaitMs = -1;
|
|
|
|
|
|
|
|
std::string strAlignSrcCamera;
|
|
|
|
|
|
|
|
std::string strAlignSrcChannel;
|
|
|
|
|
|
|
|
long time_edge_e;
|
|
|
|
|
|
|
|
if (TryReuseAlignFromSource(strAlignSrcCamera, strAlignSrcChannel, nAlignReuseWaitMs))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 复用成功:m_pEdge_Align_Result / m_outer_rroi / m_inner_rroi / m_tag_roiList 已用明场结果填充
|
|
|
|
|
|
|
|
PublishAlignShare(true);
|
|
|
|
|
|
|
|
time_edge_e = CheckUtil::getcurTime();
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect",
|
|
|
|
|
|
|
|
"-------------------AI_Edge reuse from %s|%s--wait %d ms----succ---time %ld----\n",
|
|
|
|
|
|
|
|
strAlignSrcCamera.c_str(), strAlignSrcChannel.c_str(), nAlignReuseWaitMs, time_edge_e - time_edge_s);
|
|
|
|
|
|
|
|
// 定位模型不跑,但把手检测仍要执行:暗场图像 + 明场 bigmask
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
long handle_s = CheckUtil::getcurTime();
|
|
|
|
|
|
|
|
CheckHandleByBigMask(m_CheckResult_shareP->in_shareImage->img, 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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi, m_tag_roiList);
|
|
|
|
if (reedge != 0)
|
|
|
|
if (reedge != 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge);
|
|
|
|
|
|
|
|
PublishAlignShare(false); // 定位失败:通知可能的等待方(暗场复用),让其回退自行定位
|
|
|
|
m_nErrorCode = reedge;
|
|
|
|
m_nErrorCode = reedge;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
return m_nErrorCode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
long time_edge_e = CheckUtil::getcurTime();
|
|
|
|
PublishAlignShare(true);
|
|
|
|
|
|
|
|
time_edge_e = CheckUtil::getcurTime();
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect", "-------------------------AI_Edge------------succ---time %ld----\n", time_edge_e - time_edge_s);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect", "-------------------------AI_Edge------------succ---time %ld----\n", time_edge_e - time_edge_s);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*生成检测图:用 m_outer_rroi(旋转矩形)确定产品区域,并把该区域旋转摆正后输出;
|
|
|
|
/*生成检测图:用 m_outer_rroi(旋转矩形)确定产品区域,并把该区域旋转摆正后输出;
|
|
|
|
原图坐标 -> 检测图坐标 的映射存入 m_matSrc2Det / m_matDet2Src,后续坐标换算都走这对矩阵*/
|
|
|
|
原图坐标 -> 检测图坐标 的映射存入 m_matSrc2Det / m_matDet2Src,后续坐标换算都走这对矩阵*/
|
|
|
|
|