diff --git a/hgdriver/ImageProcess/ImageApplyOutHole.cpp b/hgdriver/ImageProcess/ImageApplyOutHole.cpp index 41e82e7..9effeb8 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.cpp +++ b/hgdriver/ImageProcess/ImageApplyOutHole.cpp @@ -1,10 +1,5 @@ #include "ImageApplyOutHole.h" #include "ImageProcess_Public.h" -//#include - -#ifdef LOG -#include "Device/filetools.h" -#endif // LOG //#define DRAW_PIC @@ -50,10 +45,8 @@ void CImageApplyOutHole::dilateContour(std::vector& contour, int dist } } -#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 @@ -119,22 +112,6 @@ void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) 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); @@ -184,10 +161,6 @@ void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) cv::imwrite("mask3.jpg", mask); #endif - //膨胀算法,增大孔洞连通区域面积 - //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)); - #ifdef DRAW_PIC cv::imwrite("mask4.jpg", mask); #endif @@ -204,7 +177,9 @@ void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) 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()); + cv::Mat thumbnail; + cv::resize(front(roi_front), thumbnail, cv::Size(200, 200)); + cv::Scalar color = hg::getBackGroundColor(thumbnail, cv::Mat(), m_threshold); roi_front.x /= resize_scale; roi_front.y /= resize_scale; roi_front.width /= resize_scale; @@ -222,7 +197,9 @@ 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_back.size.area()); + + cv::resize(back(roi_back), thumbnail, cv::Size(200, 200)); + color = hg::getBackGroundColor(thumbnail, cv::Mat(), m_threshold); roi_back.x /= resize_scale; roi_back.y /= resize_scale; roi_back.width /= resize_scale; @@ -240,7 +217,7 @@ void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) } std::vector> contours_temp; - dilateContour(hole_contour, 5); + dilateContour(hole_contour, m_borderSize / 4); contours_temp.push_back(hole_contour); cv::Mat back_temp = mats[1](roi_back); hg::fillPolys(back_temp, contours_temp, color); @@ -378,81 +355,4 @@ std::vector> CImageApplyOutHole::filterPoly(std::vector pixelPoints) -{ - if (pixelPoints.empty()) return cv::Scalar(255, 255, 255); - - int channels = image.channels(); - - int temp[3] = { 0 }; - for (size_t i = 0, length = pixelPoints.size(); i < length; ++i) - { - int x = cv::min(cv::max(0, pixelPoints[i].x), image.cols - 1); - int y = cv::min(cv::max(0, pixelPoints[i].y), image.rows - 1); - - const unsigned char* ptr = image.ptr(y, x); - for (int j = 0; j < channels; ++j) - temp[j] += ptr[j]; - } - - return cv::Scalar(temp[0] / static_cast(pixelPoints.size()), - temp[1] / static_cast(pixelPoints.size()), - temp[2] / static_cast(pixelPoints.size())); -} - -cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, int total) -{ - if (image.channels() == 3) - { - cv::Mat image_bgr[3]; - cv::split(image, image_bgr); - - uchar bgr[3]; - for (size_t i = 0; i < 3; i++) - bgr[i] = getBackGroudChannelMean(image_bgr[i], total); - return cv::Scalar(bgr[0], bgr[1], bgr[2]); - } - else - return cv::Scalar::all(getBackGroudChannelMean(image, total)); -} - -uchar CImageApplyOutHole::getBackGroudChannelMean(const cv::Mat& gray, int total) -{ - cv::Mat image_clone; - cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25); - - int threnshold = total / 32; - int channels[] = { 0 }; - int nHistSize[] = { 256 }; - float range[] = { 0, 256 }; - const float* fHistRanges[] = { range }; - cv::Mat hist; - cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false); - - int hist_array[256]; - for (int i = 0; i < 256; i++) - hist_array[i] = hist.at(i, 0); - - int length = 1; - const int length_max = 255; - while (length < length_max) - { - for (size_t i = 1; i < 256 - length; i++) - { - int count = 0; - uint pixSum = 0; - for (size_t j = 0; j < length; j++) - { - count += hist_array[j + i]; - pixSum += hist_array[j + i] * (i + j); - } - - if (count >= threnshold) - return pixSum / count; - } - length++; - } - return 255; } \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageApplyOutHole.h b/hgdriver/ImageProcess/ImageApplyOutHole.h index b361720..c3063a8 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.h +++ b/hgdriver/ImageProcess/ImageApplyOutHole.h @@ -4,31 +4,32 @@ * 功能:装订孔填充 * 作者:刘丁维 * 生成时间:2020/11/21 - * 最近修改时间:2020/05/12 v1.0 - * 2020/11/17 v1.1 - * 2021/09/06 v1.2 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。 - * 2021/11/03 v1.3 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。 - * 2021/11/04 v1.4 增加背景抗噪机制,能够抗5像素的背景噪声。 - * 2021/11/17 v1.5 调整代码格式,避免一些由于opencv版本导致的BUG。 - * 2022/04/18 v1.6 修复由于图像超出边界导致的定位孔洞异常的BUG。 - * 2022/05/04 v1.6.1 增加逻辑判断,如果出现黑图,直接返回,不对原图进行任何处理。 - * 2022/07/16 v1.6.2 修复自动识别填充颜色的BUG - * 2022/07/18 v1.6.3 修复mask的一些逻辑错误 - * 2022/07/18 v1.7 修复逻辑BUG,替换构造函数borderSize逻辑,由原来面积改为边长,定义穿孔范围为[borderSize, borderSize * 6] - * 2022/07/22 v1.7.1 修复自动识别填充颜色的BUG - * 2022/08/02 v1.7.2 调整部分默认参数以及参数命名 - * 2022/09/07 v1.8 去掉上下左右边缘范围的统一比例,取而代之是分别设置上下左右的边缘比例 - * 2022/09/09 v1.8.1 修复边缘定位的精确BUG。 - * 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。 - * 2023/05/16 v1.9.3 修复提取纸张最大轮廓的逻辑BUG。 - * 2023/11/18 v1.10 替换形态学膨胀孔洞轮廓,改为特征矩阵膨胀轮廓说 - * 2023/11/28 v1.10.1 形态学kSize根据borderSize调整 - * 版本号:v1.10.1 + * 最近修改时间:v1.0 2020/05/12 + * v1.1 2020/11/17 + * v1.2 2021/09/06 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。 + * v1.3 2021/11/03 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。 + * v1.4 2021/11/04 增加背景抗噪机制,能够抗5像素的背景噪声。 + * v1.5 2021/11/17 调整代码格式,避免一些由于opencv版本导致的BUG。 + * v1.6 2022/04/18 修复由于图像超出边界导致的定位孔洞异常的BUG。 + * v1.6.1 2022/05/04 增加逻辑判断,如果出现黑图,直接返回,不对原图进行任何处理。 + * v1.6.2 2022/07/16 修复自动识别填充颜色的BUG + * v1.6.3 2022/07/18 修复mask的一些逻辑错误 + * v1.7 2022/07/18 修复逻辑BUG,替换构造函数borderSize逻辑,由原来面积改为边长,定义穿孔范围为[borderSize, borderSize * 6] + * v1.7.1 2022/07/22 修复自动识别填充颜色的BUG + * v1.7.2 2022/08/02 调整部分默认参数以及参数命名 + * v1.8 2022/09/07 去掉上下左右边缘范围的统一比例,取而代之是分别设置上下左右的边缘比例 + * v1.8.1 2022/09/09 修复边缘定位的精确BUG。 + * v1.8.2 2022/09/15 修复一些逻辑BUG。 + * v1.8.3 2022/09/15 提高抗背景噪声能力。 + * v1.8.4 2022/09/15 修复导致崩溃的BUG + * v1.9 2022/09/16 优化内存消耗 + * v1.9.1 2022/09/16 修复缩放比例的逻辑错误。 + * v1.9.2 2022/11/17 修复寻找孔洞轮廓BUG。 + * v1.9.3 2023/05/16 修复提取纸张最大轮廓的逻辑BUG。 + * v1.10 2023/11/18 替换形态学膨胀孔洞轮廓,改为特征矩阵膨胀轮廓说。 + * v1.10.1 2023/11/28 形态学kSize根据borderSize调整。 + * v1.11 2023/12/02 替换文稿底色提取方案;修复部分孔洞填充不完全的问题。 + * 版本号:v1.11 * ==================================================== */ @@ -77,12 +78,6 @@ private: std::vector > filterPoly(std::vector>& contours, std::vector& m, cv::RotatedRect roi, cv::Vec4f edgeScale, float sideLengthLow); - cv::Scalar getBackGroudColor(const cv::Mat& image, const std::vector pixelPoints); - - cv::Scalar getBackGroudColor(const cv::Mat& image, int total); - - uchar getBackGroudChannelMean(const cv::Mat& gray, int total); - void dilateContour(std::vector& contour, int distance); private: