diff --git a/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp b/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp index c2724a3..37d6ed0 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp +++ b/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp @@ -4,6 +4,10 @@ #include #include "ImageApplyDispersion.h" +#define COLOR_BACKGROUND_THRE 20 +#define FRONT_TOP 70 +#define FX_FY 0.5f + CImageApplyAutoCrop::CImageApplyAutoCrop() : m_isCrop(false) , m_isDesaskew(false) @@ -15,11 +19,13 @@ CImageApplyAutoCrop::CImageApplyAutoCrop() , m_indent(5) , m_normalCrop(false) , m_isDispersion(true) + , m_fx(1.0) + , m_fy(1.0) { } CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor, - double threshold, int noise, int indent, bool normalCrop, bool dispersion) + double threshold, int noise, int indent, bool normalCrop, bool dispersion, double fx, double fy) : m_isCrop(isCrop) , m_isDesaskew(isDesaskew) , m_isFillBlank(isFillBlank) @@ -31,6 +37,8 @@ CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFi , m_fixedSize(fixedSize) , m_normalCrop(normalCrop) , m_isDispersion(dispersion) + , m_fx(fx) + , m_fy(fy) { } @@ -42,7 +50,7 @@ void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side) { cv::Mat dst; autoCrop_desaskew_fillBlank(pDib, dst, m_isCrop, m_isDesaskew, m_isFillBlank, m_fixedSize.width, m_fixedSize.height, - m_isConvexHull, m_isFillColor, m_threshold, m_noise, m_indent, m_normalCrop, m_isDispersion); + m_isConvexHull, m_isFillColor, m_threshold, m_noise, m_indent, m_normalCrop, m_isDispersion, m_fx, m_fy); pDib = dst; } @@ -59,10 +67,7 @@ void CImageApplyAutoCrop::apply(std::vector& mats, bool isTwoSide) } } -#define FRONT_TOP 70 -#define FX_FY 0.5f - -void myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, cv::Size dsize, int flags, int borderType, const cv::Scalar& borderValue) +void CImageApplyAutoCrop::myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, cv::Size dsize, int flags, int borderType, const cv::Scalar& borderValue) { int interpolation = flags; cv::Mat src = _src.getMat(), M0 = _M0.getMat(); @@ -94,68 +99,74 @@ void myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, M, interpolation, borderType, borderValue.val); } -uchar getBackGroudChannelMean(const cv::Mat& gray, int total, int threshold) -{ - 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 - threshold; - while (length < length_max) - { - for (size_t i = threshold + 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; -} - -cv::Scalar getBackGroudColor(const cv::Mat& image, int total, int threshold) +cv::Scalar CImageApplyAutoCrop::getBackGroudColor(const cv::Mat& image, int threshold) { if (image.channels() == 3) { - cv::Mat image_bgr[3]; - cv::split(image, image_bgr); + uchar table[768] = { 0 }; + int hist_bgr[3][256] = { 0 }; + int width = image.cols, height = image.rows, bytesPerLine = image.step; + memset(table + threshold * 3, 255, 768 - threshold * 3); - uchar bgr[3]; - for (size_t i = 0; i < 3; i++) - bgr[i] = getBackGroudChannelMean(image_bgr[i], total, threshold); - return cv::Scalar(bgr[0], bgr[1], bgr[2]); + unsigned char* ptr_data = image.data; + unsigned char b = 0; + for (uint i = 0; i < height; i++, ptr_data += bytesPerLine) + for (uint j = 0, x = 0; j < width; j++, x += 3) + { + b = table[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]]; + for (uint k = 0; k < 3; k++) + hist_bgr[k][ptr_data[x + k] & b]++; + } + + int max_vals[3] = { 0 }; + cv::Scalar max_indexes(0, 0, 0); + + for (uint i = 5; i < 256; i++) + for (uint j = 0; j < 3; j++) + if (hist_bgr[j][i] > max_vals[j]) + { + max_vals[j] = hist_bgr[j][i]; + max_indexes[j] = i; + } + + return max_indexes; } else - return cv::Scalar::all(getBackGroudChannelMean(image, total, threshold)); + { + uchar table[256] = { 0 }; + int hist_bgr[256] = { 0 }; + int width = image.cols, height = image.rows, bytesPerLine = image.step; + memset(table + threshold, 255, 256 - threshold); + unsigned char* ptr_data = image.data; + unsigned char b = 0; + for (uint i = 0; i < height; i++, ptr_data += bytesPerLine) + for (uint j = 0, x = 0; j < width; j++, x ++) + hist_bgr[ptr_data[x] & table[ptr_data[x]]]++; + + int max_vals = 5; + for (uint i = 5; i < 256; i++) + if (hist_bgr[i] > hist_bgr[max_vals]) + max_vals = i; + + return cv::Scalar(max_vals); + } } -CImageApplyDispersion dispersion_apply; -#define COLOR_SCALE_THRE 0.5 -void autoCrop_desaskew_fillBlank(const cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, - bool isConvex, bool isColorBlank, double threshold, int noise, int indent, bool isNormalCrop, bool dispersion) +CImageApplyDispersion m_dispersion_apply; +void CImageApplyAutoCrop::autoCrop_desaskew_fillBlank(cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, + bool isConvex, bool isColorBlank, double threshold, int noise, int indent, bool isNormalCrop, bool dispersion, double fx, double fy) { if (src.empty()) return; + if (fx < 0.999999 || fx > 1.000001 || fy < 0.999999 || fy > 1.000001) + cv::resize(src, src, cv::Size(), fx, fy, cv::INTER_LINEAR); + + if (!isAutoCrop && !isDesaskew && !isFillBlank && dWidth == 0 && dHeight == 0) + { + dst = src; + return; + } + if (isNormalCrop) { cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows); @@ -204,17 +215,16 @@ void autoCrop_desaskew_fillBlank(const cv::Mat& src, cv::Mat& dst, bool isAutoCr cv::RotatedRect rect = hg::getBoundingRect(maxContour); -#ifndef x86_64 // for illegal instruction: vfmadd132ps if (dispersion) { cv::Mat mat_dispersion = src(cv::boundingRect(maxContour)); - dispersion_apply.apply(mat_dispersion, 0); + m_dispersion_apply.apply(mat_dispersion, 0); } -#endif + cv::Scalar blankColor; if (isFillBlank) if (isColorBlank) - blankColor = getBackGroudColor(resizeMat, rect.size.area() * FX_FY * FX_FY, COLOR_SCALE_THRE); + blankColor = getBackGroudColor(resizeMat, COLOR_BACKGROUND_THRE); else blankColor = cv::Scalar::all(255); else diff --git a/hgdriver/ImageProcess/ImageApplyAutoCrop.h b/hgdriver/ImageProcess/ImageApplyAutoCrop.h index 9a809c2..1f4c9d7 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoCrop.h +++ b/hgdriver/ImageProcess/ImageApplyAutoCrop.h @@ -26,7 +26,10 @@ 2022/04/24 v1.4 重构算法,增加除色散功能 2022/05/03 v1.4.1 完善逻辑 2022/06/09 v1.4.2 修复获取文稿底色时,threshold值,设为固定值0.5 - * 版本号:v1.4.2 + 2022/10/31 v1.5 增加横纵DPI缩放参数fx,fy。 + 2022/11/19 v1.5.1 修复文稿背景色识别算法的BUG。 + 2022/11/19 v1.5.2 修复灰度文稿背景色识别算法的BUG。 + * 版本号:v1.5.2 * ==================================================== */ @@ -36,6 +39,7 @@ #include "ImageApply.h" +class CImageApplyDispersion; class GIMGPROC_LIBRARY_API CImageApplyAutoCrop : public CImageApply { public: @@ -53,9 +57,11 @@ public: * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默访 * normalCrop [in]:为true时,m_isCrop m_isDesaskew m_isFillBlank失效,固定裁切采用最传统的裁切方式,默认false * dispersion [in]:为true时,除色散;false时不除色散。默认为true + * fx [in]:横向缩放比例。默认1.0 + * fy [in]:纵向缩放比例。默认1.0 */ CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex = true, - bool isFillColor = false, double threshold = 40, int noise = 8, int indent = 5, bool normalCrop = false, bool dispersion = true); + bool isFillColor = false, double threshold = 40, int noise = 8, int indent = 5, bool normalCrop = false, bool dispersion = true, double fx = 1.0, double fy = 1.0); virtual ~CImageApplyAutoCrop(); @@ -101,6 +107,14 @@ public: void setDispersion(bool enable) { m_isDispersion = enable; } + static void autoCrop_desaskew_fillBlank(cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, + bool isConvex = true, bool isColorBlank = false, double threshold = 40, int noise = 8, int indent = 5, bool isNormalCrop = false, bool dispersion = true, + double fx = 1.0, double fy = 1.0); + +private: + static void myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, cv::Size dsize, int flags, int borderType, const cv::Scalar& borderValue); + + static cv::Scalar getBackGroudColor(const cv::Mat& image, int threshold); private: bool m_isCrop; bool m_isDesaskew; @@ -117,9 +131,9 @@ private: cv::RotatedRect m_rect; std::vector m_rects; std::vector m_maxContour; + + double m_fx; + double m_fy; }; - -void autoCrop_desaskew_fillBlank(const cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, - bool isConvex = true, bool isColorBlank = false, double threshold = 40, int noise = 8, int indent = 5, bool isNormalCrop = false, bool dispersion = true); #endif // !IMAGE_APPLY_AUTO_CROP_H diff --git a/hgdriver/hgdev/hg_scanner.cpp b/hgdriver/hgdev/hg_scanner.cpp index 3cb6e2a..39d605b 100644 --- a/hgdriver/hgdev/hg_scanner.cpp +++ b/hgdriver/hgdev/hg_scanner.cpp @@ -3520,7 +3520,7 @@ int hg_scanner::image_configuration(SCANCONF& ic) ic.is_autodiscradblank_vince = image_prc_param_.bits.page == PAGE_OMIT_EMPTY_RECEIPT; ic.is_switchfrontback = image_prc_param_.bits.exchange; ic.autodescrew = image_prc_param_.bits.automatic_skew; - //ic.multi_output_red = image_prc_param_.bits.rid_red; //必须屏蔽,否则超时,未知错误不可描述。 + ic.multi_output_red = image_prc_param_.bits.rid_red; //之前加上可能导致超时,或者未知错误不可描述。 ic.hsvcorrect = image_prc_param_.bits.rid_answer_red; ic.sharpen = image_prc_param_.bits.sharpen; //ic.enhance_color = image_prc_param_.bits.rid_color; //加这个会有问题 diff --git a/hgdriver/hgdev/hg_scanner_239.cpp b/hgdriver/hgdev/hg_scanner_239.cpp index e498385..04dc788 100644 --- a/hgdriver/hgdev/hg_scanner_239.cpp +++ b/hgdriver/hgdev/hg_scanner_239.cpp @@ -346,7 +346,7 @@ int hg_scanner_239::writedown_device_configuration(bool type, setting_hardware:: if (is_multiout) { - dev_conf->params_3399.color = image_prc_param_.bits.multi_out == MULTI_COLOR_AND_BW ? 0 : 1; + dev_conf->params_3399.color = image_prc_param_.bits.multi_out == MULTI_GRAY_AND_BW ? 0 : 1; } else if ((image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) diff --git a/hgdriver/hgdev/hg_scanner_300.cpp b/hgdriver/hgdev/hg_scanner_300.cpp index 4ca511a..80fad83 100644 --- a/hgdriver/hgdev/hg_scanner_300.cpp +++ b/hgdriver/hgdev/hg_scanner_300.cpp @@ -469,7 +469,7 @@ int hg_scanner_300::on_paper_check_changed(bool& check) int hg_scanner_300::on_resolution_changed(int& dpi) { int ret = SCANNER_ERR_OK; - dsp_config.params_3288.dpi = is_kernelsnap3288_221106_ ? (dsp_config.params_3288.dpi = (dpi > 200) ? 2 : 1) : dsp_config.params_3288.dpi = 1;//暂时还未有固件支持 + dsp_config.params_3288.dpi = is_kernelsnap3288_221106_ ? (dsp_config.params_3288.dpi = (dpi > 200) ? 2 : 1) : 1;//暂时还未有固件支持 ret = writedown_device_configuration(); return ret; diff --git a/hgdriver/hgdev/hg_scanner_400.cpp b/hgdriver/hgdev/hg_scanner_400.cpp index eb83459..5a5743a 100644 --- a/hgdriver/hgdev/hg_scanner_400.cpp +++ b/hgdriver/hgdev/hg_scanner_400.cpp @@ -396,12 +396,12 @@ int hg_scanner_400::writedown_device_configuration(bool type,setting_hardware::H { d->params_3288.isColor = 1; } - if (img_conf_.is_autocrop) + if (paper_size_ == TwSS::None || paper_size_ == TwSS::USStatement) { d->params_3288.pageSize = setting3288dsp::G400_AUTO; } - size = papersize.GetPaperSize(TwSS::A4, 200, img_conf_.paperAlign); - dsp_config.params_3288.dstHeight = (int)((size.cy + 200) / 100); //非安卓可不需要 + //size = papersize.GetPaperSize(TwSS::A4, 200, img_conf_.paperAlign); + //d->params_3288.dstHeight = (int)((size.cy + 200) / 100); //非安卓可不需要 USBCB usbcb = { setting3288dsp::CONFIGURED_DATA, d->value, 0 }; len = sizeof(USBCB); @@ -467,7 +467,7 @@ int hg_scanner_400::on_resolution_changed(int& dpi) { int ret = SCANNER_ERR_OK; dsp_config.params_3288.dpi = 1; - ret = writedown_device_configuration(); + ret = writedown_device_configuration(true); return ret; } @@ -500,11 +500,11 @@ int hg_scanner_400::agreement(TwSS tw,int align) { dsp_config.params_3288.pageSize = setting3288dsp::G400_AUTO; } - if (image_prc_param_.bits.rid_color != RID_COLOR_NONE && img_conf_.pixtype != 2) - { - d.params_3288.isColor = 1; - } - + //if (image_prc_param_.bits.rid_color != RID_COLOR_NONE && img_conf_.pixtype != 2) + //{ + // d.params_3288.isColor = 1; + //} + // ret = writedown_device_configuration(true,&d); //io_->set_timeout(200); @@ -553,7 +553,7 @@ void hg_scanner_400::writedown_image_configuration(void) image_configuration(ic); - //int ret = agreement((TwSS)img_conf_.papertype, img_conf_.paperAlign); + int ret = agreement((TwSS)img_conf_.papertype, img_conf_.paperAlign); /*SCANCONF ic; diff --git a/hgdriver/hgdev/image_process.cpp b/hgdriver/hgdev/image_process.cpp index e4d65e2..469b6c9 100644 --- a/hgdriver/hgdev/image_process.cpp +++ b/hgdriver/hgdev/image_process.cpp @@ -493,7 +493,8 @@ namespace hg_imgproc buffer_.reset(new std::vector()); int i=0; - for (auto& buf : buffs) { + for (auto& buf : buffs) + { i++; cv::ImreadModes rmc = param_.channels > 1 ? cv::IMREAD_COLOR : cv::IMREAD_GRAYSCALE; try @@ -516,7 +517,7 @@ namespace hg_imgproc rmc = cv::IMREAD_COLOR; } cv::Mat mat(cv::imdecode(*buf, rmc)); - //("/home/huagao/Desktop/1.jpg",mat); + //cv::imwrite("1.jpg",mat); if (mat.empty()) { LOG_INFO(LOG_LEVEL_FATAL, "decode image data error\n"); @@ -526,7 +527,7 @@ namespace hg_imgproc { mats_.push_back(mat); //cv::imwrite(std::to_string(i)+"_decode.jpg",mat); - } + } else if(pid == 0x300 || pid == 0x400|| pid == 0x402) { cv::Mat back = mat(cv::Rect(0, 0, mat.cols / 2, mat.rows)); @@ -544,7 +545,8 @@ namespace hg_imgproc back.release(); front.release(); } - buffer_.reset(new std::vector()); + //cv::imwrite(std::to_string(i)+"_decode.jpg",mat); + buffer_.reset(new std::vector()); } catch (const std::exception& e) {