|
|
/*
|
|
|
* @Author: your name
|
|
|
* @Date: 2022-04-20 15:50:00
|
|
|
* @LastEditTime: 2025-09-23 11:34:53
|
|
|
* @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 "ImgCheckAnalysisy.hpp"
|
|
|
#include "CheckUtil.hpp"
|
|
|
#include "Define.h"
|
|
|
#include <omp.h>
|
|
|
#include "AICommonDefine.h"
|
|
|
// 用于排序轮廓的比较函数
|
|
|
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
|
|
|
{
|
|
|
double i = contourArea(contour1);
|
|
|
double j = contourArea(contour2);
|
|
|
return (i > j);
|
|
|
}
|
|
|
ImgCheckAnalysisy::ImgCheckAnalysisy()
|
|
|
: m_pAI_Edge_Algin(m_pdetlog)
|
|
|
{
|
|
|
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
m_nThreadIdx = -1;
|
|
|
m_bInitSucc = false;
|
|
|
m_bExit = false;
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
|
|
|
m_fImgage_Scale_X = 0.03f;
|
|
|
m_fImgage_Scale_Y = 0.03f;
|
|
|
m_pBasicConfig = NULL;
|
|
|
|
|
|
m_strCurDetChannel = "";
|
|
|
m_bupdateconfig = false;
|
|
|
m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction;
|
|
|
|
|
|
m_strLastDate = "";
|
|
|
m_strRootPath_TA_cls = "/home/aidlux/BOE/Cls/TA/";
|
|
|
m_strRootPath_CA_cls = "/home/aidlux/BOE/Cls/CA/";
|
|
|
creatsavedir();
|
|
|
m_pImageStorage = ImageStorage::getInstance();
|
|
|
m_nConfigIdx = -1;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
|
|
|
ImgCheckAnalysisy::~ImgCheckAnalysisy()
|
|
|
{
|
|
|
ExitSystem();
|
|
|
if (m_ImgBlobHFlagData)
|
|
|
{
|
|
|
delete[] m_ImgBlobHFlagData;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
}
|
|
|
int ImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType)
|
|
|
{
|
|
|
int re = 0;
|
|
|
switch (nConfigType)
|
|
|
{
|
|
|
case CHECK_CONFIG_Run:
|
|
|
re = LoadRunConfig(pconfig);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
// printf("---> LoadRunConfig Succ\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("---> LoadRunConfig Fail\n");
|
|
|
}
|
|
|
break;
|
|
|
case CHECK_CONFIG_Module:
|
|
|
re = LoadCheckConfig(pconfig);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
// printf("---> LoadAnalysisConfig Succ\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("---> LoadAnalysisConfig Fail\n");
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
return re;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::RunStart(void *pconfig1)
|
|
|
{
|
|
|
|
|
|
// 1 、更新参数 并判断参数是否合法
|
|
|
int re = CHECK_OK;
|
|
|
re = SetNewConfig();
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
m_nErrorCode = re;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
// printf("---> RunStart Start m_RunConfig.nThreadIdx %d \n", m_RunConfig.nThreadIdx);
|
|
|
|
|
|
m_nThreadIdx = m_RunConfig.nThreadIdx;
|
|
|
|
|
|
re = InitRun(m_RunConfig.nCpu_start_Idx);
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
m_nErrorCode = re;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
runner = std::make_shared<AIMulThreadRunBase>();
|
|
|
runner->Start();
|
|
|
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
// printf("ImgCheckAnalysisy >>>> ImgCheckThread %d Start Succ \n", m_nThreadIdx);
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetDataRun_SharePtr(std::shared_ptr<ImageAllResult> p)
|
|
|
{
|
|
|
// 设置正在检测
|
|
|
|
|
|
m_pImageAllResult = p;
|
|
|
DetImgInfo_shareP = p->result->in_shareImage;
|
|
|
m_CheckResult_shareP = p->result;
|
|
|
m_pImageAllResult->setStep(ImageAllResult::DetStep_Deting);
|
|
|
m_pdetlog = p->detlog;
|
|
|
m_pDetResult = p->pDetResult;
|
|
|
StartCheck();
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetCheckReuslt(std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
m_CheckResult_shareP.reset();
|
|
|
DetImgInfo_shareP.reset();
|
|
|
SetIDLE();
|
|
|
// m_nErrorCode = CHECK_OK;
|
|
|
// printf("4 DetImgInfo_shareP count %ld m_nCheckResultErrorCode %d \n", DetImgInfo_shareP.use_count(), m_nCheckResultErrorCode);
|
|
|
return m_nCheckResultErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckImg(std::shared_ptr<ImageDetconfig> p, std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ReJsonResul(std::shared_ptr<ImageDetconfig> p, std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::InitRun(int nId)
|
|
|
{
|
|
|
|
|
|
int re = CHECK_OK;
|
|
|
if (m_bInitSucc)
|
|
|
{
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
InitModel();
|
|
|
AI_Factory = AIFactory::GetInstance();
|
|
|
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
re = StartThread(nId);
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
m_bInitSucc = true;
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetStatus()
|
|
|
{
|
|
|
return m_nRun_Status;
|
|
|
}
|
|
|
|
|
|
std::string ImgCheckAnalysisy::GetVersion()
|
|
|
{
|
|
|
return std::string("BOE_1.1.0");
|
|
|
}
|
|
|
|
|
|
std::string ImgCheckAnalysisy::GetErrorInfo()
|
|
|
{
|
|
|
std::string str = GetErrorCodeInfo(m_nErrorCode);
|
|
|
printf("%s\n", str.c_str());
|
|
|
return str;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::creatsavedir()
|
|
|
{
|
|
|
std::string curDate = CheckUtil::getCurrentDate();
|
|
|
if (curDate == m_strLastDate)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
m_strLastDate = curDate;
|
|
|
m_strRootPath_TA_cls += m_strLastDate + "/";
|
|
|
m_strRootPath_CA_cls += m_strLastDate + "/";
|
|
|
for (int i = 0; i < AI_CLass_QX_NAME_count; i++)
|
|
|
{
|
|
|
CheckUtil::CreateDir(m_strRootPath_TA_cls + std::to_string(i) + "/");
|
|
|
CheckUtil::CreateDir(m_strRootPath_CA_cls + std::to_string(i) + "/");
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::LoadRunConfig(void *p)
|
|
|
{
|
|
|
if (p == NULL)
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_Config_Null;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
RunInfoST *pconfig = (RunInfoST *)p;
|
|
|
m_RunConfig.copy(*pconfig);
|
|
|
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::LoadCheckConfig(void *p)
|
|
|
{
|
|
|
if (p == NULL)
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_Config_Null;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
m_pConfig = (ConfigBase *)p;
|
|
|
m_nConfigIdx = m_pConfig->GetConfigIdx();
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
// 开启检测
|
|
|
int ImgCheckAnalysisy::StartCheck()
|
|
|
{
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_READY;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetIDLE()
|
|
|
{
|
|
|
// 更新参数
|
|
|
SetNewConfig();
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::StartThread(int nId)
|
|
|
{
|
|
|
// 开启检测线程
|
|
|
ptr_thread_Run = std::make_shared<std::thread>(std::bind(&ImgCheckAnalysisy::Run, this, nId));
|
|
|
if (!m_RunConfig.bRetest)
|
|
|
{
|
|
|
ptr_thread_AI = std::make_shared<std::thread>(std::bind(&ImgCheckAnalysisy::ThreadTask, this, nId + 1));
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::StopThread()
|
|
|
{
|
|
|
m_bExit = true;
|
|
|
if (ptr_thread_Run != nullptr)
|
|
|
{
|
|
|
if (ptr_thread_Run->joinable())
|
|
|
{
|
|
|
ptr_thread_Run->join();
|
|
|
}
|
|
|
}
|
|
|
if (ptr_thread_AI != nullptr)
|
|
|
{
|
|
|
if (ptr_thread_AI->joinable())
|
|
|
{
|
|
|
ptr_thread_AI->join();
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ExitSystem()
|
|
|
{
|
|
|
StopThread();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::InitModel()
|
|
|
{
|
|
|
|
|
|
// 获取当前gpu号确定的 AI处理线程
|
|
|
|
|
|
m_OtherDet_Config.nDeviceId = m_RunConfig.nDeviceId;
|
|
|
|
|
|
m_pAI_Edge_Algin.Init(&m_OtherDet_Config);
|
|
|
m_pAI_Edge_Algin.InitModel_ALL();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size, int expand, double threshold)
|
|
|
{
|
|
|
|
|
|
// 解包 stats(x, y, w, h, area)
|
|
|
int x = stats.x, y = stats.y, w = stats.width, h = stats.height;
|
|
|
|
|
|
// 将图像转换为灰度图像
|
|
|
|
|
|
// 计算感兴趣区域 (ROI)
|
|
|
cv::Rect roi(x - expand, y - expand, w + 2 * expand, h + 2 * expand);
|
|
|
roi &= cv::Rect(0, 0, img.cols, img.rows); // 确保ROI在图像内
|
|
|
roi &= cv::Rect(0, 0, mask.cols, mask.rows); // 确保ROI在mask内
|
|
|
|
|
|
// 检查 mask 是否有效
|
|
|
if (mask.empty() || roi.width <= 0 || roi.height <= 0)
|
|
|
{
|
|
|
return cv::Scalar(0, 0, 0);
|
|
|
}
|
|
|
|
|
|
cv::Mat cimg = img(roi);
|
|
|
|
|
|
// cv::cvtColor(cimg, cimg, cv::COLOR_BGR2GRAY);
|
|
|
// return cv::Scalar(0, 0, 0);
|
|
|
|
|
|
cv::Mat cmask = mask(roi);
|
|
|
// getchar();
|
|
|
// 扩张掩膜
|
|
|
|
|
|
cv::Scalar mean_bk = cv::mean(cimg, ~cmask);
|
|
|
double fbk = mean_bk[0];
|
|
|
|
|
|
cv::Scalar mean_det = cv::mean(cimg, cmask);
|
|
|
double fdet = mean_det[0];
|
|
|
|
|
|
// 计算差异图像
|
|
|
cv::Mat diff = cv::abs(cimg - fbk);
|
|
|
|
|
|
// cv::imwrite("cimg.png",cimg);
|
|
|
// cv::imwrite("cmask.png",cmask);
|
|
|
// printf("%f %f - %f \n",fbk,fdet,fbk-fdet);
|
|
|
// getchar();
|
|
|
|
|
|
// diff = diff.mul(cmask > 0);
|
|
|
cv::Mat masked_image;
|
|
|
diff.copyTo(masked_image, cmask);
|
|
|
// 计算能量
|
|
|
double energy = cv::sum(masked_image)[0];
|
|
|
|
|
|
// 计算 hj(差异图像大于0的像素均值)
|
|
|
// double hj = std::abs(fbk - fdet);
|
|
|
// double hj = CheckUtil::CalHj(cimg, cmask, mean_bk.val[0]);
|
|
|
double hj = CheckUtil::CalHjWeighted(cimg, cmask, mean_bk.val[0], 2.0f);
|
|
|
|
|
|
int worb = 0;
|
|
|
if (fdet >= fbk)
|
|
|
{
|
|
|
worb = 1;
|
|
|
}
|
|
|
// cv::imwrite("cimg.png", cimg);
|
|
|
// cv::imwrite("cmask.png", cmask);
|
|
|
// cv::imwrite("diff.png", diff);
|
|
|
// cv::imwrite("masked_image.png", masked_image);
|
|
|
// printf("fbk %f fdet %f energy %f\n", fbk, fdet, energy);
|
|
|
// getchar();
|
|
|
|
|
|
return cv::Scalar(worb, energy, hj);
|
|
|
}
|
|
|
|
|
|
Point2f GetCoorPoint(Point2f point, Mat img_mat)
|
|
|
{
|
|
|
// 越界判定
|
|
|
int coor_img_rect_x = point.x-400;
|
|
|
int coor_img_rect_y = point.y-400;
|
|
|
int coor_img_rect_w = 800;
|
|
|
int coor_img_rect_h = 800;
|
|
|
if (coor_img_rect_x < 0)
|
|
|
{
|
|
|
coor_img_rect_x = 0;
|
|
|
coor_img_rect_w = min(400, img_mat.cols);
|
|
|
}
|
|
|
if (coor_img_rect_y < 0)
|
|
|
{
|
|
|
coor_img_rect_y = 0;
|
|
|
coor_img_rect_h = min(400, img_mat.rows);
|
|
|
}
|
|
|
if (coor_img_rect_x + coor_img_rect_w > img_mat.cols)
|
|
|
{
|
|
|
coor_img_rect_w = img_mat.cols - coor_img_rect_x;
|
|
|
}
|
|
|
if (coor_img_rect_y + coor_img_rect_h > img_mat.rows)
|
|
|
{
|
|
|
coor_img_rect_h = img_mat.rows - coor_img_rect_y;
|
|
|
}
|
|
|
if (coor_img_rect_x < 0 || coor_img_rect_y < 0 || coor_img_rect_x + coor_img_rect_w > img_mat.cols || coor_img_rect_y + coor_img_rect_h > img_mat.rows)
|
|
|
{
|
|
|
return point;
|
|
|
}
|
|
|
|
|
|
Mat coor_img_mat = img_mat(Rect(coor_img_rect_x, coor_img_rect_y, coor_img_rect_w, coor_img_rect_h));
|
|
|
Mat coor_img_bin;
|
|
|
threshold(coor_img_mat, coor_img_bin, 50, 255, THRESH_BINARY);
|
|
|
|
|
|
// 6. 查找轮廓
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
|
cv::findContours(coor_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
if (contours.empty())
|
|
|
{
|
|
|
return point;
|
|
|
}
|
|
|
double maxArea = 0;
|
|
|
int maxAreaIdx = -1;
|
|
|
for (size_t i = 0; i < contours.size(); ++i)
|
|
|
{
|
|
|
double area = cv::contourArea(contours[i]);
|
|
|
if (area > maxArea)
|
|
|
{
|
|
|
maxArea = area;
|
|
|
maxAreaIdx = i;
|
|
|
}
|
|
|
}
|
|
|
if (maxAreaIdx < 0 || maxArea < 100)
|
|
|
{
|
|
|
return point;
|
|
|
}
|
|
|
cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]);
|
|
|
Point2f vertices[4];
|
|
|
rect.points(vertices);
|
|
|
|
|
|
int cornerIdx = 0;
|
|
|
float minDist = FLT_MAX;
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
{
|
|
|
float dist = std::pow(vertices[i].x - 400, 2) + std::pow(vertices[i].y - 400, 2);
|
|
|
if (dist < minDist)
|
|
|
{
|
|
|
minDist = dist;
|
|
|
cornerIdx = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Point2f new_point;
|
|
|
new_point.x = vertices[cornerIdx].x + coor_img_rect_x;
|
|
|
new_point.y = vertices[cornerIdx].y + coor_img_rect_y;
|
|
|
|
|
|
new_point.x = std::max(0.0f, std::min(new_point.x, static_cast<float>(img_mat.cols - 1)));
|
|
|
new_point.y = std::max(0.0f, std::min(new_point.y, static_cast<float>(img_mat.rows - 1)));
|
|
|
|
|
|
return new_point;
|
|
|
}
|
|
|
|
|
|
int GetEdgeRoi(Mat img, Rect &new_roi, cv::RotatedRect &rotated_roi, float scale_x, float scale_y){
|
|
|
if (img.empty())
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
// ============ Stage 1: 粗定位(大尺度缩小,速度快)============
|
|
|
Mat r_img;
|
|
|
|
|
|
int resize_width = static_cast<int>(img.cols / scale_x);
|
|
|
int resize_height = static_cast<int>(img.rows / scale_y);
|
|
|
resize(img, r_img, Size(resize_width, resize_height), 0, 0, INTER_LINEAR);
|
|
|
|
|
|
// 二值化找最大连通域
|
|
|
Mat r_img_bin;
|
|
|
threshold(r_img, r_img_bin, 15, 255, THRESH_BINARY);
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
|
cv::findContours(r_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
if (contours.empty())
|
|
|
{
|
|
|
return 2;
|
|
|
}
|
|
|
double maxArea = 0;
|
|
|
int maxAreaIdx = -1;
|
|
|
for (size_t i = 0; i < contours.size(); ++i)
|
|
|
{
|
|
|
double area = cv::contourArea(contours[i]);
|
|
|
if (area > maxArea)
|
|
|
{
|
|
|
maxArea = area;
|
|
|
maxAreaIdx = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (maxAreaIdx < 0)
|
|
|
{
|
|
|
return 3;
|
|
|
}
|
|
|
|
|
|
// 使用minAreaRect获取带旋转角度的最小外接矩形
|
|
|
cv::RotatedRect coarse_rotated_tmp = cv::minAreaRect(contours[maxAreaIdx]);
|
|
|
cv::RotatedRect coarse_rotated;
|
|
|
coarse_rotated.center.x = coarse_rotated_tmp.center.x * scale_x;
|
|
|
coarse_rotated.center.y = coarse_rotated_tmp.center.y * scale_y;
|
|
|
coarse_rotated.size.width = coarse_rotated_tmp.size.width * scale_x;
|
|
|
coarse_rotated.size.height = coarse_rotated_tmp.size.height * scale_y;
|
|
|
coarse_rotated.angle = coarse_rotated_tmp.angle;
|
|
|
cv::Rect coarse_roi = coarse_rotated.boundingRect();
|
|
|
coarse_roi.x = std::max(0, coarse_roi.x);
|
|
|
coarse_roi.y = std::max(0, coarse_roi.y);
|
|
|
coarse_roi.width = std::min(coarse_roi.width, img.cols - coarse_roi.x);
|
|
|
coarse_roi.height = std::min(coarse_roi.height, img.rows - coarse_roi.y);
|
|
|
|
|
|
// ============ Stage 2: 精修(小尺度,只处理裁剪后的局部区域)============
|
|
|
// 粗定位精度损失约 scale_x/scale_y 个像素,扩展 margin 确保包含真实边界
|
|
|
const float fine_scale = 4.0f; // 精修阶段缩放倍率,越小越精确
|
|
|
int margin_x = static_cast<int>(scale_x * 2); // 补偿粗定位误差
|
|
|
int margin_y = static_cast<int>(scale_y * 2);
|
|
|
|
|
|
Rect fine_roi;
|
|
|
fine_roi.x = std::max(0, coarse_roi.x - margin_x);
|
|
|
fine_roi.y = std::max(0, coarse_roi.y - margin_y);
|
|
|
fine_roi.width = std::min(coarse_roi.width + 2 * margin_x, img.cols - fine_roi.x);
|
|
|
fine_roi.height = std::min(coarse_roi.height + 2 * margin_y, img.rows - fine_roi.y);
|
|
|
|
|
|
Mat fine_region = img(fine_roi);
|
|
|
int fine_w = static_cast<int>(fine_region.cols / fine_scale);
|
|
|
int fine_h = static_cast<int>(fine_region.rows / fine_scale);
|
|
|
|
|
|
// 精修区域足够大时才做细化
|
|
|
if (fine_w > 50 && fine_h > 50)
|
|
|
{
|
|
|
Mat fine_resized;
|
|
|
resize(fine_region, fine_resized, Size(fine_w, fine_h), 0, 0, INTER_LINEAR);
|
|
|
|
|
|
Mat fine_bin;
|
|
|
threshold(fine_resized, fine_bin, 15, 255, THRESH_BINARY);
|
|
|
|
|
|
std::vector<std::vector<cv::Point>> fine_contours;
|
|
|
cv::findContours(fine_bin, fine_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
if (!fine_contours.empty())
|
|
|
{
|
|
|
double fine_maxArea = 0;
|
|
|
int fine_maxIdx = -1;
|
|
|
for (size_t i = 0; i < fine_contours.size(); ++i)
|
|
|
{
|
|
|
double area = cv::contourArea(fine_contours[i]);
|
|
|
if (area > fine_maxArea)
|
|
|
{
|
|
|
fine_maxArea = area;
|
|
|
fine_maxIdx = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (fine_maxIdx >= 0)
|
|
|
{
|
|
|
// 使用minAreaRect获取带旋转角度的最小外接矩形(保留旋转信息)
|
|
|
cv::RotatedRect fine_rotated = cv::minAreaRect(fine_contours[fine_maxIdx]);
|
|
|
// 映射回原图坐标:center缩放+平移,size按比例缩放,角度不变
|
|
|
rotated_roi.center.x = fine_rotated.center.x * fine_scale + fine_roi.x;
|
|
|
rotated_roi.center.y = fine_rotated.center.y * fine_scale + fine_roi.y;
|
|
|
rotated_roi.size.width = fine_rotated.size.width * fine_scale;
|
|
|
rotated_roi.size.height = fine_rotated.size.height * fine_scale;
|
|
|
rotated_roi.angle = fine_rotated.angle;
|
|
|
// 取旋转矩形的轴对齐外接框作为new_roi(用于ROI裁剪等场景)
|
|
|
cv::Rect fine_small = rotated_roi.boundingRect();
|
|
|
Rect refined_roi;
|
|
|
refined_roi.x = fine_small.x;
|
|
|
refined_roi.y = fine_small.y;
|
|
|
refined_roi.width = fine_small.width;
|
|
|
refined_roi.height = fine_small.height;
|
|
|
refined_roi.x = std::max(0, refined_roi.x);
|
|
|
refined_roi.y = std::max(0, refined_roi.y);
|
|
|
refined_roi.width = std::min(refined_roi.width, img.cols - refined_roi.x);
|
|
|
refined_roi.height = std::min(refined_roi.height, img.rows - refined_roi.y);
|
|
|
|
|
|
new_roi = refined_roi;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 精修失败则回退到粗定位结果
|
|
|
new_roi = coarse_roi;
|
|
|
rotated_roi = coarse_rotated;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
std::vector<cv::Point2f> sort_vertices(cv::RotatedRect rrect) {
|
|
|
cv::Point2f pts[4];
|
|
|
rrect.points(pts);
|
|
|
std::vector<cv::Point2f> vertices(pts, pts + 4);
|
|
|
|
|
|
// 按 y 坐标升序排序
|
|
|
std::sort(vertices.begin(), vertices.end(),
|
|
|
[](const cv::Point2f& a, const cv::Point2f& b) {
|
|
|
return a.y < b.y;
|
|
|
});
|
|
|
|
|
|
if (vertices[0].x > vertices[1].x)
|
|
|
std::swap(vertices[0], vertices[1]);
|
|
|
|
|
|
if (vertices[2].x > vertices[3].x)
|
|
|
std::swap(vertices[2], vertices[3]);
|
|
|
|
|
|
return vertices;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){
|
|
|
if (img.empty()) {
|
|
|
std::cerr << "Error: Input image 'img' is empty!" << std::endl;
|
|
|
return -1;
|
|
|
}
|
|
|
if(!b_update){
|
|
|
return 1;
|
|
|
}
|
|
|
cv::RotatedRect rot_cur_roi;
|
|
|
int get_edge_roi = GetEdgeRoi(img, cur_roi, rot_cur_roi, 20, 20);
|
|
|
if(get_edge_roi != 0){
|
|
|
return 2;
|
|
|
}
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "-------------------start--------------");
|
|
|
|
|
|
/*计算xy偏移,缩放比例*/
|
|
|
// 拷贝原始数据(old_productROI 使用 markLine.region 的 minAreaRect,保留旋转角度)
|
|
|
if(m_old_productROI.size.width == 0 || m_old_productROI.size.height == 0){
|
|
|
m_old_productROI = cv::minAreaRect(m_AnalysisyConfig.baseFunction.markLine.region);
|
|
|
m_old_cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region;
|
|
|
m_old_cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region;
|
|
|
m_old_cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1;
|
|
|
m_old_cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2;
|
|
|
m_old_cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr;
|
|
|
m_old_cur_traditional_region = m_AnalysisyConfig.baseFunction.traditionDet.detArea;
|
|
|
}
|
|
|
|
|
|
/*计算old_roi到new_roi的完整仿射变换矩阵(平移+缩放+旋转)*/
|
|
|
// old使用 minAreaRect(region) 的顶点,new使用 GetEdgeRoi 检测到的旋转矩形顶点
|
|
|
vector<cv::Point2f> old_vertices = sort_vertices(m_old_productROI);
|
|
|
vector<cv::Point2f> new_vertices = sort_vertices(rot_cur_roi);
|
|
|
|
|
|
cv::Point2f src_pts[3] = {
|
|
|
old_vertices[0], // 左上
|
|
|
old_vertices[1], // 右上
|
|
|
old_vertices[2] // 左下
|
|
|
};
|
|
|
cv::Point2f dst_pts[3] = {
|
|
|
new_vertices[0], // 对应左上
|
|
|
new_vertices[1], // 对应右上
|
|
|
new_vertices[2] // 对应左下
|
|
|
};
|
|
|
cv::Mat affine_mat = cv::getAffineTransform(src_pts, dst_pts);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "affine_mat = [%f %f %f; %f %f %f]",
|
|
|
affine_mat.at<double>(0,0), affine_mat.at<double>(0,1), affine_mat.at<double>(0,2),
|
|
|
affine_mat.at<double>(1,0), affine_mat.at<double>(1,1), affine_mat.at<double>(1,2));
|
|
|
|
|
|
// 单点仿射变换的lambda (直接使用矩阵,涵盖平移+缩放+旋转)
|
|
|
auto affinePoint = [&](const cv::Point& p) -> cv::Point {
|
|
|
return cv::Point(
|
|
|
cvRound(affine_mat.at<double>(0,0) * p.x + affine_mat.at<double>(0,1) * p.y + affine_mat.at<double>(0,2)),
|
|
|
cvRound(affine_mat.at<double>(1,0) * p.x + affine_mat.at<double>(1,1) * p.y + affine_mat.at<double>(1,2))
|
|
|
);
|
|
|
};
|
|
|
|
|
|
/*获取待修改的region引用*/
|
|
|
std::vector<cv::Point>& cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region;
|
|
|
std::vector<cv::Point>& cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region;
|
|
|
cv::Point& cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1;
|
|
|
cv::Point& cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2;
|
|
|
std::vector<RegionConfigST>& cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr;
|
|
|
std::vector<cv::Point>& cur_traditional_region = m_AnalysisyConfig.baseFunction.traditionDet.detArea;
|
|
|
|
|
|
// if (img.empty())
|
|
|
// {
|
|
|
// return 0;
|
|
|
// }
|
|
|
// Mat show_img = img.clone();
|
|
|
// cvtColor(show_img, show_img, COLOR_GRAY2BGR);
|
|
|
// // 确保 productROI 在图像范围内
|
|
|
// cv::Rect safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI;
|
|
|
// safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows);
|
|
|
// if (safe_roi.width > 0 && safe_roi.height > 0)
|
|
|
// {
|
|
|
// cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5);
|
|
|
// }
|
|
|
// if (cur_edgeDet_region.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){
|
|
|
// cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20);
|
|
|
// }
|
|
|
// if (cur_markLine_region.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){
|
|
|
// cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20);
|
|
|
// }
|
|
|
// for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){
|
|
|
// if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){
|
|
|
// cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10);
|
|
|
// }
|
|
|
// }
|
|
|
// imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_org_img.tiff", show_img);
|
|
|
|
|
|
/*使用仿射矩阵进行修改*/
|
|
|
// rect
|
|
|
m_AnalysisyConfig.baseFunction.markLine.productROI = cur_roi;
|
|
|
// point
|
|
|
cur_markLine_mark1 = affinePoint(m_old_cur_markLine_mark1);
|
|
|
cur_markLine_mark2 = affinePoint(m_old_cur_markLine_mark2);
|
|
|
// region
|
|
|
for(int i = 0; i < cur_edgeDet_region.size(); i++){
|
|
|
cur_edgeDet_region[i] = affinePoint(m_old_cur_edgeDet_region[i]);
|
|
|
}
|
|
|
for(int i = 0; i < cur_markLine_region.size(); i++){
|
|
|
cur_markLine_region[i] = affinePoint(m_old_cur_markLine_region[i]);
|
|
|
}
|
|
|
for(int i = 0 ; i < cur_regionConfigArr.size(); i++){
|
|
|
for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size(); j++){
|
|
|
cur_regionConfigArr[i].basicInfo.pointArry[j] = affinePoint(m_old_cur_regionConfigArr[i].basicInfo.pointArry[j]);
|
|
|
}
|
|
|
}
|
|
|
for(int i = 0; i < cur_traditional_region.size(); i++){
|
|
|
cur_traditional_region[i] = affinePoint(m_old_cur_traditional_region[i]);
|
|
|
}
|
|
|
|
|
|
/*show*/
|
|
|
// if (img.empty())
|
|
|
// {
|
|
|
// return 0;
|
|
|
// }
|
|
|
// show_img = img.clone();
|
|
|
// cvtColor(show_img, show_img, COLOR_GRAY2BGR);
|
|
|
// // 确保 productROI 在图像范围内
|
|
|
// safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI;
|
|
|
// safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows);
|
|
|
// if (safe_roi.width > 0 && safe_roi.height > 0)
|
|
|
// {
|
|
|
// cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5);
|
|
|
// }
|
|
|
// if (cur_edgeDet_region.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){
|
|
|
// cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20);
|
|
|
// }
|
|
|
// if (cur_markLine_region.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){
|
|
|
// cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20);
|
|
|
// }
|
|
|
// for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){
|
|
|
// if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2)
|
|
|
// {
|
|
|
// for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){
|
|
|
// cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10);
|
|
|
// }
|
|
|
// cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10);
|
|
|
// }
|
|
|
// }
|
|
|
// imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_show_img.tiff", show_img);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckRun()
|
|
|
{
|
|
|
|
|
|
// printf(">>>%s ================start \n", m_pImageAllResult->strBaseInfo.c_str());
|
|
|
|
|
|
long t1, t2, t3, t4, t5, t6, t7;
|
|
|
SetNewConfig();
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
CheckImgInit();
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
}
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "1、basic Info", "---------------------------1、basic Info---------------------------------");
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Version", "%s", GetVersion().c_str());
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Updateconfig", "%d", m_bupdateconfig);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Start", "%s", m_pImageAllResult->strBaseInfo.c_str());
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "ImgageScale", "Scale_X = %f Scale_Y = %f", m_fImgage_Scale_X, m_fImgage_Scale_Y);
|
|
|
m_bupdateconfig = false;
|
|
|
// 返回结果状态初始化
|
|
|
m_CheckResult_shareP->checkStatus = 1;
|
|
|
m_CheckResult_shareP->nresult = -1;
|
|
|
|
|
|
m_CheckResult_shareP->basicResult.img_id = m_CheckResult_shareP->in_shareImage->img_id;
|
|
|
m_CheckResult_shareP->basicResult.imgtype = m_CheckResult_shareP->in_shareImage->imgtype;
|
|
|
m_CheckResult_shareP->basicResult.imgstr = m_CheckResult_shareP->in_shareImage->imgstr;
|
|
|
m_CheckResult_shareP->basicResult.strChannel = m_CheckResult_shareP->in_shareImage->strChannel;
|
|
|
m_strCurDetChannel = m_CheckResult_shareP->basicResult.strChannel;
|
|
|
|
|
|
/*自适应更新参数*/
|
|
|
long time_adapt_s = CheckUtil::getcurTime();
|
|
|
cv::RotatedRect rot_cur_roi;
|
|
|
Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, m_pbaseCheckFunction->markLine.badapt_region);
|
|
|
long time_adapt_e = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "time = %ld", time_adapt_e - time_adapt_s);
|
|
|
|
|
|
// 2、参数检查
|
|
|
int rec = ConfigCheck(DetImgInfo_shareP->img);
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "ConfigCheck is error type = %d", rec);
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
long time_edge_s = CheckUtil::getcurTime();
|
|
|
// 3、AI 边缘定位
|
|
|
if(m_CheckResult_shareP->basicResult.strChannel == "DCA" || m_CheckResult_shareP->basicResult.strChannel == "DTA")
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Edge", "Not Use AI_Edge %s", m_CheckResult_shareP->basicResult.strChannel.c_str());
|
|
|
m_CutRoi = cv::Rect(rot_cur_roi.boundingRect().x - 50 , rot_cur_roi.boundingRect().y - 50, rot_cur_roi.boundingRect().width + 100, rot_cur_roi.boundingRect().height + 100)
|
|
|
& cv::Rect(0, 0, m_CheckResult_shareP->in_shareImage->img.cols, m_CheckResult_shareP->in_shareImage->img.rows);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Edge", "Use AI_Edge %s", m_CheckResult_shareP->basicResult.strChannel.c_str());
|
|
|
int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_CutRoi);
|
|
|
if (reedge != 0)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge);
|
|
|
m_nErrorCode = reedge;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
long 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_Crop_Roi_paramImg = m_CutRoi;
|
|
|
m_pImageAllResult->pDetResult->CutRoi = m_CutRoi;
|
|
|
m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg;
|
|
|
|
|
|
// 生成 检测的图片
|
|
|
cv::Mat image;
|
|
|
image = m_CheckResult_shareP->in_shareImage->img;
|
|
|
if (image.channels() == 3)
|
|
|
{
|
|
|
cv::cvtColor(image(m_CutRoi), m_pImageAllResult->detImg, cv::COLOR_RGB2GRAY);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_pImageAllResult->detImg = image(m_CutRoi).clone();
|
|
|
}
|
|
|
|
|
|
// bDetect为true才进行推理输出残点图,否则直接输出全黑残点图
|
|
|
long time_AI_s = CheckUtil::getcurTime();
|
|
|
if(m_pBasicConfig->bDetect)
|
|
|
{
|
|
|
// 多线程开启 传统/AI 推理检测
|
|
|
m_AItask = std::make_shared<TaskInfo>();
|
|
|
m_AItask->taskname = Task_AI;
|
|
|
m_task.sendTask(m_AItask);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 不推理:直接输出全黑残点图
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "-------------------------NO AI_Edge--------------- \n");
|
|
|
m_pImageAllResult->AIMaskImg = cv::Mat::zeros(m_pImageAllResult->detImg.size(), CV_8UC1);
|
|
|
}
|
|
|
|
|
|
ImgPreDet();
|
|
|
// 更新检测区域
|
|
|
Update_DetRoiList();
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "3、pre detect", "-------------------------pre Det--------------- \n");
|
|
|
|
|
|
// 实现边缘崩溃缺陷检测
|
|
|
{
|
|
|
long t41 = CheckUtil::getcurTime();
|
|
|
int reedge1111 = Edge_Qx_Det(m_pImageAllResult->detImg);
|
|
|
long t42 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------1、Edge_Qx_Det--------%ld-------\n", t42 - t41);
|
|
|
}
|
|
|
|
|
|
m_CheckResult_shareP->nresult = 0;
|
|
|
|
|
|
// 把临时可以绘制的结果都绘制出来。
|
|
|
DrawResult_Step_1();
|
|
|
long time_AI_e;
|
|
|
// AI 推理生成
|
|
|
{
|
|
|
long t211 = CheckUtil::getcurTime();
|
|
|
// 对AI的结果进行 处理,等待 AI 推理全部完成。
|
|
|
rec = AIMaskDet();
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
time_AI_e = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------2、AI Detect--------%ld wait AI complate %ld-------\n", time_AI_e - time_AI_s, time_AI_e - t211);
|
|
|
|
|
|
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg;
|
|
|
}
|
|
|
|
|
|
{
|
|
|
|
|
|
t4 = CheckUtil::getcurTime();
|
|
|
rec = GetCheckResultBLob();
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
t5 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "5、BLob ", "------------------------ --------%ld -------\n", t5 - t4);
|
|
|
}
|
|
|
// m_pdetlog->printLog(m_strCurDetChannel);
|
|
|
|
|
|
long te = CheckUtil::getcurTime();
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "result", " ALL use Time %ld edge %ld AI %ld blob %ld",
|
|
|
te - t1, time_edge_e - time_edge_s, time_AI_e - time_AI_s, t5 - t4);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, "End", " Check Run");
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetNewConfig()
|
|
|
{
|
|
|
if (m_nConfigIdx < 0)
|
|
|
{
|
|
|
return 1;
|
|
|
/* code */
|
|
|
}
|
|
|
|
|
|
if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx))
|
|
|
{
|
|
|
m_bupdateconfig = true;
|
|
|
// printf("************** ImgCheckAnalysisy::SetNewConfig m_nConfigIdx %d\n", m_nConfigIdx);
|
|
|
m_old_productROI = cv::RotatedRect();
|
|
|
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_pBasicConfig = &m_AnalysisyConfig.commonCheckConfig.baseConfig;
|
|
|
m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0);
|
|
|
|
|
|
UpdateImgageScale();
|
|
|
if (false)
|
|
|
{
|
|
|
printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str());
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n");
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// printf("ConfigType_Analysisy_Common_XL no Update \n");
|
|
|
}
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
|
|
|
ChannelCheckFunction *ImgCheckAnalysisy::GetChannelFuntion(std::string strChannelName)
|
|
|
{
|
|
|
ChannelCheckFunction *p = NULL;
|
|
|
for (int i = 0; i < m_AnalysisyConfig.checkFunction.channelFunctionArr.size(); i++)
|
|
|
{
|
|
|
if (CheckUtil::compareIgnoreCase(m_AnalysisyConfig.checkFunction.channelFunctionArr[i].strChannelName, strChannelName))
|
|
|
{
|
|
|
p = &m_AnalysisyConfig.checkFunction.channelFunctionArr[i];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return p;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::Run(int nId)
|
|
|
{
|
|
|
std::vector<int> vi;
|
|
|
vi.push_back(nId);
|
|
|
auto nRet = set_cpu_id(vi);
|
|
|
// printf("Check So %d bind cpu ret %d, %d\n", m_nThreadIdx, nRet, nId);
|
|
|
while (!m_bExit)
|
|
|
{
|
|
|
// 数据准备完成,开启检测
|
|
|
if (m_nRun_Status == CHECK_THREAD_STATUS_READY)
|
|
|
{
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_BUSY;
|
|
|
/* 检测 */
|
|
|
CheckRun();
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_COMPLETE;
|
|
|
m_pImageAllResult->setStep(ImageAllResult::DetStep_Complet);
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
// printf("*--------%d\n", m_nRun_Status);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
usleep(1000);
|
|
|
}
|
|
|
// printf("*-");
|
|
|
usleep(1000);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::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 ImgCheckAnalysisy::CalBlob_Other()
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " Start");
|
|
|
|
|
|
// 检查 detImg 和 AIMaskImg 是否为空
|
|
|
if (m_pImageAllResult->detImg.empty())
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " detImg is empty, return");
|
|
|
return -1;
|
|
|
}
|
|
|
if (m_pImageAllResult->AIMaskImg.empty())
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " AIMaskImg is empty, return");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
float fs_x = m_fImgage_Scale_X;
|
|
|
float fs_y = m_fImgage_Scale_Y;
|
|
|
|
|
|
float fs_resize_x = m_pImageAllResult->fscale_detToresult_x;
|
|
|
float fs_resize_y = m_pImageAllResult->fscale_detToresult_y;
|
|
|
// 遍历每个检测blob
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Blob", "%d/%d start", i, blobs.blobCount);
|
|
|
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
cv::Scalar result = calc_blob_info_withstats(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg, roi);
|
|
|
|
|
|
int QX_whiteBLACK = CONFIG_QX_BLACK;
|
|
|
if (result[0] > 0)
|
|
|
{
|
|
|
QX_whiteBLACK = CONFIG_QX_WHITE;
|
|
|
}
|
|
|
|
|
|
double hj = result[2];
|
|
|
double energe = result[1];
|
|
|
blobs.blobTab[i].energy = energe;
|
|
|
blobs.blobTab[i].grayDis = hj;
|
|
|
|
|
|
float JudgArea = blobs.blobTab[i].area * fs_x * fs_y;
|
|
|
blobs.blobTab[i].JudgArea = JudgArea;
|
|
|
float flen = roi.width * fs_x;
|
|
|
float fwid = roi.height * fs_x;
|
|
|
if (roi.height * fs_y > flen)
|
|
|
{
|
|
|
flen = roi.height * fs_y;
|
|
|
fwid = roi.width * fs_y;
|
|
|
}
|
|
|
blobs.blobTab[i].len = flen;
|
|
|
blobs.blobTab[i].breadth = fwid;
|
|
|
|
|
|
int nerrortype = 0;
|
|
|
int checkFlage = 0;
|
|
|
|
|
|
float fmaxScore = 0;
|
|
|
int config_qx_type = 0;
|
|
|
|
|
|
if (blobs.blobTab[i].ErrType == ERR_TYPE_2)
|
|
|
{
|
|
|
QX_whiteBLACK = CONFIG_QX_BLACK; // 强制为 黑色
|
|
|
}
|
|
|
blobs.blobTab[i].whiteOrblack = QX_whiteBLACK;
|
|
|
|
|
|
// 精确计算长度
|
|
|
vector<float> re_len = Cal_QXLen(m_pImageAllResult->detImg(roi), config_qx_type, fs_x, fs_y);
|
|
|
|
|
|
if (re_len.size() > 2)
|
|
|
{
|
|
|
if(re_len[0] >= 0){
|
|
|
flen = re_len[0];
|
|
|
blobs.blobTab[i].len = flen;
|
|
|
}
|
|
|
if(re_len[1] >= 0){
|
|
|
fwid = re_len[1];
|
|
|
blobs.blobTab[i].breadth = fwid;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight)
|
|
|
{
|
|
|
|
|
|
cv::Rect cutroi;
|
|
|
cv::Rect roi = qx_roi;
|
|
|
bool bresize = false;
|
|
|
{
|
|
|
|
|
|
int pc_x = roi.x + roi.width * 0.5;
|
|
|
int pc_y = roi.y + roi.height * 0.5;
|
|
|
|
|
|
if (roi.width < detwidth && roi.height < detheight)
|
|
|
{
|
|
|
cutroi.width = detwidth;
|
|
|
cutroi.x = pc_x - detwidth * 0.5;
|
|
|
cutroi.height = detheight;
|
|
|
cutroi.y = pc_y - detheight * 0.5;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 宽 高
|
|
|
if (roi.width > roi.height)
|
|
|
{
|
|
|
cutroi.width = roi.width + 20;
|
|
|
cutroi.x = roi.x - 10;
|
|
|
|
|
|
float fsx = detheight * 1.0f / detwidth;
|
|
|
cutroi.height = cutroi.width * fsx;
|
|
|
cutroi.y = pc_y - cutroi.height * 0.5;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
cutroi.height = roi.height + 20;
|
|
|
cutroi.y = roi.y - 10;
|
|
|
|
|
|
float fsy = detwidth * 1.0f / detheight;
|
|
|
cutroi.width = cutroi.height * fsy;
|
|
|
cutroi.x = pc_x - cutroi.width * 0.5;
|
|
|
}
|
|
|
|
|
|
bresize = true;
|
|
|
}
|
|
|
|
|
|
if (cutroi.x < 0)
|
|
|
{
|
|
|
cutroi.x = 0;
|
|
|
}
|
|
|
if (cutroi.y < 0)
|
|
|
{
|
|
|
cutroi.y = 0;
|
|
|
}
|
|
|
if (cutroi.x + cutroi.width >= img.cols)
|
|
|
{
|
|
|
cutroi.x = img.cols - cutroi.width;
|
|
|
if (cutroi.x < 0)
|
|
|
{
|
|
|
cutroi.x = 0;
|
|
|
if (cutroi.x + cutroi.width >= img.cols)
|
|
|
{
|
|
|
cutroi.width = img.cols;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (cutroi.y + cutroi.height >= img.rows)
|
|
|
{
|
|
|
cutroi.y = img.rows - cutroi.height;
|
|
|
if (cutroi.y < 0)
|
|
|
{
|
|
|
cutroi.y = 0;
|
|
|
if (cutroi.y + cutroi.height >= img.rows)
|
|
|
{
|
|
|
cutroi.height = img.rows;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!CheckUtil::RoiInImg(cutroi, img))
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
cv::Size sz;
|
|
|
sz.width = detwidth;
|
|
|
sz.height = detheight;
|
|
|
if (cutroi.width != sz.width || cutroi.height != sz.height)
|
|
|
{
|
|
|
cv::resize(img(cutroi), AIdetImg, sz);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
AIdetImg = img(cutroi).clone();
|
|
|
}
|
|
|
|
|
|
if (1 != AIdetImg.channels())
|
|
|
{
|
|
|
cv::cvtColor(AIdetImg, AIdetImg, cv::COLOR_BGR2GRAY);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
vector<float> ImgCheckAnalysisy::Cal_QXLen(cv::Mat qx_maskImg, int qx_type, float fsc_x, float fsc_y)
|
|
|
{
|
|
|
vector<float> resLen(3);
|
|
|
|
|
|
float nlen = -1;
|
|
|
cv::Mat detimg = qx_maskImg;
|
|
|
|
|
|
resLen[0] = nlen;
|
|
|
// 寻找轮廓
|
|
|
vector<vector<Point>> contours;
|
|
|
cv::findContours(detimg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
// 找到最大面积的轮廓
|
|
|
double maxArea = -1;
|
|
|
int maxAreaIdx = -1;
|
|
|
for (size_t i = 0; i < contours.size(); ++i)
|
|
|
{
|
|
|
double area = contourArea(contours[i]);
|
|
|
if (area > maxArea)
|
|
|
{
|
|
|
maxArea = area;
|
|
|
maxAreaIdx = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果找到了最大面积的轮廓
|
|
|
if (maxAreaIdx >= 0)
|
|
|
{
|
|
|
|
|
|
// 使用minAreaRect找到最小外接矩形
|
|
|
cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]);
|
|
|
|
|
|
// // 绘制最小外接矩形
|
|
|
// Point2f vertices[4];
|
|
|
// rect.points(vertices);
|
|
|
// for (int i = 0; i < 4; ++i)
|
|
|
// {
|
|
|
// line(detimg, vertices[i], vertices[(i + 1) % 4], Scalar(128, 255, 0), 2); // 绿色线
|
|
|
// }
|
|
|
// 输出结果
|
|
|
|
|
|
// 获取最小外接矩形的尺寸
|
|
|
float width = rect.size.width;
|
|
|
float height = rect.size.height;
|
|
|
|
|
|
// std::cout << "1 Width: " << width << ", Height: " << height << std::endl;
|
|
|
Point2f vertices[4];
|
|
|
rect.points(vertices);
|
|
|
|
|
|
vector<Point2f> newcont;
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
{
|
|
|
Point2f p;
|
|
|
p.x = vertices[i].x * fsc_x;
|
|
|
p.y = vertices[i].y * fsc_y;
|
|
|
newcont.push_back(p);
|
|
|
}
|
|
|
vector<vector<Point2f>> contours_New;
|
|
|
contours_New.push_back(newcont);
|
|
|
// Recreate the rotated rectangle with scaled vertices
|
|
|
RotatedRect scaledRect = minAreaRect(contours_New[0]);
|
|
|
|
|
|
// Calculate scaled width and height
|
|
|
width = scaledRect.size.width;
|
|
|
height = scaledRect.size.height;
|
|
|
// std::cout << "2 width: " << width << ", height: " << height << std::endl;
|
|
|
// float scale = 0.5; // 缩放比例
|
|
|
// rect.size.width *= fsc_x;
|
|
|
// rect.size.height *= fsc_y;
|
|
|
// std::cout << "fsc_x: " << fsc_x << ", fsc_y: " << fsc_y << std::endl;
|
|
|
// std::cout << "Width: " << width << ", Height: " << height << std::endl;
|
|
|
// 获取最小外接矩形的尺寸
|
|
|
// width = rect.size.width;
|
|
|
// height = rect.size.height;
|
|
|
if (width > height)
|
|
|
{
|
|
|
nlen = width;
|
|
|
resLen[0] = width;
|
|
|
resLen[1] = height;
|
|
|
/* code */
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
nlen = height;
|
|
|
resLen[0] = height;
|
|
|
resLen[1] = width;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// getchar();
|
|
|
return resLen;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetCheckResultBLob()
|
|
|
{
|
|
|
long t1, t2, t3, t4, t5, t6, t7;
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
int re = GetALLBlob();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
// 缺陷分类 多线程 实现。
|
|
|
long t11 = CheckUtil::getcurTime();
|
|
|
m_Classtask = std::make_shared<TaskInfo>();
|
|
|
m_Classtask->taskname = Task_Class;
|
|
|
m_task.sendTask(m_Classtask);
|
|
|
|
|
|
re = CalBlob_Other();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
long t12 = CheckUtil::getcurTime();
|
|
|
// 等待分类 完成。
|
|
|
m_Classtask->waitComplate();
|
|
|
long t13 = CheckUtil::getcurTime();
|
|
|
// printf("=========== cls time %ld waite time %ld\n", t13 - t11, t13 - t12);
|
|
|
|
|
|
BLobToDetResult();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void worker(const unsigned char *img, int w, int startRow, int endRow, unsigned char *rowFlags)
|
|
|
{
|
|
|
for (int y = startRow; y < endRow; y++)
|
|
|
{
|
|
|
const unsigned char *p = img + (size_t)y * w;
|
|
|
rowFlags[y] = 0;
|
|
|
for (int x = 0; x < w; x++)
|
|
|
{
|
|
|
if (p[x] != 0)
|
|
|
{
|
|
|
rowFlags[y] = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
int ImgCheckAnalysisy::GetALLBlob()
|
|
|
{
|
|
|
|
|
|
std::string strBaseLog = "Blob";
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis Start");
|
|
|
if (m_pImageAllResult->AIMaskImg.empty())
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data;
|
|
|
int width = m_pImageAllResult->AIMaskImg.cols;
|
|
|
int height = m_pImageAllResult->AIMaskImg.rows;
|
|
|
|
|
|
long t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
memset(&blobs, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
|
|
|
ERROR_DOTS_BLOBS blobs_v1;
|
|
|
memset(&blobs_v1, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
ERROR_DOTS_BLOBS blobs_big;
|
|
|
memset(&blobs_big, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
ERROR_DOTS_BLOBS blobs_big_2;
|
|
|
memset(&blobs_big_2, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
printf("=====>>>> GetALLBlob m_strCurDetChannel %s \n", m_strCurDetChannel.c_str());
|
|
|
if (m_strCurDetChannel.find("CA") != std::string::npos)
|
|
|
{
|
|
|
printf("=====>>>>GetALLBlob USE CA %s \n", m_strCurDetChannel.c_str());
|
|
|
GetBlobs_ALL_New(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount);
|
|
|
|
|
|
if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
GetBlobs_ALL_New(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount);
|
|
|
|
|
|
if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount);
|
|
|
GetBlobs_ALL_New(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
GetBlobs_oneLabe(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount);
|
|
|
|
|
|
if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
GetBlobs_oneLabe(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount);
|
|
|
|
|
|
if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount);
|
|
|
GetBlobs_oneLabe(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
PushBlob(&blobs, &blobs_big_2);
|
|
|
PushBlob(&blobs, &blobs_big);
|
|
|
PushBlob(&blobs, &blobs_v1);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob ALL num %d", blobs.blobCount);
|
|
|
// long t2 = CheckUtil::getcurTime();
|
|
|
// printf(" BLob time %ld \n", t2 - t1);
|
|
|
|
|
|
if (false || DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
int font_face = cv::FONT_HERSHEY_SIMPLEX;
|
|
|
double font_scale = 0.5;
|
|
|
int thickness = 1;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, "Save Tem Img");
|
|
|
cv::Mat tm;
|
|
|
cv::cvtColor(m_pImageAllResult->AIMaskImg, tm, cv::COLOR_GRAY2RGB); // 彩色 可选项
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
if (blobs.blobTab[i].ErrType == 0)
|
|
|
{
|
|
|
cv::rectangle(tm, roi, cv::Scalar(0, 0, 255));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
cv::rectangle(tm, roi, cv::Scalar(0, 255, 255));
|
|
|
}
|
|
|
|
|
|
char buffer[128];
|
|
|
sprintf(buffer, "id:%d type:%d m %0.1f", i,blobs.blobTab[i].ErrType, blobs.blobTab[i].density);
|
|
|
std::string text = buffer;
|
|
|
cv::Point origin = cv::Point(roi.x, roi.y);
|
|
|
cv::putText(tm, text, origin, font_face, font_scale, cv::Scalar(0, 255, 0), thickness, 1, 0);
|
|
|
|
|
|
// printf("type: %d %d %d %d %d %d %d\n", blobs.blobTab[i].ErrType, blobs.blobTab[i].area, blobs.blobTab[i].energy, roi.x, roi.y, roi.width, roi.height);
|
|
|
}
|
|
|
cv::imwrite(m_CheckResult_shareP->in_shareImage->strChannel + "_image_resize_blob.png", tm);
|
|
|
}
|
|
|
|
|
|
long te = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis End use time %ld blob %ld ms", te - t1, t2 - t1);
|
|
|
|
|
|
// getchar();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AIMaskDet()
|
|
|
{
|
|
|
|
|
|
// 计算 mask 图片的一行 是否有 残点,用以加速 Blob的计算。
|
|
|
if (m_ImgBlobHFlagData)
|
|
|
{
|
|
|
delete[] m_ImgBlobHFlagData;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
m_ImgBlobHFlagData = new unsigned char[m_pImageAllResult->detImg.rows];
|
|
|
memset(m_ImgBlobHFlagData, 0, sizeof(unsigned char) * m_pImageAllResult->detImg.rows);
|
|
|
|
|
|
// bDetect为false时不进行推理,直接输出全黑残点图
|
|
|
if(!m_pBasicConfig->bDetect)
|
|
|
{
|
|
|
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// 传统检测路径:等待异步任务完成后,计算HFlag
|
|
|
if(m_pbaseCheckFunction->traditionDet.bOpen)
|
|
|
{
|
|
|
m_AItask->waitComplate();
|
|
|
int rec = m_AItask->nresult;
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
return rec;
|
|
|
}
|
|
|
if (!m_pImageAllResult->AIMaskImg.empty())
|
|
|
{
|
|
|
unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data;
|
|
|
int width = m_pImageAllResult->AIMaskImg.cols;
|
|
|
int height = m_pImageAllResult->AIMaskImg.rows;
|
|
|
for (int y = 0; y < height; y++)
|
|
|
{
|
|
|
if (m_ImgBlobHFlagData[y] == 0)
|
|
|
{
|
|
|
unsigned char *p = pGrayErrordata + y * width;
|
|
|
for (int x = 0; x < width; x++)
|
|
|
{
|
|
|
if (p[x] != 0)
|
|
|
{
|
|
|
m_ImgBlobHFlagData[y] = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
while (true)
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> AImaskResult;
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lock(mtx_AIMaskImgBLobQueue);
|
|
|
if (m_AIMaskImgBLobQueue.size() > 0)
|
|
|
{
|
|
|
AImaskResult = std::move(m_AIMaskImgBLobQueue.front());
|
|
|
m_AIMaskImgBLobQueue.pop();
|
|
|
// printf("size ============== %ld\n", m_AIMaskImgBLobQueue.size());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 有AI mask 的结果
|
|
|
if (AImaskResult)
|
|
|
{
|
|
|
// static int ss = 0;
|
|
|
cv::Mat &outimg = *(AImaskResult->output);
|
|
|
// cv::imwrite(std::to_string(ss++) + ".png", outimg);
|
|
|
|
|
|
unsigned char *pGrayErrordata = (unsigned char *)outimg.data;
|
|
|
int width = outimg.cols;
|
|
|
int height = outimg.rows;
|
|
|
int start_Y = AImaskResult->roi.y;
|
|
|
if (cv::countNonZero(outimg != 0) != 0)
|
|
|
{
|
|
|
// #pragma omp parallel for
|
|
|
for (int y = 0; y < height; y++)
|
|
|
{
|
|
|
if (m_ImgBlobHFlagData[y + start_Y] == 0)
|
|
|
{
|
|
|
unsigned char *p = pGrayErrordata + y * width;
|
|
|
for (int x = 0; x < width; x++)
|
|
|
{
|
|
|
if (p[x] != 0)
|
|
|
{
|
|
|
m_ImgBlobHFlagData[y + start_Y] = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/* code */
|
|
|
|
|
|
if (m_AItask->isComplate())
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// printf("===========================================1 \n");
|
|
|
m_AItask->waitComplate();
|
|
|
int rec = m_AItask->nresult;
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
return rec;
|
|
|
}
|
|
|
// printf("===========================================2 \n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Contours()
|
|
|
{
|
|
|
// std::string strBaseLog = "Contours";
|
|
|
// // m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours Start");
|
|
|
// cv::Mat detimg;
|
|
|
// {
|
|
|
// // 膨胀
|
|
|
// cv::Mat se = getStructuringElement(0, Size(5, 5)); // 构造矩形结构元素
|
|
|
// cv::dilate(m_pdetlog->temImgList[TEM_IMG_IDX_AImask], detimg, se);
|
|
|
// }
|
|
|
|
|
|
// std::vector<std::vector<cv::Point>> contours;
|
|
|
// std::vector<cv::Vec4i> hierarchy;
|
|
|
// cv::findContours(detimg, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); // 只找最外层轮廓
|
|
|
|
|
|
// // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop], m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], cv::COLOR_GRAY2BGR);
|
|
|
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// { // 绘制所有轮廓
|
|
|
// cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓
|
|
|
// }
|
|
|
|
|
|
// float fx = m_pdetlog->temImgList[TEM_IMG_IDX_Result].cols * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].cols;
|
|
|
// float fy = m_pdetlog->temImgList[TEM_IMG_IDX_Result].rows * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].rows;
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// {
|
|
|
// for (int j = 0; j < contours.at(i).size(); ++j)
|
|
|
// {
|
|
|
// contours.at(i).at(j).x *= fx;
|
|
|
// contours.at(i).at(j).y *= fy;
|
|
|
// }
|
|
|
// }
|
|
|
// // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_Result], m_pdetlog->temImgList[TEM_IMG_IDX_Result], cv::COLOR_GRAY2BGR);
|
|
|
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// { // 绘制所有轮廓
|
|
|
// cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_Result], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓
|
|
|
// }
|
|
|
// cv::imwrite("TEM_IMG_IDX_Result.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]);
|
|
|
// cv::imwrite("deeeee.png", m_pdetlog->temImgList[TEM_IMG_IDX_Drawmask]);
|
|
|
// getchar();
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours End");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckImgInit()
|
|
|
{
|
|
|
// 1、初始化
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList = std::make_shared<std::vector<QX_ERROR_INFO_>>();
|
|
|
m_pdetlog->Init();
|
|
|
m_pdetlog->addLogLevel = DET_LOG_LEVEL_3;
|
|
|
memset(&blobs, 0, sizeof(ERROR_DOTS_BLOBS));
|
|
|
m_nCheckResultErrorCode = 0;
|
|
|
|
|
|
m_Draw_qxImageResult.erase(m_Draw_qxImageResult.begin(), m_Draw_qxImageResult.end());
|
|
|
|
|
|
m_DetRoiList.Init();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ConfigCheck(cv::Mat img)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "start", "Config Check");
|
|
|
int re = CHECK_OK;
|
|
|
if (img.empty())
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_CheckImg_Empty;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Error", "check Img empty");
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
// if (m_pCommonAnalysisyConfig->regionConfigArr.size() <= 0)
|
|
|
// {
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Error", "regionConfig Num = 0");
|
|
|
// m_nErrorCode = CHECK_ERROR_Config_Value;
|
|
|
// return m_nErrorCode;
|
|
|
// }
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Succ", "Config Check Succ");
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
|
|
|
{
|
|
|
std::shared_ptr<AIModel_Base> pAIDet;
|
|
|
// printf("=====>>>>AI_Detect_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str());
|
|
|
if (m_strCurDetChannel.find("BCA") != std::string::npos)
|
|
|
{
|
|
|
// printf("=====>>>>AI_Detect_Thread USE CA %s \n", m_strCurDetChannel.c_str());
|
|
|
pAIDet = AI_Factory->CELL_BCA_Det;
|
|
|
}
|
|
|
else if (m_strCurDetChannel.find("BTA") != std::string::npos)
|
|
|
{
|
|
|
pAIDet = AI_Factory->CELL_BTA_Det;
|
|
|
}
|
|
|
else if (m_strCurDetChannel.find("DCA") != std::string::npos)
|
|
|
{
|
|
|
pAIDet = AI_Factory->CELL_DCA_Det;
|
|
|
}
|
|
|
else if (m_strCurDetChannel.find("DTA") != std::string::npos)
|
|
|
{
|
|
|
pAIDet = AI_Factory->CELL_DTA_Det;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
pAIDet = AI_Factory->CELL_BTA_Det;
|
|
|
}
|
|
|
|
|
|
std::string strBaseLog = "AI_Detect";
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect Start");
|
|
|
long t1, t2, t3;
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
SmallRoiList.clear();
|
|
|
SmallRoiList.erase(SmallRoiList.begin(), SmallRoiList.end());
|
|
|
cv::Rect cutRoi;
|
|
|
cutRoi.x = 0;
|
|
|
cutRoi.y = 0;
|
|
|
cutRoi.width = img.cols - 0;
|
|
|
cutRoi.height = img.rows - 0;
|
|
|
|
|
|
int deal_image_width = pAIDet->input_0.width;
|
|
|
int deal_image_height = pAIDet->input_0.height;
|
|
|
|
|
|
int re = CheckUtil::cutSmallImg(img, SmallRoiList, cutRoi, deal_image_width, deal_image_height, 0, 0);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg Num %d", SmallRoiList.size());
|
|
|
if (re != 0 || SmallRoiList.size() <= 0)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg error %d", re);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
|
|
|
return re;
|
|
|
/* code */
|
|
|
}
|
|
|
|
|
|
// 临时存图
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
|
|
|
cv::Mat imshow;
|
|
|
if (img.channels() == 1)
|
|
|
{
|
|
|
cv::cvtColor(img, imshow, cv::COLOR_GRAY2RGB); // 彩色 可选项
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
imshow = img.clone();
|
|
|
}
|
|
|
for (int i = 0; i < SmallRoiList.size(); i++)
|
|
|
{
|
|
|
cv::rectangle(imshow, SmallRoiList.at(i), cv::Scalar(0, 0, 255), 3);
|
|
|
}
|
|
|
cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_Det_ROI.jpg", imshow);
|
|
|
}
|
|
|
|
|
|
ResultImg = cv::Mat::zeros(img.size(), CV_8UC1);
|
|
|
|
|
|
const int totalTasks = SmallRoiList.size();
|
|
|
int submitted = 0;
|
|
|
int completed = 0;
|
|
|
|
|
|
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
while (completed < totalTasks)
|
|
|
{
|
|
|
// 如果任务还没提交完,且当前处理任务数 < 2,提交新任务
|
|
|
if (submitted < totalTasks && runner->GetProcessingCount() < 10)
|
|
|
{
|
|
|
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> task = std::make_shared<AIMulThreadRunBase::AITask>();
|
|
|
task->id = completed;
|
|
|
task->roi = SmallRoiList.at(submitted);
|
|
|
task->input = img(SmallRoiList.at(submitted)).clone();
|
|
|
task->output = std::make_shared<cv::Mat>();
|
|
|
task->engine = pAIDet;
|
|
|
|
|
|
runner->SubmitTask(task);
|
|
|
submitted++;
|
|
|
}
|
|
|
|
|
|
// 尝试取结果
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> result;
|
|
|
if (runner->PopResult(result))
|
|
|
{
|
|
|
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lock(mtx_AIMaskImgBLobQueue);
|
|
|
m_AIMaskImgBLobQueue.push(result);
|
|
|
}
|
|
|
|
|
|
cv::Mat &outimg = *(result->output);
|
|
|
if (!outimg.empty())
|
|
|
{
|
|
|
outimg.copyTo(ResultImg(result->roi), outimg);
|
|
|
}
|
|
|
{
|
|
|
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
|
|
|
temAIresult->roi = result->roi;
|
|
|
temAIresult->AI_inImg = result->input;
|
|
|
temAIresult->AI_mask = outimg;
|
|
|
m_pImageAllResult->AI_Qx_MaskList.push_back(temAIresult);
|
|
|
// AI检测残点图存图
|
|
|
if (m_pbaseCheckFunction->saveImg.bSaveAIDetImg)
|
|
|
{
|
|
|
std::string roi_ext = "[" + std::to_string(result->roi.x) + "," + std::to_string(result->roi.y) + "]";
|
|
|
std::string strSaveDir = "/home/aidlux/BOE/FOG/AI_Detect/" + DetImgInfo_shareP->strImgProductID + "/";
|
|
|
CheckUtil::CreateDir(strSaveDir);
|
|
|
std::string strSavePath_in = strSaveDir + m_strCurDetChannel +"_"+ roi_ext + "_"+ "in" + ".png";
|
|
|
std::string strSavePath_out = strSaveDir + m_strCurDetChannel +"_"+ roi_ext + "_"+ "out" + ".png";
|
|
|
cv::imwrite(strSavePath_in, result->input);
|
|
|
cv::imwrite(strSavePath_out, outimg);
|
|
|
}
|
|
|
}
|
|
|
completed++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
t3 = CheckUtil::getcurTime();
|
|
|
float mean_AI = (t3 - t2) / SmallRoiList.size();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " AI Run Time: sum %ld pre %ld Run %ld mean One Small Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
|
|
|
|
|
|
// 临时存图
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_mask.png", ResultImg);
|
|
|
}
|
|
|
|
|
|
// getchar();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// ======================== 传统检测 ========================
|
|
|
int ImgCheckAnalysisy::Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
|
|
|
{
|
|
|
std::string strBaseLog = "Traditional_Detect";
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect Start");
|
|
|
|
|
|
// 输入校验
|
|
|
if (img.empty())
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect FAILED (empty image)");
|
|
|
ResultImg = cv::Mat();
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
Base_Function_TraditionDet traditionParam = m_pbaseCheckFunction->traditionDet; // 首次调用时初始化传统检测参数(从 m_AnalysisyConfig 映射)
|
|
|
{
|
|
|
CHECK_PARAM cp;
|
|
|
cp.nAreaLowFilter = 80;
|
|
|
cp.nBlockSize = traditionParam.nBlockSize;
|
|
|
cp.fZoomRatio = traditionParam.fZoomRatio;
|
|
|
cp.nFilterLow = traditionParam.nFilterLow;
|
|
|
cp.nFilterHigh = traditionParam.nFilterHigh;
|
|
|
cp.nAreaFilter = traditionParam.nAreaFilter;
|
|
|
cp.nCountFilter = traditionParam.nCountFilter;
|
|
|
cp.productId = DetImgInfo_shareP->strImgProductID;
|
|
|
cp.productChannel = m_strCurDetChannel;
|
|
|
cp.bDebugsaveImg = m_pbaseCheckFunction->saveImg.bSaveAIDetImg;
|
|
|
m_tcsCheck.SetChecConfig(&cp);
|
|
|
}
|
|
|
|
|
|
cv::Rect detroi = cv::boundingRect(traditionParam.detArea);
|
|
|
detroi.x -= m_Crop_Roi_paramImg.x;
|
|
|
detroi.y -= m_Crop_Roi_paramImg.y;
|
|
|
detroi = detroi & cv::Rect(0, 0, img.cols, img.rows);
|
|
|
if(!traditionParam.bdetArea)
|
|
|
{
|
|
|
detroi = cv::Rect(0, 0, img.cols, img.rows);
|
|
|
}
|
|
|
// 调用传统检测:输出残点二值图
|
|
|
int ret = m_tcsCheck.TraditionalDetect(img, detroi, ResultImg);
|
|
|
if (ret != 0)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect FAILED (no product)");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_mask.png", ResultImg);
|
|
|
}
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect End");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_QX_Class_Thread()
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "QX_Class", " Start");
|
|
|
|
|
|
std::shared_ptr<AIModel_Base> pAIDet;
|
|
|
// printf("=====>>>>AI_QX_Class_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str());
|
|
|
if (m_strCurDetChannel.find("CA") != std::string::npos)
|
|
|
{
|
|
|
// printf("=====>>>>AI_QX_Class_Thread USE CA %s \n", m_strCurDetChannel.c_str());
|
|
|
pAIDet = AI_Factory->CELL_CA_Cls;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
pAIDet = AI_Factory->CELL_TA_Cls;
|
|
|
}
|
|
|
|
|
|
int deal_image_width = pAIDet->input_0.width;
|
|
|
int deal_image_height = pAIDet->input_0.height;
|
|
|
|
|
|
const int totalTasks = blobs.blobCount;
|
|
|
int submitted = 0;
|
|
|
int completed = 0;
|
|
|
int detblobIdx = 0;
|
|
|
int clsnum = 0;
|
|
|
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
while (completed < totalTasks)
|
|
|
{
|
|
|
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
if (submitted < totalTasks)
|
|
|
{
|
|
|
ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[submitted];
|
|
|
if (pblob->ErrType == ERR_TYPE_2)
|
|
|
{
|
|
|
pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs;
|
|
|
submitted++;
|
|
|
completed++;
|
|
|
continue;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 如果任务还没提交完,且当前处理任务数 < 2,提交新任务
|
|
|
if (runner->GetProcessingCount() < 10)
|
|
|
{
|
|
|
clsnum++;
|
|
|
cv::Rect roi;
|
|
|
roi.x = pblob->minx;
|
|
|
roi.y = pblob->miny;
|
|
|
roi.width = pblob->maxx - pblob->minx + 1;
|
|
|
roi.height = pblob->maxy - pblob->miny + 1;
|
|
|
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> task = std::make_shared<AIMulThreadRunBase::AITask>();
|
|
|
task->id = submitted;
|
|
|
int re = GetClassImg(m_pImageAllResult->detImg, task->input, roi, deal_image_width, deal_image_height);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
task->bclass = true;
|
|
|
task->engine = pAIDet;
|
|
|
runner->SubmitTask(task);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
completed++;
|
|
|
}
|
|
|
|
|
|
submitted++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 尝试取结果
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> result;
|
|
|
if (runner->PopResult(result))
|
|
|
{
|
|
|
|
|
|
int temClass = result->cls_label;
|
|
|
int cls_num = 0;
|
|
|
|
|
|
switch (temClass)
|
|
|
{
|
|
|
case 0:
|
|
|
cls_num = AI_CLass_QX_NAME_aotudian;
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
cls_num = AI_CLass_QX_NAME_other;
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
cls_num = AI_CLass_QX_NAME_line;
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
cls_num = AI_CLass_QX_NAME_zangwu;
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
cls_num = AI_CLass_QX_NAME_dianzhuang;
|
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
cls_num = AI_CLass_QX_NAME_posun;
|
|
|
break;
|
|
|
|
|
|
case 6:
|
|
|
cls_num = AI_CLass_QX_NAME_xianwei;
|
|
|
break;
|
|
|
|
|
|
case 7:
|
|
|
cls_num = AI_CLass_QX_NAME_shuizi;
|
|
|
break;
|
|
|
|
|
|
case 8:
|
|
|
cls_num = AI_CLass_QX_NAME_danban;
|
|
|
break;
|
|
|
|
|
|
case 9:
|
|
|
cls_num = AI_CLass_QX_NAME_fuchen;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
cls_num = AI_CLass_QX_NAME_zangwu;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// std::string strclassName = AI_CLass_QX_NAME_Names[cls_num];
|
|
|
// printf("AI Class num %d = %s %f\n", cls_num, strclassName.c_str(), result->cls_score);
|
|
|
|
|
|
// 分类存图 开启。
|
|
|
if (m_pbaseCheckFunction->saveImg.bSaveAlginImg)
|
|
|
{
|
|
|
|
|
|
std::string saveimgpaht = "";
|
|
|
|
|
|
if (m_strCurDetChannel.find("TA") != std::string::npos)
|
|
|
{
|
|
|
saveimgpaht = m_strRootPath_TA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
saveimgpaht = m_strRootPath_CA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png";
|
|
|
}
|
|
|
|
|
|
{
|
|
|
m_pImageStorage->addImage(saveimgpaht, result->input);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int configqx = AIClassTypeToConfigType(cls_num);
|
|
|
|
|
|
ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[result->id];
|
|
|
pblob->AIclasstype = configqx;
|
|
|
|
|
|
completed++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
}
|
|
|
}
|
|
|
// printf("=====>>>>AI_QX_Class_Thread clsnum %d \n", clsnum);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// ======================== 传统分类 ========================
|
|
|
int ImgCheckAnalysisy::Traditional_QX_Class_Thread()
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Start");
|
|
|
|
|
|
// 1. 调用传统分类
|
|
|
if (m_pImageAllResult == nullptr || m_pImageAllResult->AIMaskImg.empty())
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " No mask image");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
int nDefectCount = m_tcsCheck.TraditionalClassify(m_pImageAllResult->AIMaskImg);
|
|
|
if (nDefectCount < 0)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Classify failed");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
// 2. TcsCheck 缺陷类型 → CONFIG_QX_NAME 映射表
|
|
|
static const int TcsDefectToConfigQX[] = {
|
|
|
CONFIG_QX_NAME_cell_other, // DEFECT_TYPE_OK = 0
|
|
|
CONFIG_QX_NAME_cell_dianzhuang, // DEFECT_TYPE_POINT = 1 (硬质颗粒 → 点状)
|
|
|
CONFIG_QX_NAME_cell_line, // DEFECT_TYPE_SCRATCH = 2 (划伤 → 线状)
|
|
|
CONFIG_QX_NAME_cell_zangwu, // DEFECT_TYPE_DIRTY = 3 (脏污)
|
|
|
CONFIG_QX_NAME_cell_danban, // DEFECT_TYPE_FADING_SPOTS = 4 (淡斑)
|
|
|
};
|
|
|
|
|
|
// 3. 将分类结果匹配到 blobs.blobTab(基于位置/面积最近邻匹配)
|
|
|
int totalTasks = blobs.blobCount;
|
|
|
for (int i = 0; i < totalTasks; i++)
|
|
|
{
|
|
|
ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[i];
|
|
|
|
|
|
if (pblob->ErrType == ERR_TYPE_2)
|
|
|
{
|
|
|
pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 在 TcsCheck 结果中找最佳匹配(中心距离最近)
|
|
|
int bestIdx = -1;
|
|
|
int bestDist2 = INT_MAX;
|
|
|
int blobCenterX = (pblob->minx + pblob->maxx) / 2;
|
|
|
int blobCenterY = (pblob->miny + pblob->maxy) / 2;
|
|
|
|
|
|
for (int j = 0; j < nDefectCount; j++)
|
|
|
{
|
|
|
const DEFECT_INFO& info = m_tcsCheck.m_vecDefectInfo[j];
|
|
|
int defCenterX = info.nDefectX + info.nDefectWidth / 2;
|
|
|
int defCenterY = info.nDefectY + info.nDefectHeight / 2;
|
|
|
int dx = blobCenterX - defCenterX;
|
|
|
int dy = blobCenterY - defCenterY;
|
|
|
int dist2 = dx * dx + dy * dy;
|
|
|
|
|
|
// 面积接近的优先(容差 50% 内)
|
|
|
int areaDiff = std::abs(pblob->area - info.nDefectArea);
|
|
|
if (areaDiff < info.nDefectArea / 2 && dist2 < bestDist2)
|
|
|
{
|
|
|
bestDist2 = dist2;
|
|
|
bestIdx = j;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (bestIdx >= 0)
|
|
|
{
|
|
|
int defectType = m_tcsCheck.m_vecDefectInfo[bestIdx].nDefectType;
|
|
|
pblob->AIclasstype = TcsDefectToConfigQX[defectType];
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
pblob->AIclasstype = CONFIG_QX_NAME_cell_other;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " End, classified %d/%d blobs", nDefectCount, totalTasks);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ThreadTask(int nId)
|
|
|
{
|
|
|
|
|
|
while (!m_bExit)
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
|
// 等待是否有任务
|
|
|
std::shared_ptr<TaskInfo> task = m_task.GetTask();
|
|
|
|
|
|
// 把任务发送给对应的任务处理函数进行处理
|
|
|
switch (task->taskname)
|
|
|
{
|
|
|
case Task_AI:
|
|
|
TaskFun_AIDet(task);
|
|
|
break;
|
|
|
case Task_Class:
|
|
|
TaskFun_QxClass(task);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ResizeImg()
|
|
|
{
|
|
|
|
|
|
cv::Size sz;
|
|
|
sz.width = RESIZE_IMAGE_WIDTH;
|
|
|
|
|
|
float fw = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
sz.height = int(m_pImageAllResult->detImg.rows * fw);
|
|
|
|
|
|
cv::resize(m_pImageAllResult->detImg, m_pImageAllResult->resultImg, sz);
|
|
|
if (m_pImageAllResult->resultImg.channels() == 1)
|
|
|
{
|
|
|
cv::cvtColor(m_pImageAllResult->resultImg, m_pImageAllResult->resultImg, cv::COLOR_GRAY2BGR);
|
|
|
}
|
|
|
m_CheckResult_shareP->resultimg = m_pImageAllResult->resultImg;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "showImg size", " [w %d,h %d]-> show img [w %d,h %d] ",
|
|
|
m_CutRoi.width, m_CutRoi.height, sz.width, sz.height);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr<TaskInfo> task)
|
|
|
{
|
|
|
task->SetStatus(TaskStep_run);
|
|
|
long t1, t2;
|
|
|
// 检测:传统检测 / AI推理
|
|
|
{
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
int rec;
|
|
|
if(m_pbaseCheckFunction->traditionDet.bOpen)
|
|
|
{
|
|
|
rec = Traditional_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
rec = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg);
|
|
|
}
|
|
|
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
task->nresult = rec;
|
|
|
}
|
|
|
task->SetStatus(TaskStep_compate);
|
|
|
}
|
|
|
|
|
|
void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr<TaskInfo> task)
|
|
|
{
|
|
|
task->SetStatus(TaskStep_run);
|
|
|
long t1, t2;
|
|
|
// 缺陷分类:传统检测 / AI推理
|
|
|
{
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
int rec;
|
|
|
if(m_pbaseCheckFunction->traditionDet.bOpen)
|
|
|
{
|
|
|
rec = Traditional_QX_Class_Thread();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
rec = AI_QX_Class_Thread();
|
|
|
}
|
|
|
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
task->nresult = rec;
|
|
|
}
|
|
|
task->SetStatus(TaskStep_compate);
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Update_DetRoiList()
|
|
|
{
|
|
|
float fx = m_pImageAllResult->fscale_detToresult_x;
|
|
|
float fy = m_pImageAllResult->fscale_detToresult_y;
|
|
|
|
|
|
// Adapt_Config 已通过仿射变换将配置区域适配到当前产品位置,
|
|
|
// 此处仅做坐标映射(减去裁剪ROI偏移 + 缩放),不再叠加边缘对齐的二次偏移
|
|
|
for (const auto ®ion : m_pCommonAnalysisyConfig->regionConfigArr)
|
|
|
{
|
|
|
m_DetRoiList.Update(region.basicInfo.pointArry, m_Crop_Roi_paramImg, fx, fy);
|
|
|
}
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "info", "roiList_Src roi num %ld", m_DetRoiList.roiList_Src.size());
|
|
|
// m_DetRoiList.print("m_DetRoiList");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::DrawResult_Step_1()
|
|
|
{
|
|
|
|
|
|
// std::cout << m_pBasicConfig->bDrawPreRoi << std::endl;
|
|
|
if (m_pBasicConfig->bDrawPreRoi)
|
|
|
{
|
|
|
int n = 0;
|
|
|
// std::cout << m_DetRoiList.roiList_Show.size() << std::endl;
|
|
|
for(int i = 0; i < m_DetRoiList.roiList_Show.size(); i++)
|
|
|
{
|
|
|
cv::polylines(m_CheckResult_shareP->resultimg, m_DetRoiList.roiList_Show[i], true, cv::Scalar(32, 128, (i*64+64)%255), 1);
|
|
|
}
|
|
|
// for (const auto &polygon : m_DetRoiList.roiList_Show)
|
|
|
// {
|
|
|
// // n++;
|
|
|
// // if (n == 1)
|
|
|
// // {
|
|
|
// // continue;
|
|
|
// // }
|
|
|
|
|
|
// // std::cout << polygon << std::endl;
|
|
|
|
|
|
// // 绘制多边形的边界(不填充),使用绿色线条,线宽为2
|
|
|
// cv::polylines(m_CheckResult_shareP->resultimg, polygon, true, cv::Scalar(128, 128, 255), 1); // true表示闭合多边形
|
|
|
// }
|
|
|
// cv::imwrite(DetImgInfo_shareP->strChannel + "roi_src.png", m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc]);
|
|
|
// cv::imwrite(DetImgInfo_shareP->strChannel + "roi_ss.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]);
|
|
|
|
|
|
// getchar();
|
|
|
}
|
|
|
|
|
|
float fs_resize_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
|
|
|
|
|
|
// 要绘制结果
|
|
|
if (m_pbaseCheckFunction && m_pbaseCheckFunction->edgeDet.bDrawResult)
|
|
|
{
|
|
|
for (const auto &r : m_Edge_DetConfig.edge_det_roi)
|
|
|
{
|
|
|
cv::Point2f vertices[4];
|
|
|
r.rrect.points(vertices);
|
|
|
for (int j = 0; j < 4; j++)
|
|
|
{
|
|
|
cv::Point p1, p2;
|
|
|
p1.x = (int)(vertices[j].x * fs_resize_x);
|
|
|
p1.y = (int)(vertices[j].y * fs_resize_y);
|
|
|
p2.x = (int)(vertices[(j+1)%4].x * fs_resize_x);
|
|
|
p2.y = (int)(vertices[(j+1)%4].y * fs_resize_y);
|
|
|
cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(255, 0, 255), 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (m_Edge_DetConfig.Det_region.size() > 2)
|
|
|
{
|
|
|
for (int i = 0; i < m_Edge_DetConfig.Det_region.size() - 1; i++)
|
|
|
{
|
|
|
cv::Point p1;
|
|
|
p1.x = m_Edge_DetConfig.Det_region[i].x * fs_resize_x;
|
|
|
p1.y = m_Edge_DetConfig.Det_region[i].y * fs_resize_y;
|
|
|
cv::Point p2;
|
|
|
p2.x = m_Edge_DetConfig.Det_region[i + 1].x * fs_resize_x;
|
|
|
p2.y = m_Edge_DetConfig.Det_region[i + 1].y * fs_resize_y;
|
|
|
cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255));
|
|
|
}
|
|
|
{
|
|
|
cv::Point p1;
|
|
|
p1.x = m_Edge_DetConfig.Det_region[0].x * fs_resize_x;
|
|
|
p1.y = m_Edge_DetConfig.Det_region[0].y * fs_resize_y;
|
|
|
cv::Point p2;
|
|
|
p2.x = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].x * fs_resize_x;
|
|
|
p2.y = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].y * fs_resize_y;
|
|
|
cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (m_pEdge_Align_Result.get() != NULL)
|
|
|
{
|
|
|
|
|
|
if (m_pbaseCheckFunction->markLine.bDraw)
|
|
|
{
|
|
|
for (size_t i = 0; i < m_pEdge_Align_Result->markresulList.size(); i++)
|
|
|
{
|
|
|
// if (m_pEdge_Align_Result->markresulList[i].status == Mark_Result_Status_OK)
|
|
|
{
|
|
|
cv::Point p;
|
|
|
p.x = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.x * fs_resize_x;
|
|
|
p.y = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.y * fs_resize_y;
|
|
|
cv::circle(m_CheckResult_shareP->resultimg, p, 5, cv::Scalar(0, 255, 0));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// cv::imwrite("sss.png", m_CheckResult_shareP->resultimg);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AIClassTypeToConfigType(int nAIQXType)
|
|
|
{
|
|
|
|
|
|
int resultError_type = CONFIG_QX_NAME_cell_aotudian;
|
|
|
switch (nAIQXType)
|
|
|
{
|
|
|
case AI_CLass_QX_NAME_aotudian:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_aotudian;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_other:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_other;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_line:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_line;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_zangwu:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_zangwu;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_dianzhuang:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_dianzhuang;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_posun:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_posun;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_xianwei:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_xianwei;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_shuizi:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_shuizi;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_danban:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_danban;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_fuchen:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_fuchen;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
return resultError_type;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::UpdateImgageScale()
|
|
|
{
|
|
|
|
|
|
if (m_pBasicConfig->fImage_Scale_x > 0 && m_pBasicConfig->fImage_Scale_x < 1 &&
|
|
|
m_pBasicConfig->fImage_Scale_y > 0 && m_pBasicConfig->fImage_Scale_y < 1)
|
|
|
{
|
|
|
|
|
|
m_fImgage_Scale_X = m_pBasicConfig->fImage_Scale_x;
|
|
|
m_fImgage_Scale_Y = m_pBasicConfig->fImage_Scale_y;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img)
|
|
|
{
|
|
|
|
|
|
m_Edge_DetConfig.Init();
|
|
|
m_Edge_DetConfig.detlog = m_pdetlog;
|
|
|
m_Edge_DetConfig.strChannel = m_strCurDetChannel;
|
|
|
m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction;
|
|
|
m_Edge_DetConfig.alginResult.corpRoi = m_Crop_Roi_paramImg;
|
|
|
m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region = m_AnalysisyConfig.baseFunction.markLine.region;
|
|
|
|
|
|
for(int i = 0; i < m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region.size(); i++)
|
|
|
{
|
|
|
m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].x -= m_Crop_Roi_paramImg.x;
|
|
|
m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].y -= m_Crop_Roi_paramImg.y;
|
|
|
}
|
|
|
if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft)
|
|
|
{
|
|
|
m_Edge_DetConfig.alginResult.offtx = m_pEdge_Align_Result->offt_x;
|
|
|
m_Edge_DetConfig.alginResult.offty = m_pEdge_Align_Result->offt_y;
|
|
|
m_Edge_DetConfig.alginResult.H = m_pEdge_Align_Result->H.clone();
|
|
|
}
|
|
|
m_Edge_DetConfig.bSaveResultImg = false;
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
m_Edge_DetConfig.bSaveResultImg = true;
|
|
|
}
|
|
|
// m_pbaseCheckFunction->print("Edge_Qx_Det");
|
|
|
int re = m_Edge_QX_Det.Detect(img, &m_Edge_DetConfig);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
for (const auto r : m_Edge_DetConfig.qx_result)
|
|
|
{
|
|
|
QX_ERROR_INFO_ temerror;
|
|
|
temerror.roi = r.roi_src;
|
|
|
temerror.Idx = m_pDetResult->pQx_ErrorList->size();
|
|
|
temerror.area = r.area_pixel;
|
|
|
temerror.JudgArea = r.area_pixel * m_fImgage_Scale_X * m_fImgage_Scale_Y;
|
|
|
temerror.JudgArea_second = temerror.JudgArea;
|
|
|
temerror.energy = 99999999;
|
|
|
temerror.flen = std::max(r.roi_src.width, r.roi_src.height);
|
|
|
temerror.fbreadth = std::min(r.roi_src.width, r.roi_src.height);
|
|
|
temerror.nconfig_qx_type = CONFIG_QX_NAME_cell_edge;
|
|
|
temerror.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_edge];
|
|
|
temerror.maxValue = 0;
|
|
|
temerror.grayDis = 255;
|
|
|
temerror.density = 0;
|
|
|
temerror.fUpIou = 0;
|
|
|
|
|
|
{
|
|
|
cv::Point pCenter;
|
|
|
pCenter.x = temerror.roi.x + temerror.roi.width * 0.5;
|
|
|
pCenter.y = temerror.roi.y + temerror.roi.height * 0.5;
|
|
|
int nmaxregionIdx = -1;
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
if (nmaxregionIdx >= 0)
|
|
|
{
|
|
|
temerror.detRegionidxList.push_back(nmaxregionIdx);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// {
|
|
|
// cv::Point pCenter;
|
|
|
// pCenter.x = temerror.roi.x + temerror.roi.width * 0.5;
|
|
|
// pCenter.y = temerror.roi.y + temerror.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;
|
|
|
// }
|
|
|
// temerror.detRegionidxList.push_back(iregion);
|
|
|
// }
|
|
|
// if (temerror.detRegionidxList.size() <= 0)
|
|
|
// {
|
|
|
// temerror.detRegionidxList.push_back(0);
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList->push_back(temerror);
|
|
|
}
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " succ qx num %ld", m_Edge_DetConfig.qx_result.size());
|
|
|
// printf("- %s idx %d a %f v %d h %f l %f\n", DetImgInfo_shareP->strChannel.c_str(), i, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, flen);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " error %d", re);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::BLobToDetResult()
|
|
|
{
|
|
|
long t1 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " Start old qx num %ld", m_pDetResult->pQx_ErrorList->size());
|
|
|
|
|
|
// 遍历每个检测blob
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
int config_qx_type = blobs.blobTab[i].AIclasstype;
|
|
|
|
|
|
float JudgArea = blobs.blobTab[i].JudgArea;
|
|
|
float fsecondArea = JudgArea;
|
|
|
std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
|
|
|
|
|
|
if (true)
|
|
|
{
|
|
|
QX_ERROR_INFO_ temerror;
|
|
|
temerror.roi = roi;
|
|
|
temerror.Idx = m_pDetResult->pQx_ErrorList->size();
|
|
|
temerror.area = blobs.blobTab[i].area;
|
|
|
temerror.JudgArea = JudgArea;
|
|
|
temerror.JudgArea_second = fsecondArea;
|
|
|
temerror.energy = blobs.blobTab[i].energy;
|
|
|
temerror.flen = blobs.blobTab[i].len;
|
|
|
temerror.fbreadth = blobs.blobTab[i].breadth;
|
|
|
temerror.nconfig_qx_type = config_qx_type;
|
|
|
temerror.qx_name = qx_name;
|
|
|
temerror.maxValue = blobs.blobTab[i].maxValue;
|
|
|
temerror.grayDis = blobs.blobTab[i].grayDis;
|
|
|
temerror.density = blobs.blobTab[i].density;
|
|
|
temerror.fUpIou = 0;
|
|
|
temerror.whiteOrBlack = blobs.blobTab[i].whiteOrblack;
|
|
|
|
|
|
{
|
|
|
cv::Point pCenter;
|
|
|
pCenter.x = roi.x + roi.width * 0.5;
|
|
|
pCenter.y = roi.y + roi.height * 0.5;
|
|
|
int nmaxregionIdx = -1;
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
if (nmaxregionIdx >= 0)
|
|
|
{
|
|
|
temerror.detRegionidxList.push_back(nmaxregionIdx);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// {
|
|
|
// cv::Point pCenter;
|
|
|
// pCenter.x = roi.x + roi.width * 0.5;
|
|
|
// pCenter.y = roi.y + roi.height * 0.5;
|
|
|
// 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;
|
|
|
// }
|
|
|
// temerror.detRegionidxList.push_back(iregion);
|
|
|
// }
|
|
|
// if (temerror.detRegionidxList.size() <= 0)
|
|
|
// {
|
|
|
// temerror.detRegionidxList.push_back(0);
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList->push_back(temerror);
|
|
|
|
|
|
// printf("- %s idx %d a %f v %d h %f l %f\n", DetImgInfo_shareP->strChannel.c_str(), i, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, flen);
|
|
|
}
|
|
|
}
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " end qx num %ld use time %ld", m_pDetResult->pQx_ErrorList->size(), t2 - t1);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::Rect &cutRoi)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "AI_Edge", "-------------------start--------------");
|
|
|
|
|
|
AI_Edge_Algin::DetConfig config;
|
|
|
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
config.bSaveResultImg = true;
|
|
|
}
|
|
|
config.strChannel = DetImgInfo_shareP->strChannel;
|
|
|
config.pBaseCheckFunction = m_pbaseCheckFunction;
|
|
|
int re = m_pAI_Edge_Algin.Detect(img, &config, m_pEdge_Align_Result);
|
|
|
if (re != 0)
|
|
|
{
|
|
|
printf("AI_Edge Is Error = %d \n", re);
|
|
|
}
|
|
|
cutRoi = m_pEdge_Align_Result->roi;
|
|
|
// getchar();
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CalProductSize()
|
|
|
{
|
|
|
float fw = m_CutRoi.width * m_fImgage_Scale_X;
|
|
|
float fh = m_CutRoi.height * m_fImgage_Scale_Y;
|
|
|
fw = std::ceil(fw * 10) / 10;
|
|
|
fh = std::ceil(fh * 10) / 10;
|
|
|
m_CheckResult_shareP->productWidht_mm = fw;
|
|
|
m_CheckResult_shareP->productHeight_mm = fh;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Det ROI", " [x%d, y%d, w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f",
|
|
|
m_CutRoi.x, m_CutRoi.y, m_CutRoi.width, m_CutRoi.height, fw, fh, m_fImgage_Scale_X, m_fImgage_Scale_Y);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
int ImgCheckAnalysisy::ImgPreDet()
|
|
|
{
|
|
|
|
|
|
// 计算产品尺寸
|
|
|
CalProductSize();
|
|
|
|
|
|
if (m_pbaseCheckFunction->saveImg.bSaveClsImg)
|
|
|
{
|
|
|
creatsavedir();
|
|
|
}
|
|
|
|
|
|
m_CheckResult_shareP->cutSrcimg = m_pImageAllResult->detImg;
|
|
|
ResizeImg();
|
|
|
|
|
|
m_pImageAllResult->fscale_detToresult_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
m_pImageAllResult->fscale_detToresult_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
|
|
|
return 0;
|
|
|
}
|