|
|
#ifndef BRIGHT_GEOSHARE_HPP_
|
|
|
#define BRIGHT_GEOSHARE_HPP_
|
|
|
|
|
|
// ============================================================================
|
|
|
// 明场(B) -> 暗场(D) 几何结果共享
|
|
|
//
|
|
|
// 背景:本机 4 台相机 BCA/DCA/BTA/DTA 中,B 与 D 是同一工位的两个光照通道
|
|
|
// (配对:BCA<->DCA, BTA<->DTA),产品/物料在图像中的位置一致,仅明暗场不同。
|
|
|
// 暗场图对比度低,定位(GetEdgeRoi/AI_Edge)与参数自适应(Adapt)不稳定,
|
|
|
// 因此 D 相机直接复用 B 相机算出的:
|
|
|
// 1) 定位结果 m_CutRoi(检测裁切框)
|
|
|
// 2) Adapt 目标:产品旋转外接矩形(rot_cur_roi)
|
|
|
// 3) 产品真实宽高(mm)
|
|
|
//
|
|
|
// 用法:
|
|
|
// Bright 侧(BCA/BTA)在几何计算完成后 Publish 快照;
|
|
|
// Dark 侧(DCA/DTA)在需要时 Take 快照(带超时,拿不到则回退自身逻辑)。
|
|
|
//
|
|
|
// 匹配键 = 工位对("CA"/"TA"),不按产品名匹配:实际流程中四个相机可能以各自独立
|
|
|
// 的“产品”送检(如 ET 套图流程按 BCA→BTA→DCA→DTA 顺序各送一次),B 与 D 的产品名
|
|
|
// 并不相同。取用即消费(Take 成功后删除),保证一份明场结果只服务一次暗场,
|
|
|
// 不会把上一块板的坐标复用到下一块板;键集合只有 CA/TA 两个,永不增长。
|
|
|
//
|
|
|
// 线程安全:内部 mutex + condition_variable,可在多相机线程间并发使用。
|
|
|
// 关闭开关:环境变量 AOI_DISABLE_BRIGHT_DARK_SHARE=1(用于 A/B 对比旧行为)。
|
|
|
// ============================================================================
|
|
|
|
|
|
#include <string>
|
|
|
#include <map>
|
|
|
#include <mutex>
|
|
|
#include <condition_variable>
|
|
|
#include <chrono>
|
|
|
#include <cstdlib>
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
|
|
// 等待明场结果的超时(ms):超时后暗场回退到自身定位/自适应逻辑。
|
|
|
// 明场与暗场同时开始检查,该值只需覆盖明场“拼接 + 粗定位 + Adapt + AI_Edge”的耗时。
|
|
|
static const long kBrightGeoWaitTimeoutMs = 60000;
|
|
|
|
|
|
// 明暗场共享开关(默认开启)
|
|
|
inline bool BrightGeoShareEnabled()
|
|
|
{
|
|
|
static const bool bEnabled = []() -> bool {
|
|
|
const char *pEnv = std::getenv("AOI_DISABLE_BRIGHT_DARK_SHARE");
|
|
|
if (pEnv == nullptr)
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
std::string s(pEnv);
|
|
|
return !(s == "1" || s == "true" || s == "TRUE" || s == "on" || s == "ON");
|
|
|
}();
|
|
|
return bEnabled;
|
|
|
}
|
|
|
|
|
|
// 相机代码(BCA/BTA/DCA/DTA) -> 工位对(CA/TA);非预期输入返回空串
|
|
|
inline std::string BrightGeoPairOfCamera(const std::string &strCameraCode)
|
|
|
{
|
|
|
if (strCameraCode.find("CA") != std::string::npos)
|
|
|
{
|
|
|
return "CA";
|
|
|
}
|
|
|
if (strCameraCode.find("TA") != std::string::npos)
|
|
|
{
|
|
|
return "TA";
|
|
|
}
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
// 是否明场相机(代码以 B 开头,如 BCA/BTA)
|
|
|
inline bool BrightGeoCameraIsBright(const std::string &strCameraCode)
|
|
|
{
|
|
|
return !strCameraCode.empty() && (strCameraCode[0] == 'B' || strCameraCode[0] == 'b');
|
|
|
}
|
|
|
|
|
|
// 是否暗场相机(代码以 D 开头,如 DCA/DTA)
|
|
|
inline bool BrightGeoCameraIsDark(const std::string &strCameraCode)
|
|
|
{
|
|
|
return !strCameraCode.empty() && (strCameraCode[0] == 'D' || strCameraCode[0] == 'd');
|
|
|
}
|
|
|
|
|
|
// 共享快照的键:工位对("CA"/"TA")
|
|
|
// (注:不按产品名匹配,原因见文件头说明)
|
|
|
|
|
|
// 明场发布给暗场的几何快照
|
|
|
struct BrightGeoSnapshot
|
|
|
{
|
|
|
std::string strProduct; // 发布该快照的产品名(仅用于日志追踪)
|
|
|
bool bValid = false; // 快照是否可用于暗场(明场定位流程是否正常完成)
|
|
|
bool bRoiValid = false; // 产品旋转外接矩形是否有效(明场 Adapt 是否成功)
|
|
|
cv::RotatedRect rotRoi; // 产品旋转外接矩形(原图坐标)
|
|
|
cv::Rect cutRoi; // 定位裁切框(原图坐标)
|
|
|
cv::Size imgSize; // 明场拼接图尺寸(暗场做一致性校验)
|
|
|
float productWidth_mm = 0.f; // 产品真实宽度(mm)
|
|
|
float productHeight_mm = 0.f; // 产品真实高度(mm)
|
|
|
};
|
|
|
|
|
|
class BrightGeoShare
|
|
|
{
|
|
|
public:
|
|
|
static BrightGeoShare &Instance()
|
|
|
{
|
|
|
static BrightGeoShare s_ins;
|
|
|
return s_ins;
|
|
|
}
|
|
|
|
|
|
// 明场发布(同一工位对覆盖旧值),唤醒等待中的暗场线程
|
|
|
void Publish(const std::string &strPair, const BrightGeoSnapshot &snap)
|
|
|
{
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lk(m_mtx);
|
|
|
m_map[strPair] = snap;
|
|
|
}
|
|
|
m_cv.notify_all();
|
|
|
}
|
|
|
|
|
|
// 暗场等待并取走明场结果(超时返回 false;成功则取走并删除,一份结果只服务一次)
|
|
|
bool Take(const std::string &strPair, BrightGeoSnapshot &snap, long nTimeoutMs)
|
|
|
{
|
|
|
std::unique_lock<std::mutex> lk(m_mtx);
|
|
|
bool bOk = m_cv.wait_for(lk, std::chrono::milliseconds(nTimeoutMs),
|
|
|
[&]() { return m_map.find(strPair) != m_map.end(); });
|
|
|
if (!bOk)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
auto it = m_map.find(strPair);
|
|
|
snap = it->second;
|
|
|
m_map.erase(it);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
BrightGeoShare() {}
|
|
|
~BrightGeoShare() {}
|
|
|
|
|
|
std::mutex m_mtx;
|
|
|
std::condition_variable m_cv;
|
|
|
std::map<std::string, BrightGeoSnapshot> m_map;
|
|
|
};
|
|
|
|
|
|
#endif
|