|
|
|
|
|
#include "AI_Edge_Algin.h"
|
|
|
#include "CheckErrorCodeDefine.hpp"
|
|
|
|
|
|
#define EDGE_GPU 0
|
|
|
|
|
|
AI_Edge_Algin::AI_Edge_Algin()
|
|
|
{
|
|
|
m_bInitialized = false;
|
|
|
m_bModelSucc = false;
|
|
|
m_str_curCamName = "";
|
|
|
AI_Factory = AIFactory::GetInstance();
|
|
|
CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Error/");
|
|
|
CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Result/");
|
|
|
CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Smasll/");
|
|
|
CheckUtil::CreateDir("/home/aidlux/BOE/FOG/Edge/Big/");
|
|
|
runner = std::make_shared<AIMulThreadRunBase>();
|
|
|
runner->Start();
|
|
|
}
|
|
|
|
|
|
AI_Edge_Algin::~AI_Edge_Algin()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared_ptr<Edge_AI_Result> &pCheckResult_Aling)
|
|
|
{
|
|
|
m_pDetConfig = pDetConfig;
|
|
|
m_str_curCamName = pDetConfig->strCamName;
|
|
|
// printf("save type saveProcessImg %d bSaveResultImg %d cam %s\n",
|
|
|
// pDetConfig->saveProcessImg, m_pDetConfig->bDebugSaveImg, m_str_curCamName.c_str());
|
|
|
|
|
|
static int erridx = 0;
|
|
|
std::string str_error = "";
|
|
|
|
|
|
// 保存过程图片
|
|
|
if (m_pDetConfig->IsSaveProcessImg())
|
|
|
{
|
|
|
erridx++;
|
|
|
if (erridx > 9999999)
|
|
|
{
|
|
|
erridx = 0;
|
|
|
}
|
|
|
str_error = "/home/aidlux/BOE/FOG/Edge/Error/" + std::to_string(erridx) + "_src.png";
|
|
|
}
|
|
|
cv::Mat showimg;
|
|
|
// 保存结果图片
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR);
|
|
|
}
|
|
|
pCheckResult_Aling = std::make_shared<Edge_AI_Result>();
|
|
|
if (img.empty())
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
long t1 = CheckUtil::getcurTime();
|
|
|
// 1、初步定位 找到产品大致区域
|
|
|
int re = 0;
|
|
|
vector<Rect> rois;
|
|
|
cv::Rect Big_roi;
|
|
|
cv::Mat mask;
|
|
|
cv::Mat big_mask;
|
|
|
re = Det_big(img, rois, pCheckResult_Aling->edge_RoiList, Big_roi, big_mask);
|
|
|
if (re != 0)
|
|
|
{
|
|
|
// printf("AICheck_Edge_Big----error %d \n", re);
|
|
|
if (m_pDetConfig->IsSaveProcessImg())
|
|
|
{
|
|
|
cv::imwrite(str_error, img);
|
|
|
}
|
|
|
return re;
|
|
|
}
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
for (const auto &roi : rois)
|
|
|
{
|
|
|
cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255));
|
|
|
}
|
|
|
cv::rectangle(showimg, Big_roi, cv::Scalar(255, 255, 255), 2);
|
|
|
cv::imwrite(pDetConfig->strCamName + "_0_edge_Small_Det_ROI.png", showimg);
|
|
|
}
|
|
|
cv::Mat Src_Mask;
|
|
|
re = Dtet_small(img, rois, Src_Mask);
|
|
|
if (re != 0)
|
|
|
{
|
|
|
// printf("AICheck_Edge_Small----error %d \n", re);
|
|
|
if (m_pDetConfig->IsSaveProcessImg())
|
|
|
{
|
|
|
cv::imwrite(str_error, img);
|
|
|
}
|
|
|
return re;
|
|
|
}
|
|
|
long t3 = CheckUtil::getcurTime();
|
|
|
cv::Mat Src_Masksss;
|
|
|
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
cv::imwrite(pDetConfig->strCamName + "_1_edge_Small_Out_Mask.png", Src_Mask);
|
|
|
}
|
|
|
cv::Rect result_roi;
|
|
|
Mat resultMask = Mat::zeros(img.size(), CV_8UC1);
|
|
|
|
|
|
{
|
|
|
vector<vector<Point>> contours;
|
|
|
findContours(Src_Mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
// 找到最大轮廓
|
|
|
double max_area = 0;
|
|
|
int max_contour_index = 0;
|
|
|
|
|
|
for (int i = 0; i < contours.size(); i++)
|
|
|
{
|
|
|
double area = contourArea(contours[i]);
|
|
|
if (area > max_area)
|
|
|
{
|
|
|
max_area = area;
|
|
|
max_contour_index = i;
|
|
|
}
|
|
|
}
|
|
|
if (max_contour_index < 0)
|
|
|
{
|
|
|
cerr << "No contours found!" << endl;
|
|
|
return 7;
|
|
|
}
|
|
|
|
|
|
if (max_contour_index >= 0)
|
|
|
{
|
|
|
result_roi = boundingRect(contours[max_contour_index]);
|
|
|
}
|
|
|
drawContours(resultMask, contours, max_contour_index, Scalar(255), FILLED); // -1表示填充所有轮廓
|
|
|
}
|
|
|
|
|
|
long t4 = CheckUtil::getcurTime();
|
|
|
// 和原始big模型做比对
|
|
|
{
|
|
|
|
|
|
double widthDiff = std::abs(result_roi.width - Big_roi.width) * 1.0f / std::min(result_roi.width, Big_roi.width);
|
|
|
double heightDiff = std::abs(result_roi.height - Big_roi.height) * 1.0f / std::min(result_roi.height, Big_roi.height);
|
|
|
// printf("big roi %s det %swidthDiff %f heightDiff %f\n", CheckUtil::GetRectString(Big_roi).c_str(), CheckUtil::GetRectString(result_roi).c_str(), widthDiff, heightDiff);
|
|
|
// 如果差异超过10%,抛出异常
|
|
|
if (widthDiff > 0.10)
|
|
|
{
|
|
|
return 51;
|
|
|
}
|
|
|
if (heightDiff > 0.10)
|
|
|
{
|
|
|
return 52;
|
|
|
}
|
|
|
}
|
|
|
if (m_pDetConfig->bUseDrawRoi_Check)
|
|
|
{
|
|
|
double widthDiff = std::abs(result_roi.width - m_pDetConfig->drawRoi.width) * 1.0f / std::min(result_roi.width, m_pDetConfig->drawRoi.width);
|
|
|
double heightDiff = std::abs(result_roi.height - m_pDetConfig->drawRoi.height) * 1.0f / std::min(result_roi.height, m_pDetConfig->drawRoi.height);
|
|
|
//printf("draw roi %s det %s widthDiff %f heightDiff %f\n", CheckUtil::GetRectString(m_pDetConfig->drawRoi).c_str(), CheckUtil::GetRectString(result_roi).c_str(), widthDiff, heightDiff);
|
|
|
// 如果差异超过10%,抛出异常
|
|
|
if (widthDiff > 0.10)
|
|
|
{
|
|
|
return 53;
|
|
|
}
|
|
|
if (heightDiff > 0.10)
|
|
|
{
|
|
|
return 54;
|
|
|
}
|
|
|
}
|
|
|
long t5 = CheckUtil::getcurTime();
|
|
|
// 用big 的来测试
|
|
|
if (false)
|
|
|
{
|
|
|
cv::Size sz_big;
|
|
|
sz_big.width = big_mask.cols;
|
|
|
sz_big.height = big_mask.rows;
|
|
|
cv::Mat size_prodct;
|
|
|
cv::resize(resultMask, size_prodct, sz_big, 0, 0, cv::INTER_AREA);
|
|
|
|
|
|
int va_big = countNonZero(big_mask);
|
|
|
int va_small = countNonZero(size_prodct);
|
|
|
if (va_big > 0)
|
|
|
{
|
|
|
int diff = std::abs(va_big - va_small); // 面积的差异值。
|
|
|
float fs = diff * 1.0f / va_big;
|
|
|
// printf("va_big %d va_small %d dff %d diffscale %f \n", va_big, va_small, diff, fs);
|
|
|
if (fs > 0.1)
|
|
|
{
|
|
|
// if (true)
|
|
|
// {
|
|
|
// cv::imwrite("big_mask.png",big_mask);
|
|
|
// cv::imwrite("size_prodct.png",size_prodct);
|
|
|
// getchar();
|
|
|
// }
|
|
|
|
|
|
return 55;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* code */
|
|
|
}
|
|
|
if (m_pDetConfig->bUseDrawRoi_Check && !m_pDetConfig->drawMask.empty())
|
|
|
{
|
|
|
cv::Size sz_big;
|
|
|
sz_big.width = big_mask.cols;
|
|
|
sz_big.height = big_mask.rows;
|
|
|
cv::Mat size_prodct;
|
|
|
cv::resize(resultMask, size_prodct, sz_big, 0, 0, cv::INTER_AREA);
|
|
|
|
|
|
cv::Mat size_drawmask;
|
|
|
cv::resize(m_pDetConfig->drawMask, size_drawmask, sz_big, 0, 0, cv::INTER_AREA);
|
|
|
|
|
|
int va_draw = countNonZero(size_drawmask);
|
|
|
int va_small = countNonZero(size_prodct);
|
|
|
if (va_draw > 0)
|
|
|
{
|
|
|
int diff = std::abs(va_draw - va_small); // 面积的差异值。
|
|
|
float fs = diff * 1.0f / va_draw;
|
|
|
// printf("va_draw %d va_small %d dff %d diffscale %f \n", va_draw, va_small, diff, fs);
|
|
|
if (fs > 0.1)
|
|
|
{
|
|
|
return 56;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
long t6 = CheckUtil::getcurTime();
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
cv::imwrite(pDetConfig->strCamName + "_3_edge_product_det_mask.png", resultMask);
|
|
|
if (!m_pDetConfig->drawMask.empty())
|
|
|
{
|
|
|
cv::imwrite(pDetConfig->strCamName + "_4_edge_product_draw_mask.png", m_pDetConfig->drawMask);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pCheckResult_Aling->DetMask_src = resultMask;
|
|
|
|
|
|
cv::Mat resultMask_erode_small;
|
|
|
// 膨胀腐蚀处理
|
|
|
{
|
|
|
// printf("m_pDetConfig->nAIErodesize %d\n", m_pDetConfig->nAIErodesize);
|
|
|
if (m_pDetConfig->nAIErodesize <= 0)
|
|
|
{
|
|
|
resultMask_erode_small = resultMask(result_roi).clone();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 定义膨胀核
|
|
|
int dilation_size = 7; // 膨胀核的大小
|
|
|
if (m_pDetConfig->nAIErodesize > 0 && m_pDetConfig->nAIErodesize < 101)
|
|
|
{
|
|
|
dilation_size = 2 * m_pDetConfig->nAIErodesize;
|
|
|
}
|
|
|
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(dilation_size, dilation_size));
|
|
|
|
|
|
// 进行膨胀操作
|
|
|
|
|
|
cv::erode(resultMask(result_roi), resultMask_erode_small, kernel);
|
|
|
}
|
|
|
|
|
|
pCheckResult_Aling->mask = ~resultMask_erode_small;
|
|
|
}
|
|
|
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
// cv::imwrite("edge_result_src_roi_thresholdvalue.png", temimg);
|
|
|
cv::imwrite(pDetConfig->strCamName + "_5_edge_result_src.png", img(result_roi));
|
|
|
cv::imwrite(pDetConfig->strCamName + "_6_edge_result_mask.png", pCheckResult_Aling->mask);
|
|
|
cv::Mat temAdd = img(result_roi).clone();
|
|
|
temAdd += pCheckResult_Aling->mask * 0.25;
|
|
|
|
|
|
{
|
|
|
// 查找轮廓
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
|
cv::findContours(resultMask_erode_small.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
// 创建一个空白图像用于绘制轮廓
|
|
|
|
|
|
// 绘制轮廓
|
|
|
cv::drawContours(temAdd, contours, -1, cv::Scalar(128, 255, 0), 2); // 绿色,线宽2
|
|
|
}
|
|
|
cv::imwrite(pDetConfig->strCamName + "_7_edge_result_Merge.png", temAdd);
|
|
|
}
|
|
|
long t7 = CheckUtil::getcurTime();
|
|
|
// 存在中间结果
|
|
|
if (m_pDetConfig->saveProcessImg != Save_Close)
|
|
|
{
|
|
|
static int svidx = 0;
|
|
|
svidx++;
|
|
|
if (svidx > 9999999)
|
|
|
{
|
|
|
svidx = 0;
|
|
|
/* code */
|
|
|
}
|
|
|
std::string str1 = "/home/aidlux/BOE/FOG/Edge/Result/" + std::to_string(svidx) + "_mask.png";
|
|
|
std::string str2 = "/home/aidlux/BOE/FOG/Edge/Result/" + std::to_string(svidx) + "_show.png";
|
|
|
|
|
|
int newWidth = 1280;
|
|
|
float aspectRatio = static_cast<float>(resultMask_erode_small.rows) / resultMask_erode_small.cols;
|
|
|
int newHeight = static_cast<int>(newWidth * aspectRatio);
|
|
|
|
|
|
// 缩放图像
|
|
|
cv::Mat resizedImage;
|
|
|
cv::resize(resultMask_erode_small, resizedImage, cv::Size(newWidth, newHeight));
|
|
|
|
|
|
cv::Mat temAdd = img(result_roi).clone();
|
|
|
cv::resize(temAdd, temAdd, cv::Size(newWidth, newHeight));
|
|
|
{
|
|
|
// 查找轮廓
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
|
cv::findContours(resizedImage.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
// 创建一个空白图像用于绘制轮廓
|
|
|
|
|
|
// 绘制轮廓
|
|
|
cv::drawContours(temAdd, contours, -1, cv::Scalar(255, 255, 0), 1); // 绿色,线宽2
|
|
|
}
|
|
|
cv::imwrite(str1, resizedImage);
|
|
|
|
|
|
cv::imwrite(str2, temAdd);
|
|
|
}
|
|
|
long t8 = CheckUtil::getcurTime();
|
|
|
|
|
|
// printf("use time %ld %ld %ld %ld %ld %ld %ld %ld \n", t8 - t1, t2 - t1, t3 - t2, t4 - t3, t5 - t4, t6 - t5, t7 - t6, t8 - t7);
|
|
|
|
|
|
pCheckResult_Aling->roi = result_roi;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::SaveSmallImg(const cv::Mat &img, const cv::Mat &mask, cv::Rect roi)
|
|
|
{
|
|
|
// 是否要保存中间过程的小图
|
|
|
if (m_pDetConfig->IsSaveProcessImg())
|
|
|
{
|
|
|
static int svsmallidx = 0;
|
|
|
svsmallidx++;
|
|
|
if (svsmallidx > 9999999)
|
|
|
{
|
|
|
svsmallidx = 0;
|
|
|
/* code */
|
|
|
}
|
|
|
bool bssss = false;
|
|
|
|
|
|
if (m_pDetConfig->saveProcessImg == Save_Filter)
|
|
|
{
|
|
|
// 4. 查找轮廓
|
|
|
vector<vector<Point>> contours;
|
|
|
vector<Vec4i> hierarchy;
|
|
|
findContours(mask.clone(), contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
if (contours.size() > 1)
|
|
|
{
|
|
|
bssss = true;
|
|
|
}
|
|
|
else if (contours.size() == 1)
|
|
|
{
|
|
|
int pointNum = 0;
|
|
|
for (int i = 0; i < contours.size(); i++)
|
|
|
{
|
|
|
pointNum += contours[i].size();
|
|
|
}
|
|
|
// printf("pointNum============== %d\n", pointNum);
|
|
|
if (pointNum > 30)
|
|
|
{
|
|
|
bssss = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else if (m_pDetConfig->saveProcessImg == Save_ALL)
|
|
|
{
|
|
|
bssss = true;
|
|
|
}
|
|
|
|
|
|
if (bssss)
|
|
|
{
|
|
|
std::string str1 = "/home/aidlux/BOE/FOG/Edge/Smasll/" + std::to_string(svsmallidx) + "_in.png";
|
|
|
std::string str2 = "/home/aidlux/BOE/FOG/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_mask.png";
|
|
|
// std::string st3 = "/home/aidlux/BOE/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_show.png";
|
|
|
cv::imwrite(str1, img);
|
|
|
cv::imwrite(str2, mask);
|
|
|
// cv::Mat showsss = temDet + smask * 0.4;
|
|
|
// cv::imwrite(st3, showsss);
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::InitModel_ALL()
|
|
|
{
|
|
|
m_bModelSucc = false;
|
|
|
int re = InitModel_Big();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
// printf("AI_Edge_Algin InitModel_Big Error \n");
|
|
|
return re;
|
|
|
}
|
|
|
re = InitModel_Small();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
// printf("AI_Edge_Algin InitModel_Small Error \n");
|
|
|
|
|
|
return re;
|
|
|
}
|
|
|
m_bModelSucc = true;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::InitModel_Big()
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::InitModel_Small()
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::Det_big(const cv::Mat &img, vector<Rect> &smallRoiList, std::shared_ptr<std::vector<cv::Rect>> edgeRoiList, cv::Rect &bigRoi, cv::Mat &big_mask)
|
|
|
{
|
|
|
std::shared_ptr<AIModel_Base> pAI_Model = AI_Factory->AI_defect_Edge_Big;
|
|
|
|
|
|
cv::Size sz;
|
|
|
sz.width = pAI_Model->input_0.width;
|
|
|
sz.height = pAI_Model->input_0.height;
|
|
|
cv::Mat detImg;
|
|
|
cv::resize(img, detImg, sz);
|
|
|
int re = 0;
|
|
|
cv::Mat mask;
|
|
|
// printf("sz %d %d \n", sz.width, sz.height);
|
|
|
|
|
|
re = pAI_Model->AIDet(detImg, mask);
|
|
|
big_mask = mask;
|
|
|
if (re != 0)
|
|
|
{
|
|
|
// printf("AICheck_Edge_Big----error \n");
|
|
|
int re123 = 100 + re;
|
|
|
return re123;
|
|
|
}
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
std::string str1 = m_str_curCamName + "_edge_big_in.png";
|
|
|
cv::imwrite(str1, detImg);
|
|
|
std::string str2 = m_str_curCamName + "_edge_big_out_mask.png";
|
|
|
cv::imwrite(str2, mask);
|
|
|
}
|
|
|
if (m_pDetConfig->IsSaveProcessImg())
|
|
|
{
|
|
|
static int bigidx = 0;
|
|
|
bigidx++;
|
|
|
if (bigidx > 9999999)
|
|
|
{
|
|
|
bigidx = 0;
|
|
|
/* code */
|
|
|
}
|
|
|
std::string str1 = "/home/aidlux/BOE/FOG/Edge/Big/" + std::to_string(bigidx) + "_in.png";
|
|
|
std::string str2 = "/home/aidlux/BOE/FOG/Edge/Big/" + std::to_string(bigidx) + "_in_mask.png";
|
|
|
cv::imwrite(str1, detImg);
|
|
|
cv::imwrite(str2, mask);
|
|
|
}
|
|
|
|
|
|
// 找到最大轮廓
|
|
|
|
|
|
bool found;
|
|
|
cv::Rect boundingBox = CheckUtil::getLargestContourROI(mask, found);
|
|
|
if (!found)
|
|
|
{
|
|
|
cerr << "No contours found!" << endl;
|
|
|
return 4;
|
|
|
}
|
|
|
|
|
|
// 形成 小图分割的检测区域
|
|
|
float fresize_x = img.cols * 1.0f / sz.width;
|
|
|
float fresize_y = img.rows * 1.0f / sz.height;
|
|
|
|
|
|
bigRoi.x = boundingBox.x * fresize_x;
|
|
|
bigRoi.y = boundingBox.y * fresize_y;
|
|
|
bigRoi.width = boundingBox.width * fresize_x;
|
|
|
bigRoi.height = boundingBox.height * fresize_y;
|
|
|
|
|
|
// 使用手动绘制的roi进行校验
|
|
|
if (m_pDetConfig->bUseDrawRoi_Check)
|
|
|
{
|
|
|
double widthDiff = std::abs(bigRoi.width - m_pDetConfig->drawRoi.width) * 1.0f / std::min(bigRoi.width, m_pDetConfig->drawRoi.width);
|
|
|
double heightDiff = std::abs(bigRoi.height - m_pDetConfig->drawRoi.height) * 1.0f / std::min(bigRoi.height, m_pDetConfig->drawRoi.height);
|
|
|
// printf("draw roi %s bigRoi %s widthDiff %f heightDiff %f\n", CheckUtil::GetRectString(m_pDetConfig->drawRoi).c_str(), CheckUtil::GetRectString(bigRoi).c_str(), widthDiff, heightDiff);
|
|
|
// 如果差异超过10%,抛出异常
|
|
|
if (widthDiff > 0.10)
|
|
|
{
|
|
|
return 5;
|
|
|
}
|
|
|
if (heightDiff > 0.10)
|
|
|
{
|
|
|
return 5;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
float fresize_x_1 = sz.width * 1.0f / img.cols;
|
|
|
float fresize_y_1 = sz.height * 1.0f / img.rows;
|
|
|
|
|
|
int resize_Small_Roi_width = 320 * fresize_x_1;
|
|
|
int resize_Small_Roi_height = 320 * fresize_y_1;
|
|
|
int haf_w = resize_Small_Roi_width / 2;
|
|
|
int haf_h = resize_Small_Roi_height / 2;
|
|
|
int step_w = resize_Small_Roi_width * 0.85;
|
|
|
int step_h = resize_Small_Roi_height * 0.85;
|
|
|
smallRoiList.clear();
|
|
|
int sizeare = resize_Small_Roi_width * resize_Small_Roi_height;
|
|
|
for (int y = boundingBox.y; y < boundingBox.y + boundingBox.height + haf_h; y += step_h)
|
|
|
{
|
|
|
int roiY = y - haf_h;
|
|
|
for (int x = boundingBox.x; x < boundingBox.x + boundingBox.width + haf_w; x += step_w)
|
|
|
{
|
|
|
int roiX = x - haf_w;
|
|
|
if (roiX < 0)
|
|
|
roiX = 0;
|
|
|
if (roiY < 0)
|
|
|
roiY = 0;
|
|
|
if (roiX + resize_Small_Roi_width >= mask.cols)
|
|
|
roiX = mask.cols - resize_Small_Roi_width;
|
|
|
if (roiY + resize_Small_Roi_height > mask.rows)
|
|
|
roiY = mask.rows - resize_Small_Roi_height;
|
|
|
Rect rect(roiX, roiY, resize_Small_Roi_width, resize_Small_Roi_height);
|
|
|
if (!CheckUtil::RoiInImg(rect, mask))
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (roiX >= 0 && roiY >= 0)
|
|
|
{
|
|
|
|
|
|
if (roiX == 0 || roiX + resize_Small_Roi_width == mask.cols)
|
|
|
{
|
|
|
cv::Rect src_Roi;
|
|
|
src_Roi.x = rect.x * fresize_x;
|
|
|
src_Roi.y = rect.y * fresize_y;
|
|
|
src_Roi.width = 320;
|
|
|
src_Roi.height = 320;
|
|
|
smallRoiList.push_back(src_Roi); // 存储ROI的矩形框
|
|
|
|
|
|
// printf("\n\n\n\n\n\n\n=================%d===============\n\n\n\n\n\n\n", smallRoiList.size());
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
int va = countNonZero(mask(rect));
|
|
|
if (va > 0 && va < sizeare)
|
|
|
{
|
|
|
cv::Rect src_Roi;
|
|
|
src_Roi.x = rect.x * fresize_x;
|
|
|
src_Roi.y = rect.y * fresize_y;
|
|
|
src_Roi.width = 320;
|
|
|
src_Roi.height = 320;
|
|
|
smallRoiList.push_back(src_Roi); // 存储ROI的矩形框
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
for (int i = 0; i < smallRoiList.size(); i++)
|
|
|
{
|
|
|
cv::Rect src_Roi = smallRoiList.at(i);
|
|
|
if (src_Roi.x < 0)
|
|
|
{
|
|
|
src_Roi.x = 0;
|
|
|
}
|
|
|
if (src_Roi.y < 0)
|
|
|
{
|
|
|
src_Roi.y = 0;
|
|
|
}
|
|
|
if (src_Roi.x + src_Roi.width > img.cols)
|
|
|
{
|
|
|
src_Roi.x = img.cols - src_Roi.width;
|
|
|
}
|
|
|
if (src_Roi.y + src_Roi.height > img.rows)
|
|
|
{
|
|
|
src_Roi.y = img.rows - src_Roi.height;
|
|
|
}
|
|
|
smallRoiList.at(i) = src_Roi;
|
|
|
}
|
|
|
|
|
|
{
|
|
|
// -------------------------
|
|
|
// 2. 查找轮廓
|
|
|
// -------------------------
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
|
cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
if (contours.empty())
|
|
|
{
|
|
|
std::cout << "No contours found" << std::endl;
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
// -------------------------
|
|
|
// 3. 找最大面积轮廓
|
|
|
// -------------------------
|
|
|
int max_idx = 0;
|
|
|
double max_area = 0;
|
|
|
for (size_t i = 0; i < contours.size(); i++)
|
|
|
{
|
|
|
double area = cv::contourArea(contours[i]);
|
|
|
if (area > max_area)
|
|
|
{
|
|
|
max_area = area;
|
|
|
max_idx = i;
|
|
|
}
|
|
|
}
|
|
|
std::vector<cv::Point> max_contour = contours[max_idx];
|
|
|
float fresize_x_1 = mask.cols * 1.0f / img.cols;
|
|
|
float fresize_y_1 = mask.rows * 1.0f / img.rows;
|
|
|
|
|
|
int resize_Small_Roi_width = 320 * fresize_x_1;
|
|
|
int resize_Small_Roi_height = 320 * fresize_y_1;
|
|
|
|
|
|
int roi_size_X = resize_Small_Roi_width;
|
|
|
int roi_size_Y = resize_Small_Roi_height;
|
|
|
double overlap_ratio = 0.2; // ROI 重叠比例,可调
|
|
|
double step_len_X = roi_size_X * (1.0 - overlap_ratio);
|
|
|
double step_len_Y = roi_size_Y * (1.0 - overlap_ratio);
|
|
|
|
|
|
std::vector<cv::Rect> rois;
|
|
|
std::set<std::pair<int, int>> roi_set;
|
|
|
|
|
|
double accumulated_len = 0.0;
|
|
|
for (size_t i = 0; i < max_contour.size(); i++)
|
|
|
{
|
|
|
cv::Point p1 = max_contour[i];
|
|
|
cv::Point p2 = max_contour[(i + 1) % max_contour.size()]; // 下一个点,闭合轮廓
|
|
|
double segment_len = cv::norm(p2 - p1);
|
|
|
|
|
|
if (segment_len <= 0)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
double dx = p2.x - p1.x;
|
|
|
double dy = p2.y - p1.y;
|
|
|
|
|
|
while (accumulated_len + 1e-6 < segment_len)
|
|
|
{ // 沿线段放置 ROI
|
|
|
double t = accumulated_len / segment_len;
|
|
|
cv::Point center = p1 + t * (p2 - p1);
|
|
|
|
|
|
int x = center.x - roi_size_X / 2;
|
|
|
int y = center.y - roi_size_Y / 2;
|
|
|
|
|
|
// 边界裁剪
|
|
|
if (x < 0)
|
|
|
x = 0;
|
|
|
if (y < 0)
|
|
|
y = 0;
|
|
|
if (x + roi_size_X > mask.cols)
|
|
|
x = mask.cols - roi_size_X;
|
|
|
if (y + roi_size_Y > mask.rows)
|
|
|
y = mask.rows - roi_size_Y;
|
|
|
|
|
|
auto key = std::make_pair(x, y);
|
|
|
if (roi_set.find(key) == roi_set.end())
|
|
|
{
|
|
|
roi_set.insert(key);
|
|
|
rois.push_back(cv::Rect(x, y, roi_size_X, roi_size_Y));
|
|
|
}
|
|
|
|
|
|
double step = (std::abs(dx) > std::abs(dy)) ? step_len_X : step_len_Y;
|
|
|
accumulated_len += step;
|
|
|
}
|
|
|
|
|
|
accumulated_len -= segment_len; // 移动到下一个线段
|
|
|
if (accumulated_len < 0)
|
|
|
accumulated_len = 0;
|
|
|
}
|
|
|
edgeRoiList->clear();
|
|
|
for (const auto &r : rois)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = r.x / fresize_x_1;
|
|
|
roi.y = r.y / fresize_y_1;
|
|
|
roi.width = 320;
|
|
|
roi.height = 320;
|
|
|
|
|
|
if (roi.x < 0)
|
|
|
{
|
|
|
roi.x = 0;
|
|
|
}
|
|
|
if (roi.y < 0)
|
|
|
{
|
|
|
roi.y = 0;
|
|
|
}
|
|
|
if (roi.x + roi.width > img.cols)
|
|
|
{
|
|
|
roi.x = img.cols - roi.width;
|
|
|
}
|
|
|
if (roi.y + roi.height > img.rows)
|
|
|
{
|
|
|
roi.y = img.rows - roi.height;
|
|
|
}
|
|
|
|
|
|
edgeRoiList->push_back(roi);
|
|
|
}
|
|
|
|
|
|
if (m_pDetConfig->bDebugSaveImg)
|
|
|
{
|
|
|
// -------------------------
|
|
|
// 5. 可视化
|
|
|
// -------------------------
|
|
|
cv::Mat vis;
|
|
|
cv::cvtColor(mask, vis, cv::COLOR_GRAY2BGR);
|
|
|
cv::Mat vis22;
|
|
|
cv::cvtColor(img, vis22, cv::COLOR_GRAY2BGR);
|
|
|
|
|
|
for (auto &r : rois)
|
|
|
{
|
|
|
cv::rectangle(vis, r, cv::Scalar(0, 0, 255), 2);
|
|
|
}
|
|
|
for (auto &r : rois)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = r.x / fresize_x_1;
|
|
|
roi.y = r.y / fresize_y_1;
|
|
|
roi.width = 320;
|
|
|
roi.height = 320;
|
|
|
cv::rectangle(vis22, roi, cv::Scalar(0, 0, 255), 2);
|
|
|
}
|
|
|
|
|
|
cv::drawContours(vis, std::vector<std::vector<cv::Point>>{max_contour}, -1, cv::Scalar(0, 255, 0), 1);
|
|
|
|
|
|
cv::imwrite("edge_det_roi_small.png", vis);
|
|
|
cv::imwrite("edge_det_roi_big.png", vis22);
|
|
|
// getchar();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AI_Edge_Algin::Dtet_small(const cv::Mat &img, vector<Rect> &smallRoiList, cv::Mat &Src_Mask)
|
|
|
{
|
|
|
std::shared_ptr<AIModel_Base> pAIDet = AI_Factory->AI_defect_Edge_Samll;
|
|
|
// 2、对每个小区域进行处理
|
|
|
Src_Mask = cv::Mat(img.rows, img.cols, CV_8U, cv::Scalar(0));
|
|
|
|
|
|
const int totalTasks = smallRoiList.size();
|
|
|
int submitted = 0;
|
|
|
int completed = 0;
|
|
|
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);
|
|
|
|
|
|
if (!CheckUtil::RoiInImg(task->roi, img))
|
|
|
{
|
|
|
CheckUtil::printROI(task->roi, "small roi 1 ");
|
|
|
// printf("img %d %d \n", img.cols, img.rows);
|
|
|
}
|
|
|
|
|
|
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))
|
|
|
{
|
|
|
|
|
|
cv::Mat &outimg = *(result->output);
|
|
|
if (!outimg.empty())
|
|
|
{
|
|
|
outimg.copyTo(Src_Mask(result->roi), outimg);
|
|
|
}
|
|
|
// 保存过程小图
|
|
|
SaveSmallImg(result->input, outimg, result->roi);
|
|
|
|
|
|
completed++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(0));
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
Image_Feature_Algin::Image_Feature_Algin()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
Image_Feature_Algin::~Image_Feature_Algin()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
int Image_Feature_Algin::Detect(DetConfig *pDetConfig, Align_Result *pResult, std::vector<std::string> &LogList)
|
|
|
{
|
|
|
// 检测目标:找到 参数模版图到 检测图的 映射关系。包括 缩放和移动。
|
|
|
|
|
|
// 先缩放 在 移动
|
|
|
std::string strlog = "";
|
|
|
if (!pDetConfig)
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
if (pDetConfig->TemplateImg.empty())
|
|
|
{
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "TemplateImg is empty ");
|
|
|
LogList.push_back(strlog);
|
|
|
return 1;
|
|
|
}
|
|
|
// 裁切位置;
|
|
|
pResult->Crop_Roi_DetImg = pDetConfig->DetImg_CropROi;
|
|
|
// 1、缩放尺度
|
|
|
float fx = 1;
|
|
|
float fy = 1;
|
|
|
// 裁切尺寸 存在 并合理
|
|
|
if (pDetConfig->param_CropRoi.width > 0 && pDetConfig->param_CropRoi.height > 0 &&
|
|
|
pDetConfig->DetImg_CropROi.width > 0 && pDetConfig->DetImg_CropROi.height > 0)
|
|
|
{
|
|
|
fx = pDetConfig->DetImg_CropROi.width * 1.0f / pDetConfig->param_CropRoi.width;
|
|
|
fy = pDetConfig->DetImg_CropROi.height * 1.0f / pDetConfig->param_CropRoi.height;
|
|
|
if (fx > 0.5 && fx < 2 && fy > 0.5 && fy < 2)
|
|
|
{
|
|
|
pResult->fCropROI_Scale_ParmToDet_X = fx;
|
|
|
pResult->fCropROI_Scale_ParmToDet_Y = fy;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Scale out 0.5--2");
|
|
|
LogList.push_back(strlog);
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "crop ROI Error");
|
|
|
LogList.push_back(strlog);
|
|
|
return 1;
|
|
|
}
|
|
|
// strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", "Scale x %f y %f\n", fx, fy);
|
|
|
// LogList.push_back(strlog);
|
|
|
|
|
|
// 2、定位
|
|
|
// 1)、模版特征图片的 缩放。
|
|
|
cv::Mat TemplateFeature;
|
|
|
cv::Size sz;
|
|
|
// fx = 1;
|
|
|
// fy = 1;
|
|
|
sz.width = int(pDetConfig->TemplateImg.cols * fx);
|
|
|
sz.height = int(pDetConfig->TemplateImg.rows * fy);
|
|
|
cv::resize(pDetConfig->TemplateImg, TemplateFeature, sz);
|
|
|
|
|
|
if (!CheckUtil::RoiInImg(pDetConfig->Search_Roi, pDetConfig->DetImg))
|
|
|
{
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Search_Roi ROI Error Not In img");
|
|
|
LogList.push_back(strlog);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
cv::Mat DetFeature = pDetConfig->DetImg(pDetConfig->Search_Roi).clone();
|
|
|
|
|
|
double confidence = 0;
|
|
|
|
|
|
int kernel_size = 128;
|
|
|
int search_size = 1024;
|
|
|
int det_search_min_size = DetFeature.cols;
|
|
|
if (DetFeature.rows < det_search_min_size)
|
|
|
{
|
|
|
det_search_min_size = DetFeature.rows;
|
|
|
}
|
|
|
int template_kernel_min_size = TemplateFeature.cols;
|
|
|
if (TemplateFeature.rows < template_kernel_min_size)
|
|
|
{
|
|
|
template_kernel_min_size = TemplateFeature.rows;
|
|
|
}
|
|
|
float f_search = search_size * 1.0f / det_search_min_size;
|
|
|
float f_Kernel = kernel_size * 1.0f / template_kernel_min_size;
|
|
|
float falign = f_search;
|
|
|
if (f_Kernel > falign)
|
|
|
{
|
|
|
falign = f_Kernel;
|
|
|
}
|
|
|
cv::Size Search_sz;
|
|
|
Search_sz.width = int(DetFeature.cols * falign);
|
|
|
Search_sz.height = int(DetFeature.rows * falign);
|
|
|
cv::Mat Search_img;
|
|
|
cv::resize(DetFeature, Search_img, Search_sz);
|
|
|
cv::Size Kernel_sz;
|
|
|
Kernel_sz.width = int(TemplateFeature.cols * falign);
|
|
|
Kernel_sz.height = int(TemplateFeature.rows * falign);
|
|
|
cv::Mat Kernel_img;
|
|
|
cv::resize(TemplateFeature, Kernel_img, Kernel_sz);
|
|
|
|
|
|
auto bestMatch = findBestTemplateMatch(Search_img, Kernel_img, confidence);
|
|
|
|
|
|
bestMatch.x /= falign;
|
|
|
bestMatch.y /= falign;
|
|
|
|
|
|
pResult->bestMatch = bestMatch;
|
|
|
if (pDetConfig->bSaveImg)
|
|
|
{
|
|
|
cv::imwrite("Align_template.png", TemplateFeature);
|
|
|
cv::imwrite("Align_Det.png", DetFeature);
|
|
|
}
|
|
|
|
|
|
if (confidence != -1)
|
|
|
{
|
|
|
std::cout << "最佳匹配位置: (" << bestMatch.x << ", " << bestMatch.y
|
|
|
<< "), 得分: " << confidence << std::endl;
|
|
|
if (confidence > pDetConfig->fscore)
|
|
|
{
|
|
|
|
|
|
/* code */
|
|
|
|
|
|
int m_x = pDetConfig->feature_Roi.x * fx - pDetConfig->Search_Roi.x;
|
|
|
int m_y = pDetConfig->feature_Roi.y * fy - pDetConfig->Search_Roi.y;
|
|
|
pResult->offt_x = bestMatch.x - m_x;
|
|
|
pResult->offt_y = bestMatch.y - m_y;
|
|
|
// printf("m_x %d bestMatch.x %d offt_x %d\n", m_x, bestMatch.x, pResult->offt_x);
|
|
|
// printf("m_y %d bestMatch.y %d offt_y %d\n", m_y, bestMatch.y, pResult->offt_y);
|
|
|
|
|
|
pResult->bDet = true;
|
|
|
|
|
|
pResult->Crop_Roi_ParmImg = pResult->Det_srcToParm_src_Rect(pResult->Crop_Roi_DetImg);
|
|
|
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", " -- Succ :Align score %f > %f offt x %d y %d Scale x %f y %f",
|
|
|
confidence, pDetConfig->fscore, pResult->offt_x, pResult->offt_y, pResult->fCropROI_Scale_ParmToDet_X, pResult->fCropROI_Scale_ParmToDet_Y);
|
|
|
|
|
|
LogList.push_back(strlog);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", " error :Align score %f< 0.9", confidence);
|
|
|
pResult->fCropROI_Scale_ParmToDet_X = 1;
|
|
|
pResult->fCropROI_Scale_ParmToDet_Y = 1;
|
|
|
LogList.push_back(strlog);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
pResult->fCropROI_Scale_ParmToDet_X = 1;
|
|
|
pResult->fCropROI_Scale_ParmToDet_Y = 1;
|
|
|
std::cout << "未找到有效匹配" << std::endl;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
cv::Point Image_Feature_Algin::findBestTemplateMatch(
|
|
|
const cv::Mat &detectionImage,
|
|
|
const cv::Mat &templateImage,
|
|
|
double &bestScore,
|
|
|
int method)
|
|
|
{
|
|
|
// 输入验证
|
|
|
if (detectionImage.empty() || templateImage.empty())
|
|
|
{
|
|
|
throw std::invalid_argument("输入图像不能为空");
|
|
|
}
|
|
|
if (detectionImage.channels() != 1 || templateImage.channels() != 1)
|
|
|
{
|
|
|
throw std::invalid_argument("必须输入灰度图像");
|
|
|
}
|
|
|
if (templateImage.rows > detectionImage.rows ||
|
|
|
templateImage.cols > detectionImage.cols)
|
|
|
{
|
|
|
throw std::invalid_argument("模板尺寸不能大于被检测图像");
|
|
|
}
|
|
|
|
|
|
// cv::imwrite("detectionImage.png", detectionImage);
|
|
|
// cv::imwrite("templateImage.png", templateImage);
|
|
|
// 执行模板匹配
|
|
|
cv::Mat resultMatrix;
|
|
|
cv::matchTemplate(detectionImage, templateImage, resultMatrix, method);
|
|
|
|
|
|
// 确定极值搜索方式
|
|
|
const bool findMinima = (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED);
|
|
|
|
|
|
// 查找极值位置
|
|
|
cv::Point extremaLoc = cv::Point(0, 0);
|
|
|
double extremaVal;
|
|
|
cv::minMaxLoc(resultMatrix,
|
|
|
findMinima ? &extremaVal : nullptr,
|
|
|
findMinima ? nullptr : &extremaVal,
|
|
|
findMinima ? &extremaLoc : nullptr,
|
|
|
findMinima ? nullptr : &extremaLoc);
|
|
|
|
|
|
// 设置有效性检查阈值(可根据方法动态调整)
|
|
|
double threshold = 0.0;
|
|
|
switch (method)
|
|
|
{
|
|
|
case cv::TM_CCOEFF_NORMED:
|
|
|
threshold = 0.6;
|
|
|
break; // [-1, 1]
|
|
|
case cv::TM_CCORR_NORMED:
|
|
|
threshold = 0.7;
|
|
|
break; // [0, 1]
|
|
|
case cv::TM_SQDIFF_NORMED:
|
|
|
threshold = 0.2;
|
|
|
break; // [0, 1]
|
|
|
default:
|
|
|
threshold = 0.0;
|
|
|
}
|
|
|
|
|
|
// 验证匹配有效性
|
|
|
const bool isValid = findMinima ? (extremaVal <= threshold) : (extremaVal >= threshold);
|
|
|
|
|
|
if (isValid)
|
|
|
{
|
|
|
bestScore = extremaVal;
|
|
|
return extremaLoc;
|
|
|
}
|
|
|
bestScore = -1; // 无效时的默认值
|
|
|
return extremaLoc;
|
|
|
}
|