From b7b85e44a83a0b0bc8369382b26c9505dcaa09bb Mon Sep 17 00:00:00 2001 From: yangjiaxuan <171295266@qq.com> Date: Mon, 4 Dec 2023 18:03:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=98=B2=E6=B8=97=E9=80=8F?= =?UTF-8?q?=E7=AE=97=E6=B3=95=EF=BC=8C=E4=BC=98=E5=8C=96=E6=95=88=E6=9E=9C?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E7=81=B0=E5=BA=A6=E5=9B=BE=E9=98=B2?= =?UTF-8?q?=E6=B8=97=E9=80=8F=EF=BC=8CBUG-769?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImageProcess/ImageApplyRefuseInflow.cpp | 58 ++++++++++++-- .../ImageProcess/ImageApplyRefuseInflow.h | 18 ++--- hgdriver/ImageProcess/ImageProcess_Public.cpp | 77 +++++++++++++++++-- hgdriver/ImageProcess/ImageProcess_Public.h | 21 ++++- hgdriver/hgdev/hg_scanner.cpp | 10 +-- hgdriver/hgdev/image_process.cpp | 2 +- 6 files changed, 152 insertions(+), 34 deletions(-) diff --git a/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp b/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp index ba592a8..d646933 100644 --- a/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp +++ b/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp @@ -1,9 +1,9 @@ #include "ImageApplyRefuseInflow.h" +#include "ImageProcess_Public.h" -CImageApplyRefuseInflow::CImageApplyRefuseInflow(int d, int sigmaColor, int sigmaSpace) - : m_d(d) - , m_sigmaColor(sigmaColor) - , m_sigmaSpace(sigmaSpace) +CImageApplyRefuseInflow::CImageApplyRefuseInflow(int threshold, int range) + : m_threshold(threshold) + , m_range(range) { } @@ -13,9 +13,53 @@ CImageApplyRefuseInflow::~CImageApplyRefuseInflow() void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side) { - cv::Mat dst; - cv::bilateralFilter(pDib, dst, m_d, m_sigmaColor, m_sigmaSpace); - pDib = dst; + if (pDib.channels() == 3) + { + cv::Mat resizeMat; + cv::resize(pDib, resizeMat, cv::Size(200, 200)); + cv::Mat mask; + cv::cvtColor(resizeMat, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY); + + cv::Scalar bgc = hg::getBackGroundColor(resizeMat, mask, m_threshold); + + std::vector low, up; + for (size_t i = 0; i < 3; i++) + { + low.push_back(cv::max((int)bgc[i] - m_range, 0)); + up.push_back(cv::min((int)bgc[i] + m_range, 255)); + } + + cv::inRange(pDib, low, up, mask); + pDib = pDib.setTo(bgc, mask); + } + else + { + cv::Mat resizeMat; + cv::resize(pDib, resizeMat, cv::Size(200, 200)); + cv::Mat mask; + cv::threshold(resizeMat, mask, m_threshold, 255, cv::THRESH_BINARY); + + cv::Mat hist; + double min, max; + cv::Point maxLoc; + float range[] = { 0, 256 }; + const float* ranges = { range }; + int histSize = 256; + cv::calcHist(&resizeMat, 1, 0, mask, hist, 1, &histSize, &ranges); + + int index_max = 0; + int max_value = 0; + for (size_t j = m_threshold; j < 256; j++) + if (hist.at(j) > max_value) + { + index_max = j; + max_value = hist.at(j); + } + + cv::inRange(pDib, cv::max(index_max - m_range, 0), cv::min(index_max + m_range, 255), mask); + pDib = pDib.setTo(cv::Scalar::all(index_max), mask); + } } void CImageApplyRefuseInflow::apply(std::vector& mats, bool isTwoSide) diff --git a/hgdriver/ImageProcess/ImageApplyRefuseInflow.h b/hgdriver/ImageProcess/ImageApplyRefuseInflow.h index 616def3..487e5ab 100644 --- a/hgdriver/ImageProcess/ImageApplyRefuseInflow.h +++ b/hgdriver/ImageProcess/ImageApplyRefuseInflow.h @@ -8,7 +8,9 @@ * v1.1 2022/05/04 重构算法,采用提高对比度实现防渗透。 * v2.0 2023/08/12 筹够算法,采用双边滤波实现防渗透。 * v2.1 2023/10/20 修复原图不能同时作为目标图的BUG。 - * 版本号:v2.1 + * v3.0 2023/12/02 更新方案,通过识别文稿底色,填充近似颜色实现防渗透。接口有所调整 + * v3.1 2023/12/04 支持灰度图防渗透 + * 版本号:v3.1 * ==================================================== */ @@ -23,12 +25,11 @@ class GIMGPROC_LIBRARY_API CImageApplyRefuseInflow : public CImageApply public: /// - /// 构造函数 + /// /// - /// 邻域的直径。取值范围[0, +∞) - /// 颜色空间滤波器的标准差。取值范围[0, +∞) - /// 空域滤波器的标准差。取值范围[0, +∞)。注意当d为0时,该参数才生效 - CImageApplyRefuseInflow(int d, int sigmaColor, int sigmaSpace); + /// 背景阈值.取值范围[0, 255] + /// 文稿底色相近范围。取值范围[0, 255] + CImageApplyRefuseInflow(int threshod = 20, int range = 40); virtual ~CImageApplyRefuseInflow(); @@ -37,8 +38,7 @@ public: virtual void apply(std::vector& mats, bool isTwoSide); private: - int m_d; - int m_sigmaColor; - int m_sigmaSpace; + int m_threshold; + int m_range; }; #endif // !IMAGE_APPLY_REFUSE_INFLOW_H diff --git a/hgdriver/ImageProcess/ImageProcess_Public.cpp b/hgdriver/ImageProcess/ImageProcess_Public.cpp index 21fce58..d8a7001 100644 --- a/hgdriver/ImageProcess/ImageProcess_Public.cpp +++ b/hgdriver/ImageProcess/ImageProcess_Public.cpp @@ -1,4 +1,7 @@ #include "ImageProcess_Public.h" +#include +#include +#include namespace hg { @@ -150,14 +153,11 @@ namespace hg void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) { -#if CV_VERSION_REVISION <= 6 - CvMat c_image = src; -#else CvMat c_image; c_image = cvMat(src.rows, src.cols, src.type(), src.data); c_image.step = src.step[0]; c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG); -#endif + cv::MemStorage storage(cvCreateMemStorage()); CvSeq* _ccontours = nullptr; @@ -205,6 +205,38 @@ namespace hg storage.release(); } + cv::Scalar getBackGroundColor(const cv::Mat& image, const cv::Mat& mask, int threshold) + { + cv::Scalar bgc; + cv::Mat mv[3]; + cv::split(image, mv); + float range[] = { 0, 256 }; + const float* ranges = { range }; + + int histSize = 256; + + cv::Mat hist[3]; + double min, max; + cv::Point maxLoc; + for (int i = 0; i < 3; i++) + { + cv::calcHist(&mv[i], 1, 0, mask, hist[i], 1, &histSize, &ranges); + + int index_max = 0; + int max_value = 0; + for (size_t j = threshold; j < 256; j++) + if (hist[i].at(j) > max_value) + { + index_max = j; + max_value = hist[i].at(j); + } + + bgc[i] = index_max; + } + + return bgc; + } + cv::RotatedRect getBoundingRect(const std::vector& contour) { if (contour.empty()) return {}; @@ -302,8 +334,11 @@ namespace hg return dst; } +#define DEFAULT_THRESHOLD 30 +#define THRESHOLD_OFFSET 10 void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) { + cv::Mat temp; if (src.channels() == 3) { #ifdef USE_ONENCL @@ -312,13 +347,39 @@ namespace hg else #endif { - cv::Mat gray = transforColor(src); - cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY); - gray.release(); + //temp = transforColor(src); + cv::cvtColor(src, temp, cv::COLOR_BGR2GRAY); } } else - cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY); + temp = src; + + if (thre > 0) + cv::threshold(temp, dst, thre, 255, cv::THRESH_BINARY); + else + { + std::vector unusual_cols; + std::vector unusual_gray; + + uchar* firstLine = temp.ptr(0); + uchar* lastLine = temp.ptr(temp.rows - 1); + + uchar temp_gray; + for (size_t i = 0, length = temp.step; i < length; i++) + { + temp_gray = cv::min(firstLine[i], lastLine[i]); + if (temp_gray > DEFAULT_THRESHOLD) + { + unusual_cols.push_back(i); + unusual_gray.push_back(temp_gray); + } + } + + cv::threshold(temp, dst, DEFAULT_THRESHOLD + THRESHOLD_OFFSET, 255, cv::THRESH_BINARY); + + for (size_t i = 0; i < unusual_cols.size(); i++) + dst(cv::Rect(unusual_cols[i], 0, 1, temp.rows)) = 0; + } } cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) diff --git a/hgdriver/ImageProcess/ImageProcess_Public.h b/hgdriver/ImageProcess/ImageProcess_Public.h index a05ae8b..632a8b8 100644 --- a/hgdriver/ImageProcess/ImageProcess_Public.h +++ b/hgdriver/ImageProcess/ImageProcess_Public.h @@ -5,9 +5,13 @@ * 作者:刘丁维 * 生成时间:2020/4/21 * 最近修改时间:2020/4/21 - * 2021/07/12 v1.1 getBoundingRect中,增加考虑纠正初始 angle > 90 的情况。 - * 2021/07/22 v1.2 convexHull中,修复点集为空可能导致崩溃的BUG。 - * 版本号:v1.2 + * 2021/07/12 v1.1 getBoundingRect中,增加考虑纠正初始 angle > 90 的情况。 + * 2021/07/22 v1.2 convexHull中,修复点集为空可能导致崩溃的BUG。 + * 2023/11/02 v1.3 threshold_Mat,当thre<0时,采用自适应背景二值化。 + * 2023/12/01 v1.4 增加getBackGroundColor算法。 + * 2023/12/02 v1.4.1 getBackGroundColor增加threshold阈值。 + * 2023/12/04 v1.4.2 兼容opencv版本接口。 + * 版本号:v1.4.2 * ==================================================== */ @@ -55,6 +59,15 @@ namespace hg void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0)); + /// + /// 获取图片文稿底色 + /// + /// 图像,三通道 + /// 掩膜 + /// 阈值,用于排除黑色背景 + /// 文稿底色 + cv::Scalar getBackGroundColor(const cv::Mat& image, const cv::Mat& mask = cv::Mat(), int threshold = 20); + /* * 功能:获取覆盖点集的最小外接矩形 * contour: 点集 @@ -90,7 +103,7 @@ namespace hg * 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值 * src: 源图 * dst: 目标图 - * thre: 阈值 + * thre: 阈值。当thre < 0时,采用背景色作为每列自适应阈值。 */ void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre); diff --git a/hgdriver/hgdev/hg_scanner.cpp b/hgdriver/hgdev/hg_scanner.cpp index da51dbe..3b34b04 100644 --- a/hgdriver/hgdev/hg_scanner.cpp +++ b/hgdriver/hgdev/hg_scanner.cpp @@ -5294,15 +5294,15 @@ void hg_scanner::image_process(std::shared_ptr& buffer, uint32_t id int lv = image_prc_param_.bits.is_permeate_lv_; //image_prc_param_.bits.is_permeate_lv_ = 0 1 2 3 4 if (0 == lv) - lv = 3; + lv = 20; else if (1 == lv) - lv = 5; + lv = 30; else if (2 == lv) - lv = 7; + lv = 40; else if (3 == lv) - lv = 9; + lv = 50; else if (4 == lv) - lv = 11; + lv = 60; hg_imgproc::antiInflow(ImagePrc_pHandle_, lv); (this->*dump_img_)(ImagePrc_pHandle_, "antiInflow"); diff --git a/hgdriver/hgdev/image_process.cpp b/hgdriver/hgdev/image_process.cpp index 85d1999..50a2617 100644 --- a/hgdriver/hgdev/image_process.cpp +++ b/hgdriver/hgdev/image_process.cpp @@ -989,7 +989,7 @@ namespace hg_imgproc std::vector mats(mats_); mats_.clear(); - CImageApplyRefuseInflow Inflow(permeate_lv, 200, 200); + CImageApplyRefuseInflow Inflow(20, permeate_lv); for (size_t i = 0; i < mats.size(); ++i) { Inflow.apply(mats[i],img_conf_.is_duplex);