You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1572 lines
42 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @Author: your name
* @Date: 2022-04-20 15:50:00
* @LastEditTime: 2025-09-23 10:29:01
* @LastEditors: xiewenji 527774126@qq.com
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp
*/
#include "CameraCheckAnalysisy.hpp"
#include "ImgCheckAnalysisy.hpp"
#include "CheckUtil.hpp"
#include "Define.h"
#include <atomic>
CameraCheckAnalysisy::CameraCheckAnalysisy()
{
m_nErrorCode = 0; // 错误代码
m_bInitSucc = false; // 初始化状态
m_bExit = false; // 是否退出检测
m_bHaveImgeDet = false;
m_strcameraName = "";
nLastCheckAnalysisyThreadIdx = 0;
m_pChannelFuntion = &m_AnalysisyConfig.checkFunction;
m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction;
m_nConfigIdx = -1;
m_pdetlog = std::make_shared<DetLog>();
m_pCommonAnalysisyConfig = NULL;
m_imageResultJudge.SetAnalysisyConfig(&m_AnalysisyConfig);
bshowimg = false;
}
CameraCheckAnalysisy::~CameraCheckAnalysisy()
{
}
int CameraCheckAnalysisy::set_cpu_id(const std::vector<int> &cpu_set_vec)
{
// for cpu affinity
int nRet = 0;
#ifdef __linux
cpu_set_t _cur_cpu_set;
CPU_ZERO(&_cur_cpu_set);
for (auto _id : cpu_set_vec)
{
CPU_SET(_id, &_cur_cpu_set);
}
if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set))
{
perror("set cpu affinity failed: ");
printf("Warning: set cpu affinity failed ... ...\n");
nRet = -1;
}
#endif //__linux
return nRet;
}
int CameraCheckAnalysisy::WaitDetImg()
{
std::unique_lock<std::mutex> lk(mtx_WaiteImg);
cond_WaiteImg.wait(lk, [this]()
{ return m_bHaveImgeDet; });
lk.unlock();
return 0;
}
// 判断物料在左还是在右
string JudgeMaterialPosition(Mat img) {
if (img.empty()) {
cerr << "Error: Input image is empty!" << endl;
return "Unknown";
}
// 原图可能是彩色,内部统一转灰度计算(形参为副本,不会改动调用方图像)
if (img.channels() != 1) {
cv::Mat grayImg;
if (img.channels() == 4) {
cv::cvtColor(img, grayImg, cv::COLOR_BGRA2GRAY);
} else {
cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY);
}
img = grayImg;
}
resize(img, img, Size(img.cols, img.rows * 0.001), 0, 0);
int rows = img.rows;
int cols = img.cols;
// 统计灰度值 < bg_val 的像素数量
int left_black_count = 0;
int right_black_count = 0;
int bg_val = 25;
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < 3; ++col) {
if (img.at<uchar>(row, col) < 25) {
left_black_count++;
}
}
for (int col = cols - 3; col < cols; ++col) {
if (img.at<uchar>(row, col) < 25) {
right_black_count++;
}
}
}
// 判断物料位置
if (left_black_count <= right_black_count) {
return "Left";
} else if (left_black_count > right_black_count) {
return "Right";
}
else{
return "Unknown";
}
}
//正常情况CA(img物料在左,img_B物料在右),TA(img物料在右,img_B物料在左)
bool ifExchange(cv::Mat &img, const cv::Mat &img_B, std::string strcam ){
string img_position = JudgeMaterialPosition(img);
string img_B_position = JudgeMaterialPosition(img_B);
if (strcam == "TA"){
if (img_position == "Left" && img_B_position == "Right"){
return true;
}
else{
return false;
}
}
else{
if (img_position == "Right" && img_B_position == "Left"){
return true;
}
else{
return false;
}
}
}
int CameraCheckAnalysisy::Detect_Pre()
{
std::string strlog;
std::string strSN;
std::string strBasic;
strSN = m_pCheck_Result->productBaseResult->strproductName;
strBasic = ">>" + strSN + " cam:" + m_strcameraName;
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================start", strBasic.c_str());
std::shared_ptr<ImageAllResult> pImageResult = m_pCheck_Result->GetNoDetImg();
if (!pImageResult)
{
return 1;
}
if (!pImageResult->result->in_shareImage->bCam_AB)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================bCam_AB = false", strBasic.c_str());
return 0;
}
if (pImageResult->result->in_shareImage->img.empty() ||
pImageResult->result->in_shareImage->img_B.empty())
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img.empty() || img_B.empty() ", strBasic.c_str());
return 1;
}
//判断图片左右,0为左,1为右
bool exchange_img = ifExchange(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B, pImageResult->result->in_shareImage->strCameraName);
if(exchange_img){
std::swap(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B);
}
// printf("===66666666666666666\n");
int re = Mergimg(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B,
pImageResult->result->in_shareImage->strCameraName, pImageResult->result->in_shareImage->strChannel);
if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg)
{
cv::imwrite(pImageResult->result->in_shareImage->strCameraName + "_MergeImg.png", pImageResult->result->in_shareImage->img);
return 2;
}
return 0;
}
int CameraCheckAnalysisy::Mergimg(cv::Mat &img, const cv::Mat &img_B, std::string strcam, std::string strchannel)
{
// std::cout << img.size() << std::endl;
// std::cout << img_B.size() << std::endl;
if (img.size() != img_B.size())
{
return -1;
}
long t1, t2;
t1 = CheckUtil::getcurTime();
int re = 0;
cv::Rect Left_Roi;
cv::Rect Right_Roi;
cv::Mat AllImg = cv::Mat::zeros(img.rows, img.cols * 2, img.type());
// cv::imwrite(strcam + strchannel + "_img.png", img);
// cv::imwrite(strcam + strchannel + "img_B.png", img_B);
if (strcam == "TA")
{
cv::Rect Left_Tem_Roi;
cv::Point Left_Tem_Point_Up;
cv::Point Left_Tem_Point_Donw;
cv::Rect Right_Tem_Roi;
cv::Point Right_Tem_Point_Up;
cv::Point Right_Tem_Point_Donw;
// left Img
{
re = GetRectAndPoint(img, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel);
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAA error %d", strcam.c_str(), re);
return 1;
}
re = GetRectAndPoint(img_B, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel);
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAB error %d", strcam.c_str(), re);
return 1;
}
img(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi));
int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y;
int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y;
float fhscle = hlen_left * 1.0f / hlen_right;
int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y;
cv::Rect allroi = Right_Tem_Roi;
allroi.height *= fhscle;
allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width;
allroi.y += dy;
cv::Size sz;
sz.width = allroi.width;
sz.height = allroi.height;
cv::resize(img_B(Right_Tem_Roi), AllImg(allroi), sz);
}
}
else
{
cv::Rect Left_Tem_Roi;
cv::Point Left_Tem_Point_Up;
cv::Point Left_Tem_Point_Donw;
cv::Rect Right_Tem_Roi;
cv::Point Right_Tem_Point_Up;
cv::Point Right_Tem_Point_Donw;
// left Img
{
re = GetRectAndPoint(img_B, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel);
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAA error %d", strcam.c_str(), re);
return 1;
}
re = GetRectAndPoint(img, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel);
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAB error %d", strcam.c_str(), re);
return 1;
}
img_B(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi));
int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y;
int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y;
float fhscle = hlen_left * 1.0f / hlen_right;
int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y;
cv::Rect allroi = Right_Tem_Roi;
allroi.height *= fhscle;
allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width;
allroi.y += dy;
cv::Size sz;
sz.width = allroi.width;
sz.height = allroi.height;
cv::resize(img(Right_Tem_Roi), AllImg(allroi), sz);
}
}
img = AllImg;
t2 = CheckUtil::getcurTime();
// cv::imwrite(strcam + strchannel + "_merg.png", AllImg);
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg use time %ld ms", strcam.c_str(), t2 - t1);
return 0;
}
int CameraCheckAnalysisy::GetRectAndPoint(const cv::Mat &img, cv::Rect &roi, cv::Point &merg_p_up, cv::Point &merg_p_down, bool bleft, std::string strcam, std::string strchannel)
{
bshowimg = false;
int A_line_up = 0;
int A_line_down = 0;
Edge_Search_Config config;
if (bshowimg)
{
if (img.channels() != 1)
{
showimg = img.clone();
}
else
{
cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR);
}
}
config.nSearchCount = 10;
config.strchannel = strchannel;
config.directSign = DirectSign_UP;
if (bleft)
{
config.roi = cv::Rect(0, 0, 200, img.rows * 0.8);
}
else
{
config.roi = cv::Rect(img.cols - 200, 0, 200, img.rows * 0.8);
}
int re123 = GetEdgePoint(img, &config, A_line_up);
if (re123 != 0)
{
printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_up %d\n", re123);
return 1;
}
config.directSign = DirectSign_DOWN;
config.strchannel = strchannel + "ccc";
config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1);
if (bleft)
{
config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1);
}
else
{
config.roi = cv::Rect(img.cols - 200, img.rows * 0.2, 200, img.rows * 0.8 - 1);
}
re123 = GetEdgePoint(img, &config, A_line_down);
if (re123 != 0)
{
printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_down %d\n", re123);
return 1;
}
{
if (bshowimg)
{
cv::line(showimg, cv::Point(0, A_line_down), cv::Point(img.cols, A_line_down), cv::Scalar(0, 255, 0), 2);
cv::line(showimg, cv::Point(0, A_line_up), cv::Point(img.cols, A_line_up), cv::Scalar(0, 255, 0), 2);
cv::imwrite(strcam + strchannel + "_line.png", showimg);
}
}
// printf("DirectSign_UP::111111111111111111 re123 %d\n", re123);
// getchar();
// 阈值化 + 轮廓提取只支持单通道,彩色原图内部转灰度(不改动调用方图像)
cv::Mat grayImg;
if (img.channels() != 1)
{
if (img.channels() == 4)
{
cv::cvtColor(img, grayImg, cv::COLOR_BGRA2GRAY);
}
else
{
cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY);
}
}
const cv::Mat &workImg = (img.channels() == 1) ? img : grayImg;
cv::Mat small, smallbin;
cv::resize(workImg, small, cv::Size(600, 1500));
cv::threshold(small, smallbin, 15, 255,
cv::THRESH_BINARY);
/* 3. contours */
std::vector<std::vector<cv::Point>> contours;
cv::findContours(smallbin, contours,
cv::RETR_EXTERNAL,
cv::CHAIN_APPROX_SIMPLE);
if (contours.empty())
return 1;
/* 4. max contour */
double maxArea = 0;
int idx = -1;
for (int i = 0; i < contours.size(); i++)
{
double area = cv::contourArea(contours[i]);
if (area > maxArea)
{
maxArea = area;
idx = i;
}
}
if (idx < 0)
return 1;
cv::Rect rSmall = cv::boundingRect(contours[idx]);
/* 5. map to original */
float sx = (float)workImg.cols / smallbin.cols;
float sy = (float)workImg.rows / smallbin.rows;
cv::Rect rectInSrc;
rectInSrc.x = int(rSmall.x * sx) - 50;
rectInSrc.y = int(rSmall.y * sy) - 50;
rectInSrc.width = int(rSmall.width * sx) + 100;
rectInSrc.height = int(rSmall.height * sy) + 100;
if (rectInSrc.y >= A_line_up)
{
rectInSrc.y = A_line_up - 5;
}
if (rectInSrc.y + rectInSrc.height <= A_line_down)
{
rectInSrc.height = A_line_down + 5 - rectInSrc.y;
}
if (rectInSrc.x < 0)
rectInSrc.x = 0;
if (rectInSrc.y < 0)
rectInSrc.y = 0;
if (rectInSrc.x + rectInSrc.width > workImg.cols)
rectInSrc.width = workImg.cols - rectInSrc.x;
if (rectInSrc.y + rectInSrc.height > workImg.rows)
{
rectInSrc.height = workImg.rows - rectInSrc.y;
}
merg_p_up.y = A_line_up;
merg_p_up.x = workImg.cols;
merg_p_down.y = A_line_down;
merg_p_down.x = workImg.cols;
roi = rectInSrc;
if (bshowimg)
{
cv::rectangle(showimg, rectInSrc, cv::Scalar(0, 0, 255), 2);
cv::imwrite(strcam + strchannel + "_rect.png", showimg);
}
return 0;
}
// 对该相机下的每一张图片进行处理
int CameraCheckAnalysisy::Detect_Images()
{
std::string strlog;
std::string strSN;
std::string strBasic;
strSN = m_pCheck_Result->productBaseResult->strproductName;
strBasic = ">>" + strSN + " cam:" + m_strcameraName;
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s ==================start", strBasic.c_str());
// // 循环处理每个图片
bool bcomplete = false;
long time_No_CheckAnalysisy = 30 * 1000;
long ts = CheckUtil::getcurTime();
while (!bcomplete)
{
std::this_thread::sleep_for(std::chrono::milliseconds(20));
ImgCheckBase *pImgCheckAnalysisy = NULL;
long t1 = CheckUtil::getcurTime();
// 拿到计算资源
while (true)
{
pImgCheckAnalysisy = GetDealResult(-1);
if (pImgCheckAnalysisy != NULL)
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(20)); //
long t2 = CheckUtil::getcurTime();
// 如果 超过秒XX都没有拿到处理资源,则直接退出
if (t2 - t1 > time_No_CheckAnalysisy)
{
m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "Error %ld ms No pImgCheckAnalysisy", time_No_CheckAnalysisy);
break;
}
}
// 没有分析检测资源,直接退出
if (pImgCheckAnalysisy == NULL)
{
continue;
}
// 1、把每张图都进行AI 推理 获得 blob 结果
std::shared_ptr<ImageAllResult> pImageResult = m_pCheck_Result->GetNoDetImg();
bool bHaveNotdetImg = false;
// 没有未检测的图片了。
if (pImageResult)
{
m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "channel %s send det ", pImageResult->strChannel.c_str());
bHaveNotdetImg = true;
pImgCheckAnalysisy->SetDataRun_SharePtr(pImageResult);
}
else
{
// 图片都已经送完了。
if (m_pCheck_Result->getImgPushComplate())
{
// printf("Cam Detect_Images %s ==================send end \n", strBasic.c_str());
// 没有图在进行 检测了。
bool bhavedet = false;
for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++)
{
if (CHECK_THREAD_STATUS_IDLE != m_pImgCheckAnalysisy[i]->GetStatus())
{
bhavedet = true;
break;
}
}
// printf("Cam Detect_Images %s ==================bhavedet %d\n", strBasic.c_str(), bhavedet);
if (!bhavedet)
{
bcomplete = true;
}
}
else
{
// printf("Cam Detect_Images %s ==================No send end\n", strBasic.c_str() );
}
}
}
long te = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s =====ALL image det complate time %ld ms=============End", strBasic.c_str(), te - ts);
return 0;
}
int CameraCheckAnalysisy::ResultParamJudge()
{
//==================================================
//======= 适用于 单相机或多相机,每个相机之间的图相互没关系。
//=======
//=======
//=======
//==================================================
std::string strlog;
std::string strSN;
std::string strBasic;
long ts = CheckUtil::getcurTime();
int ImageNum = m_pCheck_Result->ImageALLDetResultList.size();
if (ImageNum <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error ImageNum <=0");
return 1;
}
// 如果 参数是空,直接返回。
if (m_pCommonAnalysisyConfig == NULL)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error m_pCommonAnalysisyConfig == NULL");
return 1;
}
int regionNum = m_pCommonAnalysisyConfig->regionConfigArr.size();
if (regionNum <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error Config region num = 0");
}
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================start image Num %d region num %d", ImageNum, regionNum);
// 对每个图片通道进行单独分析
for (int imgidx = 0; imgidx < ImageNum; imgidx++)
{
long t1 = CheckUtil::getcurTime();
int re = m_imageResultJudge.ResultJudge(m_pCheck_Result->ImageALLDetResultList.at(imgidx));
long t2 = CheckUtil::getcurTime();
m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx));
long t3 = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2);
// 把结果转成 json 保存。 用以复测
std::shared_ptr<CheckResult> m_CheckResult_shareP = m_pCheck_Result->ImageALLDetResultList.at(imgidx)->result;
m_CheckResult_shareP->strResultJson = m_CheckResultJson.GetResultString(m_pCheck_Result->ImageALLDetResultList.at(imgidx)->pDetResult);
}
long te = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================End time %ld ms ", te - ts);
// m_pdetlog->printLog(m_strcameraName);
return 0;
}
int CameraCheckAnalysisy::Init(std::string strcameraName)
{
m_strcameraName = strcameraName;
printf("CameraCheckAnalysisy::Init start \n");
SetNewConfig();
int re = 0;
re = InitCheckAnalysisy();
if (CHECK_OK != re)
{
printf("InitCheckAnalysisy error\n");
return -1;
}
re = InitRun();
if (CHECK_OK != re)
{
printf("InitRun error\n");
m_nErrorCode = re;
return m_nErrorCode;
}
printf("CameraCheckAnalysisy::Init end \n");
return 0;
}
void CameraCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect,
const cv::RotatedRect &innerRect,
const std::vector<std::vector<cv::Point>> &pinContours)
{
for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++)
{
auto *p = static_cast<ImgCheckAnalysisy *>(m_pImgCheckAnalysisy[i]);
if (p)
{
p->SetTplInfo(outerRect, innerRect, pinContours);
}
}
}
int CameraCheckAnalysisy::StartCheck(std::shared_ptr<CameraResult> pCamera_Check_Result)
{
if (m_bHaveImgeDet)
{
return -1;
}
{
std::lock_guard<std::mutex> lock(mtx_WaiteImg);
m_pCheck_Result = pCamera_Check_Result;
if (m_pCheck_Result->bJson)
{
// 如果是 复测 直接进入 参数判断阶段。
m_pCheck_Result->SetCheckStep(Check_Step_ResultParamJudg); // 进入预处理阶段
}
else
{
m_pCheck_Result->SetCheckStep(Check_Step_PreDet); // 进入预处理阶段
}
m_bHaveImgeDet = true;
m_pdetlog = m_pCheck_Result->detlog;
m_pdetlog->AddCheckstr(PrintLevel_0, "StartCheck", "==================start %s", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
}
cond_WaiteImg.notify_all();
return 0;
}
int CameraCheckAnalysisy::StartThread()
{
m_bExit = false;
// 开启检测线程
ptr_thread_Run = std::make_shared<std::thread>(std::bind(&CameraCheckAnalysisy::Run, this));
return 0;
}
int CameraCheckAnalysisy::StopThread()
{
m_bExit = true;
if (ptr_thread_Run != nullptr)
{
if (ptr_thread_Run->joinable())
{
ptr_thread_Run->join();
}
}
return 0;
}
int CameraCheckAnalysisy::InitRun()
{
int re;
re = StartThread();
if (CHECK_OK != re)
{
return re;
}
m_bInitSucc = true;
// 检测前更新参数
SetNewConfig();
return 0;
}
int CameraCheckAnalysisy::InitCheckAnalysisy()
{
int re = 0;
// 全局递增的 CPU 核偏移:
static std::atomic<int> s_cpuOffset{0};
for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++)
{
RunInfoST RunConfig;
RunConfig.nThreadIdx = i;
{
// 核带下沉到库内部:不再依赖调用方传入的 nCpu_start_Idx / nCpu_num
int offset = s_cpuOffset.fetch_add(1) % CHECK_CPU_BAND_NUM;
RunConfig.nCpu_start_Idx = CHECK_CPU_BAND_START + offset;
}
RunConfig.nCpu_num = 1;
m_pImgCheckAnalysisy[i] = ImgCheckBase::GetInstance();
re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)&RunConfig, CHECK_CONFIG_Run);
if (re != 0)
{
printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Run, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str());
return re;
}
re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)m_pConfig.get(), CHECK_CONFIG_Module);
if (re != 0)
{
printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Module, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str());
return re;
}
re = m_pImgCheckAnalysisy[i]->RunStart();
if (re != 0)
{
printf("cami %s RunStart Fail ==%d\n", m_strcameraName.c_str(), re);
return re;
}
// printf(">>>>cami %s InitCheckAnalysisy: ImgCheckThread %d / %d Start Succ \n", m_strcameraName.c_str(), i+1, IMGCHECKANALYSISY_NUM);
if (re != 0)
{
return re;
}
}
return 0;
}
int CameraCheckAnalysisy::CheckImgRun()
{
int re = 0;
Check_Step curcheckStep = m_pCheck_Result->GetCheckStep();
m_pdetlog->bPrintStr = false;
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "------------curcheckStep:%d ", curcheckStep);
// 如果是未检测状态,则开始预处理
if (curcheckStep == Check_Step_NODet)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "Error curcheckStep = NODet ");
return 1;
}
// 检测前更新参数
SetNewConfig();
// 预处理
if (curcheckStep == Check_Step_PreDet)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
re = Detect_Pre();
if (re != 0)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet error = %d", m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), re);
curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段
}
else
{
curcheckStep = Check_Step_ImgeDet; // 进入到预图片检测阶段
}
m_pCheck_Result->SetCheckStep(curcheckStep);
}
// 检测每张图片
if (curcheckStep == Check_Step_ImgeDet)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
// 检测每张图片
re = Detect_Images();
curcheckStep = Check_Step_ResultParamJudg; // 进入到预图片检测阶段
m_pCheck_Result->SetCheckStep(curcheckStep);
}
// 对检测结果进行参数判断,判断是否NG.
if (curcheckStep == Check_Step_ResultParamJudg)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ResultParamJudg", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
// 检测每张图片
re = ResultParamJudge();
// 如果有异常
if (re != 0)
{
// 图片 送图没有完成,则继续等待。
if (!m_pCheck_Result->getImgPushComplate())
{
return 1;
}
}
curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段
m_pCheck_Result->SetCheckStep(curcheckStep);
}
if (curcheckStep == Check_Step_ImgeDet_End)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet_End", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
// 所有图片都送完了。
if (m_pCheck_Result->getImgPushComplate())
{
curcheckStep = Check_Step_Complete; // 进入到预图片检测阶段
}
else
{
printf("========came %s wait img send end \n", m_strcameraName.c_str());
}
}
// 检测完成,
if (curcheckStep == Check_Step_Complete)
{
long tend = CheckUtil::getcurTime();
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_Complete", m_pCheck_Result->cameraBaseResult->strCameraName.c_str());
std::string strTimg = CheckUtil::getCurTimeHMS();
m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "========came %s Check ALL end time %ld ms %s",
m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), tend - m_pCheck_Result->time_start, strTimg.c_str());
InsertCameraLog();
// 结果与日志(det_LogList)全部写完后,才置为 Check_Step_Complete,
// 通知 Det_Product 结果可以交付调用方;并且整个收尾过程保持在
// mtx_WaiteImg 锁内,与 StartCheck() 对 m_pCheck_Result 的赋值互斥,
// 避免同一 shared_ptr 被并发 reset/赋值(会造成控制块双重释放)。
std::lock_guard<std::mutex> lock(mtx_WaiteImg);
m_pCheck_Result->SetCheckStep(Check_Step_Complete);
m_bHaveImgeDet = false;
m_pCheck_Result.reset();
}
// m_pdetlog->printLog(m_strcameraName);
return 0;
}
int CameraCheckAnalysisy::Run()
{
while (!m_bExit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(20));
WaitDetImg();
int re = CheckImgRun();
}
return 0;
}
int CameraCheckAnalysisy::ImgEdge(cv::Mat img, cv::Mat &detMaskImg, cv::Rect &roi, int productIdx)
{
int re = 0;
return re;
}
int CameraCheckAnalysisy::InsertCameraLog()
{
int ImageNum = m_pCheck_Result->ImageALLDetResultList.size();
for (int imgidx = 0; imgidx < ImageNum; imgidx++)
{
std::shared_ptr<ImageAllResult> pImageResult = m_pCheck_Result->ImageALLDetResultList.at(imgidx);
std::shared_ptr<CheckResult> m_CheckResult_shareP = pImageResult->result; // 返回结果
if (!m_CheckResult_shareP || !pImageResult)
{
continue;
}
// 1、把图片的相关日志 写到 返回 日志中。
// 注意:DetLog 可能仍被实例线程写入,使用 GetLogs() 做加锁快照,避免并发遍历。
{
std::vector<std::string> imgLogs = pImageResult->detlog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
imgLogs.begin(), imgLogs.end());
}
std::string str = "";
char buffer[256];
// 2、把缺陷信息 写的 返回日志中。
{
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
if (!pDetResult)
{
continue;
}
if (!pDetResult->pQx_ErrorList)
{
continue;
}
int qxNum = pDetResult->pQx_ErrorList->size();
// Add NG log
{
sprintf(buffer, " =====================NG num %d=============================", pImageResult->NG_num);
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
if (QX_info->result == QX_RESULT_TYPE_NG)
{
std::shared_ptr<DetLog> pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog;
std::vector<std::string> qxLogs = pQxLog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
qxLogs.begin(), qxLogs.end());
}
}
{
sprintf(buffer, " =====================YS num %d=============================", pImageResult->YS_num);
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
if (QX_info->result == QX_RESULT_TYPE_YS)
{
std::shared_ptr<DetLog> pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog;
std::vector<std::string> qxLogs = pQxLog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
qxLogs.begin(), qxLogs.end());
}
}
{
sprintf(buffer, " =====================OK num %d=============================", pImageResult->Ok_num);
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
if (QX_info->result == QX_RESULT_TYPE_OK)
{
std::shared_ptr<DetLog> pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog;
std::vector<std::string> qxLogs = pQxLog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
qxLogs.begin(), qxLogs.end());
}
}
{
sprintf(buffer, " =====================NO Judge num %d=============================", pImageResult->NoJudge_num);
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
if (QX_info->result == QX_RESULT_TYPE_NoJduge)
{
std::shared_ptr<DetLog> pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog;
std::vector<std::string> qxLogs = pQxLog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
qxLogs.begin(), qxLogs.end());
}
}
}
{
sprintf(buffer, " =====================Cam Log =============================");
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
// 3、把相机的日志 写到 返回日志中。
{
std::vector<std::string> camLogs = m_pCheck_Result->detlog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
camLogs.begin(), camLogs.end());
}
{
sprintf(buffer, " =====================Product Log =============================");
str = buffer;
m_CheckResult_shareP->det_LogList.push_back(str);
}
// 4、把产品相关日志 写到 返回日志中。
{
std::vector<std::string> productLogs = m_pCheck_Result->productBaseResult->detlog->GetLogs();
m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(),
productLogs.begin(), productLogs.end());
}
}
return 0;
}
ChannelCheckFunction *CameraCheckAnalysisy::GetChannelFuntion(std::string strChannelName)
{
ChannelCheckFunction *p = NULL;
// printf("m_pChannelFuntion->channelFunctionArr.size() %zu\n", m_pChannelFuntion->channelFunctionArr.size());
for (int i = 0; i < m_pChannelFuntion->channelFunctionArr.size(); i++)
{
if (CheckUtil::compareIgnoreCase(m_pChannelFuntion->channelFunctionArr[i].strChannelName, strChannelName))
{
p = &m_pChannelFuntion->channelFunctionArr[i];
}
}
return p;
}
int CameraCheckAnalysisy::SetNewConfig()
{
if (m_pConfig.get() == nullptr)
{
return 1;
}
if (m_nConfigIdx < 0)
{
m_nConfigIdx = m_pConfig->GetConfigIdx();
m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "CameraCheckAnalysisy:%s m_nConfigIdx %d", m_strcameraName.c_str(), m_nConfigIdx);
}
if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx))
{
m_pConfig->GetConfig(ConfigType_Analysisy_Common_XL, &m_AnalysisyConfig);
if (m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size() > 0)
{
m_pCommonAnalysisyConfig = &m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(0);
m_imageResultJudge.UpdateConfig();
}
else
{
m_pCommonAnalysisyConfig = NULL;
printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n");
}
m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "Get New analysisy config");
// printf("*******ALLImgCheckAnalysisy m_pConfig*********************** Update GetConfig \n");
// m_AnalysisyConfig.checkFunction.print("Update GetConfig");
}
return 0;
}
int CameraCheckAnalysisy::preDet_ZF(std::shared_ptr<ImageDetconfig> p, std::shared_ptr<ImageDetResult> &pResult)
{
ImgCheckBase *pImgCheckAnalysisy = NULL;
long t1 = CheckUtil::getcurTime();
int outTime = 1000 * 5;
while (true)
{
pImgCheckAnalysisy = GetDealResult(-1);
if (pImgCheckAnalysisy != NULL)
{
break;
}
long t2 = CheckUtil::getcurTime();
// 超时
if (t2 - t1 > outTime)
{
return 1;
}
std::this_thread::sleep_for(std::chrono::milliseconds(20)); // 模拟消费过程
}
p->pBaseImgCheckConfig->imgtype = 1;
pImgCheckAnalysisy->CheckImg(p, pResult);
p->pBaseImgCheckConfig->imgtype = 0;
return 0;
}
ImgCheckBase *CameraCheckAnalysisy::GetDealResult(int idx)
{
// 特殊情况
if (idx >= 0 && idx < IMGCHECKANALYSISY_NUM)
{
if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[idx]->GetStatus())
{
// printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", idx);
return m_pImgCheckAnalysisy[idx];
}
else
{
return NULL;
}
}
int re = 0;
int nidx = nLastCheckAnalysisyThreadIdx;
for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++)
{
if (nidx >= IMGCHECKANALYSISY_NUM)
{
nidx = 0;
}
if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[nidx]->GetStatus())
{
nLastCheckAnalysisyThreadIdx = nidx + 1;
// printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", nidx);
return m_pImgCheckAnalysisy[nidx];
}
nidx++;
}
return NULL;
}
int CameraCheckAnalysisy::GetEdgePoint(const cv::Mat &imgSrc, Edge_Search_Config *pEdge_Search_Config, int &outP)
{
bool bdbuge = false;
bdbuge = bshowimg;
if (imgSrc.empty())
{
return -11;
}
// 边缘搜索仅支持单通道;彩色/BGRA 原图在此内部转灰度(不改动调用方图像)
cv::Mat grayImg;
if (imgSrc.channels() != 1)
{
if (imgSrc.channels() == 4)
{
cv::cvtColor(imgSrc, grayImg, cv::COLOR_BGRA2GRAY);
}
else
{
cv::cvtColor(imgSrc, grayImg, cv::COLOR_BGR2GRAY);
}
}
const cv::Mat &img = (imgSrc.channels() == 1) ? imgSrc : grayImg;
// 检查roi;
if (!CheckUtil::RoiInImg(pEdge_Search_Config->roi, img))
{
return -13;
}
if (!pEdge_Search_Config->CheckConfigValid())
{
return -14;
}
std::vector<cv::Point> pointList;
bool search_UP_DOWN = false;
cv::Rect roi = pEdge_Search_Config->roi;
int sx = roi.x;
int ex = roi.x + roi.width;
int sy = roi.y;
int ey = roi.y + roi.height;
int nSearchLen = roi.width; // 搜索区域的长度
int nCurPoint_Step = pEdge_Search_Config->stepCount; // 当前点搜索的步长
// 搜索小范围确认
int nhalfrang = (int)pEdge_Search_Config->nSearchrange / 2;
int nrange_start = 0 - nhalfrang;
int nrange_end = 0 - nhalfrang;
int num = 0;
while (true)
{
num++;
nrange_end++;
if (num >= pEdge_Search_Config->nSearchrange)
{
break;
}
}
// 判断方向
switch (pEdge_Search_Config->directSign)
{
case DirectSign_UP:
search_UP_DOWN = true;
nSearchLen = roi.width;
sx = roi.x;
ex = roi.x + roi.width;
sy = roi.y;
ey = roi.y + roi.height;
nCurPoint_Step = pEdge_Search_Config->stepCount;
break;
case DirectSign_DOWN:
search_UP_DOWN = true;
nSearchLen = roi.width;
nCurPoint_Step = -pEdge_Search_Config->stepCount;
sx = roi.x;
ex = roi.x + roi.width;
sy = roi.y + roi.height - 1;
ey = roi.y;
break;
case DirectSign_Left:
nSearchLen = roi.height;
search_UP_DOWN = false;
nCurPoint_Step = pEdge_Search_Config->stepCount;
sx = roi.x;
ex = roi.x + roi.width;
sy = roi.y;
ey = roi.y + roi.height;
break;
case DirectSign_Right:
nSearchLen = roi.height;
search_UP_DOWN = false;
nCurPoint_Step = -pEdge_Search_Config->stepCount;
sx = roi.x + roi.width - 1;
ex = roi.x;
sy = roi.y;
ey = roi.y + roi.height;
break;
default:
break;
}
// 搜索 点数
int nSearchPointNum = pEdge_Search_Config->nSearchCount;
// 搜素点的间隔
int nSearchPointStep = 1;
if (nSearchPointNum > 1)
{
nSearchPointStep = int(nSearchLen * 1.0f / (nSearchPointNum - 1));
}
if (bdbuge)
{
cv::rectangle(showimg, roi, cv::Scalar(255, 0, 0), 2);
printf("nSearchPointStep %d nCurPoint_Step %d,nrange_start %d %d\n", nSearchPointStep, nCurPoint_Step, nrange_start, nrange_end);
}
uchar *pdata = (uchar *)img.data;
int offt = 0;
// 搜索 上下边
if (search_UP_DOWN)
{
// 每个搜索点 分布在X方向。
for (int x = sx; x < ex; x = x + nSearchPointStep)
{
int bOKNum = 0;
int cur_x = x;
int cur_y = sy;
bool bSucc = false;
int succ_y = 0;
// 对每个搜索点进行 y方向搜索
for (int y = sy;; y = y + nCurPoint_Step)
{
if (y < 0 || y >= img.rows)
{
continue;
}
//
if (nCurPoint_Step > 0 && y > ey)
{
break;
}
if (nCurPoint_Step < 0 && y < ey)
{
break;
}
offt = y * img.cols;
int range_okNum = 0;
// 对一定范围的点进行判断
for (int k = nrange_start; k < nrange_end; k++)
{
int rangeX = x + k;
if (rangeX < 0 || rangeX >= img.cols)
{
continue;
}
offt += rangeX;
if (offt < 0 || offt >= img.cols * img.rows)
{
printf("rangeX %d nCurPoint_Step %d off %d x %d y %d sy %d ey %d %d %d\n", rangeX, nCurPoint_Step, offt, x, y, sy, ey, img.cols, img.rows);
}
if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到
{
range_okNum++;
}
}
if (range_okNum >= pEdge_Search_Config->nSearchrange)
{
if (bdbuge)
{
cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255));
}
if (bOKNum == 0)
{
cur_y = y;
}
bOKNum++;
// 连续搜索到 满足要求的点。
if (bOKNum >= pEdge_Search_Config->nLimit)
{
bSucc = true;
succ_y = y;
break;
}
}
else
{
// 如果有间断,需要重新计算连续情况。
bOKNum = 0;
if (bdbuge)
{
cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0));
}
}
}
if (bSucc)
{
cv::Point p(cur_x, cur_y);
if (bdbuge)
{
cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0));
}
pointList.push_back(p);
if (pointList.size() > 5)
{
// printf("=============feeeee\n");
sy = succ_y - 100;
ey = succ_y + 100;
if (sy < 0)
{
sy = 0;
}
if (ey >= img.rows)
{
ey = img.rows - 1;
}
}
}
}
}
else // 搜索 左右边
{
// 每个搜索点 分布在X方向。
for (int y = sy; y < ey; y = y + nSearchPointStep)
{
int bOKNum = 0;
int cur_x = sx;
int cur_y = y;
bool bSucc = false;
int succ_x = 0;
// 对每个搜索点进行 y方向搜索
for (int x = sx;; x = x + nCurPoint_Step)
{
if (x < 0 || x >= img.cols)
{
continue;
}
//
if (nCurPoint_Step > 0 && x > ex)
{
break;
}
if (nCurPoint_Step < 0 && x < ex)
{
break;
}
int range_okNum = 0;
// 对一定范围的点进行判断
for (int k = nrange_start; k < nrange_end; k++)
{
int rangey = y + k;
if (rangey < 0 || rangey >= img.rows)
{
continue;
}
offt = rangey * img.cols + x;
if (offt < 0 || offt >= img.cols * img.rows)
{
printf("rangey %d off %d x %d y %d ey %d %d %d\n", rangey, offt, x, y, ey, img.cols, img.rows);
}
if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到
{
range_okNum++;
}
}
if (range_okNum >= pEdge_Search_Config->nSearchrange)
{
if (bdbuge)
{
cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255));
}
if (bOKNum == 0)
{
cur_x = x;
}
bOKNum++;
// 连续搜索到 满足要求的点。
if (bOKNum >= pEdge_Search_Config->nLimit)
{
bSucc = true;
succ_x = x;
break;
}
}
else
{
// 如果有间断,需要重新计算连续情况。
bOKNum = 0;
if (bdbuge)
{
cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0));
}
}
}
if (bSucc)
{
cv::Point p(cur_x, cur_y);
if (bdbuge)
{
cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0));
}
pointList.push_back(p);
if (pointList.size() > 5)
{
// printf("=============feeeee\n");
sx = succ_x - 100;
ex = succ_x + 100;
if (sx < 0)
{
sx = 0;
}
if (ex >= img.cols)
{
ex = img.cols - 1;
}
}
}
}
}
if (bdbuge)
{
cv::imwrite(pEdge_Search_Config->strchannel + "show.png", showimg);
}
{
const int maxDeviation = 10; // 可调阈值:最大允许偏离像素
std::vector<cv::Point> avgPoints;
int PNum = pointList.size();
// 第一次计算粗略均值
int sum_y = 0, sum_x = 0;
for (const auto &pt : pointList)
{
sum_x += pt.x;
sum_y += pt.y;
}
float avg_y = sum_y * 1.0f / PNum;
float avg_x = sum_x * 1.0f / PNum;
// 过滤异常点
std::vector<cv::Point> filtered;
for (const auto &pt : pointList)
{
if (search_UP_DOWN) // 横向:判断 y 偏差
{
if (std::abs(pt.y - avg_y) <= maxDeviation)
filtered.push_back(pt);
}
else // 纵向:判断 x 偏差
{
if (std::abs(pt.x - avg_x) <= maxDeviation)
filtered.push_back(pt);
}
}
if (filtered.empty())
return -1;
int sum_fx = 0, sum_fy = 0;
for (const auto &pt : filtered)
{
sum_fx += pt.x;
sum_fy += pt.y;
}
if (search_UP_DOWN) // 横向:判断 y 偏差
{
outP = sum_fy / (int)filtered.size();
}
else // 纵向:判断 x 偏差
{
outP = sum_fx / (int)filtered.size();
}
}
return 0;
}
int CameraCheckAnalysisy::GetLine(const cv::Mat &img, std::vector<cv::Point> &pointList, int lineNum, int xory, int &outP)
{
if (pointList.size() < 0)
return -1;
const int maxDeviation = 10; // 可调阈值:最大允许偏离像素
std::vector<cv::Point> avgPoints;
int PNum = pointList.size();
// 第一次计算粗略均值
int sum_y = 0, sum_x = 0;
for (const auto &pt : pointList)
{
sum_x += pt.x;
sum_y += pt.y;
}
float avg_y = sum_y * 1.0f / PNum;
float avg_x = sum_x * 1.0f / PNum;
// 过滤异常点
std::vector<cv::Point> filtered;
for (const auto &pt : pointList)
{
if (xory == 0) // 横向:判断 y 偏差
{
if (std::abs(pt.y - avg_y) <= maxDeviation)
filtered.push_back(pt);
}
else // 纵向:判断 x 偏差
{
if (std::abs(pt.x - avg_x) <= maxDeviation)
filtered.push_back(pt);
}
}
if (filtered.empty())
return -1;
int sum_fx = 0, sum_fy = 0;
for (const auto &pt : filtered)
{
sum_fx += pt.x;
sum_fy += pt.y;
}
if (xory == 0) // 横向:判断 y 偏差
{
outP = sum_fy / (int)filtered.size();
}
else // 纵向:判断 x 偏差
{
outP = sum_fx / (int)filtered.size();
}
return 0;
}