|
|
|
@ -9,6 +9,7 @@
|
|
|
|
#include "CameraCheckAnalysisy.hpp"
|
|
|
|
#include "CameraCheckAnalysisy.hpp"
|
|
|
|
#include "CheckUtil.hpp"
|
|
|
|
#include "CheckUtil.hpp"
|
|
|
|
#include "Define.h"
|
|
|
|
#include "Define.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
|
|
CameraCheckAnalysisy::CameraCheckAnalysisy()
|
|
|
|
CameraCheckAnalysisy::CameraCheckAnalysisy()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -174,19 +175,52 @@ int CameraCheckAnalysisy::Detect_Pre()
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img size/type != img_B ", strBasic.c_str());
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img size/type != img_B ", strBasic.c_str());
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cv::Mat &img = pImageResult->result->in_shareImage->img;
|
|
|
|
|
|
|
|
cv::Mat &img_B = pImageResult->result->in_shareImage->img_B;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 左右图存在上下错位: 找到左右图产品所在的第一行, 进行简单上下对齐
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int rowLeft = -1;
|
|
|
|
|
|
|
|
int rowRight = -1;
|
|
|
|
|
|
|
|
if (GetProductFirstRow(img, rowLeft) == 0 && GetProductFirstRow(img_B, rowRight) == 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 以较高的顶边为基准, 把较低的那张图向上平移, 使两图顶边对齐
|
|
|
|
|
|
|
|
int refRow = std::min(rowLeft, rowRight);
|
|
|
|
|
|
|
|
int shiftLeft = refRow - rowLeft; // <= 0, 负值表示向上平移
|
|
|
|
|
|
|
|
int shiftRight = refRow - rowRight; // <= 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================align rowLeft %d rowRight %d shiftLeft %d shiftRight %d",
|
|
|
|
|
|
|
|
strBasic.c_str(), rowLeft, rowRight, shiftLeft, shiftRight);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (shiftLeft < 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cv::Mat M = (cv::Mat_<double>(2, 3) << 1, 0, 0, 0, 1, (double)shiftLeft);
|
|
|
|
|
|
|
|
cv::warpAffine(img, img, M, img.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT, cv::Scalar(0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shiftRight < 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cv::Mat M = (cv::Mat_<double>(2, 3) << 1, 0, 0, 0, 1, (double)shiftRight);
|
|
|
|
|
|
|
|
cv::warpAffine(img_B, img_B, M, img_B.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT, cv::Scalar(0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================GetProductFirstRow fail, skip align", strBasic.c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const int overlap = 1056;
|
|
|
|
const int overlap = 1056;
|
|
|
|
if (pImageResult->result->in_shareImage->img.cols <= overlap)
|
|
|
|
if (img.cols <= overlap)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img.cols <= overlap %d ", strBasic.c_str(), overlap);
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img.cols <= overlap %d ", strBasic.c_str(), overlap);
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cv::Mat merge_img;
|
|
|
|
cv::Mat merge_img;
|
|
|
|
cv::hconcat(pImageResult->result->in_shareImage->img(cv::Rect(0, 0, pImageResult->result->in_shareImage->img.cols - overlap, pImageResult->result->in_shareImage->img.rows)),
|
|
|
|
cv::hconcat(img(cv::Rect(0, 0, img.cols - overlap, img.rows)), img_B, merge_img);
|
|
|
|
pImageResult->result->in_shareImage->img_B, merge_img);
|
|
|
|
img = merge_img;
|
|
|
|
pImageResult->result->in_shareImage->img = merge_img;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 拼接完成后 img_B 不再需要,立即释放内存
|
|
|
|
// 拼接完成后 img_B 不再需要,立即释放内存
|
|
|
|
pImageResult->result->in_shareImage->img_B.release();
|
|
|
|
img_B.release();
|
|
|
|
|
|
|
|
|
|
|
|
if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg)
|
|
|
|
if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -1519,3 +1553,79 @@ int CameraCheckAnalysisy::GetLine(const cv::Mat &img, std::vector<cv::Point> &po
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 找到图像中产品(亮色区域)所在的第一行(顶部边缘), 用于左右图上下对齐
|
|
|
|
|
|
|
|
// 从上往下逐行扫描, 当某一行亮像素数量超过阈值比例时, 认为该行是产品顶边
|
|
|
|
|
|
|
|
int CameraCheckAnalysisy::GetProductFirstRow(const cv::Mat &img, int &outRow)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
outRow = -1;
|
|
|
|
|
|
|
|
if (img.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cv::Mat gray;
|
|
|
|
|
|
|
|
if (img.channels() == 1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
gray = img;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (img.channels() == 3)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uchar brightThreshold = 35; // 亮像素灰度阈值(与背景判断阈值保持一致)
|
|
|
|
|
|
|
|
const int needBrightCount = std::max(1, (int)(gray.cols * 0.2)); // 该行亮像素数量占比超过 20% 认为是产品所在行
|
|
|
|
|
|
|
|
const int rowStep = 16; // 跳行扫描步长
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 判断某一行是否为产品所在行(亮像素数量达到阈值)
|
|
|
|
|
|
|
|
auto isProductRow = [&](int row) -> bool
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const uchar *p = gray.ptr<uchar>(row);
|
|
|
|
|
|
|
|
int brightCount = 0;
|
|
|
|
|
|
|
|
for (int col = 0; col < gray.cols; ++col)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p[col] >= brightThreshold)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (++brightCount >= needBrightCount)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 1、跳行粗扫: 每隔 rowStep 行扫描一次, 定位产品顶边的大致位置
|
|
|
|
|
|
|
|
int rowFound = -1;
|
|
|
|
|
|
|
|
for (int row = 0; row < gray.rows; row += rowStep)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (isProductRow(row))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
rowFound = row;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rowFound < 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return 2; // 未找到产品顶边
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2、在上一个采样行与 rowFound 之间逐行精确定位
|
|
|
|
|
|
|
|
int rowStart = std::max(0, rowFound - rowStep + 1);
|
|
|
|
|
|
|
|
for (int row = rowStart; row <= rowFound; ++row)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (isProductRow(row))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
outRow = row;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 2; // 理论上不会走到这里
|
|
|
|
|
|
|
|
}
|
|
|
|
|