更新除穿孔算法

This commit is contained in:
13038267101 2022-11-23 20:13:37 +08:00
parent 0833647b53
commit 044ad9c9d1
2 changed files with 85 additions and 21 deletions

View File

@ -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); //判断是否在纸张内 10-1
double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 10-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;
}
}

View File

@ -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]:
*/