diff --git a/hgdriver/ImageProcess/ImageApplyOutHole.cpp b/hgdriver/ImageProcess/ImageApplyOutHole.cpp index abbc465..888fa96 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.cpp +++ b/hgdriver/ImageProcess/ImageApplyOutHole.cpp @@ -1,5 +1,6 @@ #include "ImageApplyOutHole.h" #include "ImageProcess_Public.h" +//#include #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& mats, bool isTwoSide) { #ifdef LOG @@ -53,16 +58,32 @@ void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) return; } + double resize_scale = cv::min(RESIZE_FIXED_WIDTH / static_cast(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& mats, bool isTwoSide) //正反面图像寻边 std::vector> contours_front, contours_back; std::vector 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 maxContour_front = hg::getMaxContour(contours_front, b1_front); std::vector maxContour_back = hg::getMaxContour(contours_back, b1_back); @@ -107,27 +144,37 @@ void CImageApplyOutHole::apply(std::vector& 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> contours_mask; std::vector b1_mask; - hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //提取重叠图像轮廓 + hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //过滤非孔洞的联通区域 - std::vector> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize); + std::vector> 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> 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& 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 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> 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> CImageApplyOutHole::filterPoly(std::vector> CImageApplyOutHole::filterPoly(std::vector> CImageApplyOutHole::filterPoly(std::vector> CImageApplyOutHole::filterPoly(std::vector 0) + if (temp1 <= 0 || temp2 >= 0) { enabled = false; + //qDebug() << rrect.center.x << ":" << rrect.center.y << "::::" << rrect.size.width << " - " << rrect.size.height; break; } } diff --git a/hgdriver/ImageProcess/ImageApplyOutHole.h b/hgdriver/ImageProcess/ImageApplyOutHole.h index 7d00f46..b028f8c 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.h +++ b/hgdriver/ImageProcess/ImageApplyOutHole.h @@ -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]:二值化阈值 */