更新防渗透算法,优化效果,支持灰度图防渗透,BUG-769
This commit is contained in:
parent
b1b5ed44e0
commit
b7b85e44a8
|
@ -1,9 +1,9 @@
|
||||||
#include "ImageApplyRefuseInflow.h"
|
#include "ImageApplyRefuseInflow.h"
|
||||||
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
CImageApplyRefuseInflow::CImageApplyRefuseInflow(int d, int sigmaColor, int sigmaSpace)
|
CImageApplyRefuseInflow::CImageApplyRefuseInflow(int threshold, int range)
|
||||||
: m_d(d)
|
: m_threshold(threshold)
|
||||||
, m_sigmaColor(sigmaColor)
|
, m_range(range)
|
||||||
, m_sigmaSpace(sigmaSpace)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,53 @@ CImageApplyRefuseInflow::~CImageApplyRefuseInflow()
|
||||||
|
|
||||||
void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side)
|
void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
cv::Mat dst;
|
if (pDib.channels() == 3)
|
||||||
cv::bilateralFilter(pDib, dst, m_d, m_sigmaColor, m_sigmaSpace);
|
{
|
||||||
pDib = dst;
|
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<int> 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<float>(j) > max_value)
|
||||||
|
{
|
||||||
|
index_max = j;
|
||||||
|
max_value = hist.at<float>(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<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyRefuseInflow::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
* v1.1 2022/05/04 重构算法,采用提高对比度实现防渗透。
|
* v1.1 2022/05/04 重构算法,采用提高对比度实现防渗透。
|
||||||
* v2.0 2023/08/12 筹够算法,采用双边滤波实现防渗透。
|
* v2.0 2023/08/12 筹够算法,采用双边滤波实现防渗透。
|
||||||
* v2.1 2023/10/20 修复原图不能同时作为目标图的BUG。
|
* 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:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="d">邻域的直径。取值范围[0, +∞)</param>
|
/// <param name="threshod">背景阈值.取值范围[0, 255]</param>
|
||||||
/// <param name="sigmaColor">颜色空间滤波器的标准差。取值范围[0, +∞)</param>
|
/// <param name="range">文稿底色相近范围。取值范围[0, 255]</param>
|
||||||
/// <param name="sigmaSpace">空域滤波器的标准差。取值范围[0, +∞)。注意当d为0时,该参数才生效</param>
|
CImageApplyRefuseInflow(int threshod = 20, int range = 40);
|
||||||
CImageApplyRefuseInflow(int d, int sigmaColor, int sigmaSpace);
|
|
||||||
|
|
||||||
virtual ~CImageApplyRefuseInflow();
|
virtual ~CImageApplyRefuseInflow();
|
||||||
|
|
||||||
|
@ -37,8 +38,7 @@ public:
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_d;
|
int m_threshold;
|
||||||
int m_sigmaColor;
|
int m_range;
|
||||||
int m_sigmaSpace;
|
|
||||||
};
|
};
|
||||||
#endif // !IMAGE_APPLY_REFUSE_INFLOW_H
|
#endif // !IMAGE_APPLY_REFUSE_INFLOW_H
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
#include <opencv2/core/core_c.h>
|
||||||
|
#include <opencv2/core/types_c.h>
|
||||||
|
#include <opencv2/imgproc/imgproc_c.h>
|
||||||
|
|
||||||
namespace hg
|
namespace hg
|
||||||
{
|
{
|
||||||
|
@ -150,14 +153,11 @@ namespace hg
|
||||||
|
|
||||||
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
||||||
{
|
{
|
||||||
#if CV_VERSION_REVISION <= 6
|
|
||||||
CvMat c_image = src;
|
|
||||||
#else
|
|
||||||
CvMat c_image;
|
CvMat c_image;
|
||||||
c_image = cvMat(src.rows, src.cols, src.type(), src.data);
|
c_image = cvMat(src.rows, src.cols, src.type(), src.data);
|
||||||
c_image.step = src.step[0];
|
c_image.step = src.step[0];
|
||||||
c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG);
|
c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG);
|
||||||
#endif
|
|
||||||
cv::MemStorage storage(cvCreateMemStorage());
|
cv::MemStorage storage(cvCreateMemStorage());
|
||||||
CvSeq* _ccontours = nullptr;
|
CvSeq* _ccontours = nullptr;
|
||||||
|
|
||||||
|
@ -205,6 +205,38 @@ namespace hg
|
||||||
storage.release();
|
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<float>(j) > max_value)
|
||||||
|
{
|
||||||
|
index_max = j;
|
||||||
|
max_value = hist[i].at<float>(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
bgc[i] = index_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bgc;
|
||||||
|
}
|
||||||
|
|
||||||
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour)
|
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour)
|
||||||
{
|
{
|
||||||
if (contour.empty()) return {};
|
if (contour.empty()) return {};
|
||||||
|
@ -302,8 +334,11 @@ namespace hg
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEFAULT_THRESHOLD 30
|
||||||
|
#define THRESHOLD_OFFSET 10
|
||||||
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre)
|
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre)
|
||||||
{
|
{
|
||||||
|
cv::Mat temp;
|
||||||
if (src.channels() == 3)
|
if (src.channels() == 3)
|
||||||
{
|
{
|
||||||
#ifdef USE_ONENCL
|
#ifdef USE_ONENCL
|
||||||
|
@ -312,13 +347,39 @@ namespace hg
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
cv::Mat gray = transforColor(src);
|
//temp = transforColor(src);
|
||||||
cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY);
|
cv::cvtColor(src, temp, cv::COLOR_BGR2GRAY);
|
||||||
gray.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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<int> unusual_cols;
|
||||||
|
std::vector<uchar> unusual_gray;
|
||||||
|
|
||||||
|
uchar* firstLine = temp.ptr<uchar>(0);
|
||||||
|
uchar* lastLine = temp.ptr<uchar>(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)
|
cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat)
|
||||||
|
|
|
@ -5,9 +5,13 @@
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 2021/07/12 v1.1 getBoundingRect中,增加考虑纠正初始 angle > 90 的情况。
|
* 2021/07/12 v1.1 getBoundingRect中,增加考虑纠正初始 angle > 90 的情况。
|
||||||
* 2021/07/22 v1.2 convexHull中,修复点集为空可能导致崩溃的BUG。
|
* 2021/07/22 v1.2 convexHull中,修复点集为空可能导致崩溃的BUG。
|
||||||
* 版本号:v1.2
|
* 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<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy,
|
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy,
|
||||||
int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0));
|
int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取图片文稿底色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">图像,三通道</param>
|
||||||
|
/// <param name="mask">掩膜</param>
|
||||||
|
/// <param name="threshold">阈值,用于排除黑色背景</param>
|
||||||
|
/// <returns>文稿底色</returns>
|
||||||
|
cv::Scalar getBackGroundColor(const cv::Mat& image, const cv::Mat& mask = cv::Mat(), int threshold = 20);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 功能:获取覆盖点集的最小外接矩形
|
* 功能:获取覆盖点集的最小外接矩形
|
||||||
* contour: 点集
|
* contour: 点集
|
||||||
|
@ -90,7 +103,7 @@ namespace hg
|
||||||
* 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值
|
* 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值
|
||||||
* src: 源图
|
* src: 源图
|
||||||
* dst: 目标图
|
* dst: 目标图
|
||||||
* thre: 阈值
|
* thre: 阈值。当thre < 0时,采用背景色作为每列自适应阈值。
|
||||||
*/
|
*/
|
||||||
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre);
|
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre);
|
||||||
|
|
||||||
|
|
|
@ -5294,15 +5294,15 @@ void hg_scanner::image_process(std::shared_ptr<tiny_buffer>& 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
|
int lv = image_prc_param_.bits.is_permeate_lv_; //image_prc_param_.bits.is_permeate_lv_ = 0 1 2 3 4
|
||||||
|
|
||||||
if (0 == lv)
|
if (0 == lv)
|
||||||
lv = 3;
|
lv = 20;
|
||||||
else if (1 == lv)
|
else if (1 == lv)
|
||||||
lv = 5;
|
lv = 30;
|
||||||
else if (2 == lv)
|
else if (2 == lv)
|
||||||
lv = 7;
|
lv = 40;
|
||||||
else if (3 == lv)
|
else if (3 == lv)
|
||||||
lv = 9;
|
lv = 50;
|
||||||
else if (4 == lv)
|
else if (4 == lv)
|
||||||
lv = 11;
|
lv = 60;
|
||||||
|
|
||||||
hg_imgproc::antiInflow(ImagePrc_pHandle_, lv);
|
hg_imgproc::antiInflow(ImagePrc_pHandle_, lv);
|
||||||
(this->*dump_img_)(ImagePrc_pHandle_, "antiInflow");
|
(this->*dump_img_)(ImagePrc_pHandle_, "antiInflow");
|
||||||
|
|
|
@ -989,7 +989,7 @@ namespace hg_imgproc
|
||||||
std::vector<cv::Mat> mats(mats_);
|
std::vector<cv::Mat> mats(mats_);
|
||||||
mats_.clear();
|
mats_.clear();
|
||||||
|
|
||||||
CImageApplyRefuseInflow Inflow(permeate_lv, 200, 200);
|
CImageApplyRefuseInflow Inflow(20, permeate_lv);
|
||||||
for (size_t i = 0; i < mats.size(); ++i)
|
for (size_t i = 0; i < mats.size(); ++i)
|
||||||
{
|
{
|
||||||
Inflow.apply(mats[i],img_conf_.is_duplex);
|
Inflow.apply(mats[i],img_conf_.is_duplex);
|
||||||
|
|
Loading…
Reference in New Issue