更新除穿孔算法
This commit is contained in:
parent
0833647b53
commit
044ad9c9d1
|
@ -1,5 +1,6 @@
|
|||
#include "ImageApplyOutHole.h"
|
||||
#include "ImageProcess_Public.h"
|
||||
//#include <QDebug>
|
||||
|
||||
#ifdef LOG
|
||||
#include "Device/filetools.h"
|
||||
|
@ -8,7 +9,7 @@
|
|||
CImageApplyOutHole::CImageApplyOutHole(void)
|
||||
: CImageApply()
|
||||
, m_borderSize(20)
|
||||
, m_edgeScale(0.1f, 0.1f , 0.1f, 0.1f)
|
||||
, m_edgeScale(0.1f, 0.1f, 0.1f, 0.1f)
|
||||
, m_threshold(50)
|
||||
{
|
||||
}
|
||||
|
@ -31,6 +32,10 @@ void CImageApplyOutHole::apply(cv::Mat& pDib, int side)
|
|||
(void)side;
|
||||
}
|
||||
|
||||
#define MIN_CONTOUR_SIZE 10
|
||||
#define RESIZE_FIXED_WIDTH 2448.0
|
||||
#define LINE_WIDTH 18
|
||||
#define DILATE_SIZE 16
|
||||
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||
{
|
||||
#ifdef LOG
|
||||
|
@ -53,16 +58,32 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
|||
return;
|
||||
}
|
||||
|
||||
double resize_scale = cv::min(RESIZE_FIXED_WIDTH / static_cast<double>(mats[0].cols), 1.0);
|
||||
|
||||
//二值化正反面图像
|
||||
cv::Mat front = mats[0];
|
||||
cv::Mat back = mats[1];
|
||||
cv::Mat front, back;
|
||||
if (resize_scale != 1.0)
|
||||
{
|
||||
cv::resize(mats[0], front, cv::Size(), resize_scale, resize_scale);
|
||||
cv::resize(mats[1], back, cv::Size(), resize_scale, resize_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
front = mats[0];
|
||||
back = mats[1];
|
||||
}
|
||||
|
||||
cv::Mat front_thre, back_thre;
|
||||
hg::threshold_Mat(front, front_thre, m_threshold);
|
||||
hg::threshold_Mat(back, back_thre, m_threshold);
|
||||
//cv::imwrite("front_thre.jpg", front_thre);
|
||||
//cv::imwrite("back_thre.jpg", back_thre);
|
||||
|
||||
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 1));
|
||||
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5 * resize_scale, 1));
|
||||
cv::morphologyEx(front_thre, front_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||
cv::morphologyEx(back_thre, back_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||
//cv::imwrite("front_thre2.jpg", front_thre);
|
||||
//cv::imwrite("back_thre2.jpg", back_thre);
|
||||
|
||||
//反面二值化图像水平翻转
|
||||
cv::flip(back_thre, back_thre, 1); //1:Horizontal
|
||||
|
@ -70,10 +91,26 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
|||
//正反面图像寻边
|
||||
std::vector<std::vector<cv::Point>> contours_front, contours_back;
|
||||
std::vector<cv::Vec4i> b1_front, b1_back;
|
||||
hg::findContours(front_thre.clone(), contours_front, b1_front, cv::RETR_EXTERNAL);
|
||||
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_EXTERNAL);
|
||||
hg::findContours(front_thre.clone(), contours_front, b1_front, cv::RETR_CCOMP);
|
||||
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_CCOMP);
|
||||
|
||||
//提取正反面图像最大轮廓
|
||||
for (size_t i = 0; i < contours_front.size(); i++)
|
||||
if (contours_front[i].size() < MIN_CONTOUR_SIZE)
|
||||
{
|
||||
contours_front.erase(contours_front.begin() + i);
|
||||
b1_front.erase(b1_front.begin() + i);
|
||||
i--;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < contours_back.size(); i++)
|
||||
if (contours_back[i].size() < MIN_CONTOUR_SIZE)
|
||||
{
|
||||
contours_back.erase(contours_back.begin() + i);
|
||||
b1_back.erase(b1_back.begin() + i);
|
||||
i--;
|
||||
}
|
||||
|
||||
std::vector<cv::Point> maxContour_front = hg::getMaxContour(contours_front, b1_front);
|
||||
std::vector<cv::Point> maxContour_back = hg::getMaxContour(contours_back, b1_back);
|
||||
|
||||
|
@ -107,27 +144,37 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
|||
cv::bitwise_not(mask, mask);
|
||||
//cv::imwrite("mask2.jpg", mask); //反色
|
||||
|
||||
element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(10, 10));
|
||||
cv::dilate(mask, mask, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar(255)); //膨胀算法,增大孔洞连通区域面积
|
||||
//为了避免孔洞彻底贯穿纸边,人为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连
|
||||
cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(0), LINE_WIDTH * resize_scale); //绘制纸张矩形边缘
|
||||
//cv::imwrite("mask3.jpg", mask);
|
||||
|
||||
//为了避免孔洞彻底贯穿纸边,人为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连
|
||||
cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(255), 15); //绘制纸张矩形边缘
|
||||
//膨胀算法,增大孔洞连通区域面积
|
||||
element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(DILATE_SIZE * resize_scale, DILATE_SIZE * resize_scale));
|
||||
cv::dilate(mask, mask, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar(255));
|
||||
//cv::imwrite("mask4.jpg", mask);
|
||||
|
||||
//提取重叠图像轮廓
|
||||
std::vector<std::vector<cv::Point>> contours_mask;
|
||||
std::vector<cv::Vec4i> b1_mask;
|
||||
hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //提取重叠图像轮廓
|
||||
hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE);
|
||||
|
||||
//过滤非孔洞的联通区域
|
||||
std::vector<std::vector<cv::Point>> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize);
|
||||
std::vector<std::vector<cv::Point>> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize * resize_scale);
|
||||
|
||||
for (size_t i = 0; i < hole_contours.size(); i++)
|
||||
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
||||
hole_contours[i][j] /= resize_scale;
|
||||
|
||||
cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area());
|
||||
roi_front.x /= resize_scale;
|
||||
roi_front.y /= resize_scale;
|
||||
roi_front.width /= resize_scale;
|
||||
roi_front.height /= resize_scale;
|
||||
for (size_t i = 0; i < hole_contours.size(); i++)
|
||||
{
|
||||
std::vector<std::vector<cv::Point>> contourss_temp;
|
||||
contourss_temp.push_back(hole_contours[i]);
|
||||
cv::Mat front_temp = front(roi_front);
|
||||
cv::Mat front_temp = mats[0](roi_front);
|
||||
hg::fillPolys(front_temp, contourss_temp, color);
|
||||
}
|
||||
|
||||
|
@ -135,18 +182,26 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
|||
{
|
||||
int width_ = roi_back.width;
|
||||
roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转
|
||||
color = getBackGroudColor(back(roi_back), rrect_front.size.area());
|
||||
color = getBackGroudColor(back(roi_back), rrect_back.size.area());
|
||||
roi_back.x /= resize_scale;
|
||||
roi_back.y /= resize_scale;
|
||||
roi_back.width /= resize_scale;
|
||||
roi_back.height /= resize_scale;
|
||||
hole_contours.clear();
|
||||
hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, cv::Vec4f(m_edgeScale[0], m_edgeScale[1], m_edgeScale[2], m_edgeScale[3]), m_borderSize);
|
||||
hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, cv::Vec4f(m_edgeScale[0], m_edgeScale[1], m_edgeScale[2], m_edgeScale[3]), m_borderSize * resize_scale);
|
||||
|
||||
for (size_t i = 0; i < hole_contours.size(); i++)
|
||||
{
|
||||
std::vector<cv::Point> hole_contour;
|
||||
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
||||
{
|
||||
hole_contour.push_back(cv::Point(width_ - hole_contours[i][j].x - 1, hole_contours[i][j].y));
|
||||
hole_contour[j] /= resize_scale;
|
||||
}
|
||||
|
||||
std::vector<std::vector<cv::Point>> contours_temp;
|
||||
contours_temp.push_back(hole_contour);
|
||||
cv::Mat back_temp = back(roi_back);
|
||||
cv::Mat back_temp = mats[1](roi_back);
|
||||
hg::fillPolys(back_temp, contours_temp, color);
|
||||
}
|
||||
}
|
||||
|
@ -230,10 +285,10 @@ std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<s
|
|||
cv::RotatedRect roi, cv::Vec4f edgeScale, float sideLengthLow)
|
||||
{
|
||||
cv::RotatedRect roi2(roi.center,
|
||||
cv::Size2f(roi.size.width * (1 - edgeScale[0] - edgeScale[1]), roi.size.height * (1 - edgeScale[2] - edgeScale[3])),
|
||||
cv::Size2f(roi.size.width * (1 - edgeScale[2] - edgeScale[3]), roi.size.height * (1 - edgeScale[0] - edgeScale[1])),
|
||||
roi.angle);
|
||||
|
||||
cv::Point2f offset_0(roi.size.width * (edgeScale[0] - edgeScale[1]) / 2 + roi.center.x, roi.size.height * (edgeScale[2] - edgeScale[3]) / 2 + roi.center.y);
|
||||
cv::Point2f offset_0(roi.size.width * (edgeScale[2] - edgeScale[3]) / 2 + roi.center.x, roi.size.height * (edgeScale[0] - edgeScale[1]) / 2 + roi.center.y);
|
||||
roi2.center.x = (offset_0.x - roi.center.x) * cos(roi.angle * PI / 180.0f) - (offset_0.y - roi.center.y) * sin(roi2.angle * PI / 180.0f) + roi.center.x;
|
||||
roi2.center.y = (offset_0.x - roi.center.x) * sin(roi.angle * PI / 180.0f) + (offset_0.y - roi.center.y) * cos(roi2.angle * PI / 180.0f) + roi.center.y;
|
||||
|
||||
|
@ -247,6 +302,7 @@ std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<s
|
|||
{
|
||||
contours.erase(contours.begin() + i);
|
||||
m.erase(m.begin() + i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -258,6 +314,7 @@ std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<s
|
|||
{
|
||||
contours.erase(contours.begin() + i);
|
||||
m.erase(m.begin() + i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -268,9 +325,10 @@ std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<s
|
|||
double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外
|
||||
double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外
|
||||
//如果在纸张外,或者边缘内,视为非孔洞
|
||||
if (temp1 < 0 || temp2 > 0)
|
||||
if (temp1 <= 0 || temp2 >= 0)
|
||||
{
|
||||
enabled = false;
|
||||
//qDebug() << rrect.center.x << ":" << rrect.center.y << "::::" << rrect.size.width << " - " << rrect.size.height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,13 @@
|
|||
* 2022/08/02 v1.7.2 调整部分默认参数以及参数命名
|
||||
* 2022/09/07 v1.8 去掉上下左右边缘范围的统一比例,取而代之是分别设置上下左右的边缘比例
|
||||
* 2022/09/09 v1.8.1 修复边缘定位的精确BUG。
|
||||
* 版本号:v1.8.1
|
||||
* 2022/09/15 v1.8.2 修复一些逻辑BUG。
|
||||
* 2022/09/15 v1.8.3 提高抗背景噪声能力。
|
||||
* 2022/09/15 v1.8.4 修复导致崩溃的BUG
|
||||
* 2022/09/16 v1.9 优化内存消耗
|
||||
* 2022/09/16 v1.9.1 修复缩放比例的逻辑错误。
|
||||
* 2022/11/17 v1.9.2 修复寻找孔洞轮廓BUG。
|
||||
* 版本号:v1.9.2
|
||||
|
||||
* ====================================================
|
||||
*/
|
||||
|
@ -36,7 +42,7 @@ public:
|
|||
CImageApplyOutHole();
|
||||
|
||||
/*
|
||||
* borderSize [in]:孔洞面积阈值
|
||||
* borderSize [in]:孔洞边长阈值
|
||||
* edgeScale [in]:纸张边缘区域比例。依次表示为上下左右边距比例。取值范围[0, 0.5],默认值(0.1, 0.1, 0.1, 0.1)。穿孔会在该指定的边缘区域进行寻找。
|
||||
* threshold [in]:二值化阈值
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue