diff --git a/hgdriver/ImageProcess/IMulti.cpp b/hgdriver/ImageProcess/IMulti.cpp index 442cf4c..e9ad38d 100644 --- a/hgdriver/ImageProcess/IMulti.cpp +++ b/hgdriver/ImageProcess/IMulti.cpp @@ -1,10 +1,10 @@ -#include "IMulti.h" - -IMulti::IMulti(void) -{ -} - -IMulti::~IMulti(void) -{ -} - +#include "IMulti.h" + +IMulti::IMulti(void) +{ +} + +IMulti::~IMulti(void) +{ +} + diff --git a/hgdriver/ImageProcess/IMulti.h b/hgdriver/ImageProcess/IMulti.h index df7ef35..e4a841a 100644 --- a/hgdriver/ImageProcess/IMulti.h +++ b/hgdriver/ImageProcess/IMulti.h @@ -1,12 +1,12 @@ -#pragma once -#include -#include -#include "imgprocdefs.h" - -class IMulti -{ -public: - IMulti(void); - virtual ~IMulti(void); - virtual std::vector apply(cv::Mat& pDib) = 0; -}; +#pragma once +#include +#include +#include "imgprocdefs.h" + +class GIMGPROC_LIBRARY_API IMulti +{ +public: + IMulti(void); + virtual ~IMulti(void); + virtual std::vector apply(cv::Mat& pDib) = 0; +}; diff --git a/hgdriver/ImageProcess/ImageApply.cpp b/hgdriver/ImageProcess/ImageApply.cpp index 80f5fbf..e459275 100644 --- a/hgdriver/ImageProcess/ImageApply.cpp +++ b/hgdriver/ImageProcess/ImageApply.cpp @@ -1,9 +1,9 @@ -#include "ImageApply.h" - -CImageApply::CImageApply(void) -{ -} - -CImageApply::~CImageApply(void) -{ -} +#include "ImageApply.h" + +CImageApply::CImageApply(void) +{ +} + +CImageApply::~CImageApply(void) +{ +} diff --git a/hgdriver/ImageProcess/ImageApply.h b/hgdriver/ImageProcess/ImageApply.h index c94c0bc..f5cdbb8 100644 --- a/hgdriver/ImageProcess/ImageApply.h +++ b/hgdriver/ImageProcess/ImageApply.h @@ -1,21 +1,34 @@ -#ifndef IMAGE_APPLY_H -#define IMAGE_APPLY_H - -#include -#include -#include - -class CImageApply -{ -public: - CImageApply(void); - virtual ~CImageApply(void); - - virtual void apply(cv::Mat& pDib,int side) = 0; - - virtual void apply(std::vector& mats, bool isTwoSide) = 0; -}; - -typedef std::shared_ptr ImageApplyPtr; - -#endif //!IMAGE_APPLY_H +/* + * ==================================================== + + * 功能:所有图像处理功能类的基类 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_H +#define IMAGE_APPLY_H + +#include +#include +#include +#include "imgprocdefs.h" + +class GIMGPROC_LIBRARY_API CImageApply +{ +public: + CImageApply(void); + virtual ~CImageApply(void); + + virtual void apply(cv::Mat& pDib,int side) = 0; + + virtual void apply(std::vector& mats, bool isTwoSide) = 0; +}; + +typedef std::shared_ptr ImageApplyPtr; + +#endif // !IMAGE_APPLY_H diff --git a/hgdriver/ImageProcess/ImageApplyAdjustColors.cpp b/hgdriver/ImageProcess/ImageApplyAdjustColors.cpp index 3e6cd5a..b2e7a46 100644 --- a/hgdriver/ImageProcess/ImageApplyAdjustColors.cpp +++ b/hgdriver/ImageProcess/ImageApplyAdjustColors.cpp @@ -1,90 +1,90 @@ -#include "ImageApplyAdjustColors.h" - -CImageApplyAdjustColors::CImageApplyAdjustColors(void) - : m_brightness(0) - , m_contrast(0) - , m_gamma(1.0f) - , lut(1, 256, CV_8UC1) -{ - update_lutData(); -} - -CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma) - : lut(1, 256, CV_8UC1) -{ - setAdjustColors(brightness, contrast, gamma); -} - -CImageApplyAdjustColors::~CImageApplyAdjustColors(void) -{ - -} - -void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side) -{ - (void)side; - if (pDib.empty()) return; - - if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f) - cv::LUT(pDib, lut, pDib); -} - -void CImageApplyAdjustColors::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if(!var.empty()) - apply(var, 0); - i++; - } -} - -void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma) -{ - m_brightness = cv::max(-255, cv::min(brightness, 255)); - m_contrast = cv::max(-127, cv::min(contrast, 127)); - m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); - update_lutData(); -} - -void CImageApplyAdjustColors::setBrightness(int brightness) -{ - m_brightness = cv::max(-255, cv::min(brightness, 255)); - update_lutData(); -} - -void CImageApplyAdjustColors::setContrast(int contrast) -{ - m_contrast = cv::max(-127, cv::min(contrast, 127)); - update_lutData(); -} - -void CImageApplyAdjustColors::setGamma(float gamma) -{ - m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); - update_lutData(); -} - -void CImageApplyAdjustColors::update_lutData() -{ - unsigned char* ptr = lut.data; - - uchar buffer[256]; - for (int i = 0; i < 256; i++) - { - //update brightness - ptr[i] = static_cast(cv::max(0, cv::min(i + m_brightness, 255))); - - //update contrast - if (ptr[i] < 128) - ptr[i] = static_cast(cv::max(0, cv::min(ptr[i] - m_contrast, 127))); - else - ptr[i] = static_cast(cv::max(127, cv::min(ptr[i] + m_contrast, 255))); - } - float g = 1.0f / m_gamma; - for (int i = 0; i < 256; i++) - ptr[i] = static_cast(cv::min(255, static_cast(cv::pow(static_cast(ptr[i]) / 255.0f, g) * 255.0f + 0.5f))); -} +#include "ImageApplyAdjustColors.h" + +CImageApplyAdjustColors::CImageApplyAdjustColors(void) + : m_brightness(0) + , m_contrast(0) + , m_gamma(1.0f) + , lut(1, 256, CV_8UC1) +{ + update_lutData(); +} + +CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma) + : lut(1, 256, CV_8UC1) +{ + setAdjustColors(brightness, contrast, gamma); +} + +CImageApplyAdjustColors::~CImageApplyAdjustColors(void) +{ + +} + +void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side) +{ + (void)side; + if (pDib.empty()) return; + + if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f) + cv::LUT(pDib, lut, pDib); +} + +void CImageApplyAdjustColors::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if(!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + m_contrast = cv::max(-127, cv::min(contrast, 127)); + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::setBrightness(int brightness) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + update_lutData(); +} + +void CImageApplyAdjustColors::setContrast(int contrast) +{ + m_contrast = cv::max(-127, cv::min(contrast, 127)); + update_lutData(); +} + +void CImageApplyAdjustColors::setGamma(float gamma) +{ + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::update_lutData() +{ + unsigned char* ptr = lut.data; + //update gamma + + for (int i = 0; i < 256; i++) + { + //update brightness + ptr[i] = static_cast(cv::max(0, cv::min(i + m_brightness, 255))); + + //update contrast + if (ptr[i] < 128) + ptr[i] = static_cast(cv::max(0, cv::min(ptr[i] - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(ptr[i] + m_contrast, 255))); + } + float g = 1.0f / m_gamma; + for (int i = 0; i < 256; i++) + ptr[i] = static_cast(cv::min(255, static_cast(cv::pow(static_cast(ptr[i]) / 255.0f, g) * 255.0f + 0.5f))); +} diff --git a/hgdriver/ImageProcess/ImageApplyAdjustColors.h b/hgdriver/ImageProcess/ImageApplyAdjustColors.h index 83ea595..59a2198 100644 --- a/hgdriver/ImageProcess/ImageApplyAdjustColors.h +++ b/hgdriver/ImageProcess/ImageApplyAdjustColors.h @@ -1,53 +1,65 @@ -#ifndef IMAGE_APPLY_ADJUST_COLOR_H -#define IMAGE_APPLY_ADJUST_COLOR_H - -#include "ImageApply.h" - -class CImageApplyAdjustColors : public CImageApply -{ -public: - - CImageApplyAdjustColors(void); - - /* - * brightness [in]: ȵڣȡֵΧ[-255, 255] - * constrast [in]: ԱȶȵڣȡֵΧ[-128 127] - * gamma [in]: ٤ڣȡֵΧ[0.1, 5.0] - */ - CImageApplyAdjustColors(int brightness, int contrast, float gamma); - - virtual ~CImageApplyAdjustColors(void); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - void setAdjustColors(int brightness, int contrast, float gamma); - - int getContrast() { return m_contrast; } - - int getBrightness() { return m_brightness; } - - double getGamma() { return m_gamma; } - - void setBrightness(int brightness); - - void setContrast(int contrast); - - void setGamma(float gamma); - -private: - - void update_lutData(); - -private: - - int m_brightness; - int m_contrast; - float m_gamma; - cv::Mat lut; -}; - -#endif // !IMAGE_APPLY_ADJUST_COLOR_H - - +/* + * ==================================================== + + * 功能:色彩调整,可以调整伽马、亮度、对比度效果。叠加优先级:亮度 > 对比度 > 伽马 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_ADJUST_COLOR_H +#define IMAGE_APPLY_ADJUST_COLOR_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyAdjustColors : public CImageApply +{ +public: + + CImageApplyAdjustColors(void); + + /* + * brightness [in]: 亮度调节,取值范围[-255, 255] + * constrast [in]: 对比度调节,取值范围[-128, 127] + * gamma [in]: 伽马调节,取值范围[0.1, 5.0] + */ + CImageApplyAdjustColors(int brightness, int contrast, float gamma); + + virtual ~CImageApplyAdjustColors(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + void setAdjustColors(int brightness, int contrast, float gamma); + + int getContrast() { return m_contrast; } + + int getBrightness() { return m_brightness; } + + double getGamma() { return m_gamma; } + + void setBrightness(int brightness); + + void setContrast(int contrast); + + void setGamma(float gamma); + +private: + + void update_lutData(); + +private: + + int m_brightness; + int m_contrast; + float m_gamma; + cv::Mat lut; +}; + +#endif // !IMAGE_APPLY_ADJUST_COLOR_H + + diff --git a/hgdriver/ImageProcess/ImageApplyAutoContrast.cpp b/hgdriver/ImageProcess/ImageApplyAutoContrast.cpp index 4cd0d5f..2278606 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoContrast.cpp +++ b/hgdriver/ImageProcess/ImageApplyAutoContrast.cpp @@ -1,43 +1,43 @@ -#include "ImageApplyAutoContrast.h" -#include -using namespace std; -using namespace cv; - -CImageApplyAutoContrast::CImageApplyAutoContrast() -{ -} - -CImageApplyAutoContrast::~CImageApplyAutoContrast() -{ -} - -void CImageApplyAutoContrast::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.empty()) return; - - if(pDib.channels() == 1) - cv::equalizeHist(pDib,pDib); - else - { - std::vector mats(3); - cv::split(pDib,mats); - for(size_t i = 0; i < mats.size(); i++) - if(!mats[i].empty()) - cv::equalizeHist(mats[i], mats[i]); - cv::merge(mats,pDib); - } -} - -void CImageApplyAutoContrast::apply(std::vector &mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyAutoContrast.h" +#include +using namespace std; +using namespace cv; + +CImageApplyAutoContrast::CImageApplyAutoContrast() +{ +} + +CImageApplyAutoContrast::~CImageApplyAutoContrast() +{ +} + +void CImageApplyAutoContrast::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if(pDib.channels() == 1) + cv::equalizeHist(pDib,pDib); + else + { + std::vector mats(3); + cv::split(pDib,mats); + for(size_t i = 0; i < mats.size(); i++) + if(!mats[i].empty()) + cv::equalizeHist(mats[i], mats[i]); + cv::merge(mats,pDib); + } +} + +void CImageApplyAutoContrast::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyAutoContrast.h b/hgdriver/ImageProcess/ImageApplyAutoContrast.h index d8abf05..8e36a35 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoContrast.h +++ b/hgdriver/ImageProcess/ImageApplyAutoContrast.h @@ -1,32 +1,32 @@ -/* - * ==================================================== - - * ܣԶɫУʵԭΪֱͼ⻯ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 - * 汾ţv1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_AUTO_CONTRAST_H -#define IMAGE_APPLY_AUTO_CONTRAST_H - -#include "ImageApply.h" - -class CImageApplyAutoContrast : public CImageApply -{ -public: - - CImageApplyAutoContrast(); - - virtual ~CImageApplyAutoContrast(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); -private: - -}; -#endif // !IMAGE_APPLY_AUTO_CONTRAST_H +/* + * ==================================================== + + * ܣԶɫУʵԭΪֱͼ⻯ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_AUTO_CONTRAST_H +#define IMAGE_APPLY_AUTO_CONTRAST_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyAutoContrast : public CImageApply +{ +public: + + CImageApplyAutoContrast(); + + virtual ~CImageApplyAutoContrast(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + +}; +#endif // !IMAGE_APPLY_AUTO_CONTRAST_H diff --git a/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp b/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp index 6c4be07..907dfec 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp +++ b/hgdriver/ImageProcess/ImageApplyAutoCrop.cpp @@ -1,393 +1,330 @@ -#include "ImageApplyAutoCrop.h" -#include "ImageProcess_Public.h" - -CImageApplyAutoCrop::CImageApplyAutoCrop() - : m_isCrop(false) - , m_isDesaskew(false) - , m_isFillBlank(false) - , m_isConvexHull(true) - , m_isFillColor(false) - , m_threshold(40) - , m_noise(8) - , m_indent(5) - , m_normalCrop(false) -{ -} - -CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor, - double threshold, int noise, int indent, bool normalCrop) - : m_isCrop(isCrop) - , m_isDesaskew(isDesaskew) - , m_isFillBlank(isFillBlank) - , m_isConvexHull(isConvex) - , m_isFillColor(isFillColor) - , m_threshold(threshold) - , m_noise(noise) - , m_indent(indent) - , m_fixedSize(fixedSize) - , m_normalCrop(normalCrop) -{ -} - -CImageApplyAutoCrop::~CImageApplyAutoCrop() -{ -} - -void matmul(double* mul1, double* mul2, double* dst) -{ - dst[0] = mul1[0] * mul2[0] + mul1[1] * mul2[3] + mul1[2] * mul2[6]; - dst[1] = mul1[0] * mul2[1] + mul1[1] * mul2[4] + mul1[2] * mul2[7]; - dst[2] = mul1[0] * mul2[2] + mul1[1] * mul2[5] + mul1[2] * mul2[8]; - dst[3] = mul1[3] * mul2[0] + mul1[4] * mul2[3] + mul1[5] * mul2[6]; - dst[4] = mul1[3] * mul2[1] + mul1[4] * mul2[4] + mul1[5] * mul2[7]; - dst[5] = mul1[3] * mul2[2] + mul1[4] * mul2[5] + mul1[5] * mul2[8]; - dst[6] = mul1[6] * mul2[0] + mul1[7] * mul2[3] + mul1[8] * mul2[6]; - dst[7] = mul1[6] * mul2[1] + mul1[7] * mul2[4] + mul1[8] * mul2[7]; - dst[8] = mul1[6] * mul2[2] + mul1[7] * mul2[5] + mul1[8] * mul2[8]; -} - -cv::Mat concatenateMatrix(const cv::Mat& first, const cv::Mat& second) -{ - double buffer1[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ; - double buffer2[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ; - cv::Mat mul1(3, 3, CV_64FC1, buffer1); //cv::Mat::eye(3, 3, CV_64F); - cv::Mat mul2(3, 3, CV_64FC1, buffer2); //cv::Mat::eye(3, 3, CV_64F); - cv::Mat mul_r; - first.convertTo(mul_r, CV_64F); - mul_r.row(0).copyTo(mul1.row(0)); - mul_r.row(1).copyTo(mul1.row(1)); - - second.convertTo(mul_r, CV_64F); - mul_r.row(0).copyTo(mul2.row(0)); - mul_r.row(1).copyTo(mul2.row(1)); - - //mul1 = mul2 * mul1; - cv::Mat temp(3, 3, CV_64FC1); - matmul(buffer2, buffer1, (double*)temp.data); - mul1 = temp; - mul_r = first.clone(); - mul1.row(0).copyTo(mul_r.row(0)); - mul1.row(1).copyTo(mul_r.row(1)); - return mul_r; -} - -std::vector comMat() -{ - std::vector mats; - cv::Point2f srcTri[3]; - srcTri[0] = cv::Point2f(1, 1); - srcTri[1] = cv::Point2f(1, 0); - srcTri[2] = cv::Point2f(0, 1); - const float fact = 0.33f; - - float pos[] = { 0, 2 * fact, fact }; - cv::Point2f dstTri[3]; - dstTri[0] = cv::Point2f(1, 1); - dstTri[1] = cv::Point2f(1, 0.5); - dstTri[2] = cv::Point2f(0, 1); - - for (int i = 0; i < 3; i++) - { - dstTri[0] = cv::Point2f(1, 1 + pos[i]); - dstTri[1] = cv::Point2f(1, pos[i]); - dstTri[2] = cv::Point2f(0, 1 + pos[i]); - - mats.push_back(cv::getAffineTransform(srcTri, dstTri)); - } - return mats; -} - -void brightSharp(cv::Mat& src) -{ - const float a = -0.49f; - const float b = 3.0f; - //float kernel_data[] = { - // a, 0, 0, 0, a, - // 0, 0, a, 0, 0, - // 0, a, b, a, 0, - // 0, 0, a, 0, 0, - // a, 0, 0, 0, a }; - - float kernel_data[] = { - 0, a, 0, - a, b, a, - 0, a, 0 - }; - cv::Mat kernel(3, 3, CV_32FC1, kernel_data); - cv::filter2D(src, src, src.depth(), kernel); -} - -void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.empty()) return; - - if (m_normalCrop) - { - cv::Rect roi = cv::Rect((pDib.cols - m_fixedSize.width) / 2, side == 0 ? 75 : 145, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows); - pDib = pDib(roi).clone(); - m_rect = cv::RotatedRect(cv::Point2f(roi.x + roi.width / 2, roi.y + roi.height / 2), cv::Size2f(roi.width, roi.height), 0.0f); - return; - } - - if (!m_isCrop && !m_isDesaskew && !m_isFillBlank && m_fixedSize.empty()) return; - - cv::Mat src = pDib; - cv::Mat thre; - cv::Mat dst; - hg::threshold_Mat(src, thre, m_threshold); - - if (m_noise > 0) - { - cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(m_noise, 1)); - cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element); - } - - if (m_indent > 0) - { - cv::Mat element = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(m_indent, m_indent)); - cv::morphologyEx(thre, thre, cv::MORPH_ERODE, element); - } - - std::vector hierarchy; - std::vector> contours; - - hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); - m_maxContour = hg::getMaxContour(contours, hierarchy); - - if (m_maxContour.size() == 0) - { - thre.release(); - // - if (!m_isCrop) - pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone(); -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply"); -#endif // LOG - return; - } - - thre.release(); - dst.release(); - - cv::RotatedRect rect = hg::getBoundingRect(m_maxContour); - m_rect = rect; - cv::Rect boudingRect = cv::boundingRect(m_maxContour); - boudingRect.x -= 1; - boudingRect.y -= 1; - boudingRect.width += 2; - boudingRect.height += 2; - - if (m_isDesaskew && rect.angle != 0) - { - cv::Point2f srcTri[4], srcTri_temp[3], dstTri[3]; - rect.points(srcTri); - - dstTri[0] = cv::Point2f(0, rect.size.height - 1); - dstTri[1] = cv::Point2f(0, 0); - dstTri[2] = cv::Point2f(rect.size.width - 1, 0); - - srcTri_temp[0] = dstTri[0]; - srcTri_temp[1] = dstTri[1]; - srcTri_temp[2] = dstTri[2]; - cv::Mat warp_mat; - warp_mat = cv::getAffineTransform(srcTri, dstTri); - if (src.channels() == 1) - { - cv::warpAffine(src, dst, warp_mat, rect.size, cv::INTER_LINEAR); - } - else - { - cv::Mat bgr[3]; - cv::split(src, bgr); - auto mats = comMat(); - warp_mat = cv::getAffineTransform(srcTri, dstTri); - warp_mat = concatenateMatrix(mats[0], warp_mat); - - cv::warpAffine(bgr[0], bgr[0], warp_mat, rect.size, cv::INTER_LINEAR); - - warp_mat = cv::getAffineTransform(srcTri, dstTri); - warp_mat = concatenateMatrix(mats[1], warp_mat); - cv::warpAffine(bgr[1], bgr[1], warp_mat, rect.size, cv::INTER_LINEAR); - - warp_mat = cv::getAffineTransform(srcTri, dstTri); - warp_mat = concatenateMatrix(mats[2], warp_mat); - cv::warpAffine(bgr[2], bgr[2], warp_mat, rect.size, cv::INTER_LINEAR); - - cv::merge(bgr, 3, dst); - } - - double* ptr_m = reinterpret_cast(warp_mat.data); - double a = ptr_m[0]; - double b = ptr_m[1]; - double c = ptr_m[2]; - double d = ptr_m[3]; - double e = ptr_m[4]; - double f = ptr_m[5]; - - for (cv::Point& p : m_maxContour) - { - p.x = static_cast(a * p.x + b * p.y + c); - p.y = static_cast(d * p.x + e * p.y + f); - } - - for (std::vector& sub : contours) - for (cv::Point& p : sub) - { - p.x = static_cast(a * p.x + b * p.y + c); - p.y = static_cast(d * p.x + e * p.y + f); - } - } - else - { - auto t_rect = boudingRect & cv::Rect(0, 0, src.cols, src.rows); - dst = src(t_rect); - if (dst.channels() == 3) - { - cv::Mat bgr[3]; - cv::split(dst, bgr); - auto mats = comMat(); - for (int i = 0; i < 3; i++) - cv::warpAffine(bgr[i], bgr[i], mats[i], t_rect.size(), cv::INTER_LINEAR); - cv::merge(bgr, 3, dst); - } - } - - cv::Scalar autoBGColor; - if (m_isFillBlank) - { - if (m_isConvexHull) - { - if (m_maxContour.size() == 0) - { - thre.release(); - //����ǹ̶����棬�뷵�ز��к�ijߴ� - if (!m_isCrop) - pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone(); - return; - } - hg::convexHull(m_maxContour, m_maxContour); - contours.clear(); - contours.push_back(m_maxContour); - } - - contours.push_back(std::vector()); - contours[contours.size() - 1].push_back(cv::Point(-1, dst.rows - 1)); - contours[contours.size() - 1].push_back(cv::Point(-1, -1)); - contours[contours.size() - 1].push_back(cv::Point(dst.cols, -1)); - contours[contours.size() - 1].push_back(cv::Point(dst.cols, dst.rows)); - - autoBGColor = m_isFillColor ? getBackGroudColor(pDib, rect.size.area()) : cv::Scalar(255, 255, 255); - hg::fillPolys(dst, contours, autoBGColor); - } - else - { - m_maxContour.clear(); - m_maxContour.push_back(cv::Point(-1, dst.rows)); - m_maxContour.push_back(cv::Point(-1, -1)); - m_maxContour.push_back(cv::Point(dst.cols, -1)); - m_maxContour.push_back(cv::Point(dst.cols, dst.rows)); - } - - pDib.release(); - if (/*(m_isCrop && side == 0) || (side == 1 && m_fixedSize.width * m_fixedSize.height == 0)*/ m_isCrop) - pDib = dst.clone(); - else - { - pDib = cv::Mat(m_fixedSize, dst.type(), m_isFillBlank ? autoBGColor : cv::Scalar(0, 0, 0)); - - cv::Rect roi; - roi.x = dst.cols > pDib.cols ? (dst.cols - pDib.cols) / 2 : 0; - roi.width = cv::min(pDib.cols, dst.cols); - roi.y = dst.rows > pDib.rows ? (dst.rows - pDib.rows) / 2 : 0; - roi.height = cv::min(pDib.rows, dst.rows); - cv::Rect rect((pDib.cols - roi.width) / 2, (pDib.rows - roi.height) / 2, roi.width, roi.height); - - for (cv::Point& p : m_maxContour) - p += roi.tl(); - dst(roi).copyTo(pDib(rect)); - } -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply8"); -#endif // LOG -} - -void CImageApplyAutoCrop::apply(std::vector& mats, bool isTwoSide) -{ - if (mats.empty()) return; - if (!mats[0].empty()) { - apply(mats[0], 0); - m_rects.push_back(m_rect); - //brightSharp(mats[0]); - } - - if (isTwoSide && mats.size() > 1) - { - cv::Size dSize = m_fixedSize; - if (!mats[0].empty()) - m_fixedSize = mats[0].size(); - if (!mats[1].empty()) { - apply(mats[1], 1); - m_rects.push_back(m_rect); - //brightSharp(mats[1]); - } - - if (!mats[0].empty()) - m_fixedSize = dSize; - } -} - -cv::Scalar CImageApplyAutoCrop::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 CImageApplyAutoCrop::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 - m_threshold; - while (length < length_max) - { - for (size_t i = m_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; -} +#include "ImageApplyAutoCrop.h" +#include "ImageProcess_Public.h" +#include +#include +#include "ImageApplyDispersion.h" + +CImageApplyAutoCrop::CImageApplyAutoCrop() + : m_isCrop(false) + , m_isDesaskew(false) + , m_isFillBlank(false) + , m_isConvexHull(true) + , m_isFillColor(false) + , m_threshold(40) + , m_noise(8) + , m_indent(5) + , m_normalCrop(false) + , m_isDispersion(true) +{ +} + +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) + : m_isCrop(isCrop) + , m_isDesaskew(isDesaskew) + , m_isFillBlank(isFillBlank) + , m_isConvexHull(isConvex) + , m_isFillColor(isFillColor) + , m_threshold(threshold) + , m_noise(noise) + , m_indent(indent) + , m_fixedSize(fixedSize) + , m_normalCrop(normalCrop) + , m_isDispersion(dispersion) +{ +} + +CImageApplyAutoCrop::~CImageApplyAutoCrop() +{ +} + +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); + pDib = dst; +} + +void CImageApplyAutoCrop::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +#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) +{ + int interpolation = flags; + cv::Mat src = _src.getMat(), M0 = _M0.getMat(); + cv::Mat dst = _dst.getMat(); + + if (dst.data == src.data) + src = src.clone(); + + double M[6] = { 0 }; + cv::Mat matM(2, 3, CV_64F, M); + if (interpolation == cv::INTER_AREA) + interpolation = cv::INTER_LINEAR; + + M0.convertTo(matM, matM.type()); + + if (!(flags & cv::WARP_INVERSE_MAP)) + { + double D = M[0] * M[4] - M[1] * M[3]; + D = D != 0 ? 1. / D : 0; + double A11 = M[4] * D, A22 = M[0] * D; + M[0] = A11; M[1] *= -D; + M[3] *= -D; M[4] = A22; + double b1 = -M[0] * M[2] - M[1] * M[5]; + double b2 = -M[3] * M[2] - M[4] * M[5]; + M[2] = b1; M[5] = b2; + } + + cv::hal::warpAffine(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, + 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) +{ + 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, threshold); + return cv::Scalar(bgr[0], bgr[1], bgr[2]); + } + else + return cv::Scalar::all(getBackGroudChannelMean(image, total, threshold)); +} + +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) +{ + if (src.empty()) return; + + if (isNormalCrop) + { + cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows); + dst = src(roi).clone(); + return; + } + + if (!isAutoCrop && !isDesaskew && !isFillBlank && (dWidth <= 0 || dHeight <= 0)) + { + dst = src.clone(); + return; + } + + cv::Mat resizeMat; + cv::Mat thre; + + cv::resize(src, resizeMat, cv::Size(), FX_FY, FX_FY, cv::INTER_NEAREST); + hg::threshold_Mat(resizeMat, thre, threshold); + + if (noise > 0) + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, getStructuringElement(cv::MORPH_RECT, cv::Size(noise * FX_FY, 1)), + cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + std::vector hierarchy; + std::vector> contours; + + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + + for (std::vector& sub : contours) + for (cv::Point& p : sub) + p /= FX_FY; + + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + + if (maxContour.empty()) + { + if (isAutoCrop) + dst = src.clone(); + else + { + cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows); + dst = src(roi).clone(); + } + return; + } + + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + + if (dispersion) + { + cv::Mat mat_dispersion = src(cv::boundingRect(maxContour)); + dispersion_apply.apply(mat_dispersion, 0); + } + + cv::Scalar blankColor; + if (isFillBlank) + if (isColorBlank) + blankColor = getBackGroudColor(resizeMat, rect.size.area() * FX_FY * FX_FY, COLOR_SCALE_THRE); + else + blankColor = cv::Scalar::all(255); + else + blankColor = cv::Scalar::all(0); + + if (isAutoCrop) + if (isDesaskew) + dst = cv::Mat(cv::Size(rect.size), src.type(), blankColor); + else + dst = cv::Mat(rect.boundingRect().size(), src.type(), blankColor); + else + dst = cv::Mat(dHeight, dWidth, src.type(), blankColor); + + cv::Mat dstROI; + if (isDesaskew && rect.angle != 0) + { + cv::Point2f srcTri[4], dstTri[3]; + rect.points(srcTri); + srcTri[0].x -= 1; + srcTri[1].x -= 1; + srcTri[2].x -= 1; + + int w = rect.size.width; + int h = rect.size.height; + int x = (dst.cols - w) / 2; + int y = (dst.rows - h) / 2; + dstTri[0] = cv::Point2f(0, h); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(w, 0); + + dstROI = dst(cv::Rect(x, y, w, h) & cv::Rect(0, 0, dst.cols, dst.rows)); + myWarpAffine(src, dstROI, cv::getAffineTransform(srcTri, dstTri), dstROI.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + } + else + { + cv::Rect bounding = cv::boundingRect(maxContour); + + if (bounding.width > dst.cols) + { + bounding.x += (bounding.width - dst.cols) / 2; + bounding.width = dst.cols; + } + + if (bounding.height > dst.rows) + { + bounding.y += (bounding.height - dst.rows) / 2; + bounding.height = dst.rows; + } + + dstROI = dst(cv::Rect((dst.cols - bounding.width) / 2, (dst.rows - bounding.height) / 2, bounding.width, bounding.height)); + src(bounding).copyTo(dstROI); + } + + if (isFillBlank) + { + if (isConvex) + { + hg::convexHull(maxContour, maxContour); + contours.clear(); + contours.push_back(maxContour); + } + + cv::Point2f srcTri[4], dstTri[3]; + int w, h; + if (isDesaskew && rect.angle != 0) + { + rect.points(srcTri); + srcTri[0].x -= 1; + srcTri[1].x -= 1; + srcTri[2].x -= 1; + w = rect.size.width; + h = rect.size.height; + } + else + { + cv::Rect bounding = rect.boundingRect(); + srcTri[0] = cv::Point(bounding.x, bounding.br().y - 1); + srcTri[1] = cv::Point(bounding.x, bounding.y); + srcTri[2] = cv::Point(bounding.br().x - 1, bounding.y); + w = bounding.width; + h = bounding.height; + } + + dstTri[0] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + h - indent); + dstTri[1] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + indent); + dstTri[2] = cv::Point2f((dstROI.cols - w) / 2 - indent + w, (dstROI.rows - h) / 2 + indent); + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + + double* ptr_m = reinterpret_cast(warp_mat.data); + double a = ptr_m[0]; + double b = ptr_m[1]; + double c = ptr_m[2]; + double d = ptr_m[3]; + double e = ptr_m[4]; + double f = ptr_m[5]; + + int x, y; + for (std::vector& sub : contours) + for (cv::Point& p : sub) + { + x = p.x; + y = p.y; + p.x = static_cast(a * x + b * y + c); + p.y = static_cast(d * x + e * y + f); + } + + contours.push_back(std::vector()); + contours[contours.size() - 1].push_back(cv::Point(-1, dstROI.rows - 1)); + contours[contours.size() - 1].push_back(cv::Point(-1, -1)); + contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, -1)); + contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, dst.rows)); + hg::fillPolys(dstROI, contours, blankColor); + } +} diff --git a/hgdriver/ImageProcess/ImageApplyAutoCrop.h b/hgdriver/ImageProcess/ImageApplyAutoCrop.h index d09d365..9a809c2 100644 --- a/hgdriver/ImageProcess/ImageApplyAutoCrop.h +++ b/hgdriver/ImageProcess/ImageApplyAutoCrop.h @@ -1,112 +1,125 @@ -/* - * ==================================================== - - * 功能:自动裁剪、纠偏、除黑底 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/4/21 v1.0 - 2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用) - 2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度。 - 2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG。 - 2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG。 - 2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏) - 2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底。 - * 版本号:v1.3.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_AUTO_CROP_H -#define IMAGE_APPLY_AUTO_CROP_H - -#include "ImageApply.h" - -class CImageApplyAutoCrop : public CImageApply -{ -public: - CImageApplyAutoCrop(); - - - /* - * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剪 - * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 - * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 - * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像素 - * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true - * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false - * threshold [in]:二值化阈值,取值范围(0, 255),默认40 - * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默认2 - * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5 - * normalCrop [in]:为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式,默认false - */ - 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); - - virtual ~CImageApplyAutoCrop(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - bool isAutoCrop() { return m_isCrop; } - - bool isFillBlank() { return m_isFillBlank; } - - bool isDesaskew() { return m_isDesaskew; } - - bool isConvexHull() { return m_isConvexHull; } - - double threshold() { return m_threshold; } - - const cv::RotatedRect& rotatedROI() { return m_rect; } - - const std::vector& rotatedROIs() { return m_rects; } - - int noise() { return m_noise; } - - int indent() { return m_indent; } - - cv::Size fixedSize() { return m_fixedSize; } - - const std::vector& maxContour() { return m_maxContour; } - - void setAutoCrop(bool enabled) { m_isCrop = enabled; } - - void setFillBlank(bool enabled) { m_isFillBlank = enabled; } - - void setDesaskew(bool enabled) { m_isDesaskew = enabled; } - - void setConvexHull(bool convex) { m_isConvexHull = convex; } - - void setThreshold(double value) { m_threshold = value; } - - void setNoise(int value) { m_noise = value; } - - void setIndent(int value) { m_indent = value; } - - void setFixedSize(cv::Size size) { m_fixedSize = size; } - -private: - cv::Scalar getBackGroudColor(const cv::Mat& image, int total); - - uchar getBackGroudChannelMean(const cv::Mat& gray, int total); - -private: - bool m_isCrop; - bool m_isDesaskew; - bool m_isFillBlank; - bool m_isConvexHull; - bool m_isFillColor; - - double m_threshold; - int m_noise; - int m_indent; - bool m_normalCrop; //为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式 - cv::Size m_fixedSize; - cv::RotatedRect m_rect; - std::vector m_maxContour; - std::vector m_rects; -}; - -#endif // !IMAGE_APPLY_AUTO_CROP_H - +/* + * ==================================================== + + * 功能:自动裁剪、纠偏、除黑底 + * 作者:刘丁绿 + * 生成时间_020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用_ + 2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度 + 2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG + 2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG + 2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏_ + 2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底 + 2021/06/18 v1.3.1 调整默认noise + 2021/07/01 v1.3.2 修复 无裁切情况下,自适应颜色除黑底不生效的BUG + 2021/07/08 v1.3.3 完善流程。当无法定位内容时,且为固定幅面裁切,则返回按照固定幅面进行裁切的结果 + 2021/07/08 v1.3.4 调整参数,让消除背景噪声不对纵向像素造成影响 + 2021/07/09 v1.3.5 增加normalCrop机制,当m_isCrop m_isDesaskew m_isFillBlank均为false时可选用,实现传统裁切 + 2021/07/13 v1.3.6 调整normalCrop逻辑,当normalCrop为true时,m_isCrop m_isDesaskew m_isFillBlank失效 + 2021/07/19 v1.3.7 调整仿射变换模式为INTER_LINEAR + 2021/07/22 v1.3.8 修复第二次寻边,找不到外界轮廓会导致崩溃的BUG + 2021/08/02 v1.3.9 精细化除黑底算法,可以应对只有条纹内容的黑色图像 + 2021/10/08 v1.3.10 优化算法,用腐蚀代替绘制实现缩进,提高整体算法效率 + 2021/10/19 v1.3.11 解决一些极端情况,例如纸张自然0角度,纸张定格在图像顶部的处理 + 2021/10/19 v1.3.12 微调裁切纠偏像素精度 + 2022/04/24 v1.4 重构算法,增加除色散功能 + 2022/05/03 v1.4.1 完善逻辑 + 2022/06/09 v1.4.2 修复获取文稿底色时,threshold值,设为固定值0.5 + * 版本号:v1.4.2 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_AUTO_CROP_H +#define IMAGE_APPLY_AUTO_CROP_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyAutoCrop : public CImageApply +{ +public: + CImageApplyAutoCrop(); + + /* + * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剿 + * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 + * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 + * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像紿 + * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true + * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false + * threshold [in]:二值化阈值,取值范囿0, 255),默访0 + * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默访 + * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默访 + * normalCrop [in]:为true时,m_isCrop m_isDesaskew m_isFillBlank失效,固定裁切采用最传统的裁切方式,默认false + * dispersion [in]:为true时,除色散;false时不除色散。默认为true + */ + 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); + + virtual ~CImageApplyAutoCrop(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + bool isAutoCrop() { return m_isCrop; } + + bool isFillBlank() { return m_isFillBlank; } + + bool isDesaskew() { return m_isDesaskew; } + + bool isConvexHull() { return m_isConvexHull; } + + cv::RotatedRect getROI() { return m_rect; } + + double threshold() { return m_threshold; } + + int noise() { return m_noise; } + + int indent() { return m_indent; } + + cv::Size fixedSize() { return m_fixedSize; } + + const std::vector& maxContour() { return m_maxContour; } + + void setAutoCrop(bool enabled) { m_isCrop = enabled; } + + void setFillBlank(bool enabled) { m_isFillBlank = enabled; } + + void setDesaskew(bool enabled) { m_isDesaskew = enabled; } + + void setConvexHull(bool convex) { m_isConvexHull = convex; } + + void setThreshold(double value) { m_threshold = value; } + + void setNoise(int value) { m_noise = value; } + + void setIndent(int value) { m_indent = value; } + + void setFixedSize(cv::Size size) { m_fixedSize = size; } + + void setDispersion(bool enable) { m_isDispersion = enable; } + +private: + bool m_isCrop; + bool m_isDesaskew; + bool m_isFillBlank; + bool m_isConvexHull; + bool m_isFillColor; + bool m_isDispersion; + + double m_threshold; + int m_noise; + int m_indent; + bool m_normalCrop; //为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方弿 + cv::Size m_fixedSize; + cv::RotatedRect m_rect; + std::vector m_rects; + std::vector m_maxContour; +}; + + +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/ImageProcess/ImageApplyBWBinaray.cpp b/hgdriver/ImageProcess/ImageApplyBWBinaray.cpp index 7995a25..1c29d94 100644 --- a/hgdriver/ImageProcess/ImageApplyBWBinaray.cpp +++ b/hgdriver/ImageProcess/ImageApplyBWBinaray.cpp @@ -1,164 +1,167 @@ -#include "ImageApplyBWBinaray.h" - -CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant) - : m_threshold(threshold) - , m_type(type) - , m_blockSize(blockSize) - , m_constant(constant) - , m_table(new uchar[256]) -{ - memset(m_table, 255, 256); - memset(m_table, 0, static_cast(m_threshold)); -} - -CImageApplyBWBinaray::CImageApplyBWBinaray() - : m_threshold(120) - , m_type(ThresholdType::THRESH_BINARY) - , m_blockSize(25) - , m_constant(5) - , m_table(new uchar[256]) -{ - memset(m_table, 255, 256); - memset(m_table, 0, static_cast(m_threshold)); -} - -CImageApplyBWBinaray::~CImageApplyBWBinaray(void) -{ - delete[] m_table; -} - -void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.empty()) return; - - if (pDib.channels() == 3) - cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); - - //20.12.29 ޸IJΪ51 10 30 235 - //20.12.30 ޸IJΪ51 20 30 235 - // ޸IJΪ17 20 110 235 - cv::Mat integ; - int blockSize = 17;//ߴ - int threshold = 20; - int low = 110; - int up = 235; - int halfSize = blockSize / 2; - int square_blockSize = blockSize * blockSize; - switch (m_type) - { - case ThresholdType::THRESH_BINARY: - cv::integral(pDib, integ, CV_32S); - - for (int j = halfSize; j < integ.rows - halfSize - 1; j++) - { - uchar* data = pDib.ptr(j); - int* idata1 = integ.ptr(j - halfSize); - int* idata2 = integ.ptr(j + halfSize + 1); - for (int i = halfSize; i < integ.cols - halfSize - 1; i++) - { - if (data[i] < low) - data[i] = 0; - else if (data[i] > up) - data[i] = 255; - else - data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255; - } - } - - cv::threshold(pDib(cv::Rect(0, 0, halfSize, pDib.rows)), pDib(cv::Rect(0, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); - cv::threshold(pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); - cv::threshold(pDib(cv::Rect(0, 0, pDib.cols, halfSize)), pDib(cv::Rect(0, 0, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); - cv::threshold(pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); - break; - case ThresholdType::THRESH_OTSU: - cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU); - break; - case ThresholdType::ADAPTIVE_GAUSSIAN: - cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); - break; - case ThresholdType::ADAPTIVE_MEAN: - cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); - break; - case ThresholdType::ERROR_DIFFUSION: - errorDiffuse(pDib); - break; - default: - break; - } -} - -void CImageApplyBWBinaray::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} - -void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image) -{ - if (image.rows < 3 || image.cols < 3) - { - cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY); - return; - } - - cv::Mat dst; - image.convertTo(dst, CV_16S); - - size_t rows = static_cast(image.rows) - 1; - size_t cols = static_cast(image.cols) - 1; - - short** pixels_dst = new short* [static_cast(image.rows)]; - for (int i = 0; i < image.rows; i++) - pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(dst.step)); - - short error; - for (size_t y = 0; y < rows; y++) - for (size_t x = 1; x < cols; x++) - { - short dstPix = pixels_dst[y][x]; - if (dstPix >= m_threshold) - { - pixels_dst[y][x] = 255; - error = dstPix - 255; - } - else - { - pixels_dst[y][x] = 0; - error = dstPix; - } - - pixels_dst[y][x + 1] += error * 1 / 16; - pixels_dst[y + 1][x - 1] += error * 1 / 16; - pixels_dst[y + 1][x] += error * 1 / 16; - pixels_dst[y + 1][x + 1] += error * 1 / 16; - } - image.release(); - dst.convertTo(image, CV_8U); - - rows++; - uchar* ptr = image.data; - size_t step = image.step; - size_t offset; - for (size_t y = 0; y < rows; y++) - { - offset = y * step; - ptr[offset] = m_table[ptr[offset]]; - offset += cols; - ptr[offset] = m_table[ptr[offset]]; - } - - cols++; - ptr = image.data + step * (rows - 1); - for (size_t x = 0; x < cols; x++) - ptr[x] = m_table[ptr[x]]; - - delete[] pixels_dst; -} \ No newline at end of file +#include "ImageApplyBWBinaray.h" + +CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant) + : m_threshold(threshold) + , m_type(type) + , m_blockSize(blockSize) + , m_constant(constant) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::CImageApplyBWBinaray() + : m_threshold(120) + , m_type(ThresholdType::THRESH_BINARY) + , m_blockSize(51) + , m_constant(41) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::~CImageApplyBWBinaray(void) +{ + delete[] m_table; +} + +#define THRESHOLD_LOW 30 +#define THRESHOLD_UP 245 +void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if (pDib.channels() == 3) + cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + cv::Mat integ; + int blockSize = m_blockSize;//邻域尺寸 + int threshold = m_constant; + int low = THRESHOLD_LOW; + int up = THRESHOLD_UP; + int halfSize = blockSize / 2; + int square_blockSize = blockSize * blockSize; + switch (m_type) + { + case ThresholdType::THRESH_BINARY: + cv::integral(pDib, integ, CV_32S); + + for (int j = halfSize; j < integ.rows - halfSize - 1; j++) + { + uchar* data = pDib.ptr(j); + int* idata1 = integ.ptr(j - halfSize); + int* idata2 = integ.ptr(j + halfSize + 1); + for (int i = halfSize; i < integ.cols - halfSize - 1; i++) + { + if (data[i] < low) + data[i] = 0; + else if (data[i] > up) + data[i] = 255; + else + data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255; + } + } + + cv::threshold(pDib(cv::Rect(0, 0, halfSize, pDib.rows)), pDib(cv::Rect(0, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, 0, pDib.cols, halfSize)), pDib(cv::Rect(0, 0, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + break; + case ThresholdType::THRESH_OTSU: + cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU); + break; + case ThresholdType::ADAPTIVE_GAUSSIAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ADAPTIVE_MEAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ERROR_DIFFUSION: + errorDiffuse(pDib); + break; + default: + break; + } + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyBWBinaray apply"); +#endif // LOG +} + +void CImageApplyBWBinaray::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image) +{ + if (image.rows < 3 || image.cols < 3) + { + cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY); + return; + } + + cv::Mat dst; + image.convertTo(dst, CV_16S); + + size_t rows = static_cast(image.rows) - 1; + size_t cols = static_cast(image.cols) - 1; + + short** pixels_dst = new short* [static_cast(image.rows)]; + for (int i = 0; i < image.rows; i++) + pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(dst.step)); + + short error; + for (size_t y = 0; y < rows; y++) + for (size_t x = 1; x < cols; x++) + { + short dstPix = pixels_dst[y][x]; + if (dstPix >= m_threshold) + { + pixels_dst[y][x] = 255; + error = dstPix - 255; + } + else + { + pixels_dst[y][x] = 0; + error = dstPix; + } + + pixels_dst[y][x + 1] += error * 1 / 16; + pixels_dst[y + 1][x - 1] += error * 1 / 16; + pixels_dst[y + 1][x] += error * 1 / 16; + pixels_dst[y + 1][x + 1] += error * 1 / 16; + } + image.release(); + dst.convertTo(image, CV_8U); + + rows++; + uchar* ptr = image.data; + size_t step = image.step; + size_t offset; + for (size_t y = 0; y < rows; y++) + { + offset = y * step; + ptr[offset] = m_table[ptr[offset]]; + offset += cols; + ptr[offset] = m_table[ptr[offset]]; + } + + cols++; + ptr = image.data + step * (rows - 1); + for (size_t x = 0; x < cols; x++) + ptr[x] = m_table[ptr[x]]; + + delete[] pixels_dst; +} diff --git a/hgdriver/ImageProcess/ImageApplyBWBinaray.h b/hgdriver/ImageProcess/ImageApplyBWBinaray.h index 59001a4..56bb0bc 100644 --- a/hgdriver/ImageProcess/ImageApplyBWBinaray.h +++ b/hgdriver/ImageProcess/ImageApplyBWBinaray.h @@ -1,86 +1,87 @@ -/* - * ==================================================== - - * 功能:二值化处理 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法 - 2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果 - 2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果 - 2020/12/21 v1.3.1 调整自适应阈值上下限 - 2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25 - * 版本号:v1.3.2 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_BW_BINARAY_H -#define IMAGE_APPLY_BW_BINARAY_H - -#include "ImageApply.h" - -class CImageApplyBWBinaray:public CImageApply -{ -public: - - enum class ThresholdType - { - THRESH_BINARY = 0, //传统二值化 - THRESH_OTSU, //大津阈值 - - ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值 - ADAPTIVE_MEAN, //均值局部自适应阈值 - - ERROR_DIFFUSION //错误扩散 - }; - - /* - * type [in]:二值化模式 - * threshold [in]:阈值,当选择THRESH_OTSU时无效 - * blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,表示局部观察块的宽度 - * constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,与blockSize形成比例关系,作为局部筛选阈值 - */ - CImageApplyBWBinaray(ThresholdType type, int threshold = 120, int blockSize = 25, int constant = 5); - - CImageApplyBWBinaray(); - - virtual ~CImageApplyBWBinaray(void); - - virtual void apply(cv::Mat& pDib,int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - double getThreshold() { return m_threshold; } - - ThresholdType getThresholdType() { return m_type; } - - int getBlockSize() { return m_blockSize; } - - double getConstant() { return m_constant; } - - void setThreshold(double value) { m_threshold = value; } - - void setThresholdType(ThresholdType type) { m_type = type; } - - void setBlockSize(int value) { m_blockSize = value; } - - void setConstant(double value) { m_constant = value; } - -private: - - void errorDiffuse(cv::Mat& image); - -private: - double m_threshold; - - ThresholdType m_type; - - int m_blockSize; - - double m_constant; - - uchar* m_table; -}; - -#endif //!IMAGE_APPLY_BW_BINARAY_H - +/* + * ==================================================== + + * 功能:二值化处理 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法 + 2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果 + 2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果 + 2020/12/21 v1.3.1 调整自适应阈值上下限 + 2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25 + 2022/05/25 v1.3.3 调整blockSize和constant,对THRESH_BINARY同样有效 + * 版本号:v1.3.3 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_BW_BINARAY_H +#define IMAGE_APPLY_BW_BINARAY_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyBWBinaray:public CImageApply +{ +public: + + enum class ThresholdType + { + THRESH_BINARY = 0, //传统二值化 + THRESH_OTSU, //大津阈值 + + ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值 + ADAPTIVE_MEAN, //均值局部自适应阈值 + + ERROR_DIFFUSION //错误扩散 + }; + + /* + * type [in]:二值化模式 + * threshold [in]:阈值,当选择THRESH_OTSU时无效 + * blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,表示局部观察块的宽度 + * constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,与blockSize形成比例关系,作为局部筛选阈值 + */ + CImageApplyBWBinaray(ThresholdType type, int threshold = 120, int blockSize = 51, int constant = 41); + + CImageApplyBWBinaray(); + + virtual ~CImageApplyBWBinaray(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + double getThreshold() { return m_threshold; } + + ThresholdType getThresholdType() { return m_type; } + + int getBlockSize() { return m_blockSize; } + + double getConstant() { return m_constant; } + + void setThreshold(double value) { m_threshold = value; } + + void setThresholdType(ThresholdType type) { m_type = type; } + + void setBlockSize(int value) { m_blockSize = value; } + + void setConstant(double value) { m_constant = value; } + +private: + + void errorDiffuse(cv::Mat& image); + +private: + double m_threshold; + + ThresholdType m_type; + + int m_blockSize; + + double m_constant; + + uchar* m_table; +}; + +#endif //!IMAGE_APPLY_BW_BINARAY_H + diff --git a/hgdriver/ImageProcess/ImageApplyChannel.cpp b/hgdriver/ImageProcess/ImageApplyChannel.cpp index 1b9180c..e18ba75 100644 --- a/hgdriver/ImageProcess/ImageApplyChannel.cpp +++ b/hgdriver/ImageProcess/ImageApplyChannel.cpp @@ -1,127 +1,127 @@ -#include "ImageApplyChannel.h" -#include "ImageApplyAdjustColors.h" - -CImageApplyChannel::CImageApplyChannel() - : m_channel(Invalid) - , colors(new CImageApplyAdjustColors(0, 30, 1.0)) -{ -} - -CImageApplyChannel::CImageApplyChannel(Channel channel) - : m_channel(channel) - , colors(new CImageApplyAdjustColors(0, 30, 1.0)) -{ -} - -CImageApplyChannel::~CImageApplyChannel() -{ - if (colors != nullptr) delete colors; -} - -void CImageApplyChannel::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.empty()) return; - - cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1); - switch (m_channel) - { - case Red: - cv::extractChannel(pDib, dst, 2); - colors->apply(pDib, side); - break; - case Green: - cv::extractChannel(pDib, dst, 1); - break; - case Blue: - cv::extractChannel(pDib, dst, 0); - break; - case All: - colourless(pDib, dst, 80); - break; - case Except_Red: - except_channel(pDib, dst, 2); - break; - case Except_Green: - except_channel(pDib, dst, 1); - break; - case Except_Blue: - except_channel(pDib, dst, 0); - break; - default: - break; - } - pDib.release(); - pDib = dst; - -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply"); -#endif // LOG -} - -void CImageApplyChannel::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} - -void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel) -{ - cv::Mat mv[3]; - cv::split(src, mv); - cv::Mat mask, mask1, mask2; - switch (channel) - { - case 0: - mask1 = mv[0] - mv[1]; - mask2 = mv[0] - mv[2]; - break; - case 1: - mask1 = mv[1] - mv[0]; - mask2 = mv[1] - mv[2]; - break; - case 2: - mask1 = mv[2] - mv[1]; - mask2 = mv[2] - mv[0]; - break; - default: - break; - } - cv::min(mask1, mask2, mask); - - cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY); - dst -= mask; -} - -void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold) -{ - if (src.channels() != 3) - { - dst = src; - return; - } - - cv::Mat hsv; - cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL); - cv::Mat mv_hsv[3]; - cv::split(hsv, mv_hsv); - size_t total = mv_hsv[1].total(); - uchar* ptr_s = mv_hsv[1].data; - uchar* ptr_v = mv_hsv[2].data; - for (size_t i = 0; i < total; i++) - if (ptr_s[i] > threshold) - { - ptr_s[i] = 0; - ptr_v[i] = 255; - } - cv::merge(mv_hsv, 3, hsv); - cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL); - cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY); -} +#include "ImageApplyChannel.h" +#include "ImageApplyAdjustColors.h" + +CImageApplyChannel::CImageApplyChannel() + : m_channel(Invalid) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::CImageApplyChannel(Channel channel) + : m_channel(channel) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::~CImageApplyChannel() +{ + if (colors != nullptr) delete colors; +} + +void CImageApplyChannel::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1); + switch (m_channel) + { + case Red: + cv::extractChannel(pDib, dst, 2); + colors->apply(pDib, side); + break; + case Green: + cv::extractChannel(pDib, dst, 1); + break; + case Blue: + cv::extractChannel(pDib, dst, 0); + break; + case All: + colourless(pDib, dst, 80); + break; + case Except_Red: + except_channel(pDib, dst, 2); + break; + case Except_Green: + except_channel(pDib, dst, 1); + break; + case Except_Blue: + except_channel(pDib, dst, 0); + break; + default: + break; + } + pDib.release(); + pDib = dst; + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply"); +#endif // LOG +} + +void CImageApplyChannel::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel) +{ + cv::Mat mv[3]; + cv::split(src, mv); + cv::Mat mask, mask1, mask2; + switch (channel) + { + case 0: + mask1 = mv[0] - mv[1]; + mask2 = mv[0] - mv[2]; + break; + case 1: + mask1 = mv[1] - mv[0]; + mask2 = mv[1] - mv[2]; + break; + case 2: + mask1 = mv[2] - mv[1]; + mask2 = mv[2] - mv[0]; + break; + default: + break; + } + cv::min(mask1, mask2, mask); + + cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY); + dst -= mask; +} + +void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold) +{ + if (src.channels() != 3) + { + dst = src; + return; + } + + cv::Mat hsv; + cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL); + cv::Mat mv_hsv[3]; + cv::split(hsv, mv_hsv); + size_t total = mv_hsv[1].total(); + uchar* ptr_s = mv_hsv[1].data; + uchar* ptr_v = mv_hsv[2].data; + for (size_t i = 0; i < total; i++) + if (ptr_s[i] > threshold) + { + ptr_s[i] = 0; + ptr_v[i] = 255; + } + cv::merge(mv_hsv, 3, hsv); + cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL); + cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY); +} diff --git a/hgdriver/ImageProcess/ImageApplyChannel.h b/hgdriver/ImageProcess/ImageApplyChannel.h index 1e52fa9..0bc9220 100644 --- a/hgdriver/ImageProcess/ImageApplyChannel.h +++ b/hgdriver/ImageProcess/ImageApplyChannel.h @@ -1,65 +1,65 @@ -/* - * ==================================================== - - * 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:v1.0 2020/4/21 - v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。 - v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。 - v1.3 2021/5/24 替换红色增强算法方案。 - * 版本号:v1.3 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_CHANNEL_H -#define IMAGE_APPLY_CHANNEL_H - -#include "ImageApply.h" - -class CImageApplyAdjustColors; -class CImageApplyChannel : public CImageApply -{ -public: - - typedef enum channel - { - Red, //红色通道 - Green, //绿色通道 - Blue, //蓝色通道 - All, //去除所有HSV色彩结构中,S大于80的色彩 - Invalid, //无效 - Except_Red, //绿蓝色通道混合 - Except_Green, //红蓝色通道混合 - Except_Blue //红绿色通道混合 - }Channel; - -public: - - CImageApplyChannel(); - - /* - * channel [in]:通道模式 - * */ - CImageApplyChannel(Channel channel); - - virtual ~CImageApplyChannel(void); - - virtual void apply(cv::Mat& pDib,int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - -private: - - void except_channel(const cv::Mat& src, cv::Mat& dst, int channel); - - void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80); - -private: - - Channel m_channel; - CImageApplyAdjustColors* colors; -}; - -#endif // !IMAGE_APPLY_CHANNEL_H +/* + * ==================================================== + + * 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:v1.0 2020/4/21 + v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。 + v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。 + v1.3 2021/5/24 替换红色增强算法方案。 + * 版本号:v1.3 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CHANNEL_H +#define IMAGE_APPLY_CHANNEL_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class GIMGPROC_LIBRARY_API CImageApplyChannel : public CImageApply +{ +public: + + typedef enum channel + { + Red, //红色通道 + Green, //绿色通道 + Blue, //蓝色通道 + All, //去除所有HSV色彩结构中,S大于80的色彩 + Invalid, //无效 + Except_Red, //绿蓝色通道混合 + Except_Green, //红蓝色通道混合 + Except_Blue //红绿色通道混合 + }Channel; + +public: + + CImageApplyChannel(); + + /* + * channel [in]:通道模式 + * */ + CImageApplyChannel(Channel channel); + + virtual ~CImageApplyChannel(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + void except_channel(const cv::Mat& src, cv::Mat& dst, int channel); + + void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80); + +private: + + Channel m_channel; + CImageApplyAdjustColors* colors; +}; + +#endif // !IMAGE_APPLY_CHANNEL_H diff --git a/hgdriver/ImageProcess/ImageApplyColorRecognition.cpp b/hgdriver/ImageProcess/ImageApplyColorRecognition.cpp index d85896b..e276eee 100644 --- a/hgdriver/ImageProcess/ImageApplyColorRecognition.cpp +++ b/hgdriver/ImageProcess/ImageApplyColorRecognition.cpp @@ -1,126 +1,155 @@ -#include "ImageApplyColorRecognition.h" -#include "ImageApplyHeaders.h" - -static CImageApplyBWBinaray m_bw; -static CImageApplyAdjustColors m_ac(0, 50, 1.0f); - -/// -/// ͼǷDzɫǰ߼ԺɫؽжϣںɫΪɫΪDzɫ -/// -/// ͼ -/// trueΪɫfalseΪDzɫ -bool isColor(const cv::Mat& image) -{ - if (image.channels() != 3) return false; - - cv::Mat pDib_resize; - cv::resize(image, pDib_resize, cv::Size(image.cols / 9, image.rows / 9), 0, 0, cv::INTER_AREA); - - cv::Mat hsv; - cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL); - std::vector hsv_channels; - cv::split(hsv, hsv_channels); - - cv::Mat range_h1, range_h2, range_s, range_v; - cv::inRange(hsv_channels[0], 0, 85, range_h1); - cv::inRange(hsv_channels[0], 170, 255, range_h2); - cv::inRange(hsv_channels[1], 60, 255, range_s); - cv::inRange(hsv_channels[2], 100, 255, range_v); - - cv::Mat thre = (range_h1 | range_h2) & range_s & range_v; - return (cv::sum(thre)[0] / 255)> 4; -} - -bool isGray(const cv::Mat& image) -{ - if (image.channels() == 3) return true; - - cv::Mat image_clone; - cv::resize(image, image_clone, cv::Size(), 0.25, 0.25); - int channels[] = { 0 }; - int histsize[] = { 256 }; - float range[] = { 0, 256 }; - const float* histRanges[] = { range }; - cv::Mat hist; - cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, histsize, histRanges, true, false); - - float pixel_count0 = hist.at(0, 0); - float pixel_count255 = hist.at(255, 0); - float total = image_clone.total(); - - return ((pixel_count0 + pixel_count255) / total) > 0.95; -} - -CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode) - : m_mode(mode) -{ -} - -CImageApplyColorRecognition::~CImageApplyColorRecognition(void) -{ -} - -void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side) -{ - //жǷҪжDzɫ - if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono) - { - //Dzɫֱ˳ - if (isColor(pDib)) - { - m_result = Color; - return; - } - } - - if (pDib.channels() == 3) - cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); - - if (m_mode == Color_Gray) - { - m_result = Gray; - return; - } - - if (m_mode == Color_Mono) - { - m_bw.apply(pDib, side); - m_result = Mono; - return; - } - - if (isGray(pDib)) - m_result = Gray; - else - { - m_bw.apply(pDib, side); - m_result = Mono; - } -} - -void CImageApplyColorRecognition::apply(std::vector& mats, bool isTwoSide) -{ - m_results.clear(); - if (mats.empty()) return; - - if (!mats[0].empty()) - apply(mats[0], 0); - - m_results.push_back(m_result); - - if (isTwoSide && mats.size() > 1) - if (!mats[1].empty()) - apply(mats[1], 1); - - m_results.push_back(m_result); -} - -CImageApplyColorRecognition::ColorType CImageApplyColorRecognition::getResult() -{ - return m_result; -} - -std::vector CImageApplyColorRecognition::getResults() -{ - return m_results; -} +#include "ImageApplyColorRecognition.h" +#include "ImageApplyHeaders.h" + +static CImageApplyBWBinaray m_bw; +static CImageApplyAdjustColors m_ac(0, 50, 1.0f); + +/// +/// ͼǷDzɫǰ߼ԺɫؽжϣںɫΪɫΪDzɫ +/// +/// ͼ +/// trueΪɫfalseΪDzɫ +bool isColor(const cv::Mat& image) +{ + if (image.channels() != 3) return false; + + cv::Mat pDib_resize; + cv::resize(image, pDib_resize, cv::Size(image.cols / 4, image.rows / 4), 0, 0, cv::INTER_NEAREST); + + cv::Mat hsv; + cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL); + std::vector hsv_channels; + cv::split(hsv, hsv_channels); + + cv::Mat range_s1, range_s2; + cv::inRange(hsv_channels[1], 220, 255, range_s1); //Ͷ[220, 255] + cv::inRange(hsv_channels[1], 50, 220, range_s2); //Ͷ[50, 220] +#if 0 + cv::imwrite("range_s1.bmp", range_s1); + cv::imwrite("range_s2.bmp", range_s2); +#endif + double sum = cv::sum(range_s1)[0] / 255; + double total = range_s1.total(); + + // if (sum / total > 0.0001) + if (sum / total > 0.001) + return true; + sum += cv::sum(range_s2)[0] / 255; + // if (sum / total > 0.001) + if (sum / total > 0.03) + return true; + return false; +} + +bool isGray(const cv::Mat& image) +{ + //if (image.channels() == 3) return true; + + //cv::Mat image_clone; + //cv::resize(image, image_clone, cv::Size(), 0.25, 0.25); + //int channels[] = { 0 }; + //int histsize[] = { 256 }; + //float range[] = { 0, 256 }; + //const float* histRanges[] = { range }; + //cv::Mat hist; + //cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, histsize, histRanges, true, false); + //float pixels[256] = { 0 }; + //for (size_t i = 0; i < 256; i++) + // pixels[i] = hist.at(i, 0); + + + //float sum = 0; + //for (size_t i = 0; i < 40; i++) + //{ + + //} + //float pixel_count0 = hist.at(0, 0); + //float pixel_count255 = hist.at(255, 0); + //float total = image_clone.total(); + + //return ((pixel_count0 + pixel_count255) / total) > 0.95; + return false; +} + +CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode) + : m_mode(mode) +{ +} + +CImageApplyColorRecognition::~CImageApplyColorRecognition(void) +{ +} + +void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side) +{ + if (pDib.channels() != 3) + { + m_result = Gray; + return; + } + m_result = isColor(pDib) ? Color : Gray; + if (m_result == Gray && pDib.channels() == 3) + cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + //жǷҪжDzɫ + //if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono) + //{ + // //Dzɫֱ˳ + // if (isColor(pDib)) + // { + // m_result = Color; + // return; + // } + //} + + //if (pDib.channels() == 3) + // cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + //if (m_mode == Color_Gray) + //{ + // m_result = Gray; + // return; + //} + + //if (m_mode == Color_Mono) + //{ + // m_bw.apply(pDib, side); + // m_result = Mono; + // return; + //} + + //if (isGray(pDib)) + // m_result = Gray; + //else + //{ + // m_bw.apply(pDib, side); + // m_result = Mono; + //} +} + +void CImageApplyColorRecognition::apply(std::vector& mats, bool isTwoSide) +{ + m_results.clear(); + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + m_results.push_back(m_result); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); + + m_results.push_back(m_result); +} + +CImageApplyColorRecognition::ColorType CImageApplyColorRecognition::getResult() +{ + return m_result; +} + +std::vector CImageApplyColorRecognition::getResults() +{ + return m_results; +} diff --git a/hgdriver/ImageProcess/ImageApplyColorRecognition.h b/hgdriver/ImageProcess/ImageApplyColorRecognition.h index e1361f3..d0cbfb9 100644 --- a/hgdriver/ImageProcess/ImageApplyColorRecognition.h +++ b/hgdriver/ImageProcess/ImageApplyColorRecognition.h @@ -1,68 +1,68 @@ -/* - * ==================================================== - - * 功能:色彩识别,将识别会“灰度”的24位图转化为256色8位图, 把识别为“黑白”图转化为二值化的8位图 - * 作者:刘丁维 - * 生成时间:2020/7/17 - * 最近修改时间:2021/04/19 - * 版本号:v1.0 2020/7/17 - * v1.1 2020/12/15 调整策略,仅判断红色像素,存在红色像素为彩色,否则为灰度;删除输出结果,直接转换图像。 - * v1.2 2020/12/16 增加颜色限制模式(输出结果只可能两种),增加结果访问接口 - * v1.3 2021/04/19 修改识别策略,能够识别占比1‰的彩色图像。只区分彩色和灰度图。 - * v1.4 2021/06/18 调整二级色彩区间,从原来的[90, 200]调整为[50, 200]。 - * ==================================================== - */ - -#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H -#define IMAGE_APPLY_COLOR_RECOGNITION_H - -#include "ImageApply.h" - -class CImageApplyColorRecognition : public CImageApply -{ -public: - - //色彩识别模式 - enum ColorRecognitionMode - { - AllColor, //全色模式 识别结果可能会是彩色、灰度、黑白 - Color_Gray, //彩色灰度模式 识别结果只会是彩色或者灰度 - Color_Mono, //彩色黑白模式 识别结果只会是彩色或者黑白 - Gray_Mono //灰度黑白模式 识别结果只会是灰度或者黑白 - }; - - //色彩类型 - enum ColorType - { - Color, //彩色 - Gray, //灰度 - Mono //黑白 - }; -public: - CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor); - - virtual ~CImageApplyColorRecognition(void); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - /// - /// 获取图片色彩类型。配合void apply(cv::Mat&, int)接口使用 - /// - /// 色彩类型 - ColorType getResult(); - - /// - /// 获取图片色彩类型。配合void apply(std::vector&, int)接口使用 - /// - /// 色彩类型数组 - std::vector getResults(); - -private: - ColorType m_result; - std::vector m_results; - ColorRecognitionMode m_mode; -}; - -#endif // !IMAGE_APPLY_CONCATENATION_H +/* + * ==================================================== + + * ܣɫʶ𣬽ʶᡰҶȡ24λͼתΪ256ɫ8λͼ ʶΪڰסͼתΪֵ8λͼ + * ߣά + * ʱ䣺2020/7/17 + * ޸ʱ䣺2021/04/19 + * 汾ţv1.0 2020/7/17 + * v1.1 2020/12/15 ԣжϺɫأںɫΪɫΪҶȣɾֱתͼ + * v1.2 2020/12/16 ɫģʽֻ֣ӽʽӿ + * v1.3 2021/04/19 ޸ʶԣܹʶռ1IJɫͼֲֻɫͻҶͼ + * v1.4 2021/06/18 ɫ䣬ԭ[90, 200]Ϊ[50, 200] + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H +#define IMAGE_APPLY_COLOR_RECOGNITION_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyColorRecognition : public CImageApply +{ +public: + + //ɫʶģʽ + enum ColorRecognitionMode + { + AllColor, //ȫɫģʽ ʶܻDzɫҶȡڰ + Color_Gray, //ɫҶģʽ ʶֻDzɫ߻Ҷ + Color_Mono, //ɫڰģʽ ʶֻDzɫߺڰ + Gray_Mono //ҶȺڰģʽ ʶֻǻҶȻߺڰ + }; + + //ɫ + enum ColorType + { + Color, //ɫ + Gray, //Ҷ + Mono //ڰ + }; +public: + CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor); + + virtual ~CImageApplyColorRecognition(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /// + /// ȡͼƬɫ͡void apply(cv::Mat&, int)ӿʹ + /// + /// ɫ + ColorType getResult(); + + /// + /// ȡͼƬɫ͡void apply(std::vector&, int)ӿʹ + /// + /// ɫ + std::vector getResults(); + +private: + ColorType m_result; + std::vector m_results; + ColorRecognitionMode m_mode; +}; + +#endif // !IMAGE_APPLY_CONCATENATION_H diff --git a/hgdriver/ImageProcess/ImageApplyConcatenation.cpp b/hgdriver/ImageProcess/ImageApplyConcatenation.cpp index be8bd0a..5f00185 100644 --- a/hgdriver/ImageProcess/ImageApplyConcatenation.cpp +++ b/hgdriver/ImageProcess/ImageApplyConcatenation.cpp @@ -1,108 +1,108 @@ -#include "ImageApplyConcatenation.h" - -CImageApplyConcatenation::CImageApplyConcatenation() - : m_direction(autoDirection) - , m_BG_color(0, 0, 0) -{ -} - -CImageApplyConcatenation::CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& background) - : m_direction(dir) - , m_BG_color(background) -{ -} - -CImageApplyConcatenation::~CImageApplyConcatenation(void) -{ -} - -void CImageApplyConcatenation::apply(cv::Mat& pDib, int side) -{ - (void)pDib; - (void)side; -} - -void CImageApplyConcatenation::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - if (mats.size() < 2) - { - mats.clear(); - return; - } - - ConcatMode direction; - if (m_direction == ConcatMode::autoDirection) - direction = (mats[0].cols > mats[0].rows) ? ConcatMode::vertical : ConcatMode::horizontal; - else - direction = m_direction; - cv::Mat dst = concat(mats[0], mats[1], direction); - mats.clear(); - mats.push_back(dst); -} - -cv::Mat CImageApplyConcatenation::concat(cv::Mat &front, cv::Mat &back, ConcatMode direction) -{ - cv::Mat dst; - if (direction == horizontal) - { -#if 0 - int top, bottom; - if (front.rows > back.rows) - { - top = (front.rows - back.rows) / 2; - bottom = front.rows - back.rows - top; - cv::copyMakeBorder(back, back, top, bottom, 0, 0, cv::BORDER_CONSTANT); - } - else if (front.rows < back.rows) - { - top = (back.rows - front.rows) / 2; - bottom = back.rows - front.rows - top; - cv::copyMakeBorder(front, front, top, bottom, 0, 0, cv::BORDER_CONSTANT); - } - cv::hconcat(front, back, dst); -#else - int width = cv::max(front.cols, back.cols) * 2; - int height = cv::max(front.rows, back.rows); - - dst = cv::Mat(height, width, front.type(), m_BG_color); - front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); - int offset = front.cols; - front.release(); - back.copyTo(dst(cv::Rect(offset, 0, back.cols, back.rows))); - back.release(); -#endif - } - else if (direction == vertical) - { -#if 0 - int left, right; - if (front.cols > back.cols) - { - left = (front.cols - back.cols) / 2; - right = front.cols - back.cols - left; - cv::copyMakeBorder(back, back, 0, 0, left, right, cv::BORDER_CONSTANT); - } - else if (front.cols < back.cols) - { - left = (back.cols - front.cols) / 2; - right = back.cols - front.cols - left; - cv::copyMakeBorder(front, front, 0, 0, left, right, cv::BORDER_CONSTANT); - } - cv::vconcat(front, back, dst); -#else - int width = cv::max(front.cols, back.cols); - int height = cv::max(front.rows, back.rows) * 2; - - dst = cv::Mat(height, width, front.type(), m_BG_color); - front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); - int offset = front.rows; - front.release(); - back.copyTo(dst(cv::Rect(0, offset, back.cols, back.rows))); - back.release(); -#endif - } - //front.release(); - //back.release(); - return dst; -} +#include "ImageApplyConcatenation.h" + +CImageApplyConcatenation::CImageApplyConcatenation() + : m_direction(autoDirection) + , m_BG_color(0, 0, 0) +{ +} + +CImageApplyConcatenation::CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& background) + : m_direction(dir) + , m_BG_color(background) +{ +} + +CImageApplyConcatenation::~CImageApplyConcatenation(void) +{ +} + +void CImageApplyConcatenation::apply(cv::Mat& pDib, int side) +{ + (void)pDib; + (void)side; +} + +void CImageApplyConcatenation::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + if (mats.size() < 2) + { + mats.clear(); + return; + } + + ConcatMode direction; + if (m_direction == ConcatMode::autoDirection) + direction = (mats[0].cols > mats[0].rows) ? ConcatMode::vertical : ConcatMode::horizontal; + else + direction = m_direction; + cv::Mat dst = concat(mats[0], mats[1], direction); + mats.clear(); + mats.push_back(dst); +} + +cv::Mat CImageApplyConcatenation::concat(cv::Mat &front, cv::Mat &back, ConcatMode direction) +{ + cv::Mat dst; + if (direction == horizontal) + { +#if 0 + int top, bottom; + if (front.rows > back.rows) + { + top = (front.rows - back.rows) / 2; + bottom = front.rows - back.rows - top; + cv::copyMakeBorder(back, back, top, bottom, 0, 0, cv::BORDER_CONSTANT); + } + else if (front.rows < back.rows) + { + top = (back.rows - front.rows) / 2; + bottom = back.rows - front.rows - top; + cv::copyMakeBorder(front, front, top, bottom, 0, 0, cv::BORDER_CONSTANT); + } + cv::hconcat(front, back, dst); +#else + int width = cv::max(front.cols, back.cols) * 2; + int height = cv::max(front.rows, back.rows); + + dst = cv::Mat(height, width, front.type(), m_BG_color); + front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); + int offset = front.cols; + front.release(); + back.copyTo(dst(cv::Rect(offset, 0, back.cols, back.rows))); + back.release(); +#endif + } + else if (direction == vertical) + { +#if 0 + int left, right; + if (front.cols > back.cols) + { + left = (front.cols - back.cols) / 2; + right = front.cols - back.cols - left; + cv::copyMakeBorder(back, back, 0, 0, left, right, cv::BORDER_CONSTANT); + } + else if (front.cols < back.cols) + { + left = (back.cols - front.cols) / 2; + right = back.cols - front.cols - left; + cv::copyMakeBorder(front, front, 0, 0, left, right, cv::BORDER_CONSTANT); + } + cv::vconcat(front, back, dst); +#else + int width = cv::max(front.cols, back.cols); + int height = cv::max(front.rows, back.rows) * 2; + + dst = cv::Mat(height, width, front.type(), m_BG_color); + front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); + int offset = front.rows; + front.release(); + back.copyTo(dst(cv::Rect(0, offset, back.cols, back.rows))); + back.release(); +#endif + } + //front.release(); + //back.release(); + return dst; +} diff --git a/hgdriver/ImageProcess/ImageApplyConcatenation.h b/hgdriver/ImageProcess/ImageApplyConcatenation.h index c4ec540..27b6cb9 100644 --- a/hgdriver/ImageProcess/ImageApplyConcatenation.h +++ b/hgdriver/ImageProcess/ImageApplyConcatenation.h @@ -1,61 +1,60 @@ -/* - * ==================================================== - - * ܣƴӣ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/29 - * 汾ţv1.0 2020/4/21 - * 汾ţv1.1 2020/4/29 : 1m_BG_colorӿڣͼƬ2Żڴ - * ==================================================== - */ - -#ifndef IMAGE_APPLY_CONCATENATION_H -#define IMAGE_APPLY_CONCATENATION_H - -#include "ImageApply.h" - - class CImageApplyConcatenation : public CImageApply -{ -public: - //۷ - enum ConcatMode - { - horizontal = 0, //ƴ - vertical, //ƴ - autoDirection - - }; -public: - CImageApplyConcatenation(); //Ĭm_direction = autoDirection; - - /* - * dir [in]:ƴӷ - * backgroud [in]:ɫĬΪɫ - * */ - CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& backgroud = cv::Scalar(0, 0, 0)); - - virtual ~CImageApplyConcatenation(void); - - virtual void apply(std::vector& mats, bool isTwoSide); - - inline ConcatMode getConcatDirection() { return m_direction; } - - inline void setFildDirection(ConcatMode dir) { m_direction = dir; } - - inline cv::Scalar getBackGroundColor() const { return m_BG_color; } - - inline void setBackGroundColor(const cv::Scalar& color) { m_BG_color = color; } - -private: - - virtual void apply(cv::Mat& pDib, int side); - - cv::Mat concat(cv::Mat& front, cv::Mat& back, ConcatMode direction = autoDirection); - -private: - ConcatMode m_direction; - cv::Scalar m_BG_color; -}; - -#endif // !IMAGE_APPLY_CONCATENATION_H +/* + * ==================================================== + + * ܣƴӣ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/29 + * 汾ţv1.0 2020/4/21 + * 汾ţv1.1 2020/4/29 : 1m_BG_colorӿڣͼƬ2Żڴ + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CONCATENATION_H +#define IMAGE_APPLY_CONCATENATION_H + +#include "ImageApply.h" + + class GIMGPROC_LIBRARY_API CImageApplyConcatenation : public CImageApply +{ +public: + //۷ + enum ConcatMode + { + horizontal = 0, //ƴ + vertical, //ƴ + autoDirection + }; +public: + CImageApplyConcatenation(); //Ĭm_direction = autoDirection; + + /* + * dir [in]:ƴӷ + * backgroud [in]:ɫĬΪɫ + * */ + CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& backgroud = cv::Scalar(0, 0, 0)); + + virtual ~CImageApplyConcatenation(void); + + virtual void apply(std::vector& mats, bool isTwoSide); + + inline ConcatMode getConcatDirection() { return m_direction; } + + inline void setFildDirection(ConcatMode dir) { m_direction = dir; } + + inline cv::Scalar getBackGroundColor() const { return m_BG_color; } + + inline void setBackGroundColor(const cv::Scalar& color) { m_BG_color = color; } + +private: + + virtual void apply(cv::Mat& pDib, int side); + + cv::Mat concat(cv::Mat& front, cv::Mat& back, ConcatMode direction = autoDirection); + +private: + ConcatMode m_direction; + cv::Scalar m_BG_color; +}; + +#endif // !IMAGE_APPLY_CONCATENATION_H diff --git a/hgdriver/ImageProcess/ImageApplyCustomCrop.cpp b/hgdriver/ImageProcess/ImageApplyCustomCrop.cpp index 9875e38..078e7b7 100644 --- a/hgdriver/ImageProcess/ImageApplyCustomCrop.cpp +++ b/hgdriver/ImageProcess/ImageApplyCustomCrop.cpp @@ -1,32 +1,32 @@ -#include "ImageApplyCustomCrop.h" - -CImageApplyCustomCrop::CImageApplyCustomCrop(const cv::Rect &rect) - : m_rect(rect) -{ - -} - -CImageApplyCustomCrop::~CImageApplyCustomCrop() -{ - -} - -void CImageApplyCustomCrop::apply(cv::Mat &pDib, int side) -{ - (void)side; - if(pDib.empty()) return; - pDib = pDib(cv::Rect(0, 0, pDib.cols, pDib.rows) & m_rect).clone(); -} - -void CImageApplyCustomCrop::apply(std::vector &mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyCustomCrop.h" + +CImageApplyCustomCrop::CImageApplyCustomCrop(const cv::Rect &rect) + : m_rect(rect) +{ + +} + +CImageApplyCustomCrop::~CImageApplyCustomCrop() +{ + +} + +void CImageApplyCustomCrop::apply(cv::Mat &pDib, int side) +{ + (void)side; + if(pDib.empty()) return; + pDib = pDib(cv::Rect(0, 0, pDib.cols, pDib.rows) & m_rect).clone(); +} + +void CImageApplyCustomCrop::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyCustomCrop.h b/hgdriver/ImageProcess/ImageApplyCustomCrop.h index 3993a51..8c005bb 100644 --- a/hgdriver/ImageProcess/ImageApplyCustomCrop.h +++ b/hgdriver/ImageProcess/ImageApplyCustomCrop.h @@ -1,40 +1,40 @@ -/* - * ==================================================== - - * ܣԶü - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 - * 汾ţv1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_CUSTOM_CROP_H -#define IMAGE_APPLY_CUSTOM_CROP_H - -#include "ImageApply.h" - -class CImageApplyCustomCrop : public CImageApply -{ -public: - - /* - * rect [in]:ü - * */ - CImageApplyCustomCrop(const cv::Rect& rect); - - virtual~ CImageApplyCustomCrop(void); - - inline cv::Rect getROI() const { return m_rect; } - - inline void setROI(const cv::Rect& roi) { m_rect = roi; } - - virtual void apply(cv::Mat &pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); -private: - cv::Rect m_rect; -}; - -#endif // IMAGE_APPLY_CUSTOM_CROP_H +/* + * ==================================================== + + * ܣԶü + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CUSTOM_CROP_H +#define IMAGE_APPLY_CUSTOM_CROP_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyCustomCrop : public CImageApply +{ +public: + + /* + * rect [in]:ü + * */ + CImageApplyCustomCrop(const cv::Rect& rect); + + virtual~ CImageApplyCustomCrop(void); + + inline cv::Rect getROI() const { return m_rect; } + + inline void setROI(const cv::Rect& roi) { m_rect = roi; } + + virtual void apply(cv::Mat &pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + cv::Rect m_rect; +}; + +#endif // IMAGE_APPLY_CUSTOM_CROP_H diff --git a/hgdriver/ImageProcess/ImageApplyCustomGamma.cpp b/hgdriver/ImageProcess/ImageApplyCustomGamma.cpp index 8132682..4dc9267 100644 --- a/hgdriver/ImageProcess/ImageApplyCustomGamma.cpp +++ b/hgdriver/ImageProcess/ImageApplyCustomGamma.cpp @@ -1,63 +1,63 @@ -#include "ImageApplyCustomGamma.h" - -CImageApplyCustomGamma::CImageApplyCustomGamma(unsigned char* table,int length) - : emptyPtr(false) -{ - if(table==nullptr) - emptyPtr = true; - - init_gamma_table(); - setLUT(table,length == 256 ? 1 : 3); -} - -CImageApplyCustomGamma::~CImageApplyCustomGamma() -{ -} - -void CImageApplyCustomGamma::setLUT(const unsigned char* table, int byteCount) -{ - if (emptyPtr) - return; - - if (byteCount == 1) - memcpy(m_table_bit8, table, 256); - else if (byteCount == 3) - memcpy(m_table_bit24, table, 768); -} - -void CImageApplyCustomGamma::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (emptyPtr) - return; - int numOfChannels = pDib.channels(); - cv::Mat mat_table(1, 256, CV_8UC(numOfChannels), (numOfChannels == 3) ? m_table_bit24 : m_table_bit8); - cv::LUT(pDib, mat_table, pDib); -} - -void CImageApplyCustomGamma::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} - -void CImageApplyCustomGamma::setTableData(const unsigned char* data, int length) -{ - setLUT(data, length == 256 ? 1 : 3); -} - -void CImageApplyCustomGamma::init_gamma_table() -{ - for (size_t i = 0; i < 256; ++i) - { - m_table_bit8[i] = static_cast(i); - m_table_bit24[i * 3] = m_table_bit24[i * 3 + 1] = m_table_bit24[i * 3 + 2] = static_cast(i); - } -} +#include "ImageApplyCustomGamma.h" + +CImageApplyCustomGamma::CImageApplyCustomGamma(unsigned char* table,int length) + : emptyPtr(false) +{ + if(table==nullptr) + emptyPtr = true; + + init_gamma_table(); + setLUT(table,length == 256 ? 1 : 3); +} + +CImageApplyCustomGamma::~CImageApplyCustomGamma() +{ +} + +void CImageApplyCustomGamma::setLUT(const unsigned char* table, int byteCount) +{ + if (emptyPtr) + return; + + if (byteCount == 1) + memcpy(m_table_bit8, table, 256); + else if (byteCount == 3) + memcpy(m_table_bit24, table, 768); +} + +void CImageApplyCustomGamma::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (emptyPtr) + return; + int numOfChannels = pDib.channels(); + cv::Mat mat_table(1, 256, CV_8UC(numOfChannels), (numOfChannels == 3) ? m_table_bit24 : m_table_bit8); + cv::LUT(pDib, mat_table, pDib); +} + +void CImageApplyCustomGamma::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyCustomGamma::setTableData(const unsigned char* data, int length) +{ + setLUT(data, length == 256 ? 1 : 3); +} + +void CImageApplyCustomGamma::init_gamma_table() +{ + for (size_t i = 0; i < 256; ++i) + { + m_table_bit8[i] = static_cast(i); + m_table_bit24[i * 3] = m_table_bit24[i * 3 + 1] = m_table_bit24[i * 3 + 2] = static_cast(i); + } +} diff --git a/hgdriver/ImageProcess/ImageApplyCustomGamma.h b/hgdriver/ImageProcess/ImageApplyCustomGamma.h index d51949b..cf4dd27 100644 --- a/hgdriver/ImageProcess/ImageApplyCustomGamma.h +++ b/hgdriver/ImageProcess/ImageApplyCustomGamma.h @@ -1,44 +1,44 @@ -/* - * ==================================================== - - * 功能:自定义伽马校正。原理为哈希表查值 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/4/21 - * 版本号:v1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_CUSTOM_CAMMA_H -#define IMAGE_APPLY_CUSTOM_CAMMA_H - -#include "ImageApply.h" - -class CImageApplyCustomGamma : public CImageApply -{ -public: - /* - * table [in]:自定义查值表 - * length [in]:表的长度,灰度表256,彩色表768 - * */ - CImageApplyCustomGamma(unsigned char* table,int length); - - virtual ~CImageApplyCustomGamma(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - void setTableData(const unsigned char* data, int length); -private: - void init_gamma_table(); - void setLUT(const unsigned char* table, int byteCount); - bool emptyPtr; -private: - unsigned char m_table_bit8[256]; - - unsigned char m_table_bit24[768]; -}; - -#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H +/* + * ==================================================== + + * ܣԶ٤УԭΪϣֵ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CUSTOM_CAMMA_H +#define IMAGE_APPLY_CUSTOM_CAMMA_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyCustomGamma : public CImageApply +{ +public: + /* + * table [in]:Զֵ + * length [in]:ijȣҶȱ256ɫ768 + * */ + CImageApplyCustomGamma(unsigned char* table,int length); + + virtual ~CImageApplyCustomGamma(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + void setTableData(const unsigned char* data, int length); +private: + void init_gamma_table(); + void setLUT(const unsigned char* table, int byteCount); + bool emptyPtr; +private: + unsigned char m_table_bit8[256]; + + unsigned char m_table_bit24[768]; +}; + +#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H diff --git a/hgdriver/ImageProcess/ImageApplyCvtColor.cpp b/hgdriver/ImageProcess/ImageApplyCvtColor.cpp index d69979a..f554330 100644 --- a/hgdriver/ImageProcess/ImageApplyCvtColor.cpp +++ b/hgdriver/ImageProcess/ImageApplyCvtColor.cpp @@ -1,57 +1,57 @@ -#include "ImageApplyCvtColor.h" - -CImageApplyCvtColor::CImageApplyCvtColor(ConversionCodes type) - : m_code(type) -{ -} - -CImageApplyCvtColor::~CImageApplyCvtColor() -{ -} - -void CImageApplyCvtColor::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.channels() == 1) return; - if (m_code > 3) - cv::cvtColor(pDib, pDib, static_cast(m_code)); - else - { - cv::Mat gray(pDib.size(), CV_8UC1); - if (m_code == BGR_MAX) - { - for (size_t y = 0, rows = pDib.rows; y < rows; y++) - { - uchar* ptr_y = pDib.ptr(y); - uchar* gray_y = gray.ptr(y); - for (size_t x = 0, cols = pDib.cols; x < cols; x++) - gray_y[x] = cv::max(ptr_y[x * 3], cv::max(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); - } - } - else if (m_code == BGR_MIN) - { - for (size_t y = 0, rows = pDib.rows; y < rows; y++) - { - uchar* ptr_y = pDib.ptr(y); - uchar* gray_y = gray.ptr(y); - for (size_t x = 0, cols = pDib.cols; x < cols; x++) - gray_y[x] = cv::min(ptr_y[x * 3], cv::min(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); - } - } - pDib.release(); - pDib = gray; - } -} - -void CImageApplyCvtColor::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyCvtColor.h" + +CImageApplyCvtColor::CImageApplyCvtColor(ConversionCodes type) + : m_code(type) +{ +} + +CImageApplyCvtColor::~CImageApplyCvtColor() +{ +} + +void CImageApplyCvtColor::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.channels() == 1) return; + if (m_code > 3) + cv::cvtColor(pDib, pDib, static_cast(m_code)); + else + { + cv::Mat gray(pDib.size(), CV_8UC1); + if (m_code == BGR_MAX) + { + for (size_t y = 0, rows = pDib.rows; y < rows; y++) + { + uchar* ptr_y = pDib.ptr(y); + uchar* gray_y = gray.ptr(y); + for (size_t x = 0, cols = pDib.cols; x < cols; x++) + gray_y[x] = cv::max(ptr_y[x * 3], cv::max(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); + } + } + else if (m_code == BGR_MIN) + { + for (size_t y = 0, rows = pDib.rows; y < rows; y++) + { + uchar* ptr_y = pDib.ptr(y); + uchar* gray_y = gray.ptr(y); + for (size_t x = 0, cols = pDib.cols; x < cols; x++) + gray_y[x] = cv::min(ptr_y[x * 3], cv::min(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); + } + } + pDib.release(); + pDib = gray; + } +} + +void CImageApplyCvtColor::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyCvtColor.h b/hgdriver/ImageProcess/ImageApplyCvtColor.h index 2010430..bb19722 100644 --- a/hgdriver/ImageProcess/ImageApplyCvtColor.h +++ b/hgdriver/ImageProcess/ImageApplyCvtColor.h @@ -1,52 +1,52 @@ -/* - * ==================================================== - - * ܣɫʱ任 - * ߣά - * ʱ䣺2020/6/19 - * ޸ʱ䣺v1.0 2020/6/19 - v1.1 2020/6/20 BGRתHSV,BGR_MAXBGR_MIN - * 汾ţv1.1 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_CONVERT_COLOR_H -#define IMAGE_APPLY_CONVERT_COLOR_H - -#include "ImageApply.h" - -class CImageApplyCvtColor : public CImageApply -{ -public: - - //תģʽ - enum ConversionCodes - { - BGR_MAX = 1, //BGRȡֵתGRAY - BGR_MIN = 2, //BGRȡСֵתGRAY - BGR2GRAY = 6, //BGRתGRAY - BGR2HSV = 40 //BGRתHSV - }; - - /* - * type [in]:ɫתģʽĬBGRתGray - * */ - CImageApplyCvtColor(ConversionCodes type = BGR2GRAY); - - virtual ~CImageApplyCvtColor(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - inline ConversionCodes getConversionCode() { return m_code; } - - inline void setConversionCode(ConversionCodes code) { m_code = code; } - -private: - ConversionCodes m_code; - -}; - -#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H +/* + * ==================================================== + + * ܣɫʱ任 + * ߣά + * ʱ䣺2020/6/19 + * ޸ʱ䣺v1.0 2020/6/19 + v1.1 2020/6/20 BGRתHSV,BGR_MAXBGR_MIN + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CONVERT_COLOR_H +#define IMAGE_APPLY_CONVERT_COLOR_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyCvtColor : public CImageApply +{ +public: + + //תģʽ + enum ConversionCodes + { + BGR_MAX = 1, //BGRȡֵתGRAY + BGR_MIN = 2, //BGRȡСֵתGRAY + BGR2GRAY = 6, //BGRתGRAY + BGR2HSV = 40 //BGRתHSV + }; + + /* + * type [in]:ɫתģʽĬBGRתGray + * */ + CImageApplyCvtColor(ConversionCodes type = BGR2GRAY); + + virtual ~CImageApplyCvtColor(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + inline ConversionCodes getConversionCode() { return m_code; } + + inline void setConversionCode(ConversionCodes code) { m_code = code; } + +private: + ConversionCodes m_code; + +}; + +#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H diff --git a/hgdriver/ImageProcess/ImageApplyDetachNoise.cpp b/hgdriver/ImageProcess/ImageApplyDetachNoise.cpp index d32951b..4338845 100644 --- a/hgdriver/ImageProcess/ImageApplyDetachNoise.cpp +++ b/hgdriver/ImageProcess/ImageApplyDetachNoise.cpp @@ -1,42 +1,46 @@ -#include "ImageApplyDetachNoise.h" -#include "ImageProcess_Public.h" - -CImageApplyDetachNoise::CImageApplyDetachNoise(int noise) - : m_noise(noise) -{ -} - -CImageApplyDetachNoise::~CImageApplyDetachNoise(void) -{ -} - -void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side) -{ - (void)side; - if (pDib.empty()||pDib.channels() != 1) - return; - - cv::Mat mask; - cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV); - - std::vector> contours; - std::vector h; - hg::findContours(mask, contours, h); - - for (const std::vector& contour : contours) - if (contourArea(contour) < m_noise) - fillConvexPoly(pDib, contour, cv::Scalar(255)); -} - -void CImageApplyDetachNoise::apply(std::vector &mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyDetachNoise.h" +#include "ImageProcess_Public.h" + +CImageApplyDetachNoise::CImageApplyDetachNoise(int noise) + : m_noise(noise) +{ +} + +CImageApplyDetachNoise::~CImageApplyDetachNoise(void) +{ +} + +void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()||pDib.channels() != 1) + return; + + cv::Mat mask; + cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV); + + std::vector> contours; + std::vector h; + hg::findContours(mask, contours, h); + + for (const std::vector& contour : contours) + { + cv::Rect rect = cv::boundingRect(contour); + if (rect.width <= m_noise && rect.height <= m_noise) + fillConvexPoly(pDib, contour, cv::Scalar(255)); + + } +} + +void CImageApplyDetachNoise::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyDetachNoise.h b/hgdriver/ImageProcess/ImageApplyDetachNoise.h index 200985f..65eab5c 100644 --- a/hgdriver/ImageProcess/ImageApplyDetachNoise.h +++ b/hgdriver/ImageProcess/ImageApplyDetachNoise.h @@ -1,46 +1,39 @@ -/* - * ==================================================== - - * ܣ룬3*3ڵص㣬ҪԺڰͼ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 v1.0 - 2020/5/29 v1.1 ӽӿڣʹСֵɵ - * 汾ţv1.1 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_DETACH_NOISE_H -#define IMAGE_APPLY_DETACH_NOISE_H - -#include "ImageApply.h" - -class CImageApplyDetachNoise : public CImageApply -{ -public: - CImageApplyDetachNoise(int - - - - - - - - = 1); - - inline int getNoise() { return m_noise; } - - inline void setNoise(int noise) { m_noise = noise; } - - virtual ~CImageApplyDetachNoise(void); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - -private: - int m_noise; -}; -#endif // !IMAGE_APPLY_DETACH_NOISE_H - +/* + * ==================================================== + + * ܣ룬3*3ڵص㣬ҪԺڰͼ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + 2020/05/29 v1.1 ӽӿڣʹСֵɵ + 2021/08/03 v1.2 ĬnoiseߴΪ3ʾ3*3blockߴ磻ж߼ԭijߴΪγ + * 汾ţv1.2 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DETACH_NOISE_H +#define IMAGE_APPLY_DETACH_NOISE_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyDetachNoise : public CImageApply +{ +public: + CImageApplyDetachNoise(int noise = 3); + + inline int getNoise() { return m_noise; } + + inline void setNoise(int noise) { m_noise = noise; } + + virtual ~CImageApplyDetachNoise(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + int m_noise; +}; +#endif // !IMAGE_APPLY_DETACH_NOISE_H + diff --git a/hgdriver/ImageProcess/ImageApplyDiscardBlank.cpp b/hgdriver/ImageProcess/ImageApplyDiscardBlank.cpp index f9863cf..2102394 100644 --- a/hgdriver/ImageProcess/ImageApplyDiscardBlank.cpp +++ b/hgdriver/ImageProcess/ImageApplyDiscardBlank.cpp @@ -1,114 +1,114 @@ -#include "ImageApplyDiscardBlank.h" -#include "ImageProcess_Public.h" - -CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh) - : m_threshold(threshold) - , m_edge(edge) - , m_devTh(devTh) - , m_meanTh(meanTh) -{ -} - -CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void) -{ -} - -void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side) -{ - if (apply(pDib, m_threshold, m_edge, m_devTh)) - pDib.release(); -} - -void CImageApplyDiscardBlank::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} - -bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2) -{ - for (int i = 0; i < 3; i++) - if (val1[i] > val2[i]) - return false; - return true; -} - -bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh) -{ - double min, max; - cv::minMaxLoc(img, &min, &max, 0, 0, mask); - if (cv::mean(img, mask)[0] < meanTh) - return false; - return (max - min) < devTh; -} - -bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh) -{ - if (pDib.empty()) - return true; - - cv::Mat img_resize; - cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2); - - cv::Mat threshold_img; - if (img_resize.channels() == 3) - cv::cvtColor(img_resize, threshold_img, cv::COLOR_BGR2GRAY); - cv::threshold(img_resize.channels() == 3 ? threshold_img : img_resize, threshold_img, threshold, 255, CV_THRESH_BINARY); - - std::vector> contours; - std::vector h1; - hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - - std::vector contour; - for (const std::vector& sub : contours) - for (const cv::Point& p : sub) - contour.push_back(p); - - cv::RotatedRect rect = hg::getBoundingRect(contour); - rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5); - cv::Point2f box[4]; - rect.points(box); - contour.clear(); - contours.clear(); - - for (size_t i = 0; i < 4; i++) - contour.push_back(box[i]); - contours.push_back(contour); - cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1); - hg::fillPolys(mask, contours, cv::Scalar::all(255)); - cv::blur(img_resize, img_resize, cv::Size(3, 3)); - - bool b = true; - if (img_resize.channels() == 3) - { - cv::Mat bgr[3]; - cv::split(img_resize, bgr); - for (size_t i = 0; i < 3; i++) - { - b &= maxMinCompare(bgr[i], mask, devTh, meanTh); - if (!b) break; - } - } - else - b &= maxMinCompare(img_resize, mask, devTh, meanTh); - /* - if (b) - { - cv::imwrite("�հ�ҳ/img1/" + std::to_string(index) + ".bmp", img_resize); - cv::imwrite("�հ�ҳ/mask1/" + std::to_string(index) + ".bmp", mask); - } - else - { - cv::imwrite("�հ�ҳ/img2/" + std::to_string(index) + ".bmp", img_resize); - cv::imwrite("�հ�ҳ/mask2/" + std::to_string(index) + ".bmp", mask); - }*/ - - return b; -} +#include "ImageApplyDiscardBlank.h" +#include "ImageProcess_Public.h" + +CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh) + : m_threshold(threshold) + , m_edge(edge) + , m_devTh(devTh) + , m_meanTh(meanTh) +{ +} + +CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void) +{ +} + +void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side) +{ + if (apply(pDib, m_threshold, m_edge, m_devTh)) + pDib.release(); +} + +void CImageApplyDiscardBlank::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2) +{ + for (int i = 0; i < 3; i++) + if (val1[i] > val2[i]) + return false; + return true; +} + +bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh) +{ + double min, max; + cv::minMaxLoc(img, &min, &max, 0, 0, mask); + if (cv::mean(img, mask)[0] < meanTh) + return false; + return (max - min) < devTh; +} + +bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh) +{ + if (pDib.empty()) + return true; + + cv::Mat img_resize; + cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2); + + cv::Mat threshold_img; + if (img_resize.channels() == 3) + cv::cvtColor(img_resize, threshold_img, cv::COLOR_BGR2GRAY); + cv::threshold(img_resize.channels() == 3 ? threshold_img : img_resize, threshold_img, threshold, 255, CV_THRESH_BINARY); + + std::vector> contours; + std::vector h1; + hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); + + std::vector contour; + for (const std::vector& sub : contours) + for (const cv::Point& p : sub) + contour.push_back(p); + + cv::RotatedRect rect = hg::getBoundingRect(contour); + rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5); + cv::Point2f box[4]; + rect.points(box); + contour.clear(); + contours.clear(); + + for (size_t i = 0; i < 4; i++) + contour.push_back(box[i]); + contours.push_back(contour); + cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1); + hg::fillPolys(mask, contours, cv::Scalar::all(255)); + cv::blur(img_resize, img_resize, cv::Size(3, 3)); + + bool b = true; + if (img_resize.channels() == 3) + { + cv::Mat bgr[3]; + cv::split(img_resize, bgr); + for (size_t i = 0; i < 3; i++) + { + b &= maxMinCompare(bgr[i], mask, devTh, meanTh); + if (!b) break; + } + } + else + b &= maxMinCompare(img_resize, mask, devTh, meanTh); + /* + if (b) + { + cv::imwrite("հҳ/img1/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("հҳ/mask1/" + std::to_string(index) + ".bmp", mask); + } + else + { + cv::imwrite("հҳ/img2/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("հҳ/mask2/" + std::to_string(index) + ".bmp", mask); + }*/ + + return b; +} diff --git a/hgdriver/ImageProcess/ImageApplyDiscardBlank.h b/hgdriver/ImageProcess/ImageApplyDiscardBlank.h index 9b1fa19..e6f4aad 100644 --- a/hgdriver/ImageProcess/ImageApplyDiscardBlank.h +++ b/hgdriver/ImageProcess/ImageApplyDiscardBlank.h @@ -1,48 +1,48 @@ -/* - * ==================================================== - - * 功能:空白页识别。 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/4/21 v1.0 - 2020/8/12 v1.1 开放setIntensity和setMinArea;取消isNormal标识位;扩大setIntensity的设置范围,从[2, 20]扩大到[1, 100] - 2020/8/25 v1.1.1 纸张检测缩进,从100像素调整到20像素 - 2020/10/16 v1.2 添加新接口,能够高效便捷判断图片是否为空白页 - 2020/10/19 v1.2.1 修复静态空白页判断识别误判的BUG - 2021/04/13 v1.3.0 增加标准/票据标识位 - 2021/08/12 v1.3.1 添加防止不同opencv版本导致计算结果存在差异的代码。 - 2021/12/14 v1.3.2 重构算法。 - 2021/12/15 v1.3.3 微调参数。 - 2021/12/17 v1.3.4 增加背景色接口,实现对纯色纸张的空白页判定 - * 版本号:v1.3.4 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_DISCARD_BLANK_H -#define IMAGE_APPLY_DISCARD_BLANK_H - -#include "ImageApply.h" - -class CImageApplyDiscardBlank : public CImageApply -{ -public: - - CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200); - - virtual ~CImageApplyDiscardBlank(void); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - static bool apply(const cv::Mat& pDib, double threshold = 40, int edge = 150, int blockSize = 10, double devTh = 50, double meanTh = 200); - -private: - double m_threshold; - int m_edge; - double m_devTh; - double m_meanTh; -}; - +/* + * ==================================================== + + * ܣհҳʶ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + 2020/8/12 v1.1 setIntensitysetMinAreaȡisNormalʶλsetIntensity÷Χ[2, 20][1, 100] + 2020/8/25 v1.1.1 ֽż100ص20 + 2020/10/16 v1.2 ½ӿڣܹЧжͼƬǷΪհҳ + 2020/10/19 v1.2.1 ޸̬հҳжʶеBUG + 2021/04/13 v1.3.0 ӱ׼/Ʊݱʶλ + 2021/08/12 v1.3.1 ӷֹͬopencv汾¼ڲĴ롣 + 2021/12/14 v1.3.2 ع㷨 + 2021/12/15 v1.3.3 ΢ + 2021/12/17 v1.3.4 ӱɫӿڣʵֶԴɫֽŵĿհҳж + * 汾ţv1.3.4 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DISCARD_BLANK_H +#define IMAGE_APPLY_DISCARD_BLANK_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyDiscardBlank : public CImageApply +{ +public: + + CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200); + + virtual ~CImageApplyDiscardBlank(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + static bool apply(const cv::Mat& pDib, double threshold = 40, int edge = 150, int blockSize = 10, double devTh = 50, double meanTh = 200); + +private: + double m_threshold; + int m_edge; + double m_devTh; + double m_meanTh; +}; + #endif // !IMAGE_APPLY_DISCARD_BLANK_H \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageApplyDispersion.cpp b/hgdriver/ImageProcess/ImageApplyDispersion.cpp new file mode 100644 index 0000000..a1302b0 --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyDispersion.cpp @@ -0,0 +1,44 @@ +#include "ImageApplyDispersion.h" + +CImageApplyDispersion::CImageApplyDispersion(float a, float b, float c, float sharpen) + : CImageApply() + , m_kernal_b(3, 1, CV_32FC1) + , m_kernal_g(3, 1, CV_32FC1) + , m_kernal_r(3, 1, CV_32FC1) +{ + m_kernal_b.at(0, 0) = a; + m_kernal_b.at(1, 0) = 1.0f + sharpen - a; + m_kernal_b.at(2, 0) = -sharpen; + + m_kernal_g.at(0, 0) = b; + m_kernal_g.at(1, 0) = 1.0f + sharpen - b; + m_kernal_g.at(2, 0) = -sharpen; + + m_kernal_r.at(0, 0) = c; + m_kernal_r.at(1, 0) = 1.0f + sharpen - c; + m_kernal_r.at(2, 0) = -sharpen; +} + +CImageApplyDispersion::~CImageApplyDispersion() +{ +} + +void CImageApplyDispersion::apply(cv::Mat& pDib, int side) +{ + (void)side; + + if (pDib.channels() != 3) return; + + cv::Mat bgr[3]; + cv::split(pDib, bgr); + + cv::filter2D(bgr[0], bgr[0], bgr[0].depth(), m_kernal_b); + cv::filter2D(bgr[1], bgr[1], bgr[1].depth(), m_kernal_g); + cv::filter2D(bgr[2], bgr[2], bgr[2].depth(), m_kernal_r); + + cv::merge(bgr, 3, pDib); +} + +void CImageApplyDispersion::apply(std::vector& mats, bool isTwoSide) +{ +} diff --git a/hgdriver/ImageProcess/ImageApplyDispersion.h b/hgdriver/ImageProcess/ImageApplyDispersion.h new file mode 100644 index 0000000..e914e40 --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyDispersion.h @@ -0,0 +1,36 @@ +/* + * ==================================================== + + * ܣɫɢ + * ߣά + * ʱ䣺2021/09/24 + * ޸ʱ䣺2021/11/12 v1.1.0 ع㷨 + * 2022/04/21 v1.2.0 ع㷨 + * 2022/07/20 v1.3.0 Ź캯б + * 汾ţv1.3.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DISPERSION_COLOR_H +#define IMAGE_APPLY_DISPERSION_COLOR_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyDispersion : public CImageApply +{ +public: + CImageApplyDispersion(float a = 0.15f, float b = 0.806f, float c = 0.484f, float sharpen = 0.3f); + + virtual ~CImageApplyDispersion(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + cv::Mat m_kernal_b; + cv::Mat m_kernal_g; + cv::Mat m_kernal_r; +}; +#endif diff --git a/hgdriver/ImageProcess/ImageApplyDogEarDetection.cpp b/hgdriver/ImageProcess/ImageApplyDogEarDetection.cpp index 40ef3a7..aaa7982 100644 --- a/hgdriver/ImageProcess/ImageApplyDogEarDetection.cpp +++ b/hgdriver/ImageProcess/ImageApplyDogEarDetection.cpp @@ -1,67 +1,106 @@ -#include "ImageApplyDogEarDetection.h" -#include "ImageProcess_Public.h" - -CImageApplyDogEarDetection::CImageApplyDogEarDetection() - : m_threshold(40) - , m_zoom(1.0) - , m_distance(50) - , m_result(false) -{ - -} - -CImageApplyDogEarDetection::CImageApplyDogEarDetection(double threshlod, double zoom, double distance) - : m_threshold(threshlod) - , m_zoom(zoom) - , m_distance(distance) - , m_result(false) -{ - -} - -CImageApplyDogEarDetection::~CImageApplyDogEarDetection() -{ - -} - -void CImageApplyDogEarDetection::apply(cv::Mat &pDib, int side) -{ - m_result = false; - (void)side; - if (pDib.empty()) return; - cv::Mat src; - if (m_zoom != 1.0) - cv::resize(pDib, src, cv::Size(), m_zoom, m_zoom, cv::INTER_NEAREST); - else - src = pDib; - - cv::Mat thre; - hg::threshold_Mat(src, thre, m_threshold); - std::vector hierarchy; - std::vector> contours; - hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); - - std::vector maxContour = hg::getMaxContour(contours, hierarchy); - if (maxContour.size() == 0) - { - m_result = true; - return; - } - hg::convexHull(maxContour, maxContour); - cv::RotatedRect rect = hg::getBoundingRect(maxContour); - cv::Point2f vertexes[4]; - rect.points(vertexes); - - for (int i = 0; i < 4; i++) - if ((-cv::pointPolygonTest(maxContour, vertexes[i], true)) > (m_distance * m_zoom)) - { - m_result = true; - return; - } -} - -void CImageApplyDogEarDetection::apply(std::vector &mats, bool isTwoSide) -{ - (void)mats; - (void)isTwoSide; -} +#include "ImageApplyDogEarDetection.h" +#include "ImageProcess_Public.h" + +CImageApplyDogEarDetection::CImageApplyDogEarDetection() + : m_threshold(40) + , m_zoom_x(1.0) + , m_zoom_y(1.0) + , m_distance1(50) + , m_distance2(50) + , m_result(0) +{ + +} + +CImageApplyDogEarDetection::CImageApplyDogEarDetection(double threshlod, double zoom_x, double zoom_y, double distance1, double distance2) + : m_threshold(threshlod) + , m_zoom_x(zoom_x) + , m_zoom_y(zoom_y) + , m_distance1(distance1) + , m_distance2(distance2) + , m_result(0) +{ + +} + +CImageApplyDogEarDetection::~CImageApplyDogEarDetection() +{ + +} + +#define EDGE_ABS 4 +void CImageApplyDogEarDetection::apply(cv::Mat& pDib, int side) +{ + m_result = 0; + (void)side; + if (pDib.empty()) return; + cv::Mat src; + if (m_zoom_x != 1.0 && m_zoom_y != 1.0) + cv::resize(pDib, src, cv::Size(), m_zoom_x, m_zoom_y, cv::INTER_NEAREST); + else + src = pDib; + + cv::Mat thre; + hg::threshold_Mat(src, thre, m_threshold); + + cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5, 1)); + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + std::vector hierarchy; + std::vector> contours; + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + if (maxContour.size() == 0) + { + m_result = true; + return; + } + hg::convexHull(maxContour, maxContour); + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + cv::Point2f vertexes[4]; + rect.points(vertexes); + + double distance; + for (int i = 0; i < 4; i++) + { + distance = -cv::pointPolygonTest(maxContour, vertexes[i], true); + + //жǷΪͨ۽ + if (distance > (m_distance1 / m_zoom_x)) + { + if (cv::Rect(0, 0, src.cols, src.rows).contains(vertexes[i])) + m_result = 1; + else if (vertexes[i].x < 0 && cv::abs(distance + vertexes[i].x) > EDGE_ABS) //Խ۽ǣ޸m_resultֵҪжϣֹ©ͨ۽ + m_result = 1; + else if (vertexes[i].y < 0 && cv::abs(distance + vertexes[i].y) > EDGE_ABS) + m_result = 1; + else if (vertexes[i].x > src.cols && cv::abs(distance + src.cols - vertexes[i].x) > EDGE_ABS) + m_result = 1; + else if (vertexes[i].y > src.rows && cv::abs(distance + src.rows - vertexes[i].y) > EDGE_ABS) + m_result = 1; + } + + if (m_result == 1) + return; + + //жǷΪɨԽ絼µ۽ + if (distance > (m_distance2 / m_zoom_x)) + { + if (vertexes[i].x < 0 && cv::abs(distance + vertexes[i].x) < EDGE_ABS) //Խ۽ǣ޸m_resultֵҪжϣֹ©ͨ۽ + m_result = 2; + else if (vertexes[i].y < 0 && cv::abs(distance + vertexes[i].y) < EDGE_ABS) + m_result = 2; + else if (vertexes[i].x > src.cols && cv::abs(distance + src.cols - vertexes[i].x) < EDGE_ABS) + m_result = 2; + else if (vertexes[i].y > src.rows && cv::abs(distance + src.rows - vertexes[i].y) < EDGE_ABS) + m_result = 2; + } + } +} + +void CImageApplyDogEarDetection::apply(std::vector& mats, bool isTwoSide) +{ + (void)mats; + (void)isTwoSide; +} diff --git a/hgdriver/ImageProcess/ImageApplyDogEarDetection.h b/hgdriver/ImageProcess/ImageApplyDogEarDetection.h index 46dff8c..94de55b 100644 --- a/hgdriver/ImageProcess/ImageApplyDogEarDetection.h +++ b/hgdriver/ImageProcess/ImageApplyDogEarDetection.h @@ -1,56 +1,64 @@ -/* - * ==================================================== - - * 功能:折角检测。检测原理:计算纸张的理论四角顶点,到实际轮廓最小距离。当任意顶点到轮廓最小距离超过阈值,则判定为折角 - * 作者:刘丁维 - * 生成时间:2020/10/30 - * 最近修改时间:2020/10/30 - * 版本号:v1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_DOGEAR_DETECTION_H -#define IMAGE_APPLY_DOGEAR_DETECTION_H - -#include "ImageApply.h" - -class CImageApplyDogEarDetection :public CImageApply -{ -public: - - /// - /// 折角检测默认构造函数,threshold = 40, zoom = 1.0, distance = 50 - /// - CImageApplyDogEarDetection(); - - /// - /// 折角检测构造函数 - /// - /// 二值化阈值 - /// 原图缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) - /// 理论顶点到实际轮廓最小距离的阈值,大于该阈值则判定为折角,默认值50(像素) - CImageApplyDogEarDetection(double threshlod, double zoom = 1.0, double distance = 50); - - virtual ~CImageApplyDogEarDetection(void); - - /// - /// 获取检测结果。该函数须在调用apply之后使用。 - /// - /// true为折角,false为不折角 - inline bool getResult() { return m_result; } - - virtual void apply(cv::Mat& pDib, int side); - -private: - virtual void apply(std::vector& mats, bool isTwoSide); - -private: - double m_threshold; - double m_zoom; - double m_distance; - - bool m_result; -}; - -#endif // IMAGE_APPLY_DOGEAR_DETECTION_H +/* + * ==================================================== + + * 功能:折角检测。检测原理:计算纸张的理论四角顶点,到实际轮廓最小距离。当任意顶点到轮廓最小距离超过阈值,则判定为折角 + * 作者:刘丁维 + * 生成时间:2020/10/30 + * 最近修改时间:2020/10/30 v1.0 + * 2021/11/04 v1.1 增加背景抗噪机制,能够抗5像素的背景噪声 + * 2022/07/15 v1.2 增加折角类型判断。区分普通折角,以及扫描不完整导致的折角 + * 2022/07/21 v1.3 区分普通折角和越界折角判定条件。先判定是否为边界越界折角,若是,则报越界折角2;若不是再检测是否为普通折角,若是则报普通折角1。 + * 2022/07/21 v1.3.1 先判定是否为普通折角,若是,则报普通折角1;若不是再检测是否为越界折角,若是则报越界折角2。 + * 2022/07/22 v1.4 增加参数zoom_x,zoom_y。适应原图XY轴DPI不一致的问题。 + * 版本号:v1.4 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DOGEAR_DETECTION_H +#define IMAGE_APPLY_DOGEAR_DETECTION_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyDogEarDetection : public CImageApply +{ +public: + + /// + /// 折角检测默认构造函数,threshold = 40, zoom = 1.0, distance = 50 + /// + CImageApplyDogEarDetection(); + + /// + /// 折角检测构造函数 + /// + /// 二值化阈值 + /// 原图X轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) + /// 原图Y轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) + /// 理论顶点到实际轮廓最小距离的阈值,大于该阈值则判定为折角,默认值50(像素) + CImageApplyDogEarDetection(double threshlod, double zoom_x = 1.0, double zoom_y = 1.0, double distance1 = 50, double distance2 = 50); + + virtual ~CImageApplyDogEarDetection(void); + + /// + /// 获取检测结果。该函数须在调用apply之后使用。 + /// + /// 0为非折角;1为普通折角;2为可能是扫描不完整造成的折角 + inline int getResult() { return m_result; } + + virtual void apply(cv::Mat& pDib, int side); + +private: + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + double m_threshold; + double m_zoom_x; + double m_zoom_y; + double m_distance1; + double m_distance2; + + int m_result; +}; + +#endif // IMAGE_APPLY_DOGEAR_DETECTION_H diff --git a/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.cpp b/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.cpp index d66e986..4cda243 100644 --- a/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.cpp +++ b/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.cpp @@ -1,150 +1,150 @@ -#include "ImageApplyFadeBackGroundColor.h" - - -CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range) - : m_threshold(threshold) - , m_offset(offset) - , m_range(range) -{ - memset(m_table1, 255, 768); - memset(m_table1, 0, m_threshold * 3); - - memset(m_table2, 255, 256 * 3); - for (size_t i = 0; i < 256; i++) - m_table2[i] = i; -} - -CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor() -{ -} - -void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side) -{ - if (pDib.channels() != 3) - return; - -#if 0 - cv::Mat mask; - cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY); - cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY); - //cv::imwrite("mask.jpg", mask); - cv::Mat bgr[3]; - cv::split(pDib, bgr); - - int histSize = 255; - float range[] = { 0, 255 }; - const float* histRange = { range }; - - cv::Mat hist_bgr[3]; - cv::Scalar mean_bgr; - for (size_t i = 0; i < 3; i++) - { - cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange); - double maxVal = 0; - cv::Point maxLoc; - cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc); - mean_bgr[i] = maxLoc.y; - } - - cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask); -#else - fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range); -#endif -} - -void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range) -{ - int hist_bgr[3][256] = { 0 }; - - int width = bytesPerLine / 3; - unsigned char* mask = new unsigned char[width * height]; - unsigned char* ptr_data = data; - unsigned char* ptr_mask = mask; - - //ģmaskͳֱͨͼ - for (size_t i = 0; i < height; i++) - { - int x = 0; - unsigned char b = 0; - for (size_t j = 0; j < width; j++) - { - b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]]; - ptr_mask[j] = b; - for (size_t k = 0; k < 3; k++) - hist_bgr[k][ptr_data[x + k] & b]++; - x += 3; - } - ptr_data += bytesPerLine; - ptr_mask += width; - } - - //ͳƱɫ - int max_vals[3] = { 0 }; - int max_indexes[3]; - - for (size_t i = 1; i < 256; i++) - for (size_t j = 0; j < 3; j++) - if (hist_bgr[j][i] > max_vals[j]) - { - max_vals[j] = hist_bgr[j][i]; - max_indexes[j] = i; - } - - //ɫֵrangeΧڵɫͬΪɫ - for (size_t i = 0; i < 3; i++) - { - memset(m_table_rgb[i], 0, 256); - int start = cv::max(max_indexes[i] - range, 0); - int end = cv::min(max_indexes[i] + range, 255); - memset(m_table_rgb[i] + start, 255, end - start + 1); - } - - //ݱɫֵģųɫ - ptr_data = data; - ptr_mask = mask; - for (size_t i = 0; i < height; i++) - { - int x = 0; - for (size_t j = 0; j < width; j++) - { - ptr_mask[j] &= m_table_rgb[0][ptr_data[x]] & m_table_rgb[1][ptr_data[x + 1]] & m_table_rgb[2][ptr_data[x + 2]]; - x += 3; - } - ptr_data += bytesPerLine; - ptr_mask += width; - } - - //ģɫ - unsigned char offset_rgb[3]; - for (size_t i = 0; i < 3; i++) - offset_rgb[i] = 255 + offset - max_indexes[i]; - - ptr_data = data; - ptr_mask = mask; - for (size_t i = 0; i < height; i++) - { - int x = 0; - for (size_t j = 0; j < width; j++) - { - for (size_t k = 0; k < 3; k++) - ptr_data[x + k] = m_table2[(int)ptr_data[x + k] + (offset_rgb[k] & ptr_mask[j])]; - x += 3; - } - ptr_data += bytesPerLine; - ptr_mask += width; - } - delete[] mask; -} - -void CImageApplyFadeBackGroudColor::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) - if (!var.empty()) - { - apply(var, i); - i++; - } -} - +#include "ImageApplyFadeBackGroundColor.h" + + +CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range) + : m_threshold(threshold) + , m_offset(offset) + , m_range(range) +{ + memset(m_table1, 255, 768); + memset(m_table1, 0, m_threshold * 3); + + memset(m_table2, 255, 256 * 3); + for (size_t i = 0; i < 256; i++) + m_table2[i] = i; +} + +CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor() +{ +} + +void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side) +{ + if (pDib.channels() != 3) + return; + +#if 0 + cv::Mat mask; + cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY); + //cv::imwrite("mask.jpg", mask); + cv::Mat bgr[3]; + cv::split(pDib, bgr); + + int histSize = 255; + float range[] = { 0, 255 }; + const float* histRange = { range }; + + cv::Mat hist_bgr[3]; + cv::Scalar mean_bgr; + for (size_t i = 0; i < 3; i++) + { + cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange); + double maxVal = 0; + cv::Point maxLoc; + cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc); + mean_bgr[i] = maxLoc.y; + } + + cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask); +#else + fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range); +#endif +} + +void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range) +{ + int hist_bgr[3][256] = { 0 }; + + int width = bytesPerLine / 3; + unsigned char* mask = new unsigned char[width * height]; + unsigned char* ptr_data = data; + unsigned char* ptr_mask = mask; + + //ģmaskͳֱͨͼ + for (size_t i = 0; i < height; i++) + { + int x = 0; + unsigned char b = 0; + for (size_t j = 0; j < width; j++) + { + b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]]; + ptr_mask[j] = b; + for (size_t k = 0; k < 3; k++) + hist_bgr[k][ptr_data[x + k] & b]++; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //ͳƱɫ + int max_vals[3] = { 0 }; + int max_indexes[3] = { 0 }; + + for (size_t i = 1; i < 256; i++) + for (size_t j = 0; j < 3; j++) + if (hist_bgr[j][i] > max_vals[j]) + { + max_vals[j] = hist_bgr[j][i]; + max_indexes[j] = i; + } + + //ɫֵrangeΧڵɫͬΪɫ + for (size_t i = 0; i < 3; i++) + { + memset(m_table_rgb[i], 0, 256); + int start = cv::max(max_indexes[i] - range, 0); + int end = cv::min(max_indexes[i] + range, 255); + memset(m_table_rgb[i] + start, 255, end - start + 1); + } + + //ݱɫֵģųɫ + ptr_data = data; + ptr_mask = mask; + for (size_t i = 0; i < height; i++) + { + int x = 0; + for (size_t j = 0; j < width; j++) + { + ptr_mask[j] &= m_table_rgb[0][ptr_data[x]] & m_table_rgb[1][ptr_data[x + 1]] & m_table_rgb[2][ptr_data[x + 2]]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //ģɫ + unsigned char offset_rgb[3]; + for (size_t i = 0; i < 3; i++) + offset_rgb[i] = 255 + offset - max_indexes[i]; + + ptr_data = data; + ptr_mask = mask; + for (size_t i = 0; i < height; i++) + { + int x = 0; + for (size_t j = 0; j < width; j++) + { + for (size_t k = 0; k < 3; k++) + ptr_data[x + k] = m_table2[(int)ptr_data[x + k] + (offset_rgb[k] & ptr_mask[j])]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + delete[] mask; +} + +void CImageApplyFadeBackGroudColor::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) + if (!var.empty()) + { + apply(var, i); + i++; + } +} + diff --git a/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.h b/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.h index 493883a..b84a74d 100644 --- a/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.h +++ b/hgdriver/ImageProcess/ImageApplyFadeBackGroundColor.h @@ -1,64 +1,65 @@ -/* - * ==================================================== - - * ܣĸֽŵɫ - * ߣά - * ʱ䣺2020/11/30 - * ޸ʱ䣺2021/04/14 v2.0 Ϊλ - * 2021/04/14 v2.1 LINUXһ¡ - * 2021/08/03 v2.2 ԶȡͶ㷨ⲻͬopencv汾ƫ - * 2021/10/12 v2.3 ع㷨ȥԭֵ趨ΪԶʶɫȥɫ - * 2021/10/23 v3.0 ع㷨ܿɫģĸƽɫס - * 2021/10/26 v3.1 캯Ӳģʱֵ - * 2021/10/28 v3.2 ع㷨ôC++ʵֹܣߴٶȡ - * 2021/10/29 v3.3 Ż㷨rangeԸݵͼܹЧ𱳾ͷDZݡ - * 汾ţv3.2 - - * ==================================================== - */ - - -#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H -#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H - -#include "ImageApply.h" - -class CImageApplyAdjustColors; -class CImageApplyFadeBackGroudColor : public CImageApply -{ -public: - /// - /// 캯 - /// - /// ԶʶײĻϣӵƫȡֵΧ[-255, 255] - CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40); - - virtual ~CImageApplyFadeBackGroudColor(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - -private: - - /// - /// ĸɫ㷨֧24λͼ - /// - /// ͼͷָ - /// ÿݴС - /// ͼ߶ - /// ֵοֵΪ100 - /// ĸɫƫĬΪ0ֵԽ󣬱Խף֮Խ - /// ɫΧɫʶ𵽵ĵɫ[-range, range]ΧڣΪɫ򲻻ᱻ - void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range); - -private: - int m_threshold; - int m_offset; - int m_range; - uchar m_table1[768]; - uchar m_table2[512]; - uchar m_table_rgb[3][256]; -}; - -#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H +/* + * ==================================================== + + * ܣĸֽŵɫ + * ߣά + * ʱ䣺2020/11/30 + * ޸ʱ䣺2021/04/14 v2.0 Ϊλ + * 2021/04/14 v2.1 LINUXһ¡ + * 2021/08/03 v2.2 ԶȡͶ㷨ⲻͬopencv汾ƫ + * 2021/10/12 v2.3 ع㷨ȥԭֵ趨ΪԶʶɫȥɫ + * 2021/10/23 v3.0 ع㷨ܿɫģĸƽɫס + * 2021/10/26 v3.1 캯Ӳģʱֵ + * 2021/10/28 v3.2 ع㷨ôC++ʵֹܣߴٶȡ + * 2021/10/29 v3.3 Ż㷨rangeԸݵͼܹЧ𱳾ͷDZݡ + * 2022/03/08 v3.4 ޸δʼBUG + * 汾ţv3.4 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H +#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class GIMGPROC_LIBRARY_API CImageApplyFadeBackGroudColor : public CImageApply +{ +public: + /// + /// 캯 + /// + /// ԶʶײĻϣӵƫȡֵΧ[-255, 255] + CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40); + + virtual ~CImageApplyFadeBackGroudColor(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + /// + /// ĸɫ㷨֧24λͼ + /// + /// ͼͷָ + /// ÿݴС + /// ͼ߶ + /// ֵοֵΪ100 + /// ĸɫƫĬΪ0ֵԽ󣬱Խף֮Խ + /// ɫΧɫʶ𵽵ĵɫ[-range, range]ΧڣΪɫ򲻻ᱻ + void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range); + +private: + int m_threshold; + int m_offset; + int m_range; + uchar m_table1[768]; + uchar m_table2[512]; + uchar m_table_rgb[3][256]; +}; + +#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H diff --git a/hgdriver/ImageProcess/ImageApplyFilter.cpp b/hgdriver/ImageProcess/ImageApplyFilter.cpp index 80e40b9..f640983 100644 --- a/hgdriver/ImageProcess/ImageApplyFilter.cpp +++ b/hgdriver/ImageProcess/ImageApplyFilter.cpp @@ -1,97 +1,97 @@ -#include "ImageApplyFilter.h" - -CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize) - : m_type(type) - , m_kernel(kSize) -{ - m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9; -} - -CImageApplyFilter::~CImageApplyFilter() -{ -} - -void CImageApplyFilter::apply(cv::Mat& pDib, int side) -{ -#ifdef LOG - FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply"); -#endif // LOG - - switch (m_type) - { - case FilterMode::Sharpen: - case FilterMode::Sharpen_More: - sharpen(pDib, m_kSize); - break; - case FilterMode::AverBlur: - case FilterMode::AverBlur_More: - averblur(pDib, static_cast(m_kSize)); - break; - case FilterMode::BilateralFilter: - bilateralFilter(pDib, m_kernel); - break; - case FilterMode::GaussianBlur: - gaussianBlur(pDib, m_kernel); - break; - case FilterMode::BrightSharp: - brightSharp(pDib); - break; - } - -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply"); -#endif // LOG -} - -void CImageApplyFilter::apply(std::vector& mats, bool isTwoSide) -{ - if (mats.empty()) return; - - if (!mats[0].empty()) - apply(mats[0], 0); - - if (isTwoSide && mats.size() > 1) - if (!mats[1].empty()) - apply(mats[1], 1); -} - -void CImageApplyFilter::averblur(cv::Mat& src, int kSize) -{ - cv::blur(src, src, cv::Size(kSize, kSize)); -} - -void CImageApplyFilter::sharpen(cv::Mat& src, float kSize) -{ - float other = (1.0f - kSize) / 4; - float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 }; - cv::Mat kernel(3, 3, CV_32FC1, kernel_data); - - cv::filter2D(src, src, src.depth(), kernel); -} - -void CImageApplyFilter::brightSharp(cv::Mat& src) -{ - const float a = -0.49f; - const float b = 3.0f; - float kernel_data[] = - { - 0, a, 0, - a, b, a, - 0, a, 0 - }; - cv::Mat kernel(3, 3, CV_32FC1, kernel_data); - cv::filter2D(src, src, src.depth(), kernel); -} - -void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel) -{ - cv::Mat dst; - cv::bilateralFilter(src, dst, static_cast(kernel), kernel * 2, kernel / 2); - src.release(); - src = dst; -} - -void CImageApplyFilter::gaussianBlur(cv::Mat src, int kSize) -{ - cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0); -} +#include "ImageApplyFilter.h" + +CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize) + : m_type(type) + , m_kernel(kSize) +{ + m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9; +} + +CImageApplyFilter::~CImageApplyFilter() +{ +} + +void CImageApplyFilter::apply(cv::Mat& pDib, int side) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply"); +#endif // LOG + + switch (m_type) + { + case FilterMode::Sharpen: + case FilterMode::Sharpen_More: + sharpen(pDib, m_kSize); + break; + case FilterMode::AverBlur: + case FilterMode::AverBlur_More: + averblur(pDib, static_cast(m_kSize)); + break; + case FilterMode::BilateralFilter: + bilateralFilter(pDib, m_kernel); + break; + case FilterMode::GaussianBlur: + gaussianBlur(pDib, m_kernel); + break; + case FilterMode::BrightSharp: + brightSharp(pDib); + break; + } + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply"); +#endif // LOG +} + +void CImageApplyFilter::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); +} + +void CImageApplyFilter::averblur(cv::Mat& src, int kSize) +{ + cv::blur(src, src, cv::Size(kSize, kSize)); +} + +void CImageApplyFilter::sharpen(cv::Mat& src, float kSize) +{ + float other = (1.0f - kSize) / 4; + float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::brightSharp(cv::Mat& src) +{ + const float a = -0.49f; + const float b = 3.0f; + float kernel_data[] = + { + 0, a, 0, + a, b, a, + 0, a, 0 + }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel) +{ + cv::Mat dst; + cv::bilateralFilter(src, dst, static_cast(kernel), kernel * 2, kernel / 2); + src.release(); + src = dst; +} + +void CImageApplyFilter::gaussianBlur(cv::Mat src, int kSize) +{ + cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0); +} diff --git a/hgdriver/ImageProcess/ImageApplyFilter.h b/hgdriver/ImageProcess/ImageApplyFilter.h index 09e4675..ffd55ab 100644 --- a/hgdriver/ImageProcess/ImageApplyFilter.h +++ b/hgdriver/ImageProcess/ImageApplyFilter.h @@ -1,64 +1,64 @@ -/* - * ==================================================== - - * ܣ˾Ŀǰ񻯡ǿ񻯡ģͼǿģ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 v1.0 - 2020/7/17 v1.1 ˫˲BilateralFilterЧʵ֡ƽ; - 2020/11/30 v1.2 Ӹ˹ģGaussianBlur - 2021/07/21 v1.2.1 񻯣BrightSharp - 2021/10/19 v1.2.2 񻯲 - * 汾ţv1.2.2 - - * ==================================================== - */ - - -#ifndef IMAGE_APPLY_FILTER_H -#define IMAGE_APPLY_FILTER_H - -#include "ImageApply.h" - -class CImageApplyFilter : public CImageApply -{ -public: - enum FilterMode - { - None, - Sharpen, // - Sharpen_More, //һ - AverBlur, //ģ - AverBlur_More, //һģ - BilateralFilter, //˫˲--ƽٸӱɫjpgѹ - GaussianBlur, - BrightSharp //5 * 5 - }; - - /* - * sharpentype [in]:˾ģʽ - */ - CImageApplyFilter(FilterMode type, int kSize = 30); - - virtual ~CImageApplyFilter(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); -private: - void averblur(cv::Mat& src, int kSize); - - void sharpen(cv::Mat& src, float kSize); - - void brightSharp(cv::Mat& src); - - void bilateralFilter(cv::Mat& src, double kernel); - - void gaussianBlur(cv::Mat src, int kSize); -private: - int m_type; - float m_kSize; - double m_kernel; -}; - -#endif // !IMAGE_APPLY_SHARPEN_H +/* + * ==================================================== + + * ܣ˾Ŀǰ񻯡ǿ񻯡ģͼǿģ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + 2020/7/17 v1.1 ˫˲BilateralFilterЧʵ֡ƽ; + 2020/11/30 v1.2 Ӹ˹ģGaussianBlur + 2021/07/21 v1.2.1 񻯣BrightSharp + 2021/10/19 v1.2.2 񻯲 + * 汾ţv1.2.2 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FILTER_H +#define IMAGE_APPLY_FILTER_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyFilter : public CImageApply +{ +public: + enum FilterMode + { + None, + Sharpen, // + Sharpen_More, //һ + AverBlur, //ģ + AverBlur_More, //һģ + BilateralFilter, //˫˲--ƽٸӱɫjpgѹ + GaussianBlur, + BrightSharp //5 * 5 + }; + + /* + * sharpentype [in]:˾ģʽ + */ + CImageApplyFilter(FilterMode type, int kSize = 30); + + virtual ~CImageApplyFilter(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + void averblur(cv::Mat& src, int kSize); + + void sharpen(cv::Mat& src, float kSize); + + void brightSharp(cv::Mat& src); + + void bilateralFilter(cv::Mat& src, double kernel); + + void gaussianBlur(cv::Mat src, int kSize); +private: + int m_type; + float m_kSize; + double m_kernel; +}; + +#endif // !IMAGE_APPLY_SHARPEN_H diff --git a/hgdriver/ImageProcess/ImageApplyHSVCorrect.cpp b/hgdriver/ImageProcess/ImageApplyHSVCorrect.cpp index 4b558a8..655249c 100644 --- a/hgdriver/ImageProcess/ImageApplyHSVCorrect.cpp +++ b/hgdriver/ImageProcess/ImageApplyHSVCorrect.cpp @@ -1,144 +1,163 @@ -#include "ImageApplyHSVCorrect.h" -#include - -CImageApplyHSVCorrect::CImageApplyHSVCorrect() - : m_table(new uint[256 * 256 * 256]) -{ - initLUT(); -} - -CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode) - : m_table(new uint[256 * 256 * 256]) -{ - initLUT(); - switch (mode) - { - case CImageApplyHSVCorrect::Red_Removal: - set_HSV_value(std::pair(0, 63), std::pair(20, 255), std::pair(160, 255), 0x00FFFFFF); - set_HSV_value(std::pair(191, 255), std::pair(20, 255), std::pair(160, 255), 0x00FFFFFF); - break; - default: - break; - } -} - -CImageApplyHSVCorrect::~CImageApplyHSVCorrect() -{ - delete [] m_table; -} - -void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side) -{ - (void)side; - if (pDib.empty() || pDib.channels() != 3) return; - - uchar* src = pDib.data; - cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3); - uchar* dst = z.data; - - int total = pDib.total(); -#pragma omp parallel for - for (int i = 0; i < total; i++) - { - int offset = i * 3; - int index = *reinterpret_cast(src + offset) & 0x00ffffff; - uint color = m_table[index]; - *reinterpret_cast(dst + offset) |= color; - } - pDib = z; -} - -void CImageApplyHSVCorrect::apply(std::vector &mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} - -void CImageApplyHSVCorrect::initLUT() -{ -#if 0 - uchar h, s, v; -#endif - for (uint b = 0; b < 256; b++) - for (uint g = 0; g < 256; g++) - for (uint r = 0; r < 256; r++) - { -#if 0 - RGB_2_HSV_full(r, g, b, h, s, v); - - uint index = b | (g << 8) | (r << 16); - if (h < 12 || h > 245) - m_table[index] = index & 0x00ffffff; - else - m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff; -#else - m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16); -#endif - } -} - -void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r, - const uint dst_b, const uint dst_g, const uint dst_r) -{ - m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16); -} - -void CImageApplyHSVCorrect::set_HSV_value(const std::pair& range_h, - const std::pair& range_s, - const std::pair& range_v, - uint bgr) -{ - uchar h, s, v; - for (int b = 0; b < 256; b++) - for (int g = 0; g < 256; g++) - for (int r = 0; r < 256; r++) - { - RGB_2_HSV_full(r, g, b, h, s, v); - if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v)) - m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff; - } -} - -void CImageApplyHSVCorrect::set_table(const uint* table) -{ - memcpy(m_table, table, 256 * 256 * 256); -} - -bool CImageApplyHSVCorrect::contained(uchar value, const std::pair &range) -{ - return value >= range.first && value <= range.second; -} - -void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v) -{ - int minn = cv::min(r, cv::min(g, b)); - int maxx = cv::max(r, cv::max(g, b)); - v = static_cast(maxx); //V - - int delta = maxx - minn; - float _h; - if (maxx == 0) - { - h = s = v = 0; - return; - } - else - s = static_cast(delta * 255 / maxx); - - if (r == maxx) - _h = static_cast(g - b) / static_cast(delta); - else if (g == maxx) - _h = 2 + static_cast(b - r) / static_cast(delta); - else - _h = 4 + static_cast(r - g) / static_cast(delta); - - float __h = _h * 42.6666666667f; - h = (__h >= 0) ? static_cast(__h) : static_cast(__h + 256); -} +#include "ImageApplyHSVCorrect.h" +#include + +CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode, bool cvtColor, uint bgr) + : m_table(new uint[256 * 256 * 256]) +{ + initLUT(); + switch (mode) + { + case CImageApplyHSVCorrect::Red_Removal: + set_HSV_value(std::pair(0, 63), std::pair(30, 255), std::pair(120, 255), bgr, cvtColor); + set_HSV_value(std::pair(200, 255), std::pair(30, 255), std::pair(120, 255), bgr, cvtColor); + break; + case CImageApplyHSVCorrect::LowSaturation_Removal: + set_HSV_value(std::pair(0, 255), std::pair(0, 30), std::pair(0, 255), bgr, cvtColor); + break; + default: + break; + } +} + +CImageApplyHSVCorrect::~CImageApplyHSVCorrect() +{ + delete [] m_table; +} + +void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side) +{ + (void)side; + if (pDib.empty() || pDib.channels() != 3) return; +#if 0 + uchar* src = pDib.data; + cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3); + uchar* dst = z.data; + + int bytesPerLine = pDib.cols * pDib.channels(); + for (size_t i = 0, rows = pDib.rows; i < rows; i++) + { + uchar* ptr = pDib.ptr(i); + for (size_t j = 0, cols = pDib.cols; j < cols; j++) + { + int offset = i * 3; + int index = *reinterpret_cast(ptr + offset) & 0x00ffffff; + uint color = m_table[index]; + *reinterpret_cast(dst + offset) |= color; + } + } + pDib = z; +#else + cv::Mat bgra; + cv::cvtColor(pDib, bgra, cv::COLOR_BGR2BGRA); + + long total = bgra.total(); + uint* ptr = bgra.ptr(); + for (long i = 0; i < total; i++) + ptr[i] = m_table[ptr[i] & 0x00FFFFFF]; + + cv::cvtColor(bgra, pDib, cv::COLOR_BGRA2BGR); +#endif +} + +void CImageApplyHSVCorrect::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyHSVCorrect::initLUT() +{ +#if 0 + uchar h, s, v; +#endif + for (uint b = 0; b < 256; b++) + for (uint g = 0; g < 256; g++) + for (uint r = 0; r < 256; r++) + { +#if 0 + RGB_2_HSV_full(r, g, b, h, s, v); + + uint index = b | (g << 8) | (r << 16); + if (h < 12 || h > 245) + m_table[index] = index & 0x00ffffff; + else + m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff; +#else + m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16); +#endif + } +} + +void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r) +{ + m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16); +} + +void CImageApplyHSVCorrect::set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr, bool cvtGray) +{ + uchar h, s, v; + for (int b = 0; b < 256; b++) + for (int g = 0; g < 256; g++) + for (int r = 0; r < 256; r++) + { + RGB_2_HSV_full(r, g, b, h, s, v); + if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v)) + { + if (cvtGray) + { + int a = (b + g + r) / 3 * 0x00010101; + m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = (b + g + r) / 3 * 0x00010101; + } + else + m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff; + } + } +} + +void CImageApplyHSVCorrect::set_table(const uint* table) +{ + memcpy(m_table, table, 256 * 256 * 256 * sizeof(uint)); +} + +bool CImageApplyHSVCorrect::contained(uchar value, const std::pair &range) +{ + return value >= range.first && value <= range.second; +} + +void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v) +{ + int minn = cv::min(r, cv::min(g, b)); + int maxx = cv::max(r, cv::max(g, b)); + v = static_cast(maxx); //V + + int delta = maxx - minn; + float _h; + if (maxx == 0) + { + h = s = v = 0; + return; + } + else + s = static_cast(delta * 255 / maxx); + + if (r == maxx) + _h = static_cast(g - b) / static_cast(delta); + else if (g == maxx) + _h = 2 + static_cast(b - r) / static_cast(delta); + else + _h = 4 + static_cast(r - g) / static_cast(delta); + + float __h = _h * 42.6666666667f; + h = (__h >= 0) ? static_cast(__h) : static_cast(__h + 256); +} diff --git a/hgdriver/ImageProcess/ImageApplyHSVCorrect.h b/hgdriver/ImageProcess/ImageApplyHSVCorrect.h index 8816d13..1da8d73 100644 --- a/hgdriver/ImageProcess/ImageApplyHSVCorrect.h +++ b/hgdriver/ImageProcess/ImageApplyHSVCorrect.h @@ -1,87 +1,95 @@ -/* - * ==================================================== - - * ܣɫͼɫУLUTʵ֣ԤBGRֵHVSBGRԭͼвֵУ - * ߣά - * ʱ䣺2020/3/21 - * ޸ʱ䣺v1.0 2020/3/21 - v1.1 2020/6/15 ЧHSVȡֵΧ - * 汾ţv1.1 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_COLOR_CORRECT_H -#define IMAGE_APPLY_COLOR_CORRECT_H - -#include "ImageApply.h" - -class CImageApplyHSVCorrect : public CImageApply -{ -public: - enum CorrectOption - { - Red_Removal //ɫɫH:[0, 85][170, 255],S:[10, 255],V:[120,255] - }; -public: - - CImageApplyHSVCorrect(); - - /* - * mode [in]:Ԥɫģʽ - */ - CImageApplyHSVCorrect(CorrectOption mode); - - virtual ~CImageApplyHSVCorrect(); - - virtual void apply(cv::Mat& pDib,int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - /* - * ܣʼֵRGBRڸλBڵλ32λݽֵһ¡ - Χ[00x00FFFFFF]ڹ캯лĬϵøú - */ - void initLUT(); - - /* - * ܣֵָRGBֵΪĿֵ - = src_b | (src_g << 8) | (src_r << 16) - ֵ = dst_b | (dst_g << 8) | (dst_r << 16) - * src_b:[in] ԭֵBͨ - * src_g:[in] ԭֵGͨ - * src_r:[in] ԭֵRͨ - * dst_b:[in] ĿֵBֵͨ - * dst_g:[in] ĿֵGֵͨ - * dst_r:[in] ĿֵRֵͨ - */ - void set_single(const uint src_b, const uint src_g, const uint src_r, - const uint dst_b, const uint dst_g, const uint dst_r); - /* - * ܣHSVɫʿռɫʷΧ÷ΧӦBGRΪ0x00FFFFFF(Ĭϰɫ - * range_h:[in] HΧȡֵΧ[0, 255] - * range_s:[in] SΧȡֵΧ[0, 255] - * range_v:[in] VΧȡֵΧ[0, 255] - * bgr:[in] uintʾBGRֵBڵλRڸλ - */ - void set_HSV_value(const std::pair& range_h, - const std::pair& range_s, - const std::pair& range_v, - uint bgr = 0x00FFFFFF); - - /* - * ܣⲿֵĬϳΪ 256 * 256 * 256 * sizeof(uint - * table:[in] ָ - */ - void set_table(const uint* table); - -private: - static bool contained(uchar value, const std::pair& range); - - static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v); - -private: - uint* m_table; -}; - -#endif +/* + * ==================================================== + * + * ܣɫͼɫУLUTʵ֣ԤBGRֵHVSBGRԭͼвֵУ + * ߣά + * ʱ䣺2020/3/21 + * ޸ʱ䣺v1.0 2020/03/21 + v1.1 2020/06/15 ЧHSVȡֵΧ + v1.2 2021/08/02 ڴָ룬ӦROIͼڴƫơ + v1.3 2021/08/26 滻⿨Red_Removalʵַ + v1.4 2022/04/22 ӹܣ֧ػҶֵԭɫأɾĬϹ캯УѡDeafaultLowSaturation_Removal + v1.4.1 2022/04/25 ͣݷԽ硣 + v1.4.2 2022/06/09 ޸һڴСĴ + * 汾ţv1.4.2 + * + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_CORRECT_H +#define IMAGE_APPLY_COLOR_CORRECT_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyHSVCorrect : public CImageApply +{ +public: + enum CorrectOption + { + Deafault, //ĬϣκγɫЧ + LowSaturation_Removal, //ͱͶ + Red_Removal //ɫɫH:[0, 85][170, 255],S:[10, 255],V:[120,255] + }; +public: + /* + * mode [in]:Ԥɫģʽ + * cvtColor [in]:ʹĬֵʹûҶֵtrueΪҶֵfalseΪĬֵ + * bgr:[in] uintʾBGRֵBڵλRڸλcvtGray ΪfalseʱЧ) + */ + CImageApplyHSVCorrect(CorrectOption mode = CorrectOption::Deafault, bool cvtColor = false, uint bgr = 0x00FFFFFF); + + virtual ~CImageApplyHSVCorrect(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /* + * ܣʼֵRGBRڸλBڵλ32λݽֵһ¡ + Χ[00x00FFFFFF]ڹ캯лĬϵøú + */ + void initLUT(); + + /* + * ܣֵָRGBֵΪĿֵ + = src_b | (src_g << 8) | (src_r << 16) + ֵ = dst_b | (dst_g << 8) | (dst_r << 16) + * src_b:[in] ԭֵBͨ + * src_g:[in] ԭֵGͨ + * src_r:[in] ԭֵRͨ + * dst_b:[in] ĿֵBֵͨ + * dst_g:[in] ĿֵGֵͨ + * dst_r:[in] ĿֵRֵͨ + */ + void set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r); + + /* + * ܣHSVɫʿռɫʷΧ÷ΧӦBGRΪ0x00FFFFFF(Ĭϰɫ + * range_h:[in] HΧȡֵΧ[0, 255] + * range_s:[in] SΧȡֵΧ[0, 255] + * range_v:[in] VΧȡֵΧ[0, 255] + * bgr:[in] uintʾBGRֵBڵλRڸλcvtGray ΪfalseʱЧ) + * cvtGray:[in] ΪtrueʱRGBֵתΪҶֵ + */ + void set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr = 0x00FFFFFF, bool cvtGray = false); + + /* + * ܣⲿֵĬϳΪ 256 * 256 * 256 * sizeof(uint + * table:[in] ָ + */ + void set_table(const uint* table); + +private: + static bool contained(uchar value, const std::pair& range); + + static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v); + +private: + uint* m_table; +}; + +#endif diff --git a/hgdriver/ImageProcess/ImageApplyHeaders.h b/hgdriver/ImageProcess/ImageApplyHeaders.h index a4a77a5..540d4f8 100644 --- a/hgdriver/ImageProcess/ImageApplyHeaders.h +++ b/hgdriver/ImageProcess/ImageApplyHeaders.h @@ -1,34 +1,33 @@ -#ifndef IMAGE_APPLY_HEADER_H -#define IMAGE_APPLY_HEADER_H - -#include "ImageApply.h" -#include "ImageApplyAdjustColors.h" -#include "ImageApplyAutoCrop.h" -#include "ImageApplyBWBinaray.h" -#include "ImageApplyChannel.h" -#include "ImageApplyCrop.h" -#include "ImageApplyDiscardBlank.h" -#include "ImageApplyOutHole.h" -#include "ImageApplyDogEarDetection.h" -#include "ImageApplyResize.h" -#include "ImageApplyRotation.h" -#include "ImageApplySharpen.h" -#include "ImageApplyConcatenation.h" -#include "ImageApplyHSVCorrect.h" -#include "ImageApplyDetachNoise.h" -#include "ImageApplyColorRecognition.h" -#include "ImageApplyUV.h" -#include "ImageApplyAutoContrast.h" -#include "ImageApplyCustomCrop.h" -#include "ImageApplyCustomGamma.h" -#include "ImageApplyCvtColor.h" -#include "ImageApplyFadeBackGroundColor.h" -#include "ImageApplyFilter.h" -#include "ImageApplyRefuseInflow.h" -#include "ImageApplySplit.h" -#include "ImageApplyTextureRemoval.h" -#include "ImageMulti.h" -#include "ImageMultiOutputRed.h" -#include "ImageApplySplit.h" -#include "ImageApplySizeDetection.h" -#endif +#ifndef IMAGE_APPLY_HEADER_H +#define IMAGE_APPLY_HEADER_H + +#include "ImageApply.h" +#include "ImageApplyAdjustColors.h" +#include "ImageApplyAutoContrast.h" +#include "ImageApplyAutoCrop.h" +//#include "ImageApplyBarCodeRecognition.h" +#include "ImageApplyBWBinaray.h" +#include "ImageApplyChannel.h" +#include "ImageApplyColorRecognition.h" +#include "ImageApplyConcatenation.h" +#include "ImageApplyCustomCrop.h" +#include "ImageApplyCustomGamma.h" +#include "ImageApplyCvtColor.h" +#include "ImageApplyDetachNoise.h" +#include "ImageApplyDiscardBlank.h" +#include "ImageApplyDispersion.h" +#include "ImageApplyDogEarDetection.h" +#include "ImageApplyFadeBackGroundColor.h" +#include "ImageApplyFilter.h" +#include "ImageApplyHSVCorrect.h" +#include "ImageApplyOutHole.h" +#include "ImageApplyRefuseInflow.h" +#include "ImageApplyResize.h" +#include "ImageApplyRotation.h" +#include "ImageApplySplit.h" +#include "ImageApplySizeDetection.h" +#include "ImageApplyTextureRemoval.h" +#include "ImageMulti.h" +#include "ImageMultiOutputRed.h" +#include "ImageApplySplit.h" +#endif diff --git a/hgdriver/ImageProcess/ImageApplyMarkCrop.cpp b/hgdriver/ImageProcess/ImageApplyMarkCrop.cpp new file mode 100644 index 0000000..bbc710e --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyMarkCrop.cpp @@ -0,0 +1,310 @@ +#include "ImageApplyMarkCrop.h" +#include "ImageProcess_Public.h" + +#define RE 2 +//#define DRAW + +CImageApplyMarkCrop::CImageApplyMarkCrop(CImageApplyMarkCrop::DeviceModel device, bool isCropped, double threshold, int noise, CImageApplyMarkCrop::DPI dpi, DirectionMethod direction) + : m_device(device) + , m_b_isCropped(isCropped) + , m_threshold(120) + , m_noise(noise) + , m_dpi(dpi) + , m_range(30, 55) + , m_direction(direction) +{ + +} + +int CImageApplyMarkCrop::apply(const cv::Mat& src, cv::Mat& dst, Orientation markOri, bool barCode, int& angle) +{ + if (src.empty()) return -1; + + cv::Mat src_resize; + if (m_device == DeviceModel::G400) + cv::resize(src, src_resize, cv::Size(src.cols / RE, src.rows / RE)); + else + cv::resize(src, src_resize, cv::Size(src.cols / 3, src.rows / RE)); + cv::Mat scale_mat; + cv::Mat thre(src_resize.size(), CV_8UC1); + hg::threshold_Mat(src_resize, thre, m_threshold); + +#ifdef DRAW + cv::imwrite("thre.bmp", thre); +#endif + std::vector hierarchy; + std::vector> contours; + + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + + float scale = m_device == DeviceModel::G300 ? 3 : RE; + + if (maxContour.size() == 0) + { + thre.release(); + return -1; + } + + //thre.release(); + //dst.release(); + + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + + cv::Point2f vertex[4]; + rect.points(vertex); + + std::vector> marks; + std::vector rrects; + + hg::threshold_Mat(src_resize, thre, m_threshold); + cv::bitwise_not(thre, thre); + contours.clear(); + hierarchy.clear(); + hg::findContours(thre, contours, hierarchy, cv::RETR_LIST); + findMarks(contours, rect, cv::Range(m_range.start / RE, m_range.end / RE), marks, rrects); + + if (marks.size() < 3) return -2; + +#ifdef DRAW + for (int i = 0; i < marks.size(); i++) + cv::circle(thre, marks[i][0], 30, cv::Scalar(255)); + cv::imwrite("contour.bmp", thre); +#endif + + maxContour.clear(); + for (const std::vector& mark : marks) + for (const cv::Point& p : mark) + maxContour.push_back(p); + + if (rrects.size() == 3) + { + double distance1 = hg::distanceP2P(rrects[0].center, rrects[1].center); + double distance2 = hg::distanceP2P(rrects[1].center, rrects[2].center); + double distance3 = hg::distanceP2P(rrects[2].center, rrects[0].center); + + if (distance1 > distance2 && distance1 > distance3) + maxContour.push_back(((rrects[0].center + rrects[1].center) / 2 * 3 - rrects[2].center) / 2); + else if (distance2 > distance1 && distance2 > distance3) + maxContour.push_back(((rrects[1].center + rrects[2].center) / 2 * 3 - rrects[0].center) / 2); + else + maxContour.push_back(((rrects[2].center + rrects[0].center) / 2 * 3 - rrects[1].center) / 2); + } + + for (cv::Point& item : maxContour) + item *= scale; + + rect = hg::getBoundingRect(maxContour); + rect.points(vertex); + + cv::Point2f focus; + Orientation ori; + + for (size_t i = 0; i < rrects.size(); i++) + for (size_t j = i + 1; j < rrects.size(); j++) + if (rrects[i].size.area() < rrects[j].size.area()) + { + cv::RotatedRect rect_remp = rrects[j]; + rrects[j] = rrects[i]; + rrects[i] = rect_remp; + } + + for (cv::RotatedRect& item : rrects) + item.center *= scale; + + if (m_direction == DirectionMethod::Multilateral) + { + if (rrects.size() < 4) return -3; + + for (int i = 0; i < 5; i++) + focus += rrects[i].center; + focus /= 5; + + float dis_top = hg::distanceP2L(focus, vertex[1], vertex[2]); + float dis_bottom = hg::distanceP2L(focus, vertex[0], vertex[3]); + float dis_left = hg::distanceP2L(focus, vertex[0], vertex[1]); + float dis_right = hg::distanceP2L(focus, vertex[2], vertex[3]); + + float dis_min = cv::min(dis_top, cv::min(dis_bottom, cv::min(dis_left, dis_right))); + if (dis_top == dis_min) + ori = Top_RB; + else if (dis_bottom == dis_min) + ori = Bottom_LT; + else if (dis_left == dis_min) + ori = Left_RT; + else + ori = Right_LB; + } + else if (m_direction == DirectionMethod::Trilateral_7Net) + { + for (int i = 0; i < 3; i++) + focus += rrects[i].center; + focus /= 3; + + float dis_top = hg::distanceP2L(focus, vertex[1], vertex[2]); + float dis_bottom = hg::distanceP2L(focus, vertex[0], vertex[3]); + float dis_left = hg::distanceP2L(focus, vertex[0], vertex[1]); + float dis_right = hg::distanceP2L(focus, vertex[2], vertex[3]); + + float dis_min_lr = cv::min(dis_left, dis_right); + float dis_min_tb = cv::min(dis_top, dis_bottom); + if (dis_min_lr == dis_right && dis_min_tb == dis_bottom) + ori = Bottom_LT; + else if (dis_min_lr == dis_left && dis_min_tb == dis_top) + ori = Top_RB; + else if (dis_min_lr == dis_right && dis_min_tb == dis_top) + ori = Right_LB; + else + ori = Left_RT; + } + + cv::Point2f srcTri[4]; + cv::Point2f dstTri[3]; + rect.points(srcTri); + + if (m_device == DeviceModel::G300) + for (cv::Point2f& p : srcTri) + p.y = p.y * RE / m_device; + + cv::Size temp_size; + float width = rect.size.width; + float height = hg::distanceP2P(srcTri[0], srcTri[1]); + if (markOri == Default || markOri == ori) + { + dstTri[0] = cv::Point2f(0, height - 1); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(width - 1, 0); + temp_size.width = width; + temp_size.height = height; + angle = 0; + } + else if (markOri - ori == -3 || markOri - ori == 1) + { + dstTri[0] = cv::Point2f(0, 0); + dstTri[1] = cv::Point2f(height - 1, 0); + dstTri[2] = cv::Point2f(height - 1, width - 1); + temp_size.width = height; + temp_size.height = width; + angle = -90; + } + else if (markOri - ori == -2 || markOri - ori == 2) + { + dstTri[0] = cv::Point2f(width - 1, 0); + dstTri[1] = cv::Point2f(width - 1, height - 1); + dstTri[2] = cv::Point2f(0, height - 1); + temp_size.width = width; + temp_size.height = height; + angle = 180; + } + else if (markOri - ori == -1 || markOri - ori == 3) + { + dstTri[0] = cv::Point2f(height - 1, width - 1); + dstTri[1] = cv::Point2f(0, width - 1); + dstTri[2] = cv::Point2f(0, 0); + temp_size.width = height; + temp_size.height = width; + angle = 90; + } + + if (m_b_isCropped) + { + cv::Mat warp_mat; + warp_mat = cv::getAffineTransform(srcTri, dstTri); + cv::warpAffine(src, dst, warp_mat, temp_size); + } + else + { + if (angle == 0) + dst = src.clone(); + else if (angle == 90) + { + cv::transpose(src, dst); + cv::flip(dst, dst, 0); + } + else if (angle == -90) + { + cv::transpose(src, dst); + cv::flip(dst, dst, 1); + } + else + { + cv::flip(src, dst, 0); + cv::flip(dst, dst, 1); + } + } + + //Ҫж + if (barCode) + { + //cv::imwrite("dst.bmp", dst); + if (dst.cols < 600 || dst.rows < 400) + return -4; + if (!isContainBarCode(dst(cv::Rect(0, 0, 600, 400)))) + return -5; + } + + return 0; + +#ifdef DRAW + cv::imwrite("dst.bmp", dst); +#endif +} + +void CImageApplyMarkCrop::findMarks(const std::vector>& contours, const cv::RotatedRect& region, + const cv::Range& range, std::vector>& marks, std::vector& rrect) +{ + cv::RotatedRect region_outside = region; + cv::RotatedRect region_inside = region; + region_inside.size = cv::Size2f(region.size.width * 0.9, region.size.height * 0.9); + + cv::Point2f outside[4], inside[4]; + region_outside.points(outside); + region_inside.points(inside); + + std::vector v_outside, v_inside; + for (size_t i = 0; i < 4; i++) + { + v_outside.push_back(cv::Point(outside[i].x, outside[i].y)); + v_inside.push_back(cv::Point(inside[i].x, inside[i].y)); + } + for (size_t i = 0, length = contours.size(); i < length; i++) + { + std::vector contour = contours[i]; + cv::RotatedRect rect = cv::minAreaRect(contour); + double area = cv::contourArea(contour); + + if (rect.size.width < range.start || rect.size.height < range.start || rect.size.width > range.end || rect.size.height > range.end) + continue; + if (rect.size.width * rect.size.height < 40 / RE) + continue; + + if (cv::pointPolygonTest(v_outside, rect.center, true) > 0 && cv::pointPolygonTest(v_inside, rect.center, true) < 0) + { + marks.push_back(contour); + rrect.push_back(rect); + } + } +} + +bool CImageApplyMarkCrop::isContainBarCode(const cv::Mat& image) +{ + cv::Mat thre; + hg::threshold_Mat(image, thre, 127); + cv::bitwise_not(thre, thre); + + cv::Mat element = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(20, 1)); + cv::morphologyEx(thre, thre, cv::MorphTypes::MORPH_DILATE, element); + //cv::imwrite("barCode.bmp", thre); + + std::vector hierarchy; + std::vector> contours; + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + + for (size_t i = 0; i < contours.size(); i++) + { + cv::Rect rect = cv::boundingRect(contours[i]); + if (rect.width > 250 && rect.height > 50) + return true; + } + return false; +} diff --git a/hgdriver/ImageProcess/ImageApplyMarkCrop.h b/hgdriver/ImageProcess/ImageApplyMarkCrop.h new file mode 100644 index 0000000..29b1398 --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyMarkCrop.h @@ -0,0 +1,116 @@ +/* + * ==================================================== + + * 功能:Mark点定位裁剪。识别试卷中的mark点,进行纠偏裁剪。该功能不能完全独立使用,因为可能会识别失败,然后需要继续用传统裁剪纠偏进行补充。 + * 作者:刘丁维 + * 生成时间:2020/5/22 + * 最近修改时间:2020/5/22 v1.0 + 2020/7/29 v1.1 优化Mark点识别,以及文稿方向判定 + 2020/7/30 v1.1.1 优化Mark点识别,以及文稿方向判定 + 2020/8/3 v1.2 针对七天,添加三Mark点识别文稿方向,原来的方式定义为多边识别文稿方向 + 2020/8/12 v1.3 针对七天,添加了条码判断算法,用于判定试卷是否为指定试卷。该条码只是粗略识别是否是条码,而不进行准确识别。 + apply接口增加barCode参数,用于是否开启粗判断条码功能 + 2020/8/12 v1.4 针对七天,添加裁剪接口,可进行裁剪与不裁剪两种选择 + * 版本号:v1.4 + + * ==================================================== + */ + +#ifndef IMAGEMARKCROPAPPLY_H +#define IMAGEMARKCROPAPPLY_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyMarkCrop +{ +public: + + //识别文稿方向方式 + enum DirectionMethod + { + Trilateral_7Net, //三边定位文稿方向(针对七天需求) + Multilateral //多边定位文稿方向 + }; + + enum DPI : ushort + { + DPI_200 = 200, + DPI_300 = 300 + }; + + enum DeviceModel + { + G400 = 2, + G300 = 3 + }; + + enum Orientation + { + Default = 0, + Left_RT, //多边文稿方向识别时靠左为正;7天3mark识别时,缺角在右上为正 + Top_RB, //多边文稿方向识别时靠上为正;7天3mark识别时,缺角在右下为正 + Right_LB, //多边文稿方向识别时靠右为正;7天3mark识别时,缺角在左下为正 + Bottom_LT //多边文稿方向识别时靠下为正;7天3mark识别时,缺角在左上为正 + }; + +public: + CImageApplyMarkCrop(DeviceModel device, bool isCropped = true, double threshold = 20, int noise = 40, DPI dpi = DPI::DPI_200, DirectionMethod direction = DirectionMethod::Multilateral); + + /* + * src [in]: 原图 + * dst [out]:处理成功时,返回的结果图像 + * markOri [in]: 文稿方向判定方式 + * barCode [in]: 是否判断条形码,该功能只针对Trilateral_7Net模式 + * angle [out]:返回文稿方向偏转角度。有0、90、180、270四种情况 + * 返回值: 0:成功; + -1:原图为空,或者无法找到图片轮廓(纯黑图会报该错误); + -2:mark小于3个 + -3:选择Multilateral模式时,mark点小于4个 + -4:识别条形码时,目标图像过小,无法包含条形码 + -5:无条形码 + */ + int apply(const cv::Mat& src, cv::Mat& dst, Orientation markOri, bool barCode, int& angle); + + inline DeviceModel getDeviceModel() { return m_device; } + + inline void setDeviceModel(DeviceModel device) { m_device = device; } + + inline bool isCropped() { return m_b_isCropped; } + + inline void setCropped(bool cropped) { m_b_isCropped = cropped; } + + inline double getThreshold() { return m_threshold; } + + inline void setThreshold(double threshold) { m_threshold = threshold; } + + inline int getNoise() { return m_noise; } + + inline void setNoise(int noise) { m_noise = noise; } + + inline DPI getDPI() { return m_dpi; } + + inline void setDPI(DPI dpi) { m_dpi = dpi; } + + inline const cv::Range getSizeRange() { return m_range; } + + inline void setSizeRange(const cv::Range& range) { m_range = range; } + + inline void setSizeRange(int low, int up) { m_range = cv::Range(low, up); } + +private: + + void findMarks(const std::vector>& contours, const cv::RotatedRect& region, const cv::Range& range, + std::vector>& marks, std::vector& rrect); + + bool isContainBarCode(const cv::Mat& image); +private: + DeviceModel m_device; + bool m_b_isCropped; + double m_threshold; + int m_noise; + DPI m_dpi; + cv::Range m_range; + DirectionMethod m_direction; +}; + +#endif // IMAGEMARKCROPAPPLY_H \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageApplyOutHole.cpp b/hgdriver/ImageProcess/ImageApplyOutHole.cpp index 3baeeff..7b793ab 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.cpp +++ b/hgdriver/ImageProcess/ImageApplyOutHole.cpp @@ -1,323 +1,342 @@ -#include "ImageApplyOutHole.h" -#include "ImageProcess_Public.h" - -#ifdef LOG -#include "Device/filetools.h" -#endif // LOG - -CImageApplyOutHole::CImageApplyOutHole(void) - : CImageApply() - , m_borderSize(600) - , m_edgeScale(0.1f) - , m_threshold(100) -{ -} - -CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold) - : CImageApply() - , m_borderSize(borderSize) - , m_edgeScale(edgeScale) - , m_threshold(threshold) -{ -} - -CImageApplyOutHole::~CImageApplyOutHole(void) -{ -} - -void CImageApplyOutHole::apply(cv::Mat& pDib, int side) -{ - (void)pDib; - (void)side; -} - -void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) -{ -#ifdef LOG - FileTools::write_log("imgprc.txt", "enter ImageOutHole apply"); -#endif // LOG - - if (mats.size() < 2) - { -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); -#endif // LOG - return; - } - - if (mats[0].empty() || mats[1].empty()) - { -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); -#endif // LOG - return; - } - - //二值化正反面图像 - cv::Mat front = mats[0]; - cv::Mat 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::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 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::flip(back_thre, back_thre, 1); //1:Horizontal - - //正反面图像寻边 - 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); - - //提取正反面图像最大轮廓 - std::vector maxContour_front = hg::getMaxContour(contours_front, b1_front); - std::vector maxContour_back = hg::getMaxContour(contours_back, b1_back); - - cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //提取正面最大轮廓的最小外接矩形 - cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //提取反面最大轮廓的最小外接矩形 - - //如果正反面图像尺寸差异超过20个像素,直接放弃处理 - if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 || - cv::abs(rrect_front.size.height - rrect_back.size.height) > 20) - return; - - //提取正反面图像重叠部分区域 - cv::Rect roi_front, roi_back; - cv::RotatedRect mask_rotatedRect; - getRoi(rrect_front, rrect_back, cv::Size(front.cols, front.rows), roi_front, roi_back, mask_rotatedRect); - - cv::Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分 - cv::Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分 - - //正反面二值图像做或运算,真正镂空区域保留0,其他地方填充为255 - cv::Mat mask; - cv::bitwise_or(roiMat_front, roiMat_back, mask); //或运算,正反面二值图像重叠 - - //cv::imwrite("roiMat_front.jpg", roiMat_front); - //cv::imwrite("roiMat_back.jpg", roiMat_back); - - //二值图像重叠图像颜色取反,膨胀,提取轮廓 - cv::bitwise_not(mask, 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), 15); //绘制纸张矩形边缘 - - std::vector> contours_mask; - std::vector b1_mask; - 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); - //for (size_t i = 0; i < hole_contours.size(); i++) - // cv::drawContours(mask, hole_contours, static_cast(i), cv::Scalar(127), 2); - //cv::imwrite("mask.jpg", mask); - cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area()); - 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); - hg::fillPolys(front_temp, contourss_temp, color); - } - - if (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()); - 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)); - - std::vector> contours_temp; - contours_temp.push_back(hole_contour); - cv::Mat back_temp = back(roi_back); - hg::fillPolys(back_temp, contours_temp, color); - } - } -#ifdef LOG - FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); -#endif // LOG -} - -void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize, - cv::Rect& roi_front, cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect) -{ - cv::Size size(static_cast(rrect_front.size.width + rrect_back.size.width) / 2, static_cast(rrect_front.size.height + rrect_back.size.height) / 2); - float angle = (rrect_front.angle + rrect_back.angle) / 2; - - rrect_front.size = rrect_back.size = size; - rrect_front.angle = rrect_back.angle = angle; - - roi_front = rrect_front.boundingRect(); - roi_back = rrect_back.boundingRect(); - - if (roi_front.width != roi_back.width || roi_front.height != roi_back.height) - { - roi_front.height = roi_back.height; - roi_front.width = roi_back.width; - } - - cv::Point offset(0, 0); - int top = std::min(roi_front.y, roi_back.y); - if (top < 0) - { - roi_front.y -= top; - roi_back.y -= top; - roi_front.height += top; - roi_back.height += top; - offset.y += top; - } - - int left = std::min(roi_front.x, roi_back.x); - if (left < 0) - { - roi_front.x -= left; - roi_back.x -= left; - roi_front.width += left; - roi_back.width += left; - offset.x += left; - } - - int right = std::max(roi_front.x + roi_front.width, roi_back.x + roi_back.width); - if (right >= srcSize.width) - { - roi_front.width -= (right - srcSize.width + 1); - roi_back.width -= (right - srcSize.width + 1); - } - - int bottom = std::max(roi_front.y + roi_front.height, roi_back.y + roi_back.height); - if (bottom >= srcSize.height) - { - roi_front.height -= (bottom - srcSize.height + 1); - roi_back.height -= (bottom - srcSize.height + 1); - } - - mask_rotatedRect.center = cv::Point((roi_front.width + offset.x) / 2, (roi_front.height + offset.y) / 2); - mask_rotatedRect.size = size; - mask_rotatedRect.angle = angle; -} - -std::vector> CImageApplyOutHole::filterPoly(std::vector>& contours, const std::vector& m, - cv::RotatedRect roi, float edgeScale, float areaThreshold) -{ - edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f)); - cv::RotatedRect roi2(roi.center, cv::Size(static_cast(roi.size.width * (1 - edgeScale * 2)), - static_cast(roi.size.height * (1 - edgeScale * 2))), roi.angle); - - std::vector vertices_roi1 = hg::getVertices(roi); - std::vector vertices_roi2 = hg::getVertices(roi2); - - std::vector> hole_contours; - for (size_t i = 0, length = contours.size(); i < length; i++) - { - if (m[i][2] != -1) continue; - - cv::RotatedRect rrect = hg::getBoundingRect(contours[i]); - if (rrect.size.area() < areaThreshold) continue; - - bool enabled = true; - for (size_t j = 0, count = contours[i].size(); j < count; j++) - { - cv::Point p(contours[i][j]); - double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外 - double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外 - //如果在纸张外,或者边缘内,视为非孔洞 - if (temp1 < 0 || temp2 > 0) - { - enabled = false; - break; - } - } - - if (enabled) - hole_contours.push_back(contours[i]); - } - return hole_contours; -} - -cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const 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 - m_threshold; - while (length < length_max) - { - for (size_t i = m_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; +#include "ImageApplyOutHole.h" +#include "ImageProcess_Public.h" + +#ifdef LOG +#include "Device/filetools.h" +#endif // LOG + +CImageApplyOutHole::CImageApplyOutHole(void) + : CImageApply() + , m_borderSize(600) + , m_edgeScale(0.1f) + , m_threshold(100) +{ +} + +CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold) + : CImageApply() + , m_borderSize(borderSize) + , m_edgeScale(edgeScale) + , m_threshold(threshold) +{ +} + +CImageApplyOutHole::~CImageApplyOutHole(void) +{ +} + +void CImageApplyOutHole::apply(cv::Mat& pDib, int side) +{ + (void)pDib; + (void)side; +} + +void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter ImageOutHole apply"); +#endif // LOG + + if (mats.size() < 2) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + if (mats[0].empty() || mats[1].empty()) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + //ֵͼ + cv::Mat front = mats[0]; + cv::Mat 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::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 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::flip(back_thre, back_thre, 1); //1:Horizontal + + //ͼѰ + 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); + + //ȡͼ + std::vector maxContour_front = hg::getMaxContour(contours_front, b1_front); + std::vector maxContour_back = hg::getMaxContour(contours_back, b1_back); + + if (maxContour_front.empty() || maxContour_back.empty()) + return; + + cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //ȡСӾ + cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //ȡСӾ + + //ͼߴ쳬20أֱӷ + if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 || + cv::abs(rrect_front.size.height - rrect_back.size.height) > 20) + return; + + //ȡͼص + cv::Rect roi_front, roi_back; + cv::RotatedRect mask_rotatedRect; + getRoi(rrect_front, rrect_back, front.size(), back.size(), roi_front, roi_back, mask_rotatedRect); + + cv::Mat roiMat_front(front_thre, roi_front); //ֵͼнȡص + cv::Mat roiMat_back(back_thre, roi_back); //ڷֵͼнȡص + //cv::imwrite("roiMat_front.jpg", roiMat_front); + //cv::imwrite("roiMat_back.jpg", roiMat_back); + + //ֵͼ㣬ο0طΪ255 + cv::Mat mask; + cv::bitwise_or(roiMat_front, roiMat_back, mask); //㣬ֵͼص + //cv::imwrite("mask1.jpg", mask); + + //ֵͼصͼɫȡͣȡ + 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::imwrite("mask3.jpg", mask); + + //Ϊ˱׶׹ᴩֽߣΪֽȷп׶ΪͼΣ뱳ճ + cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(255), 15); //ֽžαԵ + //cv::imwrite("mask4.jpg", mask); + + std::vector> contours_mask; + std::vector b1_mask; + 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); + + cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area()); + 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); + hg::fillPolys(front_temp, contourss_temp, color); + } + + if (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()); + 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)); + + std::vector> contours_temp; + contours_temp.push_back(hole_contour); + cv::Mat back_temp = back(roi_back); + hg::fillPolys(back_temp, contours_temp, color); + } + } +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG +} + +void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, const cv::Size& srcSize_front, const cv::Size& srcSize_back, cv::Rect& roi_front, + cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect) +{ + cv::Rect roi_front_ = rrect_front.boundingRect(); + cv::Rect roi_back_ = rrect_back.boundingRect(); + + cv::Size meanSize = (roi_front_.size() + roi_back_.size()) / 2; + roi_front_.x += (roi_front_.width - meanSize.width) / 2; + roi_front_.width = meanSize.width; + roi_front_.y += (roi_front_.height - meanSize.height) / 2; + roi_front_.height = meanSize.height; + roi_back_.x += (roi_back_.width - meanSize.width) / 2; + roi_back_.width = meanSize.width; + roi_back_.y += (roi_back_.height - meanSize.height) / 2; + roi_back_.height = meanSize.height; + + mask_rotatedRect.angle = (rrect_front.angle + rrect_back.angle) / 2; + mask_rotatedRect.size = (rrect_front.size + rrect_back.size) / 2.0f; + mask_rotatedRect.center = cv::Point2f(roi_front_.size().width + roi_back_.size().width, roi_front_.size().height + roi_back_.size().height) / 4.0f; + + roi_front = roi_front_ & cv::Rect(cv::Point(0, 0), srcSize_front); + roi_back = roi_back_ & cv::Rect(cv::Point(0, 0), srcSize_back); + + int offset_left_f = roi_front.x - roi_front_.x; + int offset_left_b = roi_back.x - roi_back_.x; + int offset_top_f = roi_front.y - roi_front_.y; + int offset_top_b = roi_back.y - roi_back_.y; + int offset_right_f = roi_front_.br().x - roi_front.br().x; + int offset_right_b = roi_back_.br().x - roi_back.br().x; + int offset_bottom_f = roi_front_.br().y - roi_front.br().y; + int offset_bottom_b = roi_back_.br().y - roi_back.br().y; + + if (offset_left_f > offset_left_b) + { + roi_back.x += offset_left_f - offset_left_b; + roi_back.width -= offset_left_f - offset_left_b; + mask_rotatedRect.center.x -= offset_left_f - offset_left_b; + } + else + { + roi_front.x += offset_left_b - offset_left_f; + roi_front.width -= offset_left_b - offset_left_f; + mask_rotatedRect.center.x -= offset_left_b - offset_left_f; + } + + if (offset_top_f > offset_top_b) + { + roi_back.y += offset_top_f - offset_top_b; + roi_back.height -= offset_top_f - offset_top_b; + mask_rotatedRect.center.y -= offset_top_f - offset_top_b; + } + else + { + roi_front.y += offset_top_b - offset_top_f; + roi_front.height -= offset_top_b - offset_top_f; + mask_rotatedRect.center.y -= offset_top_b - offset_top_f; + } + + if (offset_right_f > offset_right_b) + roi_back.width -= offset_right_f - offset_right_b; + else + roi_front.width -= offset_right_b - offset_right_f; + + if (offset_bottom_f > offset_bottom_b) + roi_back.height -= offset_bottom_f - offset_bottom_b; + else + roi_front.height -= offset_bottom_b - offset_bottom_f; +} + +std::vector> CImageApplyOutHole::filterPoly(std::vector>& contours, const std::vector& m, + cv::RotatedRect roi, float edgeScale, float areaThreshold) +{ + edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f)); + cv::RotatedRect roi2(roi.center, cv::Size(static_cast(roi.size.width * (1 - edgeScale * 2)), + static_cast(roi.size.height * (1 - edgeScale * 2))), roi.angle); + + std::vector vertices_roi1 = hg::getVertices(roi); + std::vector vertices_roi2 = hg::getVertices(roi2); + + std::vector> hole_contours; + for (size_t i = 0, length = contours.size(); i < length; i++) + { + if (m[i][2] != -1) continue; + + cv::RotatedRect rrect = hg::getBoundingRect(contours[i]); + if (rrect.size.width < areaThreshold || + rrect.size.height < areaThreshold || + rrect.size.width > areaThreshold * 6 || + rrect.size.height > areaThreshold * 6) + continue; + + bool enabled = true; + for (size_t j = 0, count = contours[i].size(); j < count; j++) + { + cv::Point p(contours[i][j]); + double temp1 = pointPolygonTest(vertices_roi1, p, false); //жǷֽ 1ڣ0ϣ-1 + double temp2 = pointPolygonTest(vertices_roi2, p, false); //жǷڱԵ 1ڣ0ϣ-1 + //ֽ⣬߱ԵڣΪǿ׶ + if (temp1 < 0 || temp2 > 0) + { + enabled = false; + break; + } + } + + if (enabled) + hole_contours.push_back(contours[i]); + } + return hole_contours; +} + +cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const 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 4d0feaf..7bd7cce 100644 --- a/hgdriver/ImageProcess/ImageApplyOutHole.h +++ b/hgdriver/ImageProcess/ImageApplyOutHole.h @@ -1,74 +1,80 @@ -/* - * ==================================================== - - * 功能:装订孔填充 - * 作者:刘丁维 - * 生成时间: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。 - * 版本号:v1.5 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_OUT_HOLE_H -#define IMAGE_APPLY_OUT_HOLE_H - -#include "ImageApply.h" - -class CImageApplyOutHole : public CImageApply -{ -public: - - CImageApplyOutHole(); - - /* - * borderSize [in]:孔洞面积阈值 - * edgeScale [in]:纸张边缘区域比例,取值范围(0,0.5),默认值0.1 - * threshold [in]:二值化阈值 - */ - CImageApplyOutHole(float borderSize, float edgeScale, double threshold); - - ~CImageApplyOutHole(void); - - virtual void apply(std::vector& mats, bool isTwoSide); - - float getBorderSize() { return m_borderSize; } - - float getEdgeScale() { return m_edgeScale; } - - double getThreshold() { return m_threshold; } - - void setBorderSize(float size) { m_borderSize = size; } - - void setEdgeScale(float scale) { m_edgeScale = scale; } - - void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); } - -private: - - virtual void apply(cv::Mat& pDib, int side); - - void getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize, cv::Rect& roi_front, - cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect); - - std::vector > filterPoly(std::vector>& contours, const std::vector& m, cv::RotatedRect roi, - float edgeScale, float areaThreshold); - - 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); - -private: - float m_borderSize; - float m_edgeScale; - double m_threshold; -}; - -#endif // !IMAGE_APPLY_OUT_HOLE_H +/* + * ==================================================== + + * ܣװ + * ߣά + * ʱ䣺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 + * 汾ţv1.7.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_OUT_HOLE_H +#define IMAGE_APPLY_OUT_HOLE_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyOutHole : public CImageApply +{ +public: + + CImageApplyOutHole(); + + /* + * borderSize [in]:׶ֵ + * edgeScale [in]:ֽűԵȡֵΧ(0,0.5),Ĭֵ0.1 + * threshold [in]:ֵֵ + */ + CImageApplyOutHole(float borderSize, float edgeScale, double threshold); + + ~CImageApplyOutHole(void); + + virtual void apply(std::vector& mats, bool isTwoSide); + + float getBorderSize() { return m_borderSize; } + + float getEdgeScale() { return m_edgeScale; } + + double getThreshold() { return m_threshold; } + + void setBorderSize(float size) { m_borderSize = size; } + + void setEdgeScale(float scale) { m_edgeScale = scale; } + + void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); } + +private: + + virtual void apply(cv::Mat& pDib, int side); + + void getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, const cv::Size& srcSize_front, const cv::Size& srcSize_back, cv::Rect& roi_front, + cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect); + + std::vector > filterPoly(std::vector>& contours, const std::vector& m, cv::RotatedRect roi, + float edgeScale, float areaThreshold); + + 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); + +private: + float m_borderSize; + float m_edgeScale; + double m_threshold; +}; + +#endif // !IMAGE_APPLY_OUT_HOLE_H diff --git a/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp b/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp index 45f91e0..6e41ca4 100644 --- a/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp +++ b/hgdriver/ImageProcess/ImageApplyRefuseInflow.cpp @@ -1,64 +1,64 @@ -#include "ImageApplyRefuseInflow.h" -#include "ImageApplyAdjustColors.h" - -CImageApplyRefuseInflow::CImageApplyRefuseInflow(int constrast) - : m_adjustColor(new CImageApplyAdjustColors(0, constrast, 1.0f)) -{ -} - -CImageApplyRefuseInflow::~CImageApplyRefuseInflow() -{ - delete m_adjustColor; -} - -void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side) -{ - (void)side; -#if 0 - static unsigned char table_contrast[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255 }; - static cv::Mat mat_table(1, 256, CV_8UC1, table_contrast); - cv::LUT(pDib, mat_table, pDib); -#else - m_adjustColor->apply(pDib, side); -#endif -} - -void CImageApplyRefuseInflow::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyRefuseInflow.h" +#include "ImageApplyAdjustColors.h" + +CImageApplyRefuseInflow::CImageApplyRefuseInflow(int constrast) + : m_adjustColor(new CImageApplyAdjustColors(0, constrast, 1.0f)) +{ +} + +CImageApplyRefuseInflow::~CImageApplyRefuseInflow() +{ + delete m_adjustColor; +} + +void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side) +{ + (void)side; +#if 0 + static unsigned char table_contrast[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255 }; + static cv::Mat mat_table(1, 256, CV_8UC1, table_contrast); + cv::LUT(pDib, mat_table, pDib); +#else + m_adjustColor->apply(pDib, side); +#endif +} + +void CImageApplyRefuseInflow::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyRefuseInflow.h b/hgdriver/ImageProcess/ImageApplyRefuseInflow.h index 672cd0d..72a5ba5 100644 --- a/hgdriver/ImageProcess/ImageApplyRefuseInflow.h +++ b/hgdriver/ImageProcess/ImageApplyRefuseInflow.h @@ -1,34 +1,34 @@ -/* - * ==================================================== - - * ܣ͸ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺v1.0 2020/04/21 - * v1.1 2022/05/04 ع㷨߶Աȶʵַ͸ - * 汾ţv1.1 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_REFUSE_INFLOW_H -#define IMAGE_APPLY_REFUSE_INFLOW_H - -#include "ImageApply.h" - -class CImageApplyAdjustColors; -class CImageApplyRefuseInflow : public CImageApply -{ -public: - CImageApplyRefuseInflow(int constrast = 15); - - virtual ~CImageApplyRefuseInflow(); - - virtual void apply(cv::Mat& pDib, int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - -private: - CImageApplyAdjustColors* m_adjustColor; -}; -#endif // !IMAGE_APPLY_REFUSE_INFLOW_H +/* + * ==================================================== + + * ܣ͸ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺v1.0 2020/04/21 + * v1.1 2022/05/04 ع㷨߶Աȶʵַ͸ + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_REFUSE_INFLOW_H +#define IMAGE_APPLY_REFUSE_INFLOW_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class GIMGPROC_LIBRARY_API CImageApplyRefuseInflow : public CImageApply +{ +public: + CImageApplyRefuseInflow(int constrast = 15); + + virtual ~CImageApplyRefuseInflow(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + CImageApplyAdjustColors* m_adjustColor; +}; +#endif // !IMAGE_APPLY_REFUSE_INFLOW_H diff --git a/hgdriver/ImageProcess/ImageApplyResize.cpp b/hgdriver/ImageProcess/ImageApplyResize.cpp index 7411eee..3c62054 100644 --- a/hgdriver/ImageProcess/ImageApplyResize.cpp +++ b/hgdriver/ImageProcess/ImageApplyResize.cpp @@ -1,45 +1,47 @@ -#include "ImageApplyResize.h" - -CImageApplyResize::CImageApplyResize() - : m_fx(1.0) - , m_fy(1.0) - , m_type(ResizeType::RATIO) -{ -} - -CImageApplyResize::CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy) - : m_type(type) - , m_dSize(size) - , m_fx(fx) - , m_fy(fy) -{ -} - - -CImageApplyResize::~CImageApplyResize(void) -{ -} - - -void CImageApplyResize::apply(cv::Mat& pDib,int side) -{ - (void)side; - if (pDib.empty()) return; - if (m_type == ResizeType::RATIO) - cv::resize(pDib, pDib, cv::Size(0, 0), m_fx, m_fy); - else - cv::resize(pDib, pDib, m_dSize); -} - -void CImageApplyResize::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyResize.h" + +CImageApplyResize::CImageApplyResize() + : m_fx(1.0) + , m_fy(1.0) + , m_type(ResizeType::RATIO) +{ +} + +CImageApplyResize::CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy) + : m_type(type) + , m_dSize(size) + , m_fx(fx) + , m_fy(fy) +{ +} + + +CImageApplyResize::~CImageApplyResize(void) +{ +} + + +void CImageApplyResize::apply(cv::Mat& pDib,int side) +{ + (void)side; + if (pDib.empty()) return; + + if (m_type == ResizeType::RATIO) + cv::resize(pDib, pDib, cv::Size(0, 0), m_fx, m_fy); + else + cv::resize(pDib, pDib, m_dSize); +} + +void CImageApplyResize::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyResize.h b/hgdriver/ImageProcess/ImageApplyResize.h index f7dfc21..c243744 100644 --- a/hgdriver/ImageProcess/ImageApplyResize.h +++ b/hgdriver/ImageProcess/ImageApplyResize.h @@ -1,69 +1,69 @@ -/* - * ==================================================== - - * 功能:自定义伽马校正。原理为哈希表查值 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/4/21 - * 版本号:v1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_RESIZE_H -#define IMAGE_APPLY_RESIZE_H - -#include "ImageApply.h" - -class CImageApplyResize : public CImageApply -{ -public: - - enum class ResizeType - { - RATIO, //比例缩放 - DSIZE //尺寸缩放 - }; - -public: - CImageApplyResize(); - - /* - * type [in]:缩放类型 - * size [in]:目标尺寸,当type为DSIZE时生效 - * fx [in]:横向目标比例,当type为RATIO时生效 - * fy [in]:纵向目标比例,当type为RATIO时生效 - */ - CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy); - - virtual ~CImageApplyResize(void); - - virtual void apply(cv::Mat& pDib,int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - - double getFX() { return m_fx; } - - double getFY() { return m_fy; } - - cv::Size getDSize() { return m_dSize; } - - ResizeType getType() { return m_type; } - - void setFX(double value) { m_fx = value; } - - void setFY(double value) { m_fy = value; } - - void setDSize(const cv::Size& size) { m_dSize = size; } - - void setType(ResizeType type) { m_type = type; } - -private: - double m_fx; - double m_fy; - cv::Size m_dSize; - ResizeType m_type; -}; - -#endif // !IMAGE_APPLY_RESIZE_H +/* + * ==================================================== + + * ܣԶ٤УԭΪϣֵ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_RESIZE_H +#define IMAGE_APPLY_RESIZE_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyResize : public CImageApply +{ +public: + + enum class ResizeType + { + RATIO, // + DSIZE //ߴ + }; + +public: + CImageApplyResize(); + + /* + * type [in]: + * size [in]:Ŀߴ磬typeΪDSIZEʱЧ + * fx [in]:ĿtypeΪRATIOʱЧ + * fy [in]:ĿtypeΪRATIOʱЧ + */ + CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy); + + virtual ~CImageApplyResize(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + + double getFX() { return m_fx; } + + double getFY() { return m_fy; } + + cv::Size getDSize() { return m_dSize; } + + ResizeType getType() { return m_type; } + + void setFX(double value) { m_fx = value; } + + void setFY(double value) { m_fy = value; } + + void setDSize(const cv::Size& size) { m_dSize = size; } + + void setType(ResizeType type) { m_type = type; } + +private: + double m_fx; + double m_fy; + cv::Size m_dSize; + ResizeType m_type; +}; + +#endif // !IMAGE_APPLY_RESIZE_H diff --git a/hgdriver/ImageProcess/ImageApplyRotation.cpp b/hgdriver/ImageProcess/ImageApplyRotation.cpp index 782d6c0..51f27a2 100644 --- a/hgdriver/ImageProcess/ImageApplyRotation.cpp +++ b/hgdriver/ImageProcess/ImageApplyRotation.cpp @@ -1,172 +1,139 @@ -#include "ImageApplyRotation.h" -//#define USE_TESSERCAT - -//#define USE_HANWANG - -//#define HG_GPDF_API_BUILD -#include "hg_ocr.h" - -CImageApplyRotation::CImageApplyRotation(RotationType rotation, bool isBackTransposed, int dpi, const char* tessdataPath) - : m_rotation(rotation) - , m_backTranspose(isBackTransposed) - , m_dpi(dpi) - , osd(nullptr) -{ - if (rotation == RotationType::AutoTextOrientation) - { -#ifdef USE_TESSERCAT - osd = new HG_OCR(); - std::string strpath(tessdataPath); - reinterpret_cast(osd)->init(strpath.c_str(), HG_OCR::PSM_TYPE::Orientation); -#endif - } -} - -CImageApplyRotation::~CImageApplyRotation() -{ -#ifdef USE_TESSERCAT - if (osd) delete reinterpret_cast(osd); -#endif -} - -void CImageApplyRotation::apply(cv::Mat& pDib, int side) -{ - m_angleResult = 0; - if (pDib.empty()) - { - return; - } - - if (m_rotation == RotationType::AutoTextOrientation) //�Զ��ı�����ʶ�� - { -#ifdef USE_HANWANG - cv::Mat temp; - if (m_dpi != 200) - { - double scale = 200 / static_cast(m_dpi); - int new_w = static_cast(pDib.cols * scale) / 4 * 4; - int new_h = pDib.rows * scale; - cv::resize(pDib, temp, cv::Size(new_w, new_h)); - } - else - temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); - - if (temp.channels() == 3) - cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); - cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU); - - int orientation = HG_OCR::orientation(temp.data, temp.cols, temp.rows, temp.channels()); - - switch (orientation) - { - case 90: - cv::transpose(pDib, pDib); - cv::flip(pDib, pDib, 0); - break; - case 180: - cv::flip(pDib, pDib, 0); - cv::flip(pDib, pDib, 1); - break; - case 270: - cv::transpose(pDib, pDib); - cv::flip(pDib, pDib, 1); - break; - default: - break; - } -#endif -#ifdef USE_TESSERCAT - if (osd) - { - cv::Mat temp; - if (m_dpi != 200) - { - double scale = 200 / static_cast(m_dpi); - int new_w = (static_cast(pDib.cols * scale) + 3) / 4 * 4; - int new_h = pDib.rows * scale; - cv::resize(pDib, temp, cv::Size(new_w, new_h)); - } - else - temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); - - - HG_OCR* ptr_osd = reinterpret_cast(osd); - int ori = -1; - int direction = -1; - int order = -1; - float angle = -1; - ptr_osd->getOrientation(temp.data, temp.cols, temp.rows, temp.channels(), temp.step1(), - ori, direction, order, angle); - - switch (ori) - { - case 1: - cv::transpose(pDib, pDib); - cv::flip(pDib, pDib, 0); - m_angleResult = 90; - break; - case 2: - cv::flip(pDib, pDib, 0); - cv::flip(pDib, pDib, 1); - m_angleResult = 180; - break; - case 3: - cv::transpose(pDib, pDib); - cv::flip(pDib, pDib, 1); - m_angleResult = 270; - break; - default: - m_angleResult = 0; - break; - } - } -#endif - } - else if (m_backTranspose && side == 1) //������ת180 - { - if (m_rotation != RotationType::Rotate_180) //��ת180�� - { - if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� - { - transpose(pDib, pDib); - flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1); - m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 270 : 90; - } - else - { - flip(pDib, pDib, 0); - flip(pDib, pDib, 1); - m_angleResult = 180; - } - } - } - else //zh - { - if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� - { - transpose(pDib, pDib); - flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 1 : 0); - m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 90 : 270; - } - else if (m_rotation == RotationType::Rotate_180) - { - flip(pDib, pDib, 0); - flip(pDib, pDib, 1); - m_angleResult = 180; - } - } -} - -void CImageApplyRotation::apply(std::vector& mats, bool isTwoSide) -{ - (void)isTwoSide; - m_angleResults.clear(); - int i = 0; - for (cv::Mat& var : mats) { - if (!var.empty()) { - apply(var, i); - m_angleResults.push_back(m_angleResult); - i++; - } - } -} +#include "ImageApplyRotation.h" + +#ifdef _WIN32 +#ifdef USE_HANWANG +#include +#endif +#endif + +CImageApplyRotation::CImageApplyRotation(RotationType rotation, bool isBackTransposed, int dpi, const char* tessdataPath) + : m_rotation(rotation) + , m_backTranspose(isBackTransposed) + , m_dpi(dpi) +#ifdef _WIN32 +#ifdef USE_HANWANG + , m_ocr(nullptr) +#endif +#endif +{ +#ifdef _WIN32 +#ifdef USE_HANWANG + if (tessdataPath != nullptr) + { + std::wstringstream wss; + wss << tessdataPath; + m_ocr = new HG_OCR(wss.str().c_str()); + } +#endif +#endif +} + +CImageApplyRotation::~CImageApplyRotation() +{ +#ifdef _WIN32 +#ifdef USE_HANWANG + if (m_ocr) + delete m_ocr; +#endif +#endif +} + +void CImageApplyRotation::apply(cv::Mat& pDib, int side) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter CImageApplyRotation apply"); +#endif // LOG + if (pDib.empty()) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyRotation apply"); +#endif // LOG + return; + } + + if (m_rotation == RotationType::AutoTextOrientation) //�Զ��ı�����ʶ�� + { +#ifdef USE_HANWANG + cv::Mat temp; + if (m_dpi != 200) + { + double scale = 200 / static_cast(m_dpi); + int new_w = static_cast(pDib.cols * scale) / 4 * 4; + int new_h = pDib.rows * scale; + cv::resize(pDib, temp, cv::Size(new_w, new_h)); + } + else + temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); + + if (temp.channels() == 3) + cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); + cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU); + + int orientation = 0; + if (m_ocr) + orientation = m_ocr->orientation(temp.data, temp.cols, temp.rows, temp.channels()); + + switch (orientation) + { + case 90: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 0); + break; + case 180: + cv::flip(pDib, pDib, 0); + cv::flip(pDib, pDib, 1); + break; + case 270: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 1); + break; + default: + break; + } +#endif + } + else if (m_backTranspose && side == 1) //������ת180 + { + if (m_rotation != RotationType::Rotate_180) //��ת180�� + { + if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� + { + transpose(pDib, pDib); + flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1); + } + else + { + flip(pDib, pDib, 0); + flip(pDib, pDib, 1); + } + } + } + else //zh + { + if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� + { + transpose(pDib, pDib); + flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 1 : 0); + } + else if (m_rotation == RotationType::Rotate_180) + { + flip(pDib, pDib, 0); + flip(pDib, pDib, 1); + } + } +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyRotation apply"); +#endif // LOG +} + +void CImageApplyRotation::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (!var.empty()) { + apply(var, i); + i++; + } + } +} \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageApplyRotation.h b/hgdriver/ImageProcess/ImageApplyRotation.h index 5412dd9..2310438 100644 --- a/hgdriver/ImageProcess/ImageApplyRotation.h +++ b/hgdriver/ImageProcess/ImageApplyRotation.h @@ -1,56 +1,82 @@ -#ifndef IMAGE_APPLY_ROTATION_H -#define IMAGE_APPLY_ROTATION_H - -#include "ImageApply.h" - -class CImageApplyRotation : public CImageApply -{ -public: - enum class RotationType - { - Invalid, - Rotate_90_clockwise, - Rotate_180, - Rotate_90_anti_clockwise, - - AutoTextOrientation - }; - -public: - - CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr); - - virtual ~CImageApplyRotation(); - - virtual void apply(cv::Mat& pDib, int side) override; - - virtual void apply(std::vector& mats, bool isTwoSide); - - bool isBackTransposed() { return m_backTranspose; } - - int getDPI() { return m_dpi; } - - int angleResult() { return m_angleResult; } - - const std::vector& angleResults() { return m_angleResults; } - - RotationType getRotationType() { return m_rotation; } - - void setBackTransposed(bool enabled) { m_backTranspose = enabled; } - - void setDPI(int dpi) { m_dpi = dpi; } - - void setRotationType(RotationType type) { m_rotation = type; } - -private: - RotationType m_rotation; - bool m_backTranspose; - int m_dpi; - - void* osd; - - int m_angleResult; - std::vector m_angleResults; -}; - -#endif // !IMAGE_APPLY_ROTATION_H +/* + * ==================================================== + + * ܣתͼ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺v1.0 2020/04/21 + v1.1 2020/08/12 ޸ĸ巽Զʶ±BUG + v1.2 2021/10/15 ĸ巽ʶģ + v1.2.1 2022/04/25 л汾Ԥ + * 汾ţv1.2.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_ROTATION_H +#define IMAGE_APPLY_ROTATION_H + +#include "ImageApply.h" + +#ifdef _WIN32 + //#define USE_HANWANG +#ifdef USE_HANWANG +#define HG_GPDF_API_BUILD +#include +#endif +#endif + +class GIMGPROC_LIBRARY_API CImageApplyRotation : public CImageApply +{ +public: + enum class RotationType + { + Invalid, //Ч + Rotate_90_clockwise, //˳ʱ90 + Rotate_180, //180 + Rotate_90_anti_clockwise, //ʱ90㣬270 + + AutoTextOrientation //Զĸ巽ʶת + }; + +public: + + /* + * rotation [in]:ת + * isBackTransposed [in]:trueΪ180ת֮Ȼ + * dpi [in]:ǰͼDPIòrotationΪAutoTextOrientationʱЧʶĸ巽ʱĬϽͼ任Ϊ200DPIʶ + * tessadataPath [in]:ѵļ·òrotationΪAutoTextOrientationʱЧ + */ + CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr); + + virtual ~CImageApplyRotation(); + + virtual void apply(cv::Mat& pDib, int side) override; + + virtual void apply(std::vector& mats, bool isTwoSide); + + bool isBackTransposed() { return m_backTranspose; } + + int getDPI() { return m_dpi; } + + RotationType getRotationType() { return m_rotation; } + + void setBackTransposed(bool enabled) { m_backTranspose = enabled; } + + void setDPI(int dpi) { m_dpi = dpi; } + + void setRotationType(RotationType type) { m_rotation = type; } + +private: + RotationType m_rotation; + bool m_backTranspose; + int m_dpi; + +#ifdef _WIN32 +#ifdef USE_HANWANG + HG_OCR* m_ocr; +#endif +#endif +}; + +#endif // !IMAGE_APPLY_ROTATION_H diff --git a/hgdriver/ImageProcess/ImageApplySizeDetection.cpp b/hgdriver/ImageProcess/ImageApplySizeDetection.cpp index 4a9da84..67eb894 100644 --- a/hgdriver/ImageProcess/ImageApplySizeDetection.cpp +++ b/hgdriver/ImageProcess/ImageApplySizeDetection.cpp @@ -1,47 +1,46 @@ -#include "ImageApplySizeDetection.h" -#include "ImageProcess_Public.h" - -CImageApplySizeDetection::CImageApplySizeDetection(int paperType, int thre_x, int thre_y) - : m_paperType(paperType) - , m_thre_x(thre_x) - , m_thre_y(thre_y) -{ - printf("\n paperType =%d \r\n", paperType); -} - -CImageApplySizeDetection::~CImageApplySizeDetection() -{ -} - -#define THRESHOLD 40 -#define ELEMNT_K 8 -int CImageApplySizeDetection::apply(const cv::Mat& pDib) -{ - if (pDib.empty()) return 0; - - float width, height; - cv::Mat thre; - hg::threshold_Mat(pDib, thre, THRESHOLD); - cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(ELEMNT_K, 1)); - cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); - std::vector> contours; - std::vector hierarchy; - hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); - std::vector maxContour = hg::getMaxContour(contours, hierarchy); - cv::RotatedRect rect = hg::getBoundingRect(maxContour); - width = rect.size.width; - height = rect.size.height; - printf("\n width =%f ,height = %f ", width, height); - - HGSize dstSize; - if (m_supportPaper.count((PaperSize)m_paperType) > 0)//包含设置的幅面 - { - dstSize = m_supportPaper[(PaperSize)m_paperType]; - if ((width > (dstSize.width + m_thre_x)) || - (width < (dstSize.width - m_thre_x)) || - (height > (dstSize.height + m_thre_y)) || - (height < (dstSize.height - m_thre_y))) - return 1; - } - return 0; -} +#include "ImageApplySizeDetection.h" +#include "ImageProcess_Public.h" + +CImageApplySizeDetection::CImageApplySizeDetection(int paperType, int thre_x, int thre_y) + : m_paperType(paperType) + , m_thre_x(thre_x) + , m_thre_y(thre_y) +{ +} + +CImageApplySizeDetection::~CImageApplySizeDetection() +{ +} + +#define THRESHOLD 40 +#define ELEMNT_K 8 +int CImageApplySizeDetection::apply(const cv::Mat& pDib) +{ + if (pDib.empty()) return 0; + + float width, height; + cv::Mat thre; + hg::threshold_Mat(pDib, thre, THRESHOLD); + cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(ELEMNT_K, 1)); + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + std::vector> contours; + std::vector hierarchy; + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + width = rect.size.width; + height = rect.size.height; + printf("\n width =%f ,height = %f ", width, height); + + HGSize dstSize; + if (m_supportPaper.count((PaperSize)m_paperType) > 0)//õķ + { + dstSize = m_supportPaper[(PaperSize)m_paperType]; + if ((width > (dstSize.width + m_thre_x)) || + (width < (dstSize.width - m_thre_x)) || + (height > (dstSize.height + m_thre_y)) || + (height < (dstSize.height - m_thre_y))) + return 1; + } + return 0; +} diff --git a/hgdriver/ImageProcess/ImageApplySizeDetection.h b/hgdriver/ImageProcess/ImageApplySizeDetection.h index 75c5023..c82bbc5 100644 --- a/hgdriver/ImageProcess/ImageApplySizeDetection.h +++ b/hgdriver/ImageProcess/ImageApplySizeDetection.h @@ -1,84 +1,83 @@ -/* - * ==================================================== - - * ܣߴ - * ߣά - * ʱ䣺2022/05/11 - * ޸ʱ䣺2022/05/11 - * 汾ţv1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_SIZE_DETECTION_H -#define IMAGE_APPLY_SIZE_DETECTION_H - -#include "ImageApply.h" -#include - -class CImageApplySizeDetection -{ -public: - enum PaperSize - { - G400_A3, - G400_A4, - G400_A4R, - G400_A5, - G400_A5R, - G400_A6, - G400_A6R, - G400_B4, - G400_B5, - G400_B5R, - G400_B6R, - G400_B6, - G400_DOUBLELETTER, - G400_LEGAL, - G400_LETTER, - G400_LONGLETTER, - G400_MAXSIZE - }; - - struct HGSize - { - int width; - int height; - }; - -public: - - CImageApplySizeDetection(int paperType, int thre_x = 70, int thre_y = 80); - - ~CImageApplySizeDetection(); - - virtual int apply(const cv::Mat& pDib); - - inline void setPaperType(int paperType) { m_paperType = paperType; } - -private: - int m_paperType; - int m_thre_x; - int m_thre_y; - std::map m_supportPaper = { - {PaperSize::G400_A3,HGSize{2338,3307}}, - {PaperSize::G400_A4,HGSize{1653,2338}}, - {PaperSize::G400_A4R,HGSize{2338,1653}}, - {PaperSize::G400_A5,HGSize{1165,1653}}, - {PaperSize::G400_A5R,HGSize{1653,1165}}, - {PaperSize::G400_A6,HGSize{826,1165}}, - {PaperSize::G400_A6R,HGSize{1165,826}}, - {PaperSize::G400_B4,HGSize{1969,2780}}, - {PaperSize::G400_B5,HGSize{1385,1968}}, - {PaperSize::G400_B5R,HGSize{1968,1385}}, - {PaperSize::G400_B6R,HGSize{1433,1007}}, - {PaperSize::G400_B6,HGSize{1007,1433}}, - {PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}}, - {PaperSize::G400_LEGAL,HGSize{1700,2800}}, - {PaperSize::G400_LETTER,HGSize{1700,2198}}, - {PaperSize::G400_LONGLETTER,HGSize{2040,2640}}, - {PaperSize::G400_MAXSIZE,HGSize{2338,6614}} - }; -}; - -#endif // !IMAGE_APPLY_SIZE_DETECTION_H +/* + * ==================================================== + + * 功能:尺寸检测 + * 作者:刘丁维 + * 生成时间:2022/05/11 + * 最近修改时间:2022/05/11 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_SIZE_DETECTION_H +#define IMAGE_APPLY_SIZE_DETECTION_H + +#include "ImageApply.h" +#include +class GIMGPROC_LIBRARY_API CImageApplySizeDetection +{ +public: + enum PaperSize + { + G400_A3, + G400_A4, + G400_A4R, + G400_A5, + G400_A5R, + G400_A6, + G400_A6R, + G400_B4, + G400_B5, + G400_B5R, + G400_B6R, + G400_B6, + G400_DOUBLELETTER, + G400_LEGAL, + G400_LETTER, + G400_LONGLETTER, + G400_MAXSIZE + }; + + struct HGSize + { + int width; + int height; + }; + +public: + + CImageApplySizeDetection(int paperType, int thre_x = 70, int thre_y = 80); + + ~CImageApplySizeDetection(); + + virtual int apply(const cv::Mat& pDib); + + inline void setPaperType(int paperType) { m_paperType = paperType; } + +private: + int m_paperType; + int m_thre_x; + int m_thre_y; + std::map m_supportPaper = { + {PaperSize::G400_A3,HGSize{2338,3307}}, + {PaperSize::G400_A4,HGSize{1653,2338}}, + {PaperSize::G400_A4R,HGSize{2338,1653}}, + {PaperSize::G400_A5,HGSize{1165,1653}}, + {PaperSize::G400_A5R,HGSize{1653,1165}}, + {PaperSize::G400_A6,HGSize{826,1165}}, + {PaperSize::G400_A6R,HGSize{1165,826}}, + {PaperSize::G400_B4,HGSize{1969,2780}}, + {PaperSize::G400_B5,HGSize{1385,1968}}, + {PaperSize::G400_B5R,HGSize{1968,1385}}, + {PaperSize::G400_B6R,HGSize{1433,1007}}, + {PaperSize::G400_B6,HGSize{1007,1433}}, + {PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}}, + {PaperSize::G400_LEGAL,HGSize{1700,2800}}, + {PaperSize::G400_LETTER,HGSize{1700,2198}}, + {PaperSize::G400_LONGLETTER,HGSize{2040,2640}}, + {PaperSize::G400_MAXSIZE,HGSize{2338,6614}} + }; +}; + +#endif // !IMAGE_APPLY_SIZE_DETECTION_H diff --git a/hgdriver/ImageProcess/ImageApplySplit.cpp b/hgdriver/ImageProcess/ImageApplySplit.cpp index 8d0cc5f..291a61e 100644 --- a/hgdriver/ImageProcess/ImageApplySplit.cpp +++ b/hgdriver/ImageProcess/ImageApplySplit.cpp @@ -1,115 +1,113 @@ -#include "ImageApplySplit.h" -#include - -#define BPP(type,index) -CImageApplySplit::CImageApplySplit(int multitype,bool split, bool ismulti_filter_red,int colormode) : - m_bmulti_filter_red(ismulti_filter_red) - , m_split(split) - , m_multitype(multitype) - , m_colormode(colormode) -{ -} - -CImageApplySplit::~CImageApplySplit(void) -{ -} - -std::vector CImageApplySplit::SplitMats(std::vector& mats, bool isTwoSide) -{ - std::vector rets; - for (size_t i = 0; i < mats.size(); i++) - { - if (mats[i].empty()) - continue; -// if (i != 0 && isTwoSide == false) -// break; - - int bpp = getBpp(i); - if (m_split)// - { - std::vector retmats = apply(mats[i]); - if (bpp != -1) { - } - else {// - if (m_colormode == 0) bpp = 1;//bw - else if (m_colormode == 1) bpp = 8; - else bpp = 24; - } - - for (size_t j = 0; j < retmats.size(); j++) - { - if (!retmats[j].empty()) { - cv::transpose(retmats[j],retmats[j]); - cv::flip(retmats[j],retmats[j],i==0?1:0); - MatEx matex(retmats[j], bpp); - rets.push_back(matex); - } - } - } - else { - MatEx matex(mats[i], bpp); - rets.push_back(matex); - } - } - return rets; -} - -std::vector CImageApplySplit::apply(cv::Mat& pDib) -{ - if (pDib.empty()) - return std::vector(); - std::vector retMats; - int heigth = pDib.rows; - int width = pDib.cols; - if (heigth > width) - { - cv::Mat matF = pDib(cv::Rect(0, 0, width, (int)(0.5 * heigth))); - cv::Mat matB = pDib(cv::Rect(0, (int)(0.5 * heigth), width, (int)(0.5 * heigth))); - retMats.push_back(matF); - retMats.push_back(matB); - } - else - { - cv::Mat matF = pDib(cv::Rect(0, 0, (int)(width*0.5), heigth)); - cv::Mat matB = pDib(cv::Rect((int)(width*0.5), 0, (int)(width * 0.5), heigth)); - retMats.push_back(matF); - retMats.push_back(matB); - } - return retMats; -} - -int CImageApplySplit::getBpp(int matIndex) -{ - int ret = -1; - if (m_bmulti_filter_red) { - ret = matIndex == 0 ? 24 : 8; - } - else - { - if (m_multitype == -1) - return ret; - switch (m_multitype) - { - case 0://all - if (matIndex == 0) ret = 24; - else if (matIndex == 1) ret = 8; - else ret = 1; - break; - case 1://clolr +gray - if (matIndex == 0) ret = 24; - else ret = 8; - break; - case 2://color+bw - if (matIndex == 0) ret = 24; - else ret = 1; - break; - case 3://gray+bw - if (matIndex == 0) ret = 8; - else ret = 1; - break; - default: - break; - } - } - return ret; -} +#include "ImageApplySplit.h" +#include + +#define BPP(type,index) +CImageApplySplit::CImageApplySplit(int multitype,bool split, bool ismulti_filter_red,int colormode) : + m_bmulti_filter_red(ismulti_filter_red) + , m_split(split) + , m_multitype(multitype) + , m_colormode(colormode) +{ +} + +CImageApplySplit::~CImageApplySplit(void) +{ +} + +std::vector CImageApplySplit::SplitMats(std::vector& mats, bool isTwoSide) +{ + std::vector rets; + for (size_t i = 0; i < mats.size(); i++) + { + if (mats[i].empty()) + continue; + if (i != 0 && isTwoSide == false) + break; + + int bpp = getBpp(i); + if (m_split)// + { + std::vector retmats = apply(mats[i]); + if (bpp != -1) { + } + else {// + if (m_colormode == 0) bpp = 1;//bw + else if (m_colormode == 1) bpp = 8; + else bpp = 24; + } + + for (size_t j = 0; j < retmats.size(); j++) + { + if (!retmats[j].empty()) { + MatEx matex(retmats[j], bpp); + rets.push_back(matex); + } + } + } + else { + MatEx matex(mats[i], bpp); + rets.push_back(matex); + } + } + return rets; +} + +std::vector CImageApplySplit::apply(cv::Mat& pDib) +{ + if (pDib.empty()) + return std::vector(); + std::vector retMats; + int heigth = pDib.rows; + int width = pDib.cols; + if (heigth > width) + { + cv::Mat matF = pDib(cv::Rect(0, 0, width, (int)(0.5 * heigth))); + cv::Mat matB = pDib(cv::Rect(0, (int)(0.5 * heigth), width, (int)(0.5 * heigth))); + retMats.push_back(matF); + retMats.push_back(matB); + } + else + { + cv::Mat matF = pDib(cv::Rect(0, 0, (int)(width*0.5), heigth)); + cv::Mat matB = pDib(cv::Rect((int)(width*0.5), 0, (int)(width * 0.5), heigth)); + retMats.push_back(matF); + retMats.push_back(matB); + } + return retMats; +} + +int CImageApplySplit::getBpp(int matIndex) +{ + int ret = -1; + if (m_bmulti_filter_red) { + ret = matIndex == 0 ? 24 : 8; + } + else + { + if (m_multitype == -1) + return ret; + switch (m_multitype) + { + case 0://all + if (matIndex == 0) ret = 24; + else if (matIndex == 1) ret = 8; + else ret = 1; + break; + case 1://clolr +gray + if (matIndex == 0) ret = 24; + else ret = 8; + break; + case 2://color+bw + if (matIndex == 0) ret = 24; + else ret = 1; + break; + case 3://gray+bw + if (matIndex == 0) ret = 8; + else ret = 1; + break; + default: + break; + } + } + return ret; +} diff --git a/hgdriver/ImageProcess/ImageApplySplit.h b/hgdriver/ImageProcess/ImageApplySplit.h index 35103a8..4deed9c 100644 --- a/hgdriver/ImageProcess/ImageApplySplit.h +++ b/hgdriver/ImageProcess/ImageApplySplit.h @@ -1,38 +1,36 @@ -/* - * ==================================================== - - * ܣͼ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 - * 汾ţv1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_SPLIT_H -#define IMAGE_APPLY_SPLIT_H -#include "MatEx.h" -#include -#include "imgprocdefs.h" - -class CImageApplySplit -{ -public: - CImageApplySplit(int multitype=-1,bool split=false,bool ismulti_filter_red=false,int colormode=1);//Ĭϲ Ҷ - - ~CImageApplySplit(void); - std::vector SplitMats(std::vector& mats, bool isTwoSide); - -//private: - std::vector apply(cv::Mat& pDib); - int getBpp(int matIndex); - -private://field - bool m_bmulti_filter_red; - int m_multitype; - int m_colormode; - bool m_split; -}; - -#endif // !IMAGE_APPLY_SPLIT_H +/* + * ==================================================== + + * ܣͼ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_SPLIT_H +#define IMAGE_APPLY_SPLIT_H +#include "MatEx.h" +#include +#include "imgprocdefs.h" + +class GIMGPROC_LIBRARY_API CImageApplySplit +{ +public: + CImageApplySplit(int multitype=-1,bool split=false,bool ismulti_filter_red=false,int colormode=1);//Ĭϲ Ҷ + + ~CImageApplySplit(void); + std::vector SplitMats(std::vector& mats, bool isTwoSide); +private: + std::vector apply(cv::Mat& pDib); + int getBpp(int matIndex); +private://field + bool m_bmulti_filter_red; + int m_multitype; + int m_colormode; + bool m_split; +}; + +#endif // !IMAGE_APPLY_SPLIT_H diff --git a/hgdriver/ImageProcess/ImageApplyTextureRemoval.cpp b/hgdriver/ImageProcess/ImageApplyTextureRemoval.cpp index 5c42622..db1e4fd 100644 --- a/hgdriver/ImageProcess/ImageApplyTextureRemoval.cpp +++ b/hgdriver/ImageProcess/ImageApplyTextureRemoval.cpp @@ -1,172 +1,187 @@ -#include "ImageApplyTextureRemoval.h" - -//Խ -void zero_to_center(cv::Mat& image, int colToCut, int rowToCut) -{ - cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut)); - cv::Mat q2(image, cv::Rect(colToCut, 0, colToCut, rowToCut)); - cv::Mat q3(image, cv::Rect(0, rowToCut, colToCut, rowToCut)); - cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut)); - - //ڶ޺͵޽н - cv::Mat tmpImg; - q1.copyTo(tmpImg); - q4.copyTo(q1); - tmpImg.copyTo(q4); - - //һ޺͵޽н - q2.copyTo(tmpImg); - q3.copyTo(q2); - tmpImg.copyTo(q3); -} - -// -cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5) -{ - cv::Mat dst; - cv::magnitude(matArray[0], matArray[1], dst); -#if 1 - cv::divide(dst, dst.cols * dst.rows, dst, scale); - //imshow("Ƶ", dst); -#else - dst += Scalar::all(1); - log(dst, dst); - normalize(dst, dst, 1, 0, CV_MINMAX); -#endif - -#if 0 - imshow("Ƶ", dst); -#endif - return dst; -} - -//Ҷ任 -void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst) -{ - cv::Mat complexIDFT; - cv::Mat matArray[2]; - cv::idft(src, complexIDFT); - cv::split(complexIDFT, matArray); - cv::magnitude(matArray[0], matArray[1], dst); - cv::normalize(dst, dst, 0, 1, CV_MINMAX); -} - -//ݲ˲ -cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize) -{ - cv::Mat temp; - spectrum.convertTo(temp, CV_8UC1, 255); - cv::threshold(temp, temp, 0, 255, CV_THRESH_OTSU); - //imshow("ֵ", temp); - - cv::Mat element1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(dilateSize, dilateSize)); - cv::Mat element2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(erodeSize, erodeSize)); - cv::dilate(temp, temp, element1); - cv::erode(temp, temp, element2); - cv::floodFill(temp, cv::Point(temp.cols / 2, temp.rows / 2), cv::Scalar(0)); //ˮ - cv::medianBlur(~temp, temp, 3); //ֵ˲ - //temp = ~temp; - //cv::imshow("ֵ", temp); - - //ݲ˲ - cv::Mat filter; - temp.convertTo(filter, CV_32FC1); - cv::normalize(filter, filter, 1, 0.01, CV_MINMAX); - std::vector mv; - mv.push_back(filter); - mv.push_back(filter); - cv::merge(mv, filter); - - return filter; -} - -void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img) -{ - //õDFTѳߴ磨2ָԼټ - cv::Mat paddedImg; - int m = cv::getOptimalDFTSize(img.rows); - int n = cv::getOptimalDFTSize(img.cols); - - //ͼ¶˺Ҷ - cv::copyMakeBorder(img, paddedImg, 0, m - img.rows, 0, n - img.cols, - cv::BORDER_CONSTANT, cv::Scalar::all(0)); - - //ͼһĶά飨ͨMatDFT - cv::Mat matArray[] = { cv::Mat_(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) }; - cv::Mat complexInput, complexOutput; - cv::merge(matArray, 2, complexInput); - cv::dft(complexInput, complexOutput); - cv::split(complexOutput, matArray); //ףҶף - - //˲ - //ʵ鲿Ƶͼķʽλ - //Ƶͼģ˲ - zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2); - zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2); - cv::Mat spectrum = create_spectrum(matArray); - - //˲ - cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize); - cv::merge(matArray, 2, complexOutput); - cv::multiply(complexOutput, filter, filter); - - //IDFTõ˲ - cv::Size imgSize = img.size(); - inverseFourierTransform(filter, img); - img = img(cv::Rect(cv::Point(0, 0), imgSize)); - img *= 255; - img.convertTo(img, CV_8UC1); -} - -CImageApplyTextureRemoval::CImageApplyTextureRemoval() - : CImageApply() - , m_dilateSize(5) - , m_erodeSize(3) -{ - -} - -CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize) - : CImageApply() - , m_dilateSize(dilateSize) - , m_erodeSize(erodeSize) -{ - -} - -CImageApplyTextureRemoval::~CImageApplyTextureRemoval() -{ - -} - -void CImageApplyTextureRemoval::apply(cv::Mat &pDib, int side) -{ - (void)side; - - if (pDib.channels() == 1) - textureRemovalGray(pDib); - else - { - std::vector rgb(3); - cv::split(pDib, rgb); - for (cv::Mat& var : rgb) - textureRemovalGray(var); - cv::merge(rgb, pDib); - } - - pDib *= 1.15; -} - -void CImageApplyTextureRemoval::apply(std::vector &mats, bool isTwoSide) -{ - (void)isTwoSide; - - int i = 0; - for (cv::Mat& var : mats) { - if (i != 0 && isTwoSide == false) - break; - if (!var.empty()) - apply(var, 0); - i++; - } -} +#include "ImageApplyTextureRemoval.h" + +//Խ +void zero_to_center(cv::Mat& image, int colToCut, int rowToCut) +{ + cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut)); + cv::Mat q2(image, cv::Rect(colToCut, 0, colToCut, rowToCut)); + cv::Mat q3(image, cv::Rect(0, rowToCut, colToCut, rowToCut)); + cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut)); + + //ڶ޺͵޽н + cv::Mat tmpImg; + q1.copyTo(tmpImg); + q4.copyTo(q1); + tmpImg.copyTo(q4); + + //һ޺͵޽н + q2.copyTo(tmpImg); + q3.copyTo(q2); + tmpImg.copyTo(q3); +} + +// +cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5) +{ + cv::Mat dst; + cv::magnitude(matArray[0], matArray[1], dst); +#if 1 + cv::divide(dst, dst.cols * dst.rows, dst, scale); + //imshow("Ƶ", dst); +#else + dst += Scalar::all(1); + log(dst, dst); + normalize(dst, dst, 1, 0, CV_MINMAX); +#endif + +#if 0 + imshow("Ƶ", dst); +#endif + return dst; +} + +//Ҷ任 +void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst) +{ + cv::Mat complexIDFT; + cv::Mat matArray[2]; + cv::idft(src, complexIDFT); + cv::split(complexIDFT, matArray); + cv::magnitude(matArray[0], matArray[1], dst); + cv::normalize(dst, dst, 0, 1, CV_MINMAX); +} + +//ݲ˲ +cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize) +{ + cv::Mat temp; + spectrum.convertTo(temp, CV_8UC1, 255); + //cv::imwrite("filter/temp.bmp", temp); + cv::threshold(temp, temp, 0, 255, CV_THRESH_OTSU); + //cv::imwrite("filter/temp1.bmp", temp); + + cv::Mat element1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(dilateSize, dilateSize)); + cv::Mat element2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(erodeSize, erodeSize)); + cv::line(temp, cv::Point(0, temp.rows / 2), cv::Point(temp.cols - 1, temp.rows / 2), cv::Scalar(255)); + cv::line(temp, cv::Point(temp.cols / 2, 0), cv::Point(temp.cols / 2, temp.rows - 1), cv::Scalar(255)); + cv::dilate(temp, temp, element1); + cv::erode(temp, temp, element2); + //cv::imwrite("filter/temp2.bmp", temp); + cv::floodFill(temp, cv::Point(temp.cols / 2, temp.rows / 2), cv::Scalar(0)); //ˮ + cv::blur(~temp, temp, cv::Size(3, 3)); //ֵ˲ + + //cv::imwrite("filter/temp3.bmp", temp); + //temp = ~temp; + + //ݲ˲ + cv::Mat filter; + temp.convertTo(filter, CV_32FC1); + cv::normalize(filter, filter, 1, 0.01, CV_MINMAX); + std::vector mv; + mv.push_back(filter); + mv.push_back(filter); + cv::merge(mv, filter); + + return filter; +} + +void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img) +{ + //õDFTѳߴ磨2ָԼټ + cv::Mat resizeMat; + + cv::resize(img, resizeMat, cv::Size(), 0.5, 0.5); + + cv::Mat paddedImg; + int m = cv::getOptimalDFTSize(resizeMat.rows); + int n = cv::getOptimalDFTSize(resizeMat.cols); + + //ͼ¶˺Ҷ + cv::copyMakeBorder(resizeMat, paddedImg, 0, m - resizeMat.rows, 0, n - resizeMat.cols, + cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + //ͼһĶά飨ͨMatDFT + cv::Mat matArray[] = { cv::Mat_(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) }; + cv::Mat complexInput, complexOutput; + cv::merge(matArray, 2, complexInput); + cv::dft(complexInput, complexOutput); + cv::split(complexOutput, matArray); //ףҶף + + //˲ + //ʵ鲿Ƶͼķʽλ + //Ƶͼģ˲ + zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2); + zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2); + cv::Mat spectrum = create_spectrum(matArray); + + //˲ + cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize); + cv::merge(matArray, 2, complexOutput); + cv::multiply(complexOutput, filter, filter); + + cv::Size imgSize = img.size(); + m = cv::getOptimalDFTSize(img.rows); + n = cv::getOptimalDFTSize(img.cols); + //ͼ¶˺Ҷ + cv::copyMakeBorder(img, img, 0, m - img.rows, 0, n - img.cols, + cv::BORDER_CONSTANT, cv::Scalar::all(0)); + cv::copyMakeBorder(filter, filter, 0, m - filter.rows, 0, n - filter.cols, + cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + //IDFTõ˲ + inverseFourierTransform(filter, img); + img = img(cv::Rect(cv::Point(0, 0), imgSize)); + img *= 255; + img.convertTo(img, CV_8UC1); +} + +CImageApplyTextureRemoval::CImageApplyTextureRemoval() + : CImageApply() + , m_dilateSize(9) + , m_erodeSize(5) +{ + +} + +CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize) + : CImageApply() + , m_dilateSize(dilateSize) + , m_erodeSize(erodeSize) +{ + +} + +CImageApplyTextureRemoval::~CImageApplyTextureRemoval() +{ + +} + +void CImageApplyTextureRemoval::apply(cv::Mat& pDib, int side) +{ + (void)side; + + if (pDib.channels() == 1) + textureRemovalGray(pDib); + else + { + std::vector rgb(3); + cv::split(pDib, rgb); + for (cv::Mat& var : rgb) + textureRemovalGray(var); + cv::merge(rgb, pDib); + } +} + +void CImageApplyTextureRemoval::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess/ImageApplyTextureRemoval.h b/hgdriver/ImageProcess/ImageApplyTextureRemoval.h index f97080d..a09845a 100644 --- a/hgdriver/ImageProcess/ImageApplyTextureRemoval.h +++ b/hgdriver/ImageProcess/ImageApplyTextureRemoval.h @@ -1,50 +1,51 @@ -/* - * ==================================================== - - * 功能:去除网纹 - * 作者:刘丁维 - * 生成时间:2020/4/21 - * 最近修改时间:2020/4/21 - * 版本号:v1.0 - - * ==================================================== - */ - -#ifndef IMAGE_APPLY_TEXTURE_REMOVAL_H -#define IMAGE_APPLY_TEXTURE_REMOVAL_H - -#include "ImageApply.h" - -class CImageApplyTextureRemoval : public CImageApply -{ -public: - CImageApplyTextureRemoval(void); - - /* - * dilateSize [in]:膨胀像素 - * erodeSize [in]:腐蚀像素 - */ - CImageApplyTextureRemoval(int dilateSize, int erodeSize); - - virtual ~CImageApplyTextureRemoval(void); - - virtual void apply(cv::Mat& pDib,int side); - - virtual void apply(std::vector& mats, bool isTwoSide); - - int getDilateSize() {return m_dilateSize;} - - int getErodeSize() {return m_erodeSize;} - - void setDilateSize(int size) {m_dilateSize = size;} - - void setErodeSize(int size) {m_erodeSize = size;} -private: - void textureRemovalGray(cv::Mat& img); - -private: - int m_dilateSize; - int m_erodeSize; -}; - -#endif +/* + * ==================================================== + + * ܣȥ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + * 2022/4/09 v1.1 㷨Ч + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_TEXTURE_REMOVAL_H +#define IMAGE_APPLY_TEXTURE_REMOVAL_H + +#include "ImageApply.h" + +class GIMGPROC_LIBRARY_API CImageApplyTextureRemoval : public CImageApply +{ +public: + CImageApplyTextureRemoval(void); + + /* + * dilateSize [in]: + * erodeSize [in]:ʴ + */ + CImageApplyTextureRemoval(int dilateSize, int erodeSize); + + virtual ~CImageApplyTextureRemoval(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + int getDilateSize() { return m_dilateSize; } + + int getErodeSize() { return m_erodeSize; } + + void setDilateSize(int size) { m_dilateSize = size; } + + void setErodeSize(int size) { m_erodeSize = size; } +private: + void textureRemovalGray(cv::Mat& img); + +private: + int m_dilateSize; + int m_erodeSize; +}; + +#endif diff --git a/hgdriver/ImageProcess/ImageApplyUVMerge.cpp b/hgdriver/ImageProcess/ImageApplyUVMerge.cpp new file mode 100644 index 0000000..88035a7 --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyUVMerge.cpp @@ -0,0 +1,186 @@ +#include "ImageApplyUVMerge.h" +#include "ImageProcess_Public.h" +using namespace cv; +#define SCA 50 + +CImageApplyUVMerge::CImageApplyUVMerge(): lut(1, 256, CV_8UC1) +{ +} + +CImageApplyUVMerge::~CImageApplyUVMerge() +{ +} + +void CImageApplyUVMerge::update_lutData(int contrast) +{ + unsigned char* ptr = lut.data; + int m_contrast = cv::max(-127, cv::min(contrast, 127)); + for (int i = 0; i < 256; i++) + { + //update contrast + if (i < 128) + ptr[i] = static_cast(cv::max(0, cv::min(i - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(i + m_contrast, 255))); + } +} + +void CImageApplyUVMerge::Apply(cv::Mat& image, const cv::Mat& uv, int dpi, int thresh) +{ + update_lutData(12); + cv::LUT(uv, lut, uv); + Mat uv_resize; + cv::resize(uv, uv_resize, cv::Size(uv.cols * SCA / dpi, uv.rows * SCA / dpi)); + if (uv_resize.channels() == 3) + cv::cvtColor(uv_resize, uv_resize, cv::COLOR_BGR2GRAY); + cv::threshold(uv_resize, uv_resize, 0, 255, THRESH_OTSU); + cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1500 / dpi, 1500 / dpi)); + cv::dilate(uv_resize, uv_resize, element); + std::vector> contours; + std::vector hierarchy; + hg::findContours(uv_resize, contours, hierarchy, cv::RETR_EXTERNAL); + + std::map map_color; + for (int i = 0; i < contours.size(); i++) + { + cv::Rect roi = cv::boundingRect(contours[i]); + roi.x *= dpi / SCA; + roi.y *= dpi / SCA; + roi.width *= dpi / SCA; + roi.height *= dpi / SCA; + + purgeQR_kernal(image, roi, map_color, dpi, thresh); + } +} + +cv::Mat CImageApplyUVMerge::Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle) +{ + if (uvRoi.size.width == 0) return cv::Mat(); + + cv::RotatedRect uvRoi_clone = uvRoi; + cv::Mat dst = cv::Mat::zeros(image.rows > image.cols ? image.rows : (image.rows * 2), image.cols > image.rows ? image.cols : (image.cols * 2), image.type()); + image.copyTo(dst(cv::Rect(0, 0, image.cols, image.rows))); + + cv::Mat dst_uv = dst(cv::Rect(image.rows > image.cols ? image.cols : 0, image.rows > image.cols ? 0 : image.rows, image.cols, image.rows)); + if (isDesaskew) + { + cv::Point2f srcTri[4]; + cv::Point2f dstTri[3]; + uvRoi_clone.points(srcTri); + + + if (angle == 90) + { + dstTri[0] = cv::Point2f(0, 0); + dstTri[1] = cv::Point2f(dst_uv.cols - 1, 0); + dstTri[2] = cv::Point2f(dst_uv.cols - 1, dst_uv.rows - 1); + } + else if (angle == 180) + { + dstTri[0] = cv::Point2f(dst_uv.cols - 1, 0); + dstTri[1] = cv::Point2f(dst_uv.cols - 1, dst_uv.rows - 1); + dstTri[2] = cv::Point2f(0, dst_uv.rows - 1); + } + else if (angle == 270) + { + dstTri[0] = cv::Point2f(dst_uv.cols - 1, dst_uv.rows - 1); + dstTri[1] = cv::Point2f(0, dst_uv.rows - 1); + dstTri[2] = cv::Point2f(0, 0); + } + else + { + dstTri[0] = cv::Point2f(0, dst_uv.rows - 1); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(dst_uv.cols - 1, 0); + } + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + if (uv.channels() == 1 && dst_uv.channels() == 3) + { + cv::Mat uv_temp; + cv::warpAffine(uv, uv_temp, warp_mat, dst_uv.size()); + cv::cvtColor(uv_temp, dst_uv, cv::COLOR_GRAY2BGR); + } + else + cv::warpAffine(uv, dst_uv, warp_mat, dst_uv.size()); + } + else + { + cv::Rect uvBoundingRect = uvRoi_clone.boundingRect(); + + cv::Rect roi_dst_right; + roi_dst_right.x = dst_uv.cols > uvBoundingRect.width ? (dst_uv.cols - uvBoundingRect.width) / 2 : 0; + roi_dst_right.width = cv::min(dst_uv.cols, uvBoundingRect.width); + roi_dst_right.y = dst_uv.rows > uvBoundingRect.height ? (dst_uv.rows - uvBoundingRect.height) / 2 : 0; + roi_dst_right.height = cv::min(dst_uv.rows, uvBoundingRect.height); + + cv::Rect roi_uv_BoundingRect((uvBoundingRect.width - roi_dst_right.width) / 2, + (uvBoundingRect.height - roi_dst_right.height) / 2, roi_dst_right.width, roi_dst_right.height); + + Mat uvCrop = (uv(uvBoundingRect))(roi_uv_BoundingRect); + if (uvCrop.channels() == 1 && dst_uv.channels() == 3) + cv::cvtColor(uvCrop, uvCrop, cv::COLOR_GRAY2BGR); + uvCrop.copyTo(dst_uv(roi_dst_right)); + } + return dst; +} + + +void CImageApplyUVMerge::purgeQR_kernal(cv::Mat& image, const cv::Rect& roi, std::map map_color, int dpi, int threshold) +{ + cv::Mat image_roi = image(roi); + cv::Mat mask; + cv::cvtColor(image_roi, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, 127, 255, cv::THRESH_OTSU); + cv::Mat image_resize; + cv::resize(image, image_resize, cv::Size(image.cols, 800)); + + for (int i = 0, cols = image_roi.cols, rows = image_roi.rows; i < cols; i++) + { + cv::Scalar color_fill; + if (map_color.find(i + roi.x) == map_color.end()) + { + color_fill = getColor(image_resize, roi.x + i, threshold); + map_color[i + roi.x] = color_fill; + } + else + color_fill = map_color[i + roi.x]; + + for (int j = 0; j < rows; j++) + { + if (*mask.ptr(j, i)) + { + uchar* color = image_roi.ptr(j, i); + color[0] = color_fill[0]; + color[1] = color_fill[1]; + color[2] = color_fill[2]; + } + } + } +} + +cv::Scalar CImageApplyUVMerge::getColor(const cv::Mat& image, int col, int threshold) +{ + cv::Scalar color(0, 0, 0); + int num = 0; + + for (int i = 0, length = image.rows; i < length; i++) + { + const uchar* ptr = image.ptr(i, col); + int gray = (ptr[0] * 30 + ptr[1] * 59 + ptr[2] * 11) / 100; + if (gray > threshold) + { + color[0] += ptr[0]; + color[1] += ptr[1]; + color[2] += ptr[2]; + num++; + } + } + + if (num) + color /= num; + else + color[0] = color[1] = color[2] = 255; + + return color; +} diff --git a/hgdriver/ImageProcess/ImageApplyUVMerge.h b/hgdriver/ImageProcess/ImageApplyUVMerge.h new file mode 100644 index 0000000..731d676 --- /dev/null +++ b/hgdriver/ImageProcess/ImageApplyUVMerge.h @@ -0,0 +1,34 @@ +/* + * ==================================================== + + * ���ܣ�UVͼ��ԭͼ�ϲ�������ԭͼ��ƫ���ü��Լ���ת�����UV����ԭͼ�Ĵ�����������ԭͼƴ��Ϊһ��ͼ�� + �ù�������UVһ����С� + * ���ߣ�����ά + * ����ʱ�䣺2020/7/20 + * ����޸�ʱ�䣺2020/7/20 + * �汾�ţ�v1.0 2020/7/20 + * ==================================================== + */ + +#ifndef IMAGE_APPLY_UV_MERGE_H +#define IMAGE_APPLY_UV_MERGE_H + +#include "ImageApply.h" +#include + +class GIMGPROC_LIBRARY_API CImageApplyUVMerge +{ +public: + CImageApplyUVMerge(); + ~CImageApplyUVMerge(); + void Apply(cv::Mat& image, const cv::Mat& uv, int dpi = 200, int thresh = 100); + + static cv::Mat Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle); +private: + void purgeQR_kernal(cv::Mat& image, const cv::Rect& roi, std::map map_color, int dpi, int threshold); + cv::Scalar getColor(const cv::Mat& image, int col, int threshold); + void update_lutData(int contrast); + cv::Mat lut; +}; + +#endif // !IMAGE_APPLY_UV_MERGE_H \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageMulti.cpp b/hgdriver/ImageProcess/ImageMulti.cpp index 422f707..4c8761b 100644 --- a/hgdriver/ImageProcess/ImageMulti.cpp +++ b/hgdriver/ImageProcess/ImageMulti.cpp @@ -1,72 +1,72 @@ -#include "ImageMulti.h" - -IMageMulti::IMageMulti(int multiType,int thre) -{ - m_multiType = multiType; - m_thre = thre; -} - -IMageMulti::~IMageMulti(void) -{ -} - -std::vector IMageMulti::apply(cv::Mat& pDib) -{ - std::vector retMats; - if (pDib.empty()) - return retMats; - retMats.push_back(pDib); - switch (m_multiType) - { - case ALL: - { - if (pDib.channels() == 3){ - cv::Mat dst; - cv::cvtColor(pDib, dst,cv::COLOR_BGR2GRAY); - retMats.push_back(dst); - } - cv::Mat dstThre; - cv::cvtColor(pDib, dstThre,cv::COLOR_BGR2GRAY); - //cv::threshold(dstThre, dstThre, m_thre, 255, cv::THRESH_BINARY); - cv::adaptiveThreshold(dstThre,dstThre,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); - if (!dstThre.empty()) - { - retMats.push_back(dstThre); - } - } - break; - case COLORGRAY: - { - if (pDib.channels() == 3) { - cv::Mat dstGray; - cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); - retMats.push_back(dstGray); - } - } - break; - case COLORBW: - { - if (pDib.channels() == 3) { - cv::Mat dstGray; - cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); - cv::Mat dstBW; - cv::adaptiveThreshold(dstGray,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); - retMats.push_back(dstBW); - } - } - break; - case GRAYBW://pDib should be GreyImage(channels() == 1) - { - cv::Mat dstBW; - cv::adaptiveThreshold(pDib,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); - if (!dstBW.empty()) - { - retMats.push_back(dstBW); - } - } - break; - default: - break; - } - return retMats; -} +#include "ImageMulti.h" + +IMageMulti::IMageMulti(int multiType,int thre) +{ + m_multiType = multiType; + m_thre = thre; +} + +IMageMulti::~IMageMulti(void) +{ +} + +std::vector IMageMulti::apply(cv::Mat& pDib) +{ + std::vector retMats; + if (pDib.empty()) + return retMats; + retMats.push_back(pDib); + switch (m_multiType) + { + case ALL: + { + if (pDib.channels() == 3){ + cv::Mat dst; + cv::cvtColor(pDib, dst,cv::COLOR_BGR2GRAY); + retMats.push_back(dst); + } + cv::Mat dstThre; + cv::cvtColor(pDib, dstThre,cv::COLOR_BGR2GRAY); + //cv::threshold(dstThre, dstThre, m_thre, 255, cv::THRESH_BINARY); + cv::adaptiveThreshold(dstThre,dstThre,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + if (!dstThre.empty()) + { + retMats.push_back(dstThre); + } + } + break; + case COLORGRAY: + { + if (pDib.channels() == 3) { + cv::Mat dstGray; + cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); + retMats.push_back(dstGray); + } + } + break; + case COLORBW: + { + if (pDib.channels() == 3) { + cv::Mat dstGray; + cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); + cv::Mat dstBW; + cv::adaptiveThreshold(dstGray,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + retMats.push_back(dstBW); + } + } + break; + case GRAYBW://pDib should be GreyImage(channels() == 1) + { + cv::Mat dstBW; + cv::adaptiveThreshold(pDib,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + if (!dstBW.empty()) + { + retMats.push_back(dstBW); + } + } + break; + default: + break; + } + return retMats; +} diff --git a/hgdriver/ImageProcess/ImageMulti.h b/hgdriver/ImageProcess/ImageMulti.h index 0a79195..ae290ae 100644 --- a/hgdriver/ImageProcess/ImageMulti.h +++ b/hgdriver/ImageProcess/ImageMulti.h @@ -1,26 +1,26 @@ -#ifndef IMAGE_MULTI_H -#define IMAGE_MULTI_H -#include "IMulti.h" - -class IMageMulti - :public IMulti -{ -public: - enum MultiOutput - { - NONE=-1, - ALL, - COLORGRAY, - COLORBW, - GRAYBW - }; -public: - IMageMulti(int multiType = 0,int thre = 128); - virtual ~IMageMulti(void); - virtual std::vector apply(cv::Mat& pDib); -private: - int m_multiType; - int m_thre; -}; - +#ifndef IMAGE_MULTI_H +#define IMAGE_MULTI_H +#include "IMulti.h" + +class GIMGPROC_LIBRARY_API IMageMulti + :public IMulti +{ +public: + enum MultiOutput + { + NONE=-1, + ALL, + COLORGRAY, + COLORBW, + GRAYBW + }; +public: + IMageMulti(int multiType = 0,int thre = 128); + virtual ~IMageMulti(void); + virtual std::vector apply(cv::Mat& pDib); +private: + int m_multiType; + int m_thre; +}; + #endif // !IMAGE_MULTI_H \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageMultiOutputRed.cpp b/hgdriver/ImageProcess/ImageMultiOutputRed.cpp index 5cc08d2..26a142b 100644 --- a/hgdriver/ImageProcess/ImageMultiOutputRed.cpp +++ b/hgdriver/ImageProcess/ImageMultiOutputRed.cpp @@ -1,63 +1,63 @@ -#include "ImageMultiOutputRed.h" -#include - -using namespace std; - -ImageMultiOutputRed::ImageMultiOutputRed(short channelIndex) -{ - m_channelIndex = channelIndex; -} - -ImageMultiOutputRed::~ImageMultiOutputRed(void) -{ -} - -std::vector ImageMultiOutputRed::apply(cv::Mat& pDib) -{ - std::vector retMats; - if (pDib.empty()) - return retMats; - retMats.push_back(pDib); - cv::Mat mat = FilterColor(pDib, m_channelIndex); - if (!mat.empty()) - retMats.push_back(mat); - return retMats; -} - -cv::Mat ImageMultiOutputRed::FilterColor(cv::Mat image, short channel) -{ - cv::Mat dstImage(image.rows, image.cols, CV_8UC1); - int channels = image.channels(); - if (channel > channels - 1) - { - return cv::Mat(); - } - if ((channel == 3) && (channels != 4) && (channels != 8)) - { - return cv::Mat(); - } - if (channels <= 4) - { - int srcOffset = image.step - image.cols * channels; - int dstOffset = dstImage.step - dstImage.cols; - unsigned char *src = image.data; - unsigned char *dst = dstImage.data; - src += channel; - - for (int y = 0; y < image.rows; y++) - { - for (int x = 0; x < image.cols; x++, src += channels, dst++) - { - unsigned short pix = *src; - if (pix >= 130) - { - pix = 255; - } - *dst = pix; - } - src += srcOffset; - dst += dstOffset; - } - } - return dstImage; -} +#include "ImageMultiOutputRed.h" +#include + +using namespace std; + +ImageMultiOutputRed::ImageMultiOutputRed(short channelIndex) +{ + m_channelIndex = channelIndex; +} + +ImageMultiOutputRed::~ImageMultiOutputRed(void) +{ +} + +std::vector ImageMultiOutputRed::apply(cv::Mat& pDib) +{ + std::vector retMats; + if (pDib.empty()) + return retMats; + retMats.push_back(pDib); + cv::Mat mat = FilterColor(pDib, m_channelIndex); + if (!mat.empty()) + retMats.push_back(mat); + return retMats; +} + +cv::Mat ImageMultiOutputRed::FilterColor(cv::Mat image, short channel) +{ + cv::Mat dstImage(image.rows, image.cols, CV_8UC1); + int channels = image.channels(); + if (channel > channels - 1) + { + return cv::Mat(); + } + if ((channel == 3) && (channels != 4) && (channels != 8)) + { + return cv::Mat(); + } + if (channels <= 4) + { + int srcOffset = image.step - image.cols * channels; + int dstOffset = dstImage.step - dstImage.cols; + unsigned char *src = image.data; + unsigned char *dst = dstImage.data; + src += channel; + + for (int y = 0; y < image.rows; y++) + { + for (int x = 0; x < image.cols; x++, src += channels, dst++) + { + unsigned short pix = *src; + if (pix >= 130) + { + pix = 255; + } + *dst = pix; + } + src += srcOffset; + dst += dstOffset; + } + } + return dstImage; +} diff --git a/hgdriver/ImageProcess/ImageMultiOutputRed.h b/hgdriver/ImageProcess/ImageMultiOutputRed.h index a7ed28c..2aa13f9 100644 --- a/hgdriver/ImageProcess/ImageMultiOutputRed.h +++ b/hgdriver/ImageProcess/ImageMultiOutputRed.h @@ -1,17 +1,17 @@ -#ifndef IMAGE_MULTI_OUTPUT_RED_H -#define IMAGE_MULTI_OUTPUT_RED_H -#include "IMulti.h" - -class ImageMultiOutputRed - :public IMulti -{ -public: - ImageMultiOutputRed(short channelIndex); - virtual ~ImageMultiOutputRed(void); - virtual std::vector apply(cv::Mat& pDib) override; - -private: - short m_channelIndex; - cv::Mat FilterColor(cv::Mat image, short channel); -}; -#endif //!IMAGE_MULTI_OUTPUT_RED_H +#ifndef IMAGE_MULTI_OUTPUT_RED_H +#define IMAGE_MULTI_OUTPUT_RED_H +#include "IMulti.h" + +class GIMGPROC_LIBRARY_API ImageMultiOutputRed + :public IMulti +{ +public: + ImageMultiOutputRed(short channelIndex); + virtual ~ImageMultiOutputRed(void); + virtual std::vector apply(cv::Mat& pDib) override; + +private: + short m_channelIndex; + cv::Mat FilterColor(cv::Mat image, short channel); +}; +#endif //!IMAGE_MULTI_OUTPUT_RED_H diff --git a/hgdriver/ImageProcess/ImageProcess.pro b/hgdriver/ImageProcess/ImageProcess.pro new file mode 100644 index 0000000..7e0f1c0 --- /dev/null +++ b/hgdriver/ImageProcess/ImageProcess.pro @@ -0,0 +1,165 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-12-29T09:49:19 +# +#------------------------------------------------- + +QT -= core gui + +TARGET = hgimgproc +TEMPLATE = lib + +DEFINES += GIMGPROC_LIBRARY GIMGPROC_LIBRARY_BUILD + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +#DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +INCLUDEPATH += $$PWD/../Tirdparty/3rdparty/nick +DEPENDPATH += $$PWD/../Tirdparty/3rdparty/nick + + +win32 { + DEFINES += _WIN32 + + INCLUDEPATH += $$PWD/../gpdf + DEPENDPATH += $$PWD/../gpdf + + INCLUDEPATH += $$PWD/../Tirdparty/3party/3rdparty/win/hgOCR/include + DEPENDPATH += $$PWD/../Tirdparty/3rdparty/win/hgOCR/include + INCLUDEPATH += $$PWD/../Tirdparty/3rdparty/win/opencv/include + DEPENDPATH += $$PWD/../Tirdparty/3rdparty/win/opencv/include + LIBS += -L$$PWD/../Tirdparty/3rdparty/win/hgOCR/x86/lib + INCLUDEPATH += $$PWD/include + + contains(QT_ARCH, i386) { + CONFIG(release, debug|release) { + DESTDIR += ../bin/x86/release + LIBS += -L$$PWD/../Tirdparty/3rdparty/win/opencv/lib/x86/Release -lopencv_world346 + LIBS += -L$$PWD/../bin/x86/release -lhg_gpdf + #LIBS += -L$$PWD/lib/release -lzxing -lzbar + LIBS += -lwinmm + } + CONFIG(debug, debug|release) { + DESTDIR += ../bin/x86/debug + LIBS += -L$$PWD/../Tirdparty/3rdparty/win/opencv/lib/x86/Debug -lopencv_world346d + LIBS += -L$$PWD/../bin/x86/debug -lhg_gpdf + #LIBS += -L$$PWD/lib/debug -lzxing -lzbar + LIBS += -lwinmm + } + } else { + CONFIG(release, debug|release) { + DESTDIR += ../bin/x64/release + LIBS += -L$$PWD/../Tirdparty/3rdparty/win/opencv/lib/x64/Release -lopencv_world346 + LIBS += -L$$PWD/../bin/x64/release -lhg_gpdf + } + CONFIG(debug, debug|release) { + DESTDIR += ../bin/x64/debug + LIBS += -L$$PWD/../Tirdparty/3rdparty/win/opencv/lib/x64/Debug -lopencv_world346d + LIBS += -L$$PWD/../bin/x64/debug -lhg_gpdf + } + } +} + +else:unix:!macx: { + #LIBS += -lopencv_world + #linux系统上面需安装opencv3.4.6库 + INCLUDEPATH += $$PWD/../Tirdparty/3rdparty/opencv/include + + CONFIG(debug, debug|release) { + DESTDIR += ../bin/x86/debug + LIBS += -L$$PWD/../Tirdparty/3rdparty/opencv/lib/Debug -lopencv_world -llibtiff -llibjpeg-turbo -lIlmImf -littnotify -llibjasper \ + -llibprotobuf -llibwebp -llibpng -lquirc -lzlib + #LIBS += -L$$PWD/../bin/x86/debug -lhg_gpdf + } + CONFIG(release, debug|release) { + DESTDIR += ../bin/x86/release + LIBS += -L$$PWD/../Tirdparty/3rdparty/opencv/lib/Debug -lopencv_world -llibtiff -llibjpeg-turbo -lIlmImf -littnotify -llibjasper \ + -llibprotobuf -llibwebp -llibpng -lquirc -lzlib + #LIBS += -L$$PWD/../bin/x86/release -lhg_gpdf + } +} + +SOURCES += \ + ImageApply.cpp \ + ImageApplyAdjustColors.cpp \ + ImageApplyAutoContrast.cpp \ + ImageApplyAutoCrop.cpp \ + ImageApplyBWBinaray.cpp \ + #ImageApplyBarCodeRecognition.cpp \ + ImageApplyChannel.cpp \ + ImageApplyColorRecognition.cpp \ + ImageApplyConcatenation.cpp \ + ImageApplyCustomCrop.cpp \ + ImageApplyCustomGamma.cpp \ + ImageApplyCvtColor.cpp \ + ImageApplyDetachNoise.cpp \ + ImageApplyDiscardBlank.cpp \ + ImageApplyDispersion.cpp \ + ImageApplyDogEarDetection.cpp \ + ImageApplyFadeBackGroundColor.cpp \ + ImageApplyFilter.cpp \ + ImageApplyHSVCorrect.cpp \ + ImageApplyMarkCrop.cpp \ + ImageApplyOutHole.cpp \ + ImageApplyRefuseInflow.cpp \ + ImageApplyResize.cpp \ + ImageApplyRotation.cpp \ + ImageApplySizeDetection.cpp \ + ImageApplySplit.cpp \ + ImageApplyTextureRemoval.cpp \ + #ImageApplyUVMerge.cpp \ + ImageMulti.cpp \ + ImageMultiOutputRed.cpp \ + ImageProcess_Public.cpp \ + IMulti.cpp + +HEADERS += \ + ImageApply.h \ + ImageApplyAdjustColors.h \ + ImageApplyAutoContrast.h \ + ImageApplyAutoCrop.h \ + ImageApplyBWBinaray.h \ + #ImageApplyBarCodeRecognition.h \ + ImageApplyChannel.h \ + ImageApplyColorRecognition.h \ + ImageApplyConcatenation.h \ + ImageApplyCustomCrop.h \ + ImageApplyCustomGamma.h \ + ImageApplyCvtColor.h \ + ImageApplyDetachNoise.h \ + ImageApplyDiscardBlank.h \ + ImageApplyDispersion.h \ + ImageApplyDogEarDetection.h \ + ImageApplyFadeBackGroundColor.h \ + ImageApplyFilter.h \ + ImageApplyHSVCorrect.h \ + ImageApplyHeaders.h \ + ImageApplyMarkCrop.h \ + ImageApplyOutHole.h \ + ImageApplyRefuseInflow.h \ + ImageApplyResize.h \ + ImageApplyRotation.h \ + ImageApplySizeDetection.h \ + ImageApplySplit.h \ + ImageApplyTextureRemoval.h \ + #ImageApplyUVMerge.h \ + ImageMulti.h \ + ImageMultiOutputRed.h \ + ImageProcess_Public.h \ + IMulti.h\ + imgprocdefs.h + + +#VERSION = 1.0.0.0 +QMAKE_TARGET_PRODUCT = "gimgproc" +QMAKE_TARGET_COMPANY = "huagaoscan" +QMAKE_TARGET_DESCRIPTION = "文件描述" +QMAKE_TARGET_COPYRIGHT = "版权" diff --git a/hgdriver/ImageProcess/ImageProcess_Public.cpp b/hgdriver/ImageProcess/ImageProcess_Public.cpp index 7096570..21fce58 100644 --- a/hgdriver/ImageProcess/ImageProcess_Public.cpp +++ b/hgdriver/ImageProcess/ImageProcess_Public.cpp @@ -1,336 +1,349 @@ -#include "ImageProcess_Public.h" - -namespace hg -{ - void convexHull(const std::vector& src, std::vector& dst, bool clockwise) - { - CvMemStorage* storage = cvCreateMemStorage(); // - CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage - - // - for (const cv::Point& item : src) - { - CvPoint p; - p.x = item.x; - p.y = item.y; - cvSeqPush(ptseq, &p); - } - - //hullstorage - CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0); - - //dst - dst.clear(); - for (int i = 0, hullCount = hull->total; i < hullCount; i++) - dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i)); - - //storage - cvReleaseMemStorage(&storage); - } - -#define R_COLOR 255 - void fillConvexHull(cv::Mat& image, const std::vector& points) - { - uint index_top = 0; - uint index_bottom = 0; - for (size_t i = 0, length = points.size(); i < length; i++) - { - if (points[i].y < points[index_top].y) - index_top = i; - if (points[i].y > points[index_bottom].y) - index_bottom = i; - } - - std::vector edge_left; - uint temp = index_top; - while (temp != index_bottom) - { - edge_left.push_back(points[temp]); - temp = (temp + points.size() - 1) % points.size(); - } - edge_left.push_back(points[index_bottom]); - - std::vector edge_right; - temp = index_top; - while (temp != index_bottom) - { - edge_right.push_back(points[temp]); - temp = (temp + points.size() + 1) % points.size(); - } - edge_right.push_back(points[index_bottom]); - - std::vector left_edge_x; - std::vector left_edge_y; - for (size_t i = 0, length = edge_left.size() - 1; i < length; i++) - { - int y_top = edge_left[i].y; - int x_top = edge_left[i].x; - int y_bottom = edge_left[i + 1].y; - int x_bottom = edge_left[i + 1].x; - for (int y = y_top; y < y_bottom; y++) - if (y >= 0 && y_top != y_bottom && y < image.rows) - { - left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); - left_edge_y.push_back(y); - } - } - size_t step = image.step; - unsigned char* ptr; - ptr = image.data + static_cast(left_edge_y[0]) * step; - for (size_t i = 0, length = left_edge_x.size(); i < length; i++) - { - int pix = left_edge_x[i]; - if (pix < image.cols - 1 && pix > 0) - memset(ptr + i * step, R_COLOR, static_cast((pix + 1) * image.channels())); - } - - std::vector right_edge_x; - std::vector right_edge_y; - for (size_t i = 0, length = edge_right.size() - 1; i < length; i++) - { - int y_top = edge_right[i].y; - int x_top = edge_right[i].x; - int y_bottom = edge_right[i + 1].y; - int x_bottom = edge_right[i + 1].x; - for (int y = y_top; y < y_bottom; y++) - if (y_top != y_bottom && y < image.rows && y >= 0) - { - right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); - right_edge_y.push_back(y); - } - } - - ptr = image.data + static_cast(right_edge_y[0]) * step; - for (size_t i = 0, length = right_edge_x.size(); i < length; i++) - { - int pix = right_edge_x[i]; - if (pix < image.cols - 1 && pix > 0) - memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast(pix * image.channels())); - } - - if (edge_left[0].y > 0) - memset(image.data, R_COLOR, static_cast(edge_left[0].y) * step); - - if (edge_left.back().y < image.rows - 1) - memset(image.data + static_cast(edge_left.back().y) * step, R_COLOR, - static_cast(image.rows - edge_left.back().y) * step); - } - - void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color) - { - if (contours.empty()) return; - - size_t count = contours.size(); - cv::Point** pointss = new cv::Point*[count]; - int* npts = new int[count]; - - for (size_t i = 0; i < count; i++) - { - size_t length = contours[i].size(); - npts[i] = length; - pointss[i] = new cv::Point[length]; - for (size_t j = 0; j < length; j++) - pointss[i][j] = contours[i][j]; - } - cv::fillPoly(image, const_cast(pointss), npts, count, color); - - for (size_t i = 0; i < count; i++) - delete[] pointss[i]; - - delete[] pointss; - delete[] npts; - } - - void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) - { - CvMat c_image; - CV_DbgAssert(src.dims <= 2); - c_image = cvMat(src.rows, src.dims == 1 ? 1 : src.cols, src.type(), src.data); - c_image.step = (int)src.step[0]; - c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG); - cv::MemStorage storage(cvCreateMemStorage()); - CvSeq* _ccontours = nullptr; - cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint({ offset.x,offset.y })); - - if (!_ccontours) - { - contours.clear(); - return; - } - cv::Seq all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); - size_t total = all_contours.size(); - contours.resize(total); - - cv::SeqIterator it = all_contours.begin(); - for (size_t i = 0; i < total; i++, ++it) - { - CvSeq* c = *it; - reinterpret_cast(c)->color = static_cast(i); - int count = c->total; - int* data = new int[static_cast(count * 2)]; - cvCvtSeqToArray(c, data); - for (int j = 0; j < count; j++) - { - contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); - } - delete[] data; - } - - hierarchy.resize(total); - it = all_contours.begin(); - for (size_t i = 0; i < total; i++, ++it) - { - CvSeq* c = *it; - int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; - int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; - int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; - int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; - hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); - } - - storage.release(); - } - - cv::RotatedRect getBoundingRect(const std::vector& contour) - { - if (contour.empty()) return {}; - - cv::RotatedRect rect = minAreaRect(contour); - if (rect.angle < -45) - { - rect.angle += 90; - float temp = rect.size.width; - rect.size.width = rect.size.height; - rect.size.height = temp; - } - - if (rect.angle > 45) - { - rect.angle -= 90; - float temp = rect.size.width; - rect.size.width = rect.size.height; - rect.size.height = temp; - } - - return rect; - } - - std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy) - { - std::vector maxContour; - if (contours.size() < 1) return {}; - - for (size_t i = 0, length = hierarchy.size(); i < length; i++) - if (hierarchy[i][3] == -1) - for (const auto &item : contours[i]) - maxContour.push_back(item); - - return maxContour; - } - - std::vector getVertices(const cv::RotatedRect& rect) - { - cv::Point2f box[4]; - rect.points(box); - std::vector points; - for (int i = 0; i < 4; i++) - points.push_back(cv::Point(box[i])); - - return points; - } - - void polyIndent(std::vector& points, const cv::Point& center, int indent) - { - static cv::Point zero(0, 0); - for (cv::Point& item : points) - { -#if 0 - cv::Point vec = item - center; - if (vec != zero) - { - int length = vec.x * vec.x + vec.y * vec.y; - float x = cv::sqrt(static_cast(vec.x * vec.x / length)) * indent; - float y = cv::sqrt(static_cast(vec.y * vec.y / length)) * indent; - - if (vec.x < 0) x *= -1.0f; - if (vec.y < 0) y *= -1.0f; - - item.x -= static_cast(x); - item.y -= static_cast(y); - } -#else - if (item.x > center.x) - item.x -= indent; - else - item.x += indent; - - if (item.y > center.y) - item.y -= indent; - else - item.y += indent; -#endif - } - } - - cv::Mat transforColor(const cv::Mat& src) - { - if (src.channels() == 1) return src.clone(); - - std::vector channels(3); - cv::split(src, channels); - - cv::Mat temp, dst; - bitwise_or(channels[0], channels[1], temp); - bitwise_or(channels[2], temp, dst); - temp.release(); - - for (cv::Mat& index : channels) - index.release(); - return dst; - } - - void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) - { - if (src.channels() == 3) - { -#ifdef USE_ONENCL - if (cl_res.context) - transforColor_threshold_opencl(src, dst, static_cast(thre)); - else -#endif - { - cv::Mat gray = transforColor(src); - cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY); - gray.release(); - } - } - else - cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY); - } - - cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) - { - double src_data[3] = { static_cast(p.x), static_cast(p.y), 1 }; - cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1 - - cv::Mat dst = warp_mat * src; - double* ptr = reinterpret_cast(dst.data); - return cv::Point(static_cast(ptr[0]), static_cast(ptr[1])); - } - - int distanceP2P(const cv::Point& p1, const cv::Point& p2) - { - return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2)); - } - - float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2) - { - //ֱ߷ - int A = 0, B = 0, C = 0; - A = l1.y - l2.y; - B = l2.x - l1.x; - C = l1.x * l2.y - l1.y * l2.x; - //㵽ֱ߾빫ʽ - return ((float)abs(A * p.x + B * p.y + C)) / ((float)sqrtf(A * A + B * B)); - } +#include "ImageProcess_Public.h" + +namespace hg +{ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise) + { + CvMemStorage* storage = cvCreateMemStorage(); // + CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage + + //srcĵ㼯ptseq + for (const cv::Point& item : src) + { + CvPoint p; + p.x = item.x; + p.y = item.y; + cvSeqPush(ptseq, &p); + } + + //ȡ + CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0); + + if (hull == nullptr) + { + //ͷstorage + cvReleaseMemStorage(&storage); + return; + } + + //dst + dst.clear(); + for (int i = 0, hullCount = hull->total; i < hullCount; i++) + dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i)); + + //ͷstorage + cvReleaseMemStorage(&storage); + } + +#define R_COLOR 255 + void fillConvexHull(cv::Mat& image, const std::vector& points) + { + uint index_top = 0; + uint index_bottom = 0; + for (size_t i = 0, length = points.size(); i < length; i++) + { + if (points[i].y < points[index_top].y) + index_top = i; + if (points[i].y > points[index_bottom].y) + index_bottom = i; + } + + std::vector edge_left; + uint temp = index_top; + while (temp != index_bottom) + { + edge_left.push_back(points[temp]); + temp = (temp + points.size() - 1) % points.size(); + } + edge_left.push_back(points[index_bottom]); + + std::vector edge_right; + temp = index_top; + while (temp != index_bottom) + { + edge_right.push_back(points[temp]); + temp = (temp + points.size() + 1) % points.size(); + } + edge_right.push_back(points[index_bottom]); + + std::vector left_edge_x; + std::vector left_edge_y; + for (size_t i = 0, length = edge_left.size() - 1; i < length; i++) + { + int y_top = edge_left[i].y; + int x_top = edge_left[i].x; + int y_bottom = edge_left[i + 1].y; + int x_bottom = edge_left[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y >= 0 && y_top != y_bottom && y < image.rows) + { + left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + left_edge_y.push_back(y); + } + } + size_t step = image.step; + unsigned char* ptr; + ptr = image.data + static_cast(left_edge_y[0]) * step; + for (size_t i = 0, length = left_edge_x.size(); i < length; i++) + { + int pix = left_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step, R_COLOR, static_cast((pix + 1) * image.channels())); + } + + std::vector right_edge_x; + std::vector right_edge_y; + for (size_t i = 0, length = edge_right.size() - 1; i < length; i++) + { + int y_top = edge_right[i].y; + int x_top = edge_right[i].x; + int y_bottom = edge_right[i + 1].y; + int x_bottom = edge_right[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y_top != y_bottom && y < image.rows && y >= 0) + { + right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + right_edge_y.push_back(y); + } + } + + ptr = image.data + static_cast(right_edge_y[0]) * step; + for (size_t i = 0, length = right_edge_x.size(); i < length; i++) + { + int pix = right_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast(pix * image.channels())); + } + + if (edge_left[0].y > 0) + memset(image.data, R_COLOR, static_cast(edge_left[0].y) * step); + + if (edge_left.back().y < image.rows - 1) + memset(image.data + static_cast(edge_left.back().y) * step, R_COLOR, + static_cast(image.rows - edge_left.back().y) * step); + } + + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color) + { + if (contours.empty()) return; + + size_t count = contours.size(); + cv::Point** pointss = new cv::Point*[count]; + int* npts = new int[count]; + + for (size_t i = 0; i < count; i++) + { + size_t length = contours[i].size(); + npts[i] = length; + pointss[i] = new cv::Point[length]; + for (size_t j = 0; j < length; j++) + pointss[i][j] = contours[i][j]; + } + cv::fillPoly(image, const_cast(pointss), npts, count, color); + + for (size_t i = 0; i < count; i++) + delete[] pointss[i]; + + delete[] pointss; + delete[] npts; + } + + 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; + +#if CV_VERSION_REVISION <= 6 + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset)); +#else + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint{ offset.x, offset.y }); +#endif + if (!_ccontours) + { + contours.clear(); + return; + } + cv::Seq all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); + size_t total = all_contours.size(); + contours.resize(total); + + cv::SeqIterator it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + reinterpret_cast(c)->color = static_cast(i); + int count = c->total; + int* data = new int[static_cast(count * 2)]; + cvCvtSeqToArray(c, data); + for (int j = 0; j < count; j++) + { + contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); + } + delete[] data; + } + + hierarchy.resize(total); + it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; + int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; + int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; + int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; + hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); + } + + storage.release(); + } + + cv::RotatedRect getBoundingRect(const std::vector& contour) + { + if (contour.empty()) return {}; + + cv::RotatedRect rect = minAreaRect(contour); + if (rect.angle < -45) + { + rect.angle += 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + if (rect.angle > 45) + { + rect.angle -= 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + + return rect; + } + + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy) + { + std::vector maxContour; + if (contours.size() < 1) return {}; + + for (size_t i = 0, length = hierarchy.size(); i < length; i++) + if (hierarchy[i][3] == -1) + for (const auto &item : contours[i]) + maxContour.push_back(item); + + return maxContour; + } + + std::vector getVertices(const cv::RotatedRect& rect) + { + cv::Point2f box[4]; + rect.points(box); + std::vector points; + for (int i = 0; i < 4; i++) + points.push_back(cv::Point(box[i])); + + return points; + } + + void polyIndent(std::vector& points, const cv::Point& center, int indent) + { + static cv::Point zero(0, 0); + for (cv::Point& item : points) + { +#if 0 + cv::Point vec = item - center; + if (vec != zero) + { + int length = vec.x * vec.x + vec.y * vec.y; + float x = cv::sqrt(static_cast(vec.x * vec.x / length)) * indent; + float y = cv::sqrt(static_cast(vec.y * vec.y / length)) * indent; + + if (vec.x < 0) x *= -1.0f; + if (vec.y < 0) y *= -1.0f; + + item.x -= static_cast(x); + item.y -= static_cast(y); + } +#else + if (item.x > center.x) + item.x -= indent; + else + item.x += indent; + + if (item.y > center.y) + item.y -= indent; + else + item.y += indent; +#endif + } + } + + cv::Mat transforColor(const cv::Mat& src) + { + if (src.channels() == 1) return src.clone(); + + std::vector channels(3); + cv::split(src, channels); + + cv::Mat temp, dst; + bitwise_or(channels[0], channels[1], temp); + bitwise_or(channels[2], temp, dst); + temp.release(); + + for (cv::Mat& index : channels) + index.release(); + return dst; + } + + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) + { + if (src.channels() == 3) + { +#ifdef USE_ONENCL + if (cl_res.context) + transforColor_threshold_opencl(src, dst, static_cast(thre)); + else +#endif + { + cv::Mat gray = transforColor(src); + cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY); + gray.release(); + } + } + else + cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY); + } + + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) + { + double src_data[3] = { static_cast(p.x), static_cast(p.y), 1 }; + cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1 + + cv::Mat dst = warp_mat * src; + double* ptr = reinterpret_cast(dst.data); + return cv::Point(static_cast(ptr[0]), static_cast(ptr[1])); + } + + int distanceP2P(const cv::Point& p1, const cv::Point& p2) + { + return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2)); + } + + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2) + { + //ֱ߷ + int A = 0, B = 0, C = 0; + A = l1.y - l2.y; + B = l2.x - l1.x; + C = l1.x * l2.y - l1.y * l2.x; + //㵽ֱ߾빫ʽ + return ((float)abs(A * p.x + B * p.y + C)) / ((float)sqrtf(A * A + B * B)); + } } \ No newline at end of file diff --git a/hgdriver/ImageProcess/ImageProcess_Public.h b/hgdriver/ImageProcess/ImageProcess_Public.h index b2cfa7d..a05ae8b 100644 --- a/hgdriver/ImageProcess/ImageProcess_Public.h +++ b/hgdriver/ImageProcess/ImageProcess_Public.h @@ -1,123 +1,130 @@ -/* - * ==================================================== - - * ܣͼ㷨ֹܻܿImageProcess෴ʹ - * ߣά - * ʱ䣺2020/4/21 - * ޸ʱ䣺2020/4/21 - * 汾ţv1.0 - - * ==================================================== - */ - -#ifndef IMAGE_PROCESS_PUBLIC_H -#define IMAGE_PROCESS_PUBLIC_H - -#include -#include - -namespace hg -{ - /* - * ܣԴ㼯͹㼯 - * src: Դ㼯 - * dst: Ŀ㼯 - * clockwise: trueΪ˳ʱfalseΪʱ - */ - void convexHull(const std::vector& src, std::vector& dst, bool clockwise = false); - - /* - * ܣ͹ΣĬɫΪɫ - * image: ͼ - * points: ͹㼯ʱ - */ - void fillConvexHull(cv::Mat& image, const std::vector& points); - - /* - * ܣ䰼 - * image: ͼ - * contours: 㼯ʱ - * color: ɫ - */ - void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color); - - /* - * ܣȡͨ - * src: Դͼ - * contours: - * hierarchy: ϵcontoursӦretrѡͬб仯 - * retr: ʽĬΪʽ - * method: 㷨ѡĬΪͨ - * offset: ʼ㣬ĬΪ0,0 - */ - 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::RotatedRect getBoundingRect(const std::vector& contour); - - /* - * : ȡС͹ - * contours: ÿɵ㼯ɣ - * hierarchy: У֮ĹϵcontoursӦ - * ֵ: ͹㼯 - */ - std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy); - - /* - * : ȡС͹ - * contours: ÿɵ㼯ɣ - * hierarchy: У֮ĹϵcontoursӦ - * ֵ: ͹㼯 - */ - std::vector getVertices(const cv::RotatedRect& rect); - - /* - * : - * points: 㼯 - * center: Χcenter - * indent: - */ - void polyIndent(std::vector& points, const cv::Point& center, int indent); - - /* - * : ֵܹɫͻҶͼsrcΪɫͼʱҶͼȡֵͨ - * src: Դͼ - * dst: Ŀͼ - * thre: ֵ - */ - void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre); - - /* - * : ɫתҶȣҶͼȡֵͨ - * src: Դͼ - * ֵ: Ҷͼ - */ - cv::Mat transforColor(const cv::Mat& src); - - /* - * : ȡķ任 - * p: ԭ - * warp_mat: 任ϵ - * ֵ: 任ĵ - */ - cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat); - - /* - * : 㵽 - * p1: 1 - * p2: 2 - * ֵ: 㵽 - */ - int distanceP2P(const cv::Point& p1, const cv::Point& p2); - - /* - * : 㵽ֱ߾ - * p: - * l1: ֱ߶˵1 - * l2: ֱ߶˵2 - * ֵ: 㵽ֱ߾ - */ - float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2); -} - -#endif // !IMAGE_PROCESS_C_H +/* + * ==================================================== + + * ܣͼ㷨ֹܻܿImageProcess෴ʹ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 2021/07/12 v1.1 getBoundingRectУӿǾʼ angle > 90 + * 2021/07/22 v1.2 convexHullУ޸㼯Ϊտܵ±BUG + * 汾ţv1.2 + + * ==================================================== + */ + +#ifndef IMAGE_PROCESS_PUBLIC_H +#define IMAGE_PROCESS_PUBLIC_H + +#include "opencv2/opencv.hpp" +#include + +namespace hg +{ + /* + * ܣԴ㼯͹㼯 + * src: Դ㼯 + * dst: Ŀ㼯 + * clockwise: trueΪ˳ʱfalseΪʱ + */ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise = false); + + /* + * ܣ͹ΣĬɫΪɫ + * image: ͼ + * points: ͹㼯ʱ + */ + void fillConvexHull(cv::Mat& image, const std::vector& points); + + /* + * ܣ䰼 + * image: ͼ + * contours: 㼯ʱ + * color: ɫ + */ + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color); + + /* + * ܣȡͨ + * src: Դͼ + * contours: + * hierarchy: ϵcontoursӦretrѡͬб仯 + * retr: ʽĬΪʽ + * method: 㷨ѡĬΪͨ + * offset: ʼ㣬ĬΪ0,0 + */ + 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)); + + /* + * ܣȡǵ㼯СӾ + * contour: 㼯 + * ֵ: ת + */ + cv::RotatedRect getBoundingRect(const std::vector& contour); + + /* + * : ȡС͹ + * contours: ÿɵ㼯ɣ + * hierarchy: У֮ĹϵcontoursӦ + * ֵ: ͹㼯 + */ + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy); + + /* + * : ȡС͹ + * contours: ÿɵ㼯ɣ + * hierarchy: У֮ĹϵcontoursӦ + * ֵ: ͹㼯 + */ + std::vector getVertices(const cv::RotatedRect& rect); + + /* + * : + * points: 㼯 + * center: Χcenter + * indent: + */ + void polyIndent(std::vector& points, const cv::Point& center, int indent); + + /* + * : ֵܹɫͻҶͼsrcΪɫͼʱҶͼȡֵͨ + * src: Դͼ + * dst: Ŀͼ + * thre: ֵ + */ + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre); + + /* + * : ɫתҶȣҶͼȡֵͨ + * src: Դͼ + * ֵ: Ҷͼ + */ + cv::Mat transforColor(const cv::Mat& src); + + /* + * : ȡķ任 + * p: ԭ + * warp_mat: 任ϵ + * ֵ: 任ĵ + */ + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat); + + /* + * : 㵽 + * p1: 1 + * p2: 2 + * ֵ: 㵽 + */ + int distanceP2P(const cv::Point& p1, const cv::Point& p2); + + /* + * : 㵽ֱ߾ + * p: + * l1: ֱ߶˵1 + * l2: ֱ߶˵2 + * ֵ: 㵽ֱ߾ + */ + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2); +} + +#endif // !IMAGE_PROCESS_C_H diff --git a/hgdriver/ImageProcess/MatEx.h b/hgdriver/ImageProcess/MatEx.h index ab0c469..d733ee8 100644 --- a/hgdriver/ImageProcess/MatEx.h +++ b/hgdriver/ImageProcess/MatEx.h @@ -1,22 +1,22 @@ -#pragma once -#include - -class MatEx { -public: - MatEx() : - mat(cv::Mat()) - , Bpp(-1) { - - }; - - MatEx(cv::Mat &mat, int bpp) : - mat(cv::Mat()) - , Bpp(bpp) - { - this->mat = mat; - this->Bpp = bpp; - } -public: - int Bpp; - cv::Mat mat; +#pragma once +#include + +class MatEx { +public: + MatEx() : + mat(cv::Mat()) + , Bpp(-1) { + + }; + + MatEx(cv::Mat mat, int bpp) : + mat(cv::Mat()) + , Bpp(bpp) + { + this->mat = mat.clone(); + this->Bpp = bpp; + } +public: + int Bpp; + cv::Mat mat; }; \ No newline at end of file diff --git a/hgdriver/ImageProcess/imgprocdefs.h b/hgdriver/ImageProcess/imgprocdefs.h index ba5fea9..91ef9b5 100644 --- a/hgdriver/ImageProcess/imgprocdefs.h +++ b/hgdriver/ImageProcess/imgprocdefs.h @@ -1,22 +1,21 @@ -#ifndef IMAGE_PROCESS_DEFINES_H -#define IMAGE_PROCESS_DEFINES_H - -//#if defined(_MSC_VER) -//# define HT_DECL_EXPORT __declspec(dllexport) -//# define HT_DECL_IMPORT __declspec(dllimport) -//#elif defined(__linux__) || defined(__linux) -//# define HT_DECL_EXPORT __attribute__((visibility("default"))) -//# define HT_DECL_IMPORT __attribute__((visibility("default"))) -//# define HT_DECL_HIDDEN __attribute__((visibility("hidden"))) -//#endif -// -//#if defined(GIMGPROC_LIBRARY_BUILD) -//#define HT_DECL_EXPORT -//#elif defined(_DIRECT_BUILD) -//#define -//#else -////#define HT_DECL_IMPORT -//#endif -#define IMAGE_PROCESS_DEFINES_H - -#endif // !IMAGE_PROCESS_DEFINES_H +#ifndef IMAGE_PROCESS_DEFINES_H +#define IMAGE_PROCESS_DEFINES_H + +#if defined(_MSC_VER) +# define HT_DECL_EXPORT __declspec(dllexport) +# define HT_DECL_IMPORT __declspec(dllimport) +#elif defined(__linux__) || defined(__linux) +# define HT_DECL_EXPORT __attribute__((visibility("default"))) +# define HT_DECL_IMPORT __attribute__((visibility("default"))) +# define HT_DECL_HIDDEN __attribute__((visibility("hidden"))) +#endif + +#if defined(GIMGPROC_LIBRARY_BUILD) +#define GIMGPROC_LIBRARY_API HT_DECL_EXPORT +#elif defined(_DIRECT_BUILD) +#define GIMGPROC_LIBRARY_API +#else +#define GIMGPROC_LIBRARY_API HT_DECL_IMPORT +#endif + +#endif // !IMAGE_PROCESS_DEFINES_H diff --git a/hgdriver/ImageProcess/include/bigint/BigInteger.hh b/hgdriver/ImageProcess/include/bigint/BigInteger.hh new file mode 100755 index 0000000..676af45 --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigInteger.hh @@ -0,0 +1,215 @@ +#ifndef BIGINTEGER_H +#define BIGINTEGER_H + +#include "BigUnsigned.hh" + +/* A BigInteger object represents a signed integer of size limited only by + * available memory. BigUnsigneds support most mathematical operators and can + * be converted to and from most primitive integer types. + * + * A BigInteger is just an aggregate of a BigUnsigned and a sign. (It is no + * longer derived from BigUnsigned because that led to harmful implicit + * conversions.) */ +class BigInteger { + +public: + typedef BigUnsigned::Blk Blk; + typedef BigUnsigned::Index Index; + typedef BigUnsigned::CmpRes CmpRes; + static const CmpRes + less = BigUnsigned::less , + equal = BigUnsigned::equal , + greater = BigUnsigned::greater; + // Enumeration for the sign of a BigInteger. + enum Sign { negative = -1, zero = 0, positive = 1 }; + +protected: + Sign sign; + BigUnsigned mag; + +public: + // Constructs zero. + BigInteger() : sign(zero), mag() {} + + // Copy constructor + BigInteger(const BigInteger &x) : sign(x.sign), mag(x.mag) {}; + + // Assignment operator + void operator=(const BigInteger &x); + + // Constructor that copies from a given array of blocks with a sign. + BigInteger(const Blk *b, Index blen, Sign s); + + // Nonnegative constructor that copies from a given array of blocks. + BigInteger(const Blk *b, Index blen) : mag(b, blen) { + sign = mag.isZero() ? zero : positive; + } + + // Constructor from a BigUnsigned and a sign + BigInteger(const BigUnsigned &x, Sign s); + + // Nonnegative constructor from a BigUnsigned + BigInteger(const BigUnsigned &x) : mag(x) { + sign = mag.isZero() ? zero : positive; + } + + // Constructors from primitive integer types + BigInteger(unsigned long x); + BigInteger( long x); + BigInteger(unsigned int x); + BigInteger( int x); + BigInteger(unsigned short x); + BigInteger( short x); + + /* Converters to primitive integer types + * The implicit conversion operators caused trouble, so these are now + * named. */ + unsigned long toUnsignedLong () const; + long toLong () const; + unsigned int toUnsignedInt () const; + int toInt () const; + unsigned short toUnsignedShort() const; + short toShort () const; +protected: + // Helper + template X convertToUnsignedPrimitive() const; + template X convertToSignedPrimitive() const; +public: + + // ACCESSORS + Sign getSign() const { return sign; } + /* The client can't do any harm by holding a read-only reference to the + * magnitude. */ + const BigUnsigned &getMagnitude() const { return mag; } + + // Some accessors that go through to the magnitude + Index getLength() const { return mag.getLength(); } + Index getCapacity() const { return mag.getCapacity(); } + Blk getBlock(Index i) const { return mag.getBlock(i); } + bool isZero() const { return sign == zero; } // A bit special + + // COMPARISONS + + // Compares this to x like Perl's <=> + CmpRes compareTo(const BigInteger &x) const; + + // Ordinary comparison operators + bool operator ==(const BigInteger &x) const { + return sign == x.sign && mag == x.mag; + } + bool operator !=(const BigInteger &x) const { return !operator ==(x); }; + bool operator < (const BigInteger &x) const { return compareTo(x) == less ; } + bool operator <=(const BigInteger &x) const { return compareTo(x) != greater; } + bool operator >=(const BigInteger &x) const { return compareTo(x) != less ; } + bool operator > (const BigInteger &x) const { return compareTo(x) == greater; } + + // OPERATORS -- See the discussion in BigUnsigned.hh. + void add (const BigInteger &a, const BigInteger &b); + void subtract(const BigInteger &a, const BigInteger &b); + void multiply(const BigInteger &a, const BigInteger &b); + /* See the comment on BigUnsigned::divideWithRemainder. Semantics + * differ from those of primitive integers when negatives and/or zeros + * are involved. */ + void divideWithRemainder(const BigInteger &b, BigInteger &q); + void negate(const BigInteger &a); + + /* Bitwise operators are not provided for BigIntegers. Use + * getMagnitude to get the magnitude and operate on that instead. */ + + BigInteger operator +(const BigInteger &x) const; + BigInteger operator -(const BigInteger &x) const; + BigInteger operator *(const BigInteger &x) const; + BigInteger operator /(const BigInteger &x) const; + BigInteger operator %(const BigInteger &x) const; + BigInteger operator -() const; + + void operator +=(const BigInteger &x); + void operator -=(const BigInteger &x); + void operator *=(const BigInteger &x); + void operator /=(const BigInteger &x); + void operator %=(const BigInteger &x); + void flipSign(); + + // INCREMENT/DECREMENT OPERATORS + void operator ++( ); + void operator ++(int); + void operator --( ); + void operator --(int); +}; + +// NORMAL OPERATORS +/* These create an object to hold the result and invoke + * the appropriate put-here operation on it, passing + * this and x. The new object is then returned. */ +inline BigInteger BigInteger::operator +(const BigInteger &x) const { + BigInteger ans; + ans.add(*this, x); + return ans; +} +inline BigInteger BigInteger::operator -(const BigInteger &x) const { + BigInteger ans; + ans.subtract(*this, x); + return ans; +} +inline BigInteger BigInteger::operator *(const BigInteger &x) const { + BigInteger ans; + ans.multiply(*this, x); + return ans; +} +inline BigInteger BigInteger::operator /(const BigInteger &x) const { + if (x.isZero()) throw "BigInteger::operator /: division by zero"; + BigInteger q, r; + r = *this; + r.divideWithRemainder(x, q); + return q; +} +inline BigInteger BigInteger::operator %(const BigInteger &x) const { + if (x.isZero()) throw "BigInteger::operator %: division by zero"; + BigInteger q, r; + r = *this; + r.divideWithRemainder(x, q); + return r; +} +inline BigInteger BigInteger::operator -() const { + BigInteger ans; + ans.negate(*this); + return ans; +} + +/* + * ASSIGNMENT OPERATORS + * + * Now the responsibility for making a temporary copy if necessary + * belongs to the put-here operations. See Assignment Operators in + * BigUnsigned.hh. + */ +inline void BigInteger::operator +=(const BigInteger &x) { + add(*this, x); +} +inline void BigInteger::operator -=(const BigInteger &x) { + subtract(*this, x); +} +inline void BigInteger::operator *=(const BigInteger &x) { + multiply(*this, x); +} +inline void BigInteger::operator /=(const BigInteger &x) { + if (x.isZero()) throw "BigInteger::operator /=: division by zero"; + /* The following technique is slightly faster than copying *this first + * when x is large. */ + BigInteger q; + divideWithRemainder(x, q); + // *this contains the remainder, but we overwrite it with the quotient. + *this = q; +} +inline void BigInteger::operator %=(const BigInteger &x) { + if (x.isZero()) throw "BigInteger::operator %=: division by zero"; + BigInteger q; + // Mods *this by x. Don't care about quotient left in q. + divideWithRemainder(x, q); +} +// This one is trivial +inline void BigInteger::flipSign() { + sign = Sign(-sign); +} + +#endif diff --git a/hgdriver/ImageProcess/include/bigint/BigIntegerAlgorithms.hh b/hgdriver/ImageProcess/include/bigint/BigIntegerAlgorithms.hh new file mode 100755 index 0000000..f7210aa --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigIntegerAlgorithms.hh @@ -0,0 +1,25 @@ +#ifndef BIGINTEGERALGORITHMS_H +#define BIGINTEGERALGORITHMS_H + +#include "BigInteger.hh" + +/* Some mathematical algorithms for big integers. + * This code is new and, as such, experimental. */ + +// Returns the greatest common divisor of a and b. +BigUnsigned gcd(BigUnsigned a, BigUnsigned b); + +/* Extended Euclidean algorithm. + * Given m and n, finds gcd g and numbers r, s such that r*m + s*n == g. */ +void extendedEuclidean(BigInteger m, BigInteger n, + BigInteger &g, BigInteger &r, BigInteger &s); + +/* Returns the multiplicative inverse of x modulo n, or throws an exception if + * they have a common factor. */ +BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n); + +// Returns (base ^ exponent) % modulus. +BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent, + const BigUnsigned &modulus); + +#endif diff --git a/hgdriver/ImageProcess/include/bigint/BigIntegerLibrary.hh b/hgdriver/ImageProcess/include/bigint/BigIntegerLibrary.hh new file mode 100755 index 0000000..f0219ed --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigIntegerLibrary.hh @@ -0,0 +1,8 @@ +// This header file includes all of the library header files. + +#include "NumberlikeArray.hh" +#include "BigUnsigned.hh" +#include "BigInteger.hh" +#include "BigIntegerAlgorithms.hh" +#include "BigUnsignedInABase.hh" +#include "BigIntegerUtils.hh" diff --git a/hgdriver/ImageProcess/include/bigint/BigIntegerUtils.hh b/hgdriver/ImageProcess/include/bigint/BigIntegerUtils.hh new file mode 100755 index 0000000..caeaa17 --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigIntegerUtils.hh @@ -0,0 +1,72 @@ +#ifndef BIGINTEGERUTILS_H +#define BIGINTEGERUTILS_H + +#include "BigInteger.hh" +#include +#include + +/* This file provides: + * - Convenient std::string <-> BigUnsigned/BigInteger conversion routines + * - std::ostream << operators for BigUnsigned/BigInteger */ + +// std::string conversion routines. Base 10 only. +std::string bigUnsignedToString(const BigUnsigned &x); +std::string bigIntegerToString(const BigInteger &x); +BigUnsigned stringToBigUnsigned(const std::string &s); +BigInteger stringToBigInteger(const std::string &s); + +// Creates a BigInteger from data such as `char's; read below for details. +template +BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign); + +// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'. +std::ostream &operator <<(std::ostream &os, const BigUnsigned &x); + +// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'. +// My somewhat arbitrary policy: a negative sign comes before a base indicator (like -0xFF). +std::ostream &operator <<(std::ostream &os, const BigInteger &x); + +// BEGIN TEMPLATE DEFINITIONS. + +/* + * Converts binary data to a BigInteger. + * Pass an array `data', its length, and the desired sign. + * + * Elements of `data' may be of any type `T' that has the following + * two properties (this includes almost all integral types): + * + * (1) `sizeof(T)' correctly gives the amount of binary data in one + * value of `T' and is a factor of `sizeof(Blk)'. + * + * (2) When a value of `T' is casted to a `Blk', the low bytes of + * the result contain the desired binary data. + */ +template +BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign) { + // really ceiling(numBytes / sizeof(BigInteger::Blk)) + unsigned int pieceSizeInBits = 8 * sizeof(T); + unsigned int piecesPerBlock = sizeof(BigInteger::Blk) / sizeof(T); + unsigned int numBlocks = (length + piecesPerBlock - 1) / piecesPerBlock; + + // Allocate our block array + BigInteger::Blk *blocks = new BigInteger::Blk[numBlocks]; + + BigInteger::Index blockNum, pieceNum, pieceNumHere; + + // Convert + for (blockNum = 0, pieceNum = 0; blockNum < numBlocks; blockNum++) { + BigInteger::Blk curBlock = 0; + for (pieceNumHere = 0; pieceNumHere < piecesPerBlock && pieceNum < length; + pieceNumHere++, pieceNum++) + curBlock |= (BigInteger::Blk(data[pieceNum]) << (pieceSizeInBits * pieceNumHere)); + blocks[blockNum] = curBlock; + } + + // Create the BigInteger. + BigInteger x(blocks, numBlocks, sign); + + delete [] blocks; + return x; +} + +#endif diff --git a/hgdriver/ImageProcess/include/bigint/BigUnsigned.hh b/hgdriver/ImageProcess/include/bigint/BigUnsigned.hh new file mode 100755 index 0000000..55282e9 --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigUnsigned.hh @@ -0,0 +1,418 @@ +#ifndef BIGUNSIGNED_H +#define BIGUNSIGNED_H + +#include "NumberlikeArray.hh" + +/* A BigUnsigned object represents a nonnegative integer of size limited only by + * available memory. BigUnsigneds support most mathematical operators and can + * be converted to and from most primitive integer types. + * + * The number is stored as a NumberlikeArray of unsigned longs as if it were + * written in base 256^sizeof(unsigned long). The least significant block is + * first, and the length is such that the most significant block is nonzero. */ +class BigUnsigned : protected NumberlikeArray { + +public: + // Enumeration for the result of a comparison. + enum CmpRes { less = -1, equal = 0, greater = 1 }; + + // BigUnsigneds are built with a Blk type of unsigned long. + typedef unsigned long Blk; + + typedef NumberlikeArray::Index Index; + using NumberlikeArray::N; + +protected: + // Creates a BigUnsigned with a capacity; for internal use. + BigUnsigned(int, Index c) : NumberlikeArray(0, c) {} + + // Decreases len to eliminate any leading zero blocks. + void zapLeadingZeros() { + while (len > 0 && blk[len - 1] == 0) + len--; + } + +public: + // Constructs zero. + BigUnsigned() : NumberlikeArray() {} + + // Copy constructor + BigUnsigned(const BigUnsigned &x) : NumberlikeArray(x) {} + + // Assignment operator + void operator=(const BigUnsigned &x) { + NumberlikeArray::operator =(x); + } + + // Constructor that copies from a given array of blocks. + BigUnsigned(const Blk *b, Index blen) : NumberlikeArray(b, blen) { + // Eliminate any leading zeros we may have been passed. + zapLeadingZeros(); + } + + // Destructor. NumberlikeArray does the delete for us. + ~BigUnsigned() {} + + // Constructors from primitive integer types + BigUnsigned(unsigned long x); + BigUnsigned( long x); + BigUnsigned(unsigned int x); + BigUnsigned( int x); + BigUnsigned(unsigned short x); + BigUnsigned( short x); +protected: + // Helpers + template void initFromPrimitive (X x); + template void initFromSignedPrimitive(X x); +public: + + /* Converters to primitive integer types + * The implicit conversion operators caused trouble, so these are now + * named. */ + unsigned long toUnsignedLong () const; + long toLong () const; + unsigned int toUnsignedInt () const; + int toInt () const; + unsigned short toUnsignedShort() const; + short toShort () const; +protected: + // Helpers + template X convertToSignedPrimitive() const; + template X convertToPrimitive () const; +public: + + // BIT/BLOCK ACCESSORS + + // Expose these from NumberlikeArray directly. + using NumberlikeArray::getCapacity; + using NumberlikeArray::getLength; + + /* Returns the requested block, or 0 if it is beyond the length (as if + * the number had 0s infinitely to the left). */ + Blk getBlock(Index i) const { return i >= len ? 0 : blk[i]; } + /* Sets the requested block. The number grows or shrinks as necessary. */ + void setBlock(Index i, Blk newBlock); + + // The number is zero if and only if the canonical length is zero. + bool isZero() const { return NumberlikeArray::isEmpty(); } + + /* Returns the length of the number in bits, i.e., zero if the number + * is zero and otherwise one more than the largest value of bi for + * which getBit(bi) returns true. */ + Index bitLength() const; + /* Get the state of bit bi, which has value 2^bi. Bits beyond the + * number's length are considered to be 0. */ + bool getBit(Index bi) const { + return (getBlock(bi / N) & (Blk(1) << (bi % N))) != 0; + } + /* Sets the state of bit bi to newBit. The number grows or shrinks as + * necessary. */ + void setBit(Index bi, bool newBit); + + // COMPARISONS + + // Compares this to x like Perl's <=> + CmpRes compareTo(const BigUnsigned &x) const; + + // Ordinary comparison operators + bool operator ==(const BigUnsigned &x) const { + return NumberlikeArray::operator ==(x); + } + bool operator !=(const BigUnsigned &x) const { + return NumberlikeArray::operator !=(x); + } + bool operator < (const BigUnsigned &x) const { return compareTo(x) == less ; } + bool operator <=(const BigUnsigned &x) const { return compareTo(x) != greater; } + bool operator >=(const BigUnsigned &x) const { return compareTo(x) != less ; } + bool operator > (const BigUnsigned &x) const { return compareTo(x) == greater; } + + /* + * BigUnsigned and BigInteger both provide three kinds of operators. + * Here ``big-integer'' refers to BigInteger or BigUnsigned. + * + * (1) Overloaded ``return-by-value'' operators: + * +, -, *, /, %, unary -, &, |, ^, <<, >>. + * Big-integer code using these operators looks identical to code using + * the primitive integer types. These operators take one or two + * big-integer inputs and return a big-integer result, which can then + * be assigned to a BigInteger variable or used in an expression. + * Example: + * BigInteger a(1), b = 1; + * BigInteger c = a + b; + * + * (2) Overloaded assignment operators: + * +=, -=, *=, /=, %=, flipSign, &=, |=, ^=, <<=, >>=, ++, --. + * Again, these are used on big integers just like on ints. They take + * one writable big integer that both provides an operand and receives a + * result. Most also take a second read-only operand. + * Example: + * BigInteger a(1), b(1); + * a += b; + * + * (3) Copy-less operations: `add', `subtract', etc. + * These named methods take operands as arguments and store the result + * in the receiver (*this), avoiding unnecessary copies and allocations. + * `divideWithRemainder' is special: it both takes the dividend from and + * stores the remainder into the receiver, and it takes a separate + * object in which to store the quotient. NOTE: If you are wondering + * why these don't return a value, you probably mean to use the + * overloaded return-by-value operators instead. + * + * Examples: + * BigInteger a(43), b(7), c, d; + * + * c = a + b; // Now c == 50. + * c.add(a, b); // Same effect but without the two copies. + * + * c.divideWithRemainder(b, d); + * // 50 / 7; now d == 7 (quotient) and c == 1 (remainder). + * + * // ``Aliased'' calls now do the right thing using a temporary + * // copy, but see note on `divideWithRemainder'. + * a.add(a, b); + */ + + // COPY-LESS OPERATIONS + + // These 8: Arguments are read-only operands, result is saved in *this. + void add(const BigUnsigned &a, const BigUnsigned &b); + void subtract(const BigUnsigned &a, const BigUnsigned &b); + void multiply(const BigUnsigned &a, const BigUnsigned &b); + void bitAnd(const BigUnsigned &a, const BigUnsigned &b); + void bitOr(const BigUnsigned &a, const BigUnsigned &b); + void bitXor(const BigUnsigned &a, const BigUnsigned &b); + /* Negative shift amounts translate to opposite-direction shifts, + * except for -2^(8*sizeof(int)-1) which is unimplemented. */ + void bitShiftLeft(const BigUnsigned &a, int b); + void bitShiftRight(const BigUnsigned &a, int b); + + /* `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'. + * / and % use semantics similar to Knuth's, which differ from the + * primitive integer semantics under division by zero. See the + * implementation in BigUnsigned.cc for details. + * `a.divideWithRemainder(b, a)' throws an exception: it doesn't make + * sense to write quotient and remainder into the same variable. */ + void divideWithRemainder(const BigUnsigned &b, BigUnsigned &q); + + /* `divide' and `modulo' are no longer offered. Use + * `divideWithRemainder' instead. */ + + // OVERLOADED RETURN-BY-VALUE OPERATORS + BigUnsigned operator +(const BigUnsigned &x) const; + BigUnsigned operator -(const BigUnsigned &x) const; + BigUnsigned operator *(const BigUnsigned &x) const; + BigUnsigned operator /(const BigUnsigned &x) const; + BigUnsigned operator %(const BigUnsigned &x) const; + /* OK, maybe unary minus could succeed in one case, but it really + * shouldn't be used, so it isn't provided. */ + BigUnsigned operator &(const BigUnsigned &x) const; + BigUnsigned operator |(const BigUnsigned &x) const; + BigUnsigned operator ^(const BigUnsigned &x) const; + BigUnsigned operator <<(int b) const; + BigUnsigned operator >>(int b) const; + + // OVERLOADED ASSIGNMENT OPERATORS + void operator +=(const BigUnsigned &x); + void operator -=(const BigUnsigned &x); + void operator *=(const BigUnsigned &x); + void operator /=(const BigUnsigned &x); + void operator %=(const BigUnsigned &x); + void operator &=(const BigUnsigned &x); + void operator |=(const BigUnsigned &x); + void operator ^=(const BigUnsigned &x); + void operator <<=(int b); + void operator >>=(int b); + + /* INCREMENT/DECREMENT OPERATORS + * To discourage messy coding, these do not return *this, so prefix + * and postfix behave the same. */ + void operator ++( ); + void operator ++(int); + void operator --( ); + void operator --(int); + + // Helper function that needs access to BigUnsigned internals + friend Blk getShiftedBlock(const BigUnsigned &num, Index x, + unsigned int y); + + // See BigInteger.cc. + template + friend X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a); +}; + +/* Implementing the return-by-value and assignment operators in terms of the + * copy-less operations. The copy-less operations are responsible for making + * any necessary temporary copies to work around aliasing. */ + +inline BigUnsigned BigUnsigned::operator +(const BigUnsigned &x) const { + BigUnsigned ans; + ans.add(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator -(const BigUnsigned &x) const { + BigUnsigned ans; + ans.subtract(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator *(const BigUnsigned &x) const { + BigUnsigned ans; + ans.multiply(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator /(const BigUnsigned &x) const { + if (x.isZero()) throw "BigUnsigned::operator /: division by zero"; + BigUnsigned q, r; + r = *this; + r.divideWithRemainder(x, q); + return q; +} +inline BigUnsigned BigUnsigned::operator %(const BigUnsigned &x) const { + if (x.isZero()) throw "BigUnsigned::operator %: division by zero"; + BigUnsigned q, r; + r = *this; + r.divideWithRemainder(x, q); + return r; +} +inline BigUnsigned BigUnsigned::operator &(const BigUnsigned &x) const { + BigUnsigned ans; + ans.bitAnd(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator |(const BigUnsigned &x) const { + BigUnsigned ans; + ans.bitOr(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator ^(const BigUnsigned &x) const { + BigUnsigned ans; + ans.bitXor(*this, x); + return ans; +} +inline BigUnsigned BigUnsigned::operator <<(int b) const { + BigUnsigned ans; + ans.bitShiftLeft(*this, b); + return ans; +} +inline BigUnsigned BigUnsigned::operator >>(int b) const { + BigUnsigned ans; + ans.bitShiftRight(*this, b); + return ans; +} + +inline void BigUnsigned::operator +=(const BigUnsigned &x) { + add(*this, x); +} +inline void BigUnsigned::operator -=(const BigUnsigned &x) { + subtract(*this, x); +} +inline void BigUnsigned::operator *=(const BigUnsigned &x) { + multiply(*this, x); +} +inline void BigUnsigned::operator /=(const BigUnsigned &x) { + if (x.isZero()) throw "BigUnsigned::operator /=: division by zero"; + /* The following technique is slightly faster than copying *this first + * when x is large. */ + BigUnsigned q; + divideWithRemainder(x, q); + // *this contains the remainder, but we overwrite it with the quotient. + *this = q; +} +inline void BigUnsigned::operator %=(const BigUnsigned &x) { + if (x.isZero()) throw "BigUnsigned::operator %=: division by zero"; + BigUnsigned q; + // Mods *this by x. Don't care about quotient left in q. + divideWithRemainder(x, q); +} +inline void BigUnsigned::operator &=(const BigUnsigned &x) { + bitAnd(*this, x); +} +inline void BigUnsigned::operator |=(const BigUnsigned &x) { + bitOr(*this, x); +} +inline void BigUnsigned::operator ^=(const BigUnsigned &x) { + bitXor(*this, x); +} +inline void BigUnsigned::operator <<=(int b) { + bitShiftLeft(*this, b); +} +inline void BigUnsigned::operator >>=(int b) { + bitShiftRight(*this, b); +} + +/* Templates for conversions of BigUnsigned to and from primitive integers. + * BigInteger.cc needs to instantiate convertToPrimitive, and the uses in + * BigUnsigned.cc didn't do the trick; I think g++ inlined convertToPrimitive + * instead of generating linkable instantiations. So for consistency, I put + * all the templates here. */ + +// CONSTRUCTION FROM PRIMITIVE INTEGERS + +/* Initialize this BigUnsigned from the given primitive integer. The same + * pattern works for all primitive integer types, so I put it into a template to + * reduce code duplication. (Don't worry: this is protected and we instantiate + * it only with primitive integer types.) Type X could be signed, but x is + * known to be nonnegative. */ +template +void BigUnsigned::initFromPrimitive(X x) { + if (x == 0) + ; // NumberlikeArray already initialized us to zero. + else { + // Create a single block. blk is NULL; no need to delete it. + cap = 1; + blk = new Blk[1]; + len = 1; + blk[0] = Blk(x); + } +} + +/* Ditto, but first check that x is nonnegative. I could have put the check in + * initFromPrimitive and let the compiler optimize it out for unsigned-type + * instantiations, but I wanted to avoid the warning stupidly issued by g++ for + * a condition that is constant in *any* instantiation, even if not in all. */ +template +void BigUnsigned::initFromSignedPrimitive(X x) { + if (x < 0) + throw "BigUnsigned constructor: " + "Cannot construct a BigUnsigned from a negative number"; + else + initFromPrimitive(x); +} + +// CONVERSION TO PRIMITIVE INTEGERS + +/* Template with the same idea as initFromPrimitive. This might be slightly + * slower than the previous version with the masks, but it's much shorter and + * clearer, which is the library's stated goal. */ +template +X BigUnsigned::convertToPrimitive() const { + if (len == 0) + // The number is zero; return zero. + return 0; + else if (len == 1) { + // The single block might fit in an X. Try the conversion. + X x = X(blk[0]); + // Make sure the result accurately represents the block. + if (Blk(x) == blk[0]) + // Successful conversion. + return x; + // Otherwise fall through. + } + throw "BigUnsigned::to: " + "Value is too big to fit in the requested type"; +} + +/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result, + * not a negative one that happened to convert back into the correct nonnegative + * one. (E.g., catch incorrect conversion of 2^31 to the long -2^31.) Again, + * separated to avoid a g++ warning. */ +template +X BigUnsigned::convertToSignedPrimitive() const { + X x = convertToPrimitive(); + if (x >= 0) + return x; + else + throw "BigUnsigned::to(Primitive): " + "Value is too big to fit in the requested type"; +} + +#endif diff --git a/hgdriver/ImageProcess/include/bigint/BigUnsignedInABase.hh b/hgdriver/ImageProcess/include/bigint/BigUnsignedInABase.hh new file mode 100755 index 0000000..b0d8e70 --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/BigUnsignedInABase.hh @@ -0,0 +1,122 @@ +#ifndef BIGUNSIGNEDINABASE_H +#define BIGUNSIGNEDINABASE_H + +#include "NumberlikeArray.hh" +#include "BigUnsigned.hh" +#include + +/* + * A BigUnsignedInABase object represents a nonnegative integer of size limited + * only by available memory, represented in a user-specified base that can fit + * in an `unsigned short' (most can, and this saves memory). + * + * BigUnsignedInABase is intended as an intermediary class with little + * functionality of its own. BigUnsignedInABase objects can be constructed + * from, and converted to, BigUnsigneds (requiring multiplication, mods, etc.) + * and `std::string's (by switching digit values for appropriate characters). + * + * BigUnsignedInABase is similar to BigUnsigned. Note the following: + * + * (1) They represent the number in exactly the same way, except that + * BigUnsignedInABase uses ``digits'' (or Digit) where BigUnsigned uses + * ``blocks'' (or Blk). + * + * (2) Both use the management features of NumberlikeArray. (In fact, my desire + * to add a BigUnsignedInABase class without duplicating a lot of code led me to + * introduce NumberlikeArray.) + * + * (3) The only arithmetic operation supported by BigUnsignedInABase is an + * equality test. Use BigUnsigned for arithmetic. + */ + +class BigUnsignedInABase : protected NumberlikeArray { + +public: + // The digits of a BigUnsignedInABase are unsigned shorts. + typedef unsigned short Digit; + // That's also the type of a base. + typedef Digit Base; + +protected: + // The base in which this BigUnsignedInABase is expressed + Base base; + + // Creates a BigUnsignedInABase with a capacity; for internal use. + BigUnsignedInABase(int, Index c) : NumberlikeArray(0, c) {} + + // Decreases len to eliminate any leading zero digits. + void zapLeadingZeros() { + while (len > 0 && blk[len - 1] == 0) + len--; + } + +public: + // Constructs zero in base 2. + BigUnsignedInABase() : NumberlikeArray(), base(2) {} + + // Copy constructor + BigUnsignedInABase(const BigUnsignedInABase &x) : NumberlikeArray(x), base(x.base) {} + + // Assignment operator + void operator =(const BigUnsignedInABase &x) { + NumberlikeArray::operator =(x); + base = x.base; + } + + // Constructor that copies from a given array of digits. + BigUnsignedInABase(const Digit *d, Index l, Base base); + + // Destructor. NumberlikeArray does the delete for us. + ~BigUnsignedInABase() {} + + // LINKS TO BIGUNSIGNED + BigUnsignedInABase(const BigUnsigned &x, Base base); + operator BigUnsigned() const; + + /* LINKS TO STRINGS + * + * These use the symbols ``0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'' to + * represent digits of 0 through 35. When parsing strings, lowercase is + * also accepted. + * + * All string representations are big-endian (big-place-value digits + * first). (Computer scientists have adopted zero-based counting; why + * can't they tolerate little-endian numbers?) + * + * No string representation has a ``base indicator'' like ``0x''. + * + * An exception is made for zero: it is converted to ``0'' and not the + * empty string. + * + * If you want different conventions, write your own routines to go + * between BigUnsignedInABase and strings. It's not hard. + */ + operator std::string() const; + BigUnsignedInABase(const std::string &s, Base base); + +public: + + // ACCESSORS + Base getBase() const { return base; } + + // Expose these from NumberlikeArray directly. + using NumberlikeArray::getCapacity; + using NumberlikeArray::getLength; + + /* Returns the requested digit, or 0 if it is beyond the length (as if + * the number had 0s infinitely to the left). */ + Digit getDigit(Index i) const { return i >= len ? 0 : blk[i]; } + + // The number is zero if and only if the canonical length is zero. + bool isZero() const { return NumberlikeArray::isEmpty(); } + + /* Equality test. For the purposes of this test, two BigUnsignedInABase + * values must have the same base to be equal. */ + bool operator ==(const BigUnsignedInABase &x) const { + return base == x.base && NumberlikeArray::operator ==(x); + } + bool operator !=(const BigUnsignedInABase &x) const { return !operator ==(x); } + +}; + +#endif diff --git a/hgdriver/ImageProcess/include/bigint/NumberlikeArray.hh b/hgdriver/ImageProcess/include/bigint/NumberlikeArray.hh new file mode 100755 index 0000000..61ae6ab --- /dev/null +++ b/hgdriver/ImageProcess/include/bigint/NumberlikeArray.hh @@ -0,0 +1,177 @@ +#ifndef NUMBERLIKEARRAY_H +#define NUMBERLIKEARRAY_H + +// Make sure we have NULL. +#ifndef NULL +#define NULL 0 +#endif + +/* A NumberlikeArray object holds a heap-allocated array of Blk with a + * length and a capacity and provides basic memory management features. + * BigUnsigned and BigUnsignedInABase both subclass it. + * + * NumberlikeArray provides no information hiding. Subclasses should use + * nonpublic inheritance and manually expose members as desired using + * declarations like this: + * + * public: + * NumberlikeArray< the-type-argument >::getLength; + */ +template +class NumberlikeArray { +public: + + // Type for the index of a block in the array + typedef unsigned int Index; + // The number of bits in a block, defined below. + static const unsigned int N; + + // The current allocated capacity of this NumberlikeArray (in blocks) + Index cap; + // The actual length of the value stored in this NumberlikeArray (in blocks) + Index len; + // Heap-allocated array of the blocks (can be NULL if len == 0) + Blk *blk; + + // Constructs a ``zero'' NumberlikeArray with the given capacity. + NumberlikeArray(Index c) : cap(c), len(0) { + blk = (cap > 0) ? (new Blk[cap]) : NULL; + } + + /* Constructs a zero NumberlikeArray without allocating a backing array. + * A subclass that doesn't know the needed capacity at initialization + * time can use this constructor and then overwrite blk without first + * deleting it. */ + NumberlikeArray() : cap(0), len(0) { + blk = NULL; + } + + // Destructor. Note that `delete NULL' is a no-op. + ~NumberlikeArray() { + delete [] blk; + } + + /* Ensures that the array has at least the requested capacity; may + * destroy the contents. */ + void allocate(Index c); + + /* Ensures that the array has at least the requested capacity; does not + * destroy the contents. */ + void allocateAndCopy(Index c); + + // Copy constructor + NumberlikeArray(const NumberlikeArray &x); + + // Assignment operator + void operator=(const NumberlikeArray &x); + + // Constructor that copies from a given array of blocks + NumberlikeArray(const Blk *b, Index blen); + + // ACCESSORS + Index getCapacity() const { return cap; } + Index getLength() const { return len; } + Blk getBlock(Index i) const { return blk[i]; } + bool isEmpty() const { return len == 0; } + + /* Equality comparison: checks if both objects have the same length and + * equal (==) array elements to that length. Subclasses may wish to + * override. */ + bool operator ==(const NumberlikeArray &x) const; + + bool operator !=(const NumberlikeArray &x) const { + return !operator ==(x); + } +}; + +/* BEGIN TEMPLATE DEFINITIONS. They are present here so that source files that + * include this header file can generate the necessary real definitions. */ + +template +const unsigned int NumberlikeArray::N = 8 * sizeof(Blk); + +template +void NumberlikeArray::allocate(Index c) { + // If the requested capacity is more than the current capacity... + if (c > cap) { + // Delete the old number array + delete [] blk; + // Allocate the new array + cap = c; + blk = new Blk[cap]; + } +} + +template +void NumberlikeArray::allocateAndCopy(Index c) { + // If the requested capacity is more than the current capacity... + if (c > cap) { + Blk *oldBlk = blk; + // Allocate the new number array + cap = c; + blk = new Blk[cap]; + // Copy number blocks + Index i; + for (i = 0; i < len; i++) + blk[i] = oldBlk[i]; + // Delete the old array + delete [] oldBlk; + } +} + +template +NumberlikeArray::NumberlikeArray(const NumberlikeArray &x) + : len(x.len) { + // Create array + cap = len; + blk = new Blk[cap]; + // Copy blocks + Index i; + for (i = 0; i < len; i++) + blk[i] = x.blk[i]; +} + +template +void NumberlikeArray::operator=(const NumberlikeArray &x) { + /* Calls like a = a have no effect; catch them before the aliasing + * causes a problem */ + if (this == &x) + return; + // Copy length + len = x.len; + // Expand array if necessary + allocate(len); + // Copy number blocks + Index i; + for (i = 0; i < len; i++) + blk[i] = x.blk[i]; +} + +template +NumberlikeArray::NumberlikeArray(const Blk *b, Index blen) + : cap(blen), len(blen) { + // Create array + blk = new Blk[cap]; + // Copy blocks + Index i; + for (i = 0; i < len; i++) + blk[i] = b[i]; +} + +template +bool NumberlikeArray::operator ==(const NumberlikeArray &x) const { + if (len != x.len) + // Definitely unequal. + return false; + else { + // Compare corresponding blocks one by one. + Index i; + for (i = 0; i < len; i++) + if (blk[i] != x.blk[i]) + return false; + // No blocks differed, so the objects are equal. + return true; + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/win32/zxing/iconv.h b/hgdriver/ImageProcess/include/win32/zxing/iconv.h new file mode 100755 index 0000000..351d30d --- /dev/null +++ b/hgdriver/ImageProcess/include/win32/zxing/iconv.h @@ -0,0 +1,14 @@ +#ifndef _LIBICONV_H +#define _LIBICONV_H +#include +#ifdef __cplusplus +extern "C" { +#endif +typedef void* iconv_t; +iconv_t iconv_open(const char *tocode, const char *fromcode); +int iconv_close(iconv_t cd); +size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +#ifdef __cplusplus +} +#endif +#endif//_LIBICONV_H \ No newline at end of file diff --git a/hgdriver/ImageProcess/include/win32/zxing/stdint.h b/hgdriver/ImageProcess/include/win32/zxing/stdint.h new file mode 100755 index 0000000..59d0673 --- /dev/null +++ b/hgdriver/ImageProcess/include/win32/zxing/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/hgdriver/ImageProcess/include/win32/zxing/win_iconv.c b/hgdriver/ImageProcess/include/win32/zxing/win_iconv.c new file mode 100755 index 0000000..5c703c9 --- /dev/null +++ b/hgdriver/ImageProcess/include/win32/zxing/win_iconv.c @@ -0,0 +1,2035 @@ +/* + * iconv implementation using Win32 API to convert. + * + * This file is placed in the public domain. + */ + +/* for WC_NO_BEST_FIT_CHARS */ +#ifndef WINVER +# define WINVER 0x0500 +#endif + +#define STRICT +#include +#include +#include +#include + +/* WORKAROUND: */ +#ifndef UNDER_CE +#define GetProcAddressA GetProcAddress +#endif + +#if 0 +# define MAKE_EXE +# define MAKE_DLL +# define USE_LIBICONV_DLL +#endif + +#if !defined(DEFAULT_LIBICONV_DLL) +# define DEFAULT_LIBICONV_DLL "" +#endif + +#define MB_CHAR_MAX 16 + +#define UNICODE_MODE_BOM_DONE 1 +#define UNICODE_MODE_SWAPPED 2 + +#define FLAG_USE_BOM 1 +#define FLAG_TRANSLIT 2 /* //TRANSLIT */ +#define FLAG_IGNORE 4 /* //IGNORE */ + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +typedef void* iconv_t; + +iconv_t iconv_open(const char *tocode, const char *fromcode); +int iconv_close(iconv_t cd); +size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); + +/* libiconv interface for vim */ +#if defined(MAKE_DLL) +int +iconvctl (iconv_t cd, int request, void* argument) +{ + /* not supported */ + return 0; +} +#endif + +typedef struct compat_t compat_t; +typedef struct csconv_t csconv_t; +typedef struct rec_iconv_t rec_iconv_t; + +typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode); +typedef int (*f_iconv_close)(iconv_t cd); +typedef size_t (*f_iconv)(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +typedef int* (*f_errno)(void); +typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize); +typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize); + +#define COMPAT_IN 1 +#define COMPAT_OUT 2 + +/* unicode mapping for compatibility with other conversion table. */ +struct compat_t { + uint in; + uint out; + uint flag; +}; + +struct csconv_t { + int codepage; + int flags; + f_mbtowc mbtowc; + f_wctomb wctomb; + f_mblen mblen; + f_flush flush; + DWORD mode; + compat_t *compat; +}; + +struct rec_iconv_t { + iconv_t cd; + f_iconv_close iconv_close; + f_iconv iconv; + f_errno _errno; + csconv_t from; + csconv_t to; +#if defined(USE_LIBICONV_DLL) + HMODULE hlibiconv; +#endif +}; + +static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode); +static int win_iconv_close(iconv_t cd); +static size_t win_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); + +static int load_mlang(); +static int make_csconv(const char *name, csconv_t *cv); +static int name_to_codepage(const char *name); +static uint utf16_to_ucs4(const ushort *wbuf); +static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize); +static int mbtowc_flags(int codepage); +static int must_use_null_useddefaultchar(int codepage); +static char *strrstr(const char *str, const char *token); +static char *xstrndup(const char *s, size_t n); +static int seterror(int err); + +#if defined(USE_LIBICONV_DLL) +static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode); +static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size); +static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname); + +static HMODULE hwiniconv; +#endif + +static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize); + +static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize); + +static struct { + int codepage; + const char *name; +} codepage_alias[] = { + {65001, "CP65001"}, + {65001, "UTF8"}, + {65001, "UTF-8"}, + + {1200, "CP1200"}, + {1200, "UTF16LE"}, + {1200, "UTF-16LE"}, + {1200, "UCS2LE"}, + {1200, "UCS-2LE"}, + + {1201, "CP1201"}, + {1201, "UTF16BE"}, + {1201, "UTF-16BE"}, + {1201, "UCS2BE"}, + {1201, "UCS-2BE"}, + {1201, "unicodeFFFE"}, + + {12000, "CP12000"}, + {12000, "UTF32LE"}, + {12000, "UTF-32LE"}, + {12000, "UCS4LE"}, + {12000, "UCS-4LE"}, + + {12001, "CP12001"}, + {12001, "UTF32BE"}, + {12001, "UTF-32BE"}, + {12001, "UCS4BE"}, + {12001, "UCS-4BE"}, + +#ifndef GLIB_COMPILATION + /* + * Default is big endian. + * See rfc2781 4.3 Interpreting text labelled as UTF-16. + */ + {1201, "UTF16"}, + {1201, "UTF-16"}, + {1201, "UCS2"}, + {1201, "UCS-2"}, + {12001, "UTF32"}, + {12001, "UTF-32"}, + {12001, "UCS-4"}, + {12001, "UCS4"}, +#else + /* Default is little endian, because the platform is */ + {1200, "UTF16"}, + {1200, "UTF-16"}, + {1200, "UCS2"}, + {1200, "UCS-2"}, + {12000, "UTF32"}, + {12000, "UTF-32"}, + {12000, "UCS4"}, + {12000, "UCS-4"}, +#endif + + /* copy from libiconv `iconv -l` */ + /* !IsValidCodePage(367) */ + {20127, "ANSI_X3.4-1968"}, + {20127, "ANSI_X3.4-1986"}, + {20127, "ASCII"}, + {20127, "CP367"}, + {20127, "IBM367"}, + {20127, "ISO-IR-6"}, + {20127, "ISO646-US"}, + {20127, "ISO_646.IRV:1991"}, + {20127, "US"}, + {20127, "US-ASCII"}, + {20127, "CSASCII"}, + + /* !IsValidCodePage(819) */ + {1252, "CP819"}, + {1252, "IBM819"}, + {28591, "ISO-8859-1"}, + {28591, "ISO-IR-100"}, + {28591, "ISO8859-1"}, + {28591, "ISO_8859-1"}, + {28591, "ISO_8859-1:1987"}, + {28591, "L1"}, + {28591, "LATIN1"}, + {28591, "CSISOLATIN1"}, + + {1250, "CP1250"}, + {1250, "MS-EE"}, + {1250, "WINDOWS-1250"}, + + {1251, "CP1251"}, + {1251, "MS-CYRL"}, + {1251, "WINDOWS-1251"}, + + {1252, "CP1252"}, + {1252, "MS-ANSI"}, + {1252, "WINDOWS-1252"}, + + {1253, "CP1253"}, + {1253, "MS-GREEK"}, + {1253, "WINDOWS-1253"}, + + {1254, "CP1254"}, + {1254, "MS-TURK"}, + {1254, "WINDOWS-1254"}, + + {1255, "CP1255"}, + {1255, "MS-HEBR"}, + {1255, "WINDOWS-1255"}, + + {1256, "CP1256"}, + {1256, "MS-ARAB"}, + {1256, "WINDOWS-1256"}, + + {1257, "CP1257"}, + {1257, "WINBALTRIM"}, + {1257, "WINDOWS-1257"}, + + {1258, "CP1258"}, + {1258, "WINDOWS-1258"}, + + {850, "850"}, + {850, "CP850"}, + {850, "IBM850"}, + {850, "CSPC850MULTILINGUAL"}, + + /* !IsValidCodePage(862) */ + {862, "862"}, + {862, "CP862"}, + {862, "IBM862"}, + {862, "CSPC862LATINHEBREW"}, + + {866, "866"}, + {866, "CP866"}, + {866, "IBM866"}, + {866, "CSIBM866"}, + + /* !IsValidCodePage(154) */ + {154, "CP154"}, + {154, "CYRILLIC-ASIAN"}, + {154, "PT154"}, + {154, "PTCP154"}, + {154, "CSPTCP154"}, + + /* !IsValidCodePage(1133) */ + {1133, "CP1133"}, + {1133, "IBM-CP1133"}, + + {874, "CP874"}, + {874, "WINDOWS-874"}, + + /* !IsValidCodePage(51932) */ + {51932, "CP51932"}, + {51932, "MS51932"}, + {51932, "WINDOWS-51932"}, + {51932, "EUC-JP"}, + + {932, "CP932"}, + {932, "MS932"}, + {932, "SHIFFT_JIS"}, + {932, "SHIFFT_JIS-MS"}, + {932, "SJIS"}, + {932, "SJIS-MS"}, + {932, "SJIS-OPEN"}, + {932, "SJIS-WIN"}, + {932, "WINDOWS-31J"}, + {932, "WINDOWS-932"}, + {932, "CSWINDOWS31J"}, + + {50221, "CP50221"}, + {50221, "ISO-2022-JP"}, + {50221, "ISO-2022-JP-MS"}, + {50221, "ISO2022-JP"}, + {50221, "ISO2022-JP-MS"}, + {50221, "MS50221"}, + {50221, "WINDOWS-50221"}, + + {936, "CP936"}, + {936, "GBK"}, + {936, "MS936"}, + {936, "WINDOWS-936"}, + + {950, "CP950"}, + {950, "BIG5"}, + {950, "BIG5HKSCS"}, + {950, "BIG5-HKSCS"}, + + {949, "CP949"}, + {949, "UHC"}, + {949, "EUC-KR"}, + + {1361, "CP1361"}, + {1361, "JOHAB"}, + + {437, "437"}, + {437, "CP437"}, + {437, "IBM437"}, + {437, "CSPC8CODEPAGE437"}, + + {737, "CP737"}, + + {775, "CP775"}, + {775, "IBM775"}, + {775, "CSPC775BALTIC"}, + + {852, "852"}, + {852, "CP852"}, + {852, "IBM852"}, + {852, "CSPCP852"}, + + /* !IsValidCodePage(853) */ + {853, "CP853"}, + + {855, "855"}, + {855, "CP855"}, + {855, "IBM855"}, + {855, "CSIBM855"}, + + {857, "857"}, + {857, "CP857"}, + {857, "IBM857"}, + {857, "CSIBM857"}, + + /* !IsValidCodePage(858) */ + {858, "CP858"}, + + {860, "860"}, + {860, "CP860"}, + {860, "IBM860"}, + {860, "CSIBM860"}, + + {861, "861"}, + {861, "CP-IS"}, + {861, "CP861"}, + {861, "IBM861"}, + {861, "CSIBM861"}, + + {863, "863"}, + {863, "CP863"}, + {863, "IBM863"}, + {863, "CSIBM863"}, + + {864, "CP864"}, + {864, "IBM864"}, + {864, "CSIBM864"}, + + {865, "865"}, + {865, "CP865"}, + {865, "IBM865"}, + {865, "CSIBM865"}, + + {869, "869"}, + {869, "CP-GR"}, + {869, "CP869"}, + {869, "IBM869"}, + {869, "CSIBM869"}, + + /* !IsValidCodePage(1152) */ + {1125, "CP1125"}, + + /* + * Code Page Identifiers + * http://msdn2.microsoft.com/en-us/library/ms776446.aspx + */ + {37, "IBM037"}, /* IBM EBCDIC US-Canada */ + {437, "IBM437"}, /* OEM United States */ + {500, "IBM500"}, /* IBM EBCDIC International */ + {708, "ASMO-708"}, /* Arabic (ASMO 708) */ + /* 709 Arabic (ASMO-449+, BCON V4) */ + /* 710 Arabic - Transparent Arabic */ + {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */ + {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */ + {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */ + {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */ + {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */ + {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */ + {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */ + {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */ + {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */ + {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */ + {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */ + {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */ + {864, "IBM864"}, /* OEM Arabic; Arabic (864) */ + {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */ + {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */ + {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */ + {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */ + {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */ + {875, "cp875"}, /* IBM EBCDIC Greek Modern */ + {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */ + {932, "shift-jis"}, /* alternative name for it */ + {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */ + {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */ + {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */ + {950, "big5hkscs"}, /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */ + {950, "big5-hkscs"}, /* alternative name for it */ + {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */ + {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */ + {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */ + {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */ + {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */ + {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */ + {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */ + {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */ + {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */ + {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */ + {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */ + {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */ + {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */ + {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */ + {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */ + {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */ + {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */ + {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */ + {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */ + {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */ + {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */ + {1361, "Johab"}, /* Korean (Johab) */ + {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */ + {10001, "x-mac-japanese"}, /* Japanese (Mac) */ + {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */ + {10003, "x-mac-korean"}, /* Korean (Mac) */ + {10004, "x-mac-arabic"}, /* Arabic (Mac) */ + {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */ + {10006, "x-mac-greek"}, /* Greek (Mac) */ + {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */ + {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */ + {10010, "x-mac-romanian"}, /* Romanian (Mac) */ + {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */ + {10021, "x-mac-thai"}, /* Thai (Mac) */ + {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */ + {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */ + {10081, "x-mac-turkish"}, /* Turkish (Mac) */ + {10082, "x-mac-croatian"}, /* Croatian (Mac) */ + {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */ + {20001, "x-cp20001"}, /* TCA Taiwan */ + {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */ + {20003, "x-cp20003"}, /* IBM5550 Taiwan */ + {20004, "x-cp20004"}, /* TeleText Taiwan */ + {20005, "x-cp20005"}, /* Wang Taiwan */ + {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */ + {20106, "x-IA5-German"}, /* IA5 German (7-bit) */ + {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */ + {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */ + {20127, "us-ascii"}, /* US-ASCII (7-bit) */ + {20261, "x-cp20261"}, /* T.61 */ + {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */ + {20273, "IBM273"}, /* IBM EBCDIC Germany */ + {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */ + {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */ + {20280, "IBM280"}, /* IBM EBCDIC Italy */ + {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */ + {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */ + {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */ + {20297, "IBM297"}, /* IBM EBCDIC France */ + {20420, "IBM420"}, /* IBM EBCDIC Arabic */ + {20423, "IBM423"}, /* IBM EBCDIC Greek */ + {20424, "IBM424"}, /* IBM EBCDIC Hebrew */ + {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */ + {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */ + {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */ + {20871, "IBM871"}, /* IBM EBCDIC Icelandic */ + {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */ + {20905, "IBM905"}, /* IBM EBCDIC Turkish */ + {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */ + {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */ + {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */ + {20949, "x-cp20949"}, /* Korean Wansung */ + {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */ + /* 21027 (deprecated) */ + {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */ + {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */ + {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */ + {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */ + {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */ + {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */ + {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */ + {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */ + {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */ + {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */ + {28597, "iso8859-7"}, /* ISO 8859-7 Greek */ + {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */ + {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */ + {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */ + {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */ + {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */ + {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */ + {29001, "x-Europa"}, /* Europa 3 */ + {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */ + {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */ + {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */ + {50225, "iso-2022-kr"}, /* ISO 2022 Korean */ + {50225, "iso2022-kr"}, /* ISO 2022 Korean */ + {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */ + /* 50229 ISO 2022 Traditional Chinese */ + /* 50930 EBCDIC Japanese (Katakana) Extended */ + /* 50931 EBCDIC US-Canada and Japanese */ + /* 50933 EBCDIC Korean Extended and Korean */ + /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */ + /* 50936 EBCDIC Simplified Chinese */ + /* 50937 EBCDIC US-Canada and Traditional Chinese */ + /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */ + {51932, "euc-jp"}, /* EUC Japanese */ + {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */ + {51949, "euc-kr"}, /* EUC Korean */ + /* 51950 EUC Traditional Chinese */ + {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */ + {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */ + {57002, "x-iscii-de"}, /* ISCII Devanagari */ + {57003, "x-iscii-be"}, /* ISCII Bengali */ + {57004, "x-iscii-ta"}, /* ISCII Tamil */ + {57005, "x-iscii-te"}, /* ISCII Telugu */ + {57006, "x-iscii-as"}, /* ISCII Assamese */ + {57007, "x-iscii-or"}, /* ISCII Oriya */ + {57008, "x-iscii-ka"}, /* ISCII Kannada */ + {57009, "x-iscii-ma"}, /* ISCII Malayalam */ + {57010, "x-iscii-gu"}, /* ISCII Gujarati */ + {57011, "x-iscii-pa"}, /* ISCII Punjabi */ + + {0, NULL} +}; + +/* + * SJIS SHIFTJIS table CP932 table + * ---- --------------------------- -------------------------------- + * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS + * 7E U+203E OVERLINE U+007E TILDE + * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR + * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS + * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE + * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO + * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS + * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN + * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN + * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN + * + * EUC-JP and ISO-2022-JP should be compatible with CP932. + * + * Kernel and MLang have different Unicode mapping table. Make sure + * which API is used. + */ +static compat_t cp932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0x301C, 0xFF5E, COMPAT_OUT}, + {0x2016, 0x2225, COMPAT_OUT}, + {0x2212, 0xFF0D, COMPAT_OUT}, + {0x00A2, 0xFFE0, COMPAT_OUT}, + {0x00A3, 0xFFE1, COMPAT_OUT}, + {0x00AC, 0xFFE2, COMPAT_OUT}, + {0, 0, 0} +}; + +static compat_t cp20932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN}, + {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN}, + {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN}, + {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN}, + {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN}, + {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN}, + {0, 0, 0} +}; + +static compat_t *cp51932_compat = cp932_compat; + +/* cp20932_compat for kernel. cp932_compat for mlang. */ +static compat_t *cp5022x_compat = cp932_compat; + +typedef HRESULT (WINAPI *CONVERTINETSTRING)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + DWORD dwDstEncoding, + LPCSTR lpSrcStr, + LPINT lpnSrcSize, + LPBYTE lpDstStr, + LPINT lpnDstSize +); +typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + LPCSTR lpSrcStr, + LPINT lpnMultiCharCount, + LPWSTR lpDstStr, + LPINT lpnWideCharCount +); +typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)( + LPDWORD lpdwMode, + DWORD dwEncoding, + LPCWSTR lpSrcStr, + LPINT lpnWideCharCount, + LPSTR lpDstStr, + LPINT lpnMultiCharCount +); +typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)( + DWORD dwSrcEncoding, + DWORD dwDstEncoding +); +typedef HRESULT (WINAPI *LCIDTORFC1766A)( + LCID Locale, + LPSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *LCIDTORFC1766W)( + LCID Locale, + LPWSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *RFC1766TOLCIDA)( + LCID *pLocale, + LPSTR pszRfc1766 +); +typedef HRESULT (WINAPI *RFC1766TOLCIDW)( + LCID *pLocale, + LPWSTR pszRfc1766 +); +static CONVERTINETSTRING ConvertINetString; +static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode; +static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte; +static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable; +static LCIDTORFC1766A LcidToRfc1766A; +static RFC1766TOLCIDA Rfc1766ToLcidA; + +static int +load_mlang() +{ + HMODULE h; + if (ConvertINetString != NULL) + return TRUE; + h = LoadLibrary(TEXT("mlang.dll")); + if (!h) + return FALSE; + ConvertINetString = (CONVERTINETSTRING)GetProcAddressA(h, "ConvertINetString"); + ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode"); + ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte"); + IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddressA(h, "IsConvertINetStringAvailable"); + LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddressA(h, "LcidToRfc1766A"); + Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddressA(h, "Rfc1766ToLcidA"); + return TRUE; +} + +iconv_t +iconv_open(const char *tocode, const char *fromcode) +{ + rec_iconv_t *cd; + + cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t)); + if (cd == NULL) + return (iconv_t)(-1); + +#if defined(USE_LIBICONV_DLL) + errno = 0; + if (libiconv_iconv_open(cd, tocode, fromcode)) + return (iconv_t)cd; +#endif + + /* reset the errno to prevent reporting wrong error code. + * 0 for unsorted error. */ + errno = 0; + if (win_iconv_open(cd, tocode, fromcode)) + return (iconv_t)cd; + + free(cd); + + return (iconv_t)(-1); +} + +int +iconv_close(iconv_t _cd) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + int r = cd->iconv_close(cd->cd); + int e = *(cd->_errno()); +#if defined(USE_LIBICONV_DLL) + if (cd->hlibiconv != NULL) + FreeLibrary(cd->hlibiconv); +#endif + free(cd); + errno = e; + return r; +} + +size_t +iconv(iconv_t _cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft); + errno = *(cd->_errno()); + return r; +} + +static int +win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode) +{ + if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to)) + return FALSE; + cd->iconv_close = win_iconv_close; + cd->iconv = win_iconv; + cd->_errno = _errno; + cd->cd = (iconv_t)cd; + return TRUE; +} + +static int +win_iconv_close(iconv_t cd) +{ + return 0; +} + +static size_t +win_iconv(iconv_t _cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */ + int insize; + int outsize; + int wsize; + DWORD frommode; + DWORD tomode; + uint wc; + compat_t *cp; + int i; + + if (inbuf == NULL || *inbuf == NULL) + { + if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL) + { + tomode = cd->to.mode; + outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + { + if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) + { + outsize = 0; + } + else + { + cd->to.mode = tomode; + return (size_t)(-1); + } + } + *outbuf += outsize; + *outbytesleft -= outsize; + } + cd->from.mode = 0; + cd->to.mode = 0; + return 0; + } + + while (*inbytesleft != 0) + { + frommode = cd->from.mode; + tomode = cd->to.mode; + wsize = MB_CHAR_MAX; + + insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize); + if (insize == -1) + { + if (cd->to.flags & FLAG_IGNORE) + { + cd->from.mode = frommode; + insize = 1; + wsize = 0; + } + else + { + cd->from.mode = frommode; + return (size_t)(-1); + } + } + + if (wsize == 0) + { + *inbuf += insize; + *inbytesleft -= insize; + continue; + } + + if (cd->from.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->from.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc) + { + ucs4_to_utf16(cp[i].in, wbuf, &wsize); + break; + } + } + } + + if (cd->to.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->to.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc) + { + ucs4_to_utf16(cp[i].out, wbuf, &wsize); + break; + } + } + } + + outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + { + if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) + { + cd->to.mode = tomode; + outsize = 0; + } + else + { + cd->from.mode = frommode; + cd->to.mode = tomode; + return (size_t)(-1); + } + } + + *inbuf += insize; + *outbuf += outsize; + *inbytesleft -= insize; + *outbytesleft -= outsize; + } + + return 0; +} + +static int +make_csconv(const char *_name, csconv_t *cv) +{ + CPINFO cpinfo; + int use_compat = TRUE; + int flag = 0; + char *name; + char *p; + + name = xstrndup(_name, strlen(_name)); + if (name == NULL) + return FALSE; + + /* check for option "enc_name//opt1//opt2" */ + while ((p = strrstr(name, "//")) != NULL) + { + if (_stricmp(p + 2, "nocompat") == 0) + use_compat = FALSE; + else if (_stricmp(p + 2, "translit") == 0) + flag |= FLAG_TRANSLIT; + else if (_stricmp(p + 2, "ignore") == 0) + flag |= FLAG_IGNORE; + *p = 0; + } + + cv->mode = 0; + cv->flags = flag; + cv->mblen = NULL; + cv->flush = NULL; + cv->compat = NULL; + cv->codepage = name_to_codepage(name); + if (cv->codepage == 1200 || cv->codepage == 1201) + { + cv->mbtowc = utf16_mbtowc; + cv->wctomb = utf16_wctomb; + if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 || + _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0) + cv->flags |= FLAG_USE_BOM; + } + else if (cv->codepage == 12000 || cv->codepage == 12001) + { + cv->mbtowc = utf32_mbtowc; + cv->wctomb = utf32_wctomb; + if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 || + _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0) + cv->flags |= FLAG_USE_BOM; + } + else if (cv->codepage == 65001) + { + cv->mbtowc = kernel_mbtowc; + cv->wctomb = kernel_wctomb; + cv->mblen = utf8_mblen; + } + else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang()) + { + cv->mbtowc = iso2022jp_mbtowc; + cv->wctomb = iso2022jp_wctomb; + cv->flush = iso2022jp_flush; + } + else if (cv->codepage == 51932 && load_mlang()) + { + cv->mbtowc = mlang_mbtowc; + cv->wctomb = mlang_wctomb; + cv->mblen = eucjp_mblen; + } + else if (IsValidCodePage(cv->codepage) + && GetCPInfo(cv->codepage, &cpinfo) != 0) + { + cv->mbtowc = kernel_mbtowc; + cv->wctomb = kernel_wctomb; + if (cpinfo.MaxCharSize == 1) + cv->mblen = sbcs_mblen; + else if (cpinfo.MaxCharSize == 2) + cv->mblen = dbcs_mblen; + else + cv->mblen = mbcs_mblen; + } + else + { + /* not supported */ + free(name); + errno = EINVAL; + return FALSE; + } + + if (use_compat) + { + switch (cv->codepage) + { + case 932: cv->compat = cp932_compat; break; + case 20932: cv->compat = cp20932_compat; break; + case 51932: cv->compat = cp51932_compat; break; + case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break; + } + } + + free(name); + + return TRUE; +} + +static int +name_to_codepage(const char *name) +{ + int i; + + if (*name == '\0' || + strcmp(name, "char") == 0) + return GetACP(); + else if (strcmp(name, "wchar_t") == 0) + return 1200; + else if (_strnicmp(name, "cp", 2) == 0) + return atoi(name + 2); /* CP123 */ + else if ('0' <= name[0] && name[0] <= '9') + return atoi(name); /* 123 */ + else if (_strnicmp(name, "xx", 2) == 0) + return atoi(name + 2); /* XX123 for debug */ + + for (i = 0; codepage_alias[i].name != NULL; ++i) + if (_stricmp(name, codepage_alias[i].name) == 0) + return codepage_alias[i].codepage; + return -1; +} + +/* + * http://www.faqs.org/rfcs/rfc2781.html + */ +static uint +utf16_to_ucs4(const ushort *wbuf) +{ + uint wc = wbuf[0]; + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000; + return wc; +} + +static void +ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize) +{ + if (wc < 0x10000) + { + wbuf[0] = wc; + *wbufsize = 1; + } + else + { + wc -= 0x10000; + wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF); + wbuf[1] = 0xDC00 | (wc & 0x3FF); + *wbufsize = 2; + } +} + +/* + * Check if codepage is one of those for which the dwFlags parameter + * to MultiByteToWideChar() must be zero. Return zero or + * MB_ERR_INVALID_CHARS. The docs in Platform SDK for for Windows + * Server 2003 R2 claims that also codepage 65001 is one of these, but + * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave + * out 65001 (UTF-8), and that indeed seems to be the case on XP, it + * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting + * from UTF-8. + */ +static int +mbtowc_flags(int codepage) +{ + return (codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS; +} + +/* + * Check if codepage is one those for which the lpUsedDefaultChar + * parameter to WideCharToMultiByte() must be NULL. The docs in + * Platform SDK for for Windows Server 2003 R2 claims that this is the + * list below, while the MSDN docs for MSVS2008 claim that it is only + * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform + * SDK seems to be correct, at least for XP. + */ +static int +must_use_null_useddefaultchar(int codepage) +{ + return (codepage == 65000 || codepage == 65001 || + codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 42); +} + +static char * +strrstr(const char *str, const char *token) +{ + int len = strlen(token); + const char *p = str + strlen(str); + + while (str <= --p) + if (p[0] == token[0] && strncmp(p, token, len) == 0) + return (char *)p; + return NULL; +} + +static char * +xstrndup(const char *s, size_t n) +{ + char *p; + + p = (char *)malloc(n + 1); + if (p == NULL) + return NULL; + memcpy(p, s, n); + p[n] = '\0'; + return p; +} + +static int +seterror(int err) +{ + errno = err; + return -1; +} + +#if defined(USE_LIBICONV_DLL) +static int +libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode) +{ + HMODULE hlibiconv = NULL; + HMODULE hmsvcrt = NULL; + char *dllname; + const char *p; + const char *e; + f_iconv_open _iconv_open; + + /* + * always try to load dll, so that we can switch dll in runtime. + */ + + /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */ + p = getenv("WINICONV_LIBICONV_DLL"); + if (p == NULL) + p = DEFAULT_LIBICONV_DLL; + /* parse comma separated value */ + for ( ; *p != 0; p = (*e == ',') ? e + 1 : e) + { + e = strchr(p, ','); + if (p == e) + continue; + else if (e == NULL) + e = p + strlen(p); + dllname = xstrndup(p, e - p); + if (dllname == NULL) + return FALSE; + hlibiconv = LoadLibraryA(dllname); + free(dllname); + if (hlibiconv != NULL) + { + if (hlibiconv == hwiniconv) + { + FreeLibrary(hlibiconv); + hlibiconv = NULL; + continue; + } + break; + } + } + + if (hlibiconv == NULL) + goto failed; + + hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno"); + if (hmsvcrt == NULL) + goto failed; + + _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "libiconv_open"); + if (_iconv_open == NULL) + _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "iconv_open"); + cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "libiconv_close"); + if (cd->iconv_close == NULL) + cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "iconv_close"); + cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "libiconv"); + if (cd->iconv == NULL) + cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "iconv"); + cd->_errno = (f_errno)GetProcAddressA(hmsvcrt, "_errno"); + if (_iconv_open == NULL || cd->iconv_close == NULL + || cd->iconv == NULL || cd->_errno == NULL) + goto failed; + + cd->cd = _iconv_open(tocode, fromcode); + if (cd->cd == (iconv_t)(-1)) + goto failed; + + cd->hlibiconv = hlibiconv; + return TRUE; + +failed: + if (hlibiconv != NULL) + FreeLibrary(hlibiconv); + /* do not free hmsvcrt which is obtained by GetModuleHandle() */ + return FALSE; +} + +/* + * Reference: + * http://forums.belution.com/ja/vc/000/234/78s.shtml + * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html + * + * The formal way is + * imagehlp.h or dbghelp.h + * imagehlp.lib or dbghelp.lib + * ImageDirectoryEntryToData() + */ +#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base)) +#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew)) +static PVOID +MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size) +{ + /* TODO: MappedAsImage? */ + PIMAGE_DATA_DIRECTORY p; + p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry; + if (p->VirtualAddress == 0) { + *Size = 0; + return NULL; + } + *Size = p->Size; + return (PVOID)((LPBYTE)Base + p->VirtualAddress); +} + +static HMODULE +find_imported_module_by_funcname(HMODULE hModule, const char *funcname) +{ + DWORD_PTR Base; + ULONG Size; + PIMAGE_IMPORT_DESCRIPTOR Imp; + PIMAGE_THUNK_DATA Name; /* Import Name Table */ + PIMAGE_IMPORT_BY_NAME ImpName; + + Base = (DWORD_PTR)hModule; + Imp = (PIMAGE_IMPORT_DESCRIPTOR)MyImageDirectoryEntryToData( + (LPVOID)Base, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &Size); + if (Imp == NULL) + return NULL; + for ( ; Imp->OriginalFirstThunk != 0; ++Imp) + { + Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk); + for ( ; Name->u1.Ordinal != 0; ++Name) + { + if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal)) + { + ImpName = (PIMAGE_IMPORT_BY_NAME) + (Base + (DWORD_PTR)Name->u1.AddressOfData); + if (strcmp((char *)ImpName->Name, funcname) == 0) + return GetModuleHandleA((char *)(Base + Imp->Name)); + } + } + } + return NULL; +} +#endif + +static int +sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + return 1; +} + +static int +dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1; + if (bufsize < len) + return seterror(EINVAL); + return len; +} + +static int +mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + if (cv->codepage == 54936) { + if (buf[0] <= 0x7F) len = 1; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 2 && + ((buf[1] >= 0x40 && buf[1] <= 0x7E) || + (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 4 && + buf[1] >= 0x30 && buf[1] <= 0x39) len = 4; + else + return seterror(EINVAL); + return len; + } + else + return seterror(EINVAL); +} + +static int +utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + if (buf[0] < 0x80) len = 1; + else if ((buf[0] & 0xE0) == 0xC0) len = 2; + else if ((buf[0] & 0xF0) == 0xE0) len = 3; + else if ((buf[0] & 0xF8) == 0xF0) len = 4; + else if ((buf[0] & 0xFC) == 0xF8) len = 5; + else if ((buf[0] & 0xFE) == 0xFC) len = 6; + + if (len == 0) + return seterror(EILSEQ); + else if (bufsize < len) + return seterror(EINVAL); + return len; +} + +static int +eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + if (buf[0] < 0x80) /* ASCII */ + return 1; + else if (buf[0] == 0x8E) /* JIS X 0201 */ + { + if (bufsize < 2) + return seterror(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF)) + return seterror(EILSEQ); + return 2; + } + else if (buf[0] == 0x8F) /* JIS X 0212 */ + { + if (bufsize < 3) + return seterror(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE) + || !(0xA1 <= buf[2] && buf[2] <= 0xFE)) + return seterror(EILSEQ); + return 3; + } + else /* JIS X 0208 */ + { + if (bufsize < 2) + return seterror(EINVAL); + else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE) + || !(0xA1 <= buf[1] && buf[1] <= 0xFE)) + return seterror(EILSEQ); + return 2; + } +} + +static int +kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage), + (const char *)buf, len, (wchar_t *)wbuf, *wbufsize); + if (*wbufsize == 0) + return seterror(EILSEQ); + return len; +} + +static int +kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + BOOL usedDefaultChar = 0; + BOOL *p = NULL; + int flags = 0; + int len; + + if (bufsize == 0) + return seterror(E2BIG); + if (!must_use_null_useddefaultchar(cv->codepage)) + { + p = &usedDefaultChar; +#ifdef WC_NO_BEST_FIT_CHARS + if (!(cv->flags & FLAG_TRANSLIT)) + flags |= WC_NO_BEST_FIT_CHARS; +#endif + } + len = WideCharToMultiByte(cv->codepage, flags, + (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p); + if (len == 0) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + return seterror(E2BIG); + return seterror(EILSEQ); + } + else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT)) + return seterror(EILSEQ); + else if (cv->mblen(cv, buf, len) != len) /* validate result */ + return seterror(EILSEQ); + return len; +} + +/* + * It seems that the mode (cv->mode) is fixnum. + * For example, when converting iso-2022-jp(cp50221) to unicode: + * in ascii sequence: mode=0xC42C0000 + * in jisx0208 sequence: mode=0xC42C0001 + * "C42C" is same for each convert session. + * It should be: ((codepage-1)<<16)|state + */ +static int +mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + int insize; + HRESULT hr; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + insize = len; + hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage, + (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len) + return seterror(EILSEQ); + return len; +} + +static int +mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */ + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + + hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return seterror(EILSEQ); + else if (bufsize < tmpsize) + return seterror(E2BIG); + else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize) + return seterror(EILSEQ); + memcpy(buf, tmpbuf, tmpsize); + return tmpsize; +} + +static int +utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int codepage = cv->codepage; + + /* swap endian: 1200 <-> 1201 */ + if (cv->mode & UNICODE_MODE_SWAPPED) + codepage ^= 1; + + if (bufsize < 2) + return seterror(EINVAL); + if (codepage == 1200) /* little endian */ + wbuf[0] = (buf[1] << 8) | buf[0]; + else if (codepage == 1201) /* big endian */ + wbuf[0] = (buf[0] << 8) | buf[1]; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + cv->mode |= UNICODE_MODE_BOM_DONE; + if (wbuf[0] == 0xFFFE) + { + cv->mode |= UNICODE_MODE_SWAPPED; + *wbufsize = 0; + return 2; + } + else if (wbuf[0] == 0xFEFF) + { + *wbufsize = 0; + return 2; + } + } + + if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF) + return seterror(EILSEQ); + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return seterror(EINVAL); + if (codepage == 1200) /* little endian */ + wbuf[1] = (buf[3] << 8) | buf[2]; + else if (codepage == 1201) /* big endian */ + wbuf[1] = (buf[2] << 8) | buf[3]; + if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF)) + return seterror(EILSEQ); + *wbufsize = 2; + return 4; + } + *wbufsize = 1; + return 2; +} + +static int +utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + int r; + + cv->mode |= UNICODE_MODE_BOM_DONE; + if (bufsize < 2) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + memcpy(buf, "\xFF\xFE", 2); + else if (cv->codepage == 1201) /* big endian */ + memcpy(buf, "\xFE\xFF", 2); + + r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2); + if (r == -1) + return -1; + return r + 2; + } + + if (bufsize < 2) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[0] = (wbuf[0] & 0x00FF); + buf[1] = (wbuf[0] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[0] = (wbuf[0] & 0xFF00) >> 8; + buf[1] = (wbuf[0] & 0x00FF); + } + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[2] = (wbuf[1] & 0x00FF); + buf[3] = (wbuf[1] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[2] = (wbuf[1] & 0xFF00) >> 8; + buf[3] = (wbuf[1] & 0x00FF); + } + return 4; + } + return 2; +} + +static int +utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int codepage = cv->codepage; + uint wc; + + /* swap endian: 12000 <-> 12001 */ + if (cv->mode & UNICODE_MODE_SWAPPED) + codepage ^= 1; + + if (bufsize < 4) + return seterror(EINVAL); + if (codepage == 12000) /* little endian */ + wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + else if (codepage == 12001) /* big endian */ + wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + cv->mode |= UNICODE_MODE_BOM_DONE; + if (wc == 0xFFFE0000) + { + cv->mode |= UNICODE_MODE_SWAPPED; + *wbufsize = 0; + return 4; + } + else if (wc == 0x0000FEFF) + { + *wbufsize = 0; + return 4; + } + } + + if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc) + return seterror(EILSEQ); + ucs4_to_utf16(wc, wbuf, wbufsize); + return 4; +} + +static int +utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + uint wc; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + int r; + + cv->mode |= UNICODE_MODE_BOM_DONE; + if (bufsize < 4) + return seterror(E2BIG); + if (cv->codepage == 12000) /* little endian */ + memcpy(buf, "\xFF\xFE\x00\x00", 4); + else if (cv->codepage == 12001) /* big endian */ + memcpy(buf, "\x00\x00\xFE\xFF", 4); + + r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4); + if (r == -1) + return -1; + return r + 4; + } + + if (bufsize < 4) + return seterror(E2BIG); + wc = utf16_to_ucs4(wbuf); + if (cv->codepage == 12000) /* little endian */ + { + buf[0] = wc & 0x000000FF; + buf[1] = (wc & 0x0000FF00) >> 8; + buf[2] = (wc & 0x00FF0000) >> 16; + buf[3] = (wc & 0xFF000000) >> 24; + } + else if (cv->codepage == 12001) /* big endian */ + { + buf[0] = (wc & 0xFF000000) >> 24; + buf[1] = (wc & 0x00FF0000) >> 16; + buf[2] = (wc & 0x0000FF00) >> 8; + buf[3] = wc & 0x000000FF; + } + return 4; +} + +/* + * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) + * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow + * 1 byte Kana) + * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte + * Kana - SO/SI) + * + * MultiByteToWideChar() and WideCharToMultiByte() behave differently + * depending on Windows version. On XP, WideCharToMultiByte() doesn't + * terminate result sequence with ascii escape. But Vista does. + * Use MLang instead. + */ + +#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift)) +#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF) +#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF) + +#define ISO2022_SI 0 +#define ISO2022_SO 1 + +/* shift in */ +static const char iso2022_SI_seq[] = "\x0F"; +/* shift out */ +static const char iso2022_SO_seq[] = "\x0E"; + +typedef struct iso2022_esc_t iso2022_esc_t; +struct iso2022_esc_t { + const char *esc; + int esc_len; + int len; + int cs; +}; + +#define ISO2022JP_CS_ASCII 0 +#define ISO2022JP_CS_JISX0201_ROMAN 1 +#define ISO2022JP_CS_JISX0201_KANA 2 +#define ISO2022JP_CS_JISX0208_1978 3 +#define ISO2022JP_CS_JISX0208_1983 4 +#define ISO2022JP_CS_JISX0212 5 + +static iso2022_esc_t iso2022jp_esc[] = { + {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII}, + {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN}, + {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA}, + {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */ + {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983}, + {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212}, + {NULL, 0, 0, 0} +}; + +static int +iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int insize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + if (buf[0] == 0x1B) + { + for (i = 0; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (bufsize < esc_len) + { + if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0) + return seterror(EINVAL); + } + else + { + if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0) + { + cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI); + *wbufsize = 0; + return esc_len; + } + } + } + /* not supported escape sequence */ + return seterror(EILSEQ); + } + else if (buf[0] == iso2022_SO_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO); + *wbufsize = 0; + return 1; + } + else if (buf[0] == iso2022_SI_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI); + *wbufsize = 0; + return 1; + } + + cs = ISO2022_MODE_CS(cv->mode); + shift = ISO2022_MODE_SHIFT(cv->mode); + + /* reset the mode for informal sequence */ + if (buf[0] < 0x20) + { + cs = ISO2022JP_CS_ASCII; + shift = ISO2022_SI; + } + + len = iesc[cs].len; + if (bufsize < len) + return seterror(EINVAL); + for (i = 0; i < len; ++i) + if (!(buf[i] < 0x80)) + return seterror(EILSEQ); + esc_len = iesc[cs].esc_len; + memcpy(tmp, iesc[cs].esc, esc_len); + if (shift == ISO2022_SO) + { + memcpy(tmp + esc_len, iso2022_SO_seq, 1); + esc_len += 1; + } + memcpy(tmp + esc_len, buf, len); + + if ((cv->codepage == 50220 || cv->codepage == 50221 + || cv->codepage == 50222) && shift == ISO2022_SO) + { + /* XXX: shift-out cannot be used for mbtowc (both kernel and + * mlang) */ + esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len; + memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len); + memcpy(tmp + esc_len, buf, len); + } + + insize = len + esc_len; + hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage, + (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len + esc_len) + return seterror(EILSEQ); + + /* Check for conversion error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (wbuf[0] == buf[0] + && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + return seterror(EILSEQ); + + /* reset the mode for informal sequence */ + if (cv->mode != ISO2022_MODE(cs, shift)) + cv->mode = ISO2022_MODE(cs, shift); + + return len; +} + +static int +iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + /* + * MultiByte = [escape sequence] + character + [escape sequence] + * + * Whether trailing escape sequence is added depends on which API is + * used (kernel or MLang, and its version). + */ + hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return seterror(EILSEQ); + else if (bufsize < tmpsize) + return seterror(E2BIG); + + if (tmpsize == 1) + { + cs = ISO2022JP_CS_ASCII; + esc_len = 0; + } + else + { + for (i = 1; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (strncmp(tmp, iesc[i].esc, esc_len) == 0) + { + cs = iesc[i].cs; + break; + } + } + if (iesc[i].esc == NULL) + /* not supported escape sequence */ + return seterror(EILSEQ); + } + + shift = ISO2022_SI; + if (tmp[esc_len] == iso2022_SO_seq[0]) + { + shift = ISO2022_SO; + esc_len += 1; + } + + len = iesc[cs].len; + + /* Check for converting error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80)) + return seterror(EILSEQ); + else if (tmpsize < esc_len + len) + return seterror(EILSEQ); + + if (cv->mode == ISO2022_MODE(cs, shift)) + { + /* remove escape sequence */ + if (esc_len != 0) + memmove(tmp, tmp + esc_len, len); + esc_len = 0; + } + else + { + if (cs == ISO2022JP_CS_ASCII) + { + esc_len = iesc[ISO2022JP_CS_ASCII].esc_len; + memmove(tmp + esc_len, tmp, len); + memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len); + } + if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO) + { + /* shift-in before changing to other mode */ + memmove(tmp + 1, tmp, len + esc_len); + memcpy(tmp, iso2022_SI_seq, 1); + esc_len += 1; + } + } + + if (bufsize < len + esc_len) + return seterror(E2BIG); + memcpy(buf, tmp, len + esc_len); + cv->mode = ISO2022_MODE(cs, shift); + return len + esc_len; +} + +static int +iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + int esc_len; + + if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + { + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + esc_len += 1; + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + if (bufsize < esc_len) + return seterror(E2BIG); + + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + { + memcpy(buf, iso2022_SI_seq, 1); + esc_len += 1; + } + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + { + memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc, + iesc[ISO2022JP_CS_ASCII].esc_len); + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + } + return esc_len; + } + return 0; +} + +#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL) +BOOL WINAPI +DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) +{ + switch( fdwReason ) + { + case DLL_PROCESS_ATTACH: + hwiniconv = (HMODULE)hinstDLL; + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif + +#if defined(MAKE_EXE) +#include +#include +#include +int +main(int argc, char **argv) +{ + char *fromcode = NULL; + char *tocode = NULL; + int i; + char inbuf[BUFSIZ]; + char outbuf[BUFSIZ]; + char *pin; + char *pout; + size_t inbytesleft; + size_t outbytesleft; + size_t rest = 0; + iconv_t cd; + size_t r; + FILE *in = stdin; + int ignore = 0; + char *p; + + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + + for (i = 1; i < argc; ++i) + { + if (strcmp(argv[i], "-l") == 0) + { + for (i = 0; codepage_alias[i].name != NULL; ++i) + printf("%s\n", codepage_alias[i].name); + return 0; + } + + if (strcmp(argv[i], "-f") == 0) + fromcode = argv[++i]; + else if (strcmp(argv[i], "-t") == 0) + tocode = argv[++i]; + else if (strcmp(argv[i], "-c") == 0) + ignore = 1; + else + { + in = fopen(argv[i], "rb"); + if (in == NULL) + { + fprintf(stderr, "cannot open %s\n", argv[i]); + return 1; + } + break; + } + } + + if (fromcode == NULL || tocode == NULL) + { + printf("usage: %s [-c] -f from-enc -t to-enc [file]\n", argv[0]); + return 0; + } + + if (ignore) + { + p = tocode; + tocode = (char *)malloc(strlen(p) + strlen("//IGNORE") + 1); + if (tocode == NULL) + { + perror("fatal error"); + return 1; + } + strcpy(tocode, p); + strcat(tocode, "//IGNORE"); + } + + cd = iconv_open(tocode, fromcode); + if (cd == (iconv_t)(-1)) + { + perror("iconv_open error"); + return 1; + } + + while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0 + || rest != 0) + { + inbytesleft += rest; + pin = inbuf; + pout = outbuf; + outbytesleft = sizeof(outbuf); + r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft); + fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout); + if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in))) + { + perror("conversion error"); + return 1; + } + memmove(inbuf, pin, inbytesleft); + rest = inbytesleft; + } + pout = outbuf; + outbytesleft = sizeof(outbuf); + r = iconv(cd, NULL, NULL, &pout, &outbytesleft); + fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout); + if (r == (size_t)(-1)) + { + perror("conversion error"); + return 1; + } + + iconv_close(cd); + + return 0; +} +#endif + diff --git a/hgdriver/ImageProcess/include/zbar.h b/hgdriver/ImageProcess/include/zbar.h new file mode 100755 index 0000000..f13294b --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar.h @@ -0,0 +1,1498 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ +#ifndef _ZBAR_H_ +#define _ZBAR_H_ + + /** @file + * ZBar Barcode Reader C API definition + */ + + /** @mainpage + * + * interface to the barcode reader is available at several levels. + * most applications will want to use the high-level interfaces: + * + * @section high-level High-Level Interfaces + * + * these interfaces wrap all library functionality into an easy-to-use + * package for a specific toolkit: + * - the "GTK+ 2.x widget" may be used with GTK GUI applications. a + * Python wrapper is included for PyGtk + * - the @ref zbar::QZBar "Qt4 widget" may be used with Qt GUI + * applications + * - the Processor interface (in @ref c-processor "C" or @ref + * zbar::Processor "C++") adds a scanning window to an application + * with no GUI. + * + * @section mid-level Intermediate Interfaces + * + * building blocks used to construct high-level interfaces: + * - the ImageScanner (in @ref c-imagescanner "C" or @ref + * zbar::ImageScanner "C++") looks for barcodes in a library defined + * image object + * - the Window abstraction (in @ref c-window "C" or @ref + * zbar::Window "C++") sinks library images, displaying them on the + * platform display + * - the Video abstraction (in @ref c-video "C" or @ref zbar::Video + * "C++") sources library images from a video device + * + * @section low-level Low-Level Interfaces + * + * direct interaction with barcode scanning and decoding: + * - the Scanner (in @ref c-scanner "C" or @ref zbar::Scanner "C++") + * looks for barcodes in a linear intensity sample stream + * - the Decoder (in @ref c-decoder "C" or @ref zbar::Decoder "C++") + * extracts barcodes from a stream of bar and space widths + */ + +#ifdef __cplusplus + + /** C++ namespace for library interfaces */ +namespace zbar { + extern "C" { +#endif + + + /** @name Global library interfaces */ + /*@{*/ + + /** "color" of element: bar or space. */ + typedef enum zbar_color_e { + ZBAR_SPACE = 0, /**< light area or space between bars */ + ZBAR_BAR = 1, /**< dark area or colored bar segment */ + } zbar_color_t; + + /** decoded symbol type. */ + typedef enum zbar_symbol_type_e { + ZBAR_NONE = 0, /**< no symbol decoded */ + ZBAR_PARTIAL = 1, /**< intermediate status */ + ZBAR_EAN2 = 2, /**< GS1 2-digit add-on */ + ZBAR_EAN5 = 5, /**< GS1 5-digit add-on */ + ZBAR_EAN8 = 8, /**< EAN-8 */ + ZBAR_UPCE = 9, /**< UPC-E */ + ZBAR_ISBN10 = 10, /**< ISBN-10 (from EAN-13). @since 0.4 */ + ZBAR_UPCA = 12, /**< UPC-A */ + ZBAR_EAN13 = 13, /**< EAN-13 */ + ZBAR_ISBN13 = 14, /**< ISBN-13 (from EAN-13). @since 0.4 */ + ZBAR_COMPOSITE = 15, /**< EAN/UPC composite */ + ZBAR_I25 = 25, /**< Interleaved 2 of 5. @since 0.4 */ + ZBAR_DATABAR = 34, /**< GS1 DataBar (RSS). @since 0.11 */ + ZBAR_DATABAR_EXP = 35, /**< GS1 DataBar Expanded. @since 0.11 */ + ZBAR_CODABAR = 38, /**< Codabar. @since 0.11 */ + ZBAR_CODE39 = 39, /**< Code 39. @since 0.4 */ + ZBAR_PDF417 = 57, /**< PDF417. @since 0.6 */ + ZBAR_QRCODE = 64, /**< QR Code. @since 0.10 */ + ZBAR_CODE93 = 93, /**< Code 93. @since 0.11 */ + ZBAR_CODE128 = 128, /**< Code 128 */ + + /** mask for base symbol type. + * @deprecated in 0.11, remove this from existing code + */ + ZBAR_SYMBOL = 0x00ff, + /** 2-digit add-on flag. + * @deprecated in 0.11, a ::ZBAR_EAN2 component is used for + * 2-digit GS1 add-ons + */ + ZBAR_ADDON2 = 0x0200, + /** 5-digit add-on flag. + * @deprecated in 0.11, a ::ZBAR_EAN5 component is used for + * 5-digit GS1 add-ons + */ + ZBAR_ADDON5 = 0x0500, + /** add-on flag mask. + * @deprecated in 0.11, GS1 add-ons are represented using composite + * symbols of type ::ZBAR_COMPOSITE; add-on components use ::ZBAR_EAN2 + * or ::ZBAR_EAN5 + */ + ZBAR_ADDON = 0x0700, + } zbar_symbol_type_t; + + /** decoded symbol coarse orientation. + * @since 0.11 + */ + typedef enum zbar_orientation_e { + ZBAR_ORIENT_UNKNOWN = -1, /**< unable to determine orientation */ + ZBAR_ORIENT_UP, /**< upright, read left to right */ + ZBAR_ORIENT_RIGHT, /**< sideways, read top to bottom */ + ZBAR_ORIENT_DOWN, /**< upside-down, read right to left */ + ZBAR_ORIENT_LEFT, /**< sideways, read bottom to top */ + } zbar_orientation_t; + + /** error codes. */ + typedef enum zbar_error_e { + ZBAR_OK = 0, /**< no error */ + ZBAR_ERR_NOMEM, /**< out of memory */ + ZBAR_ERR_INTERNAL, /**< internal library error */ + ZBAR_ERR_UNSUPPORTED, /**< unsupported request */ + ZBAR_ERR_INVALID, /**< invalid request */ + ZBAR_ERR_SYSTEM, /**< system error */ + ZBAR_ERR_LOCKING, /**< locking error */ + ZBAR_ERR_BUSY, /**< all resources busy */ + ZBAR_ERR_XDISPLAY, /**< X11 display error */ + ZBAR_ERR_XPROTO, /**< X11 protocol error */ + ZBAR_ERR_CLOSED, /**< output window is closed */ + ZBAR_ERR_WINAPI, /**< windows system error */ + ZBAR_ERR_NUM /**< number of error codes */ + } zbar_error_t; + + /** decoder configuration options. + * @since 0.4 + */ + typedef enum zbar_config_e { + ZBAR_CFG_ENABLE = 0, /**< enable symbology/feature */ + ZBAR_CFG_ADD_CHECK, /**< enable check digit when optional */ + ZBAR_CFG_EMIT_CHECK, /**< return check digit when present */ + ZBAR_CFG_ASCII, /**< enable full ASCII character set */ + ZBAR_CFG_NUM, /**< number of boolean decoder configs */ + + ZBAR_CFG_MIN_LEN = 0x20, /**< minimum data length for valid decode */ + ZBAR_CFG_MAX_LEN, /**< maximum data length for valid decode */ + + ZBAR_CFG_UNCERTAINTY = 0x40,/**< required video consistency frames */ + + ZBAR_CFG_POSITION = 0x80, /**< enable scanner to collect position data */ + + ZBAR_CFG_X_DENSITY = 0x100, /**< image scanner vertical scan density */ + ZBAR_CFG_Y_DENSITY, /**< image scanner horizontal scan density */ + } zbar_config_t; + + /** decoder symbology modifier flags. + * @since 0.11 + */ + typedef enum zbar_modifier_e { + /** barcode tagged as GS1 (EAN.UCC) reserved + * (eg, FNC1 before first data character). + * data may be parsed as a sequence of GS1 AIs + */ + ZBAR_MOD_GS1 = 0, + + /** barcode tagged as AIM reserved + * (eg, FNC1 after first character or digit pair) + */ + ZBAR_MOD_AIM, + + /** number of modifiers */ + ZBAR_MOD_NUM, + } zbar_modifier_t; + + /** retrieve runtime library version information. + * @param major set to the running major version (unless NULL) + * @param minor set to the running minor version (unless NULL) + * @returns 0 + */ + extern int zbar_version(unsigned* major, + unsigned* minor); + + /** set global library debug level. + * @param verbosity desired debug level. higher values create more spew + */ + extern void zbar_set_verbosity(int verbosity); + + /** increase global library debug level. + * eg, for -vvvv + */ + extern void zbar_increase_verbosity(void); + + /** retrieve string name for symbol encoding. + * @param sym symbol type encoding + * @returns the static string name for the specified symbol type, + * or "UNKNOWN" if the encoding is not recognized + */ + extern const char* zbar_get_symbol_name(zbar_symbol_type_t sym); + + /** retrieve string name for addon encoding. + * @param sym symbol type encoding + * @returns static string name for any addon, or the empty string + * if no addons were decoded + * @deprecated in 0.11 + */ + extern const char* zbar_get_addon_name(zbar_symbol_type_t sym); + + /** retrieve string name for configuration setting. + * @param config setting to name + * @returns static string name for config, + * or the empty string if value is not a known config + */ + extern const char* zbar_get_config_name(zbar_config_t config); + + /** retrieve string name for modifier. + * @param modifier flag to name + * @returns static string name for modifier, + * or the empty string if the value is not a known flag + */ + extern const char* zbar_get_modifier_name(zbar_modifier_t modifier); + + /** retrieve string name for orientation. + * @param orientation orientation encoding + * @returns the static string name for the specified orientation, + * or "UNKNOWN" if the orientation is not recognized + * @since 0.11 + */ + extern const char* zbar_get_orientation_name(zbar_orientation_t orientation); + + /** parse a configuration string of the form "[symbology.]config[=value]". + * the config must match one of the recognized names. + * the symbology, if present, must match one of the recognized names. + * if symbology is unspecified, it will be set to 0. + * if value is unspecified it will be set to 1. + * @returns 0 if the config is parsed successfully, 1 otherwise + * @since 0.4 + */ + extern int zbar_parse_config(const char* config_string, + zbar_symbol_type_t* symbology, + zbar_config_t* config, + int* value); + + /** consistently compute fourcc values across architectures + * (adapted from v4l2 specification) + * @since 0.11 + */ +#define zbar_fourcc(a, b, c, d) \ + ((unsigned long)(a) | \ + ((unsigned long)(b) << 8) | \ + ((unsigned long)(c) << 16) | \ + ((unsigned long)(d) << 24)) + + /** parse a fourcc string into its encoded integer value. + * @since 0.11 + */ + static __inline unsigned long zbar_fourcc_parse(const char* format) + { + unsigned long fourcc = 0; + if (format) { + int i; + for (i = 0; i < 4 && format[i]; i++) + fourcc |= ((unsigned long)format[i]) << (i * 8); + } + return(fourcc); + } + + /** @internal type unsafe error API (don't use) */ + extern int _zbar_error_spew(const void* object, + int verbosity); + extern const char* _zbar_error_string(const void* object, + int verbosity); + extern zbar_error_t _zbar_get_error_code(const void* object); + + /*@}*/ + + struct zbar_symbol_s; + typedef struct zbar_symbol_s zbar_symbol_t; + + struct zbar_symbol_set_s; + typedef struct zbar_symbol_set_s zbar_symbol_set_t; + + + /*------------------------------------------------------------*/ + /** @name Symbol interface + * decoded barcode symbol result object. stores type, data, and image + * location of decoded symbol. all memory is owned by the library + */ + /*@{*/ + + /** @typedef zbar_symbol_t + * opaque decoded symbol object. + */ + + /** symbol reference count manipulation. + * increment the reference count when you store a new reference to the + * symbol. decrement when the reference is no longer used. do not + * refer to the symbol once the count is decremented and the + * containing image has been recycled or destroyed. + * @note the containing image holds a reference to the symbol, so you + * only need to use this if you keep a symbol after the image has been + * destroyed or reused. + * @since 0.9 + */ + extern void zbar_symbol_ref(const zbar_symbol_t* symbol, + int refs); + + /** retrieve type of decoded symbol. + * @returns the symbol type + */ + extern zbar_symbol_type_t zbar_symbol_get_type(const zbar_symbol_t* symbol); + + /** retrieve symbology boolean config settings. + * @returns a bitmask indicating which configs were set for the detected + * symbology during decoding. + * @since 0.11 + */ + extern unsigned int zbar_symbol_get_configs(const zbar_symbol_t* symbol); + + /** retrieve symbology modifier flag settings. + * @returns a bitmask indicating which characteristics were detected + * during decoding. + * @since 0.11 + */ + extern unsigned int zbar_symbol_get_modifiers(const zbar_symbol_t* symbol); + + /** retrieve data decoded from symbol. + * @returns the data string + */ + extern const char* zbar_symbol_get_data(const zbar_symbol_t* symbol); + + /** retrieve length of binary data. + * @returns the length of the decoded data + */ + extern unsigned int zbar_symbol_get_data_length(const zbar_symbol_t* symbol); + + /** retrieve a symbol confidence metric. + * @returns an unscaled, relative quantity: larger values are better + * than smaller values, where "large" and "small" are application + * dependent. + * @note expect the exact definition of this quantity to change as the + * metric is refined. currently, only the ordered relationship + * between two values is defined and will remain stable in the future + * @since 0.9 + */ + extern int zbar_symbol_get_quality(const zbar_symbol_t* symbol); + + /** retrieve current cache count. when the cache is enabled for the + * image_scanner this provides inter-frame reliability and redundancy + * information for video streams. + * @returns < 0 if symbol is still uncertain. + * @returns 0 if symbol is newly verified. + * @returns > 0 for duplicate symbols + */ + extern int zbar_symbol_get_count(const zbar_symbol_t* symbol); + + /** retrieve the number of points in the location polygon. the + * location polygon defines the image area that the symbol was + * extracted from. + * @returns the number of points in the location polygon + * @note this is currently not a polygon, but the scan locations + * where the symbol was decoded + */ + extern unsigned zbar_symbol_get_loc_size(const zbar_symbol_t* symbol); + + /** retrieve location polygon x-coordinates. + * points are specified by 0-based index. + * @returns the x-coordinate for a point in the location polygon. + * @returns -1 if index is out of range + */ + extern int zbar_symbol_get_loc_x(const zbar_symbol_t* symbol, + unsigned index); + + /** retrieve location polygon y-coordinates. + * points are specified by 0-based index. + * @returns the y-coordinate for a point in the location polygon. + * @returns -1 if index is out of range + */ + extern int zbar_symbol_get_loc_y(const zbar_symbol_t* symbol, + unsigned index); + + /** retrieve general orientation of decoded symbol. + * @returns a coarse, axis-aligned indication of symbol orientation or + * ::ZBAR_ORIENT_UNKNOWN if unknown + * @since 0.11 + */ + extern zbar_orientation_t + zbar_symbol_get_orientation(const zbar_symbol_t* symbol); + + /** iterate the set to which this symbol belongs (there can be only one). + * @returns the next symbol in the set, or + * @returns NULL when no more results are available + */ + extern const zbar_symbol_t* zbar_symbol_next(const zbar_symbol_t* symbol); + + /** retrieve components of a composite result. + * @returns the symbol set containing the components + * @returns NULL if the symbol is already a physical symbol + * @since 0.10 + */ + extern const zbar_symbol_set_t* + zbar_symbol_get_components(const zbar_symbol_t* symbol); + + /** iterate components of a composite result. + * @returns the first physical component symbol of a composite result + * @returns NULL if the symbol is already a physical symbol + * @since 0.10 + */ + extern const zbar_symbol_t* + zbar_symbol_first_component(const zbar_symbol_t* symbol); + + /** print XML symbol element representation to user result buffer. + * @see http://zbar.sourceforge.net/2008/barcode.xsd for the schema. + * @param symbol is the symbol to print + * @param buffer is the inout result pointer, it will be reallocated + * with a larger size if necessary. + * @param buflen is inout length of the result buffer. + * @returns the buffer pointer + * @since 0.6 + */ + extern char* zbar_symbol_xml(const zbar_symbol_t* symbol, + char** buffer, + unsigned* buflen); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Symbol Set interface + * container for decoded result symbols associated with an image + * or a composite symbol. + * @since 0.10 + */ + /*@{*/ + + /** @typedef zbar_symbol_set_t + * opaque symbol iterator object. + * @since 0.10 + */ + + /** reference count manipulation. + * increment the reference count when you store a new reference. + * decrement when the reference is no longer used. do not refer to + * the object any longer once references have been released. + * @since 0.10 + */ + extern void zbar_symbol_set_ref(const zbar_symbol_set_t* symbols, + int refs); + + /** retrieve set size. + * @returns the number of symbols in the set. + * @since 0.10 + */ + extern int zbar_symbol_set_get_size(const zbar_symbol_set_t* symbols); + + /** set iterator. + * @returns the first decoded symbol result in a set + * @returns NULL if the set is empty + * @since 0.10 + */ + extern const zbar_symbol_t* + zbar_symbol_set_first_symbol(const zbar_symbol_set_t* symbols); + + /** raw result iterator. + * @returns the first decoded symbol result in a set, *before* filtering + * @returns NULL if the set is empty + * @since 0.11 + */ + extern const zbar_symbol_t* + zbar_symbol_set_first_unfiltered(const zbar_symbol_set_t* symbols); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Image interface + * stores image data samples along with associated format and size + * metadata + */ + /*@{*/ + + struct zbar_image_s; + /** opaque image object. */ + typedef struct zbar_image_s zbar_image_t; + + /** cleanup handler callback function. + * called to free sample data when an image is destroyed. + */ + typedef void (zbar_image_cleanup_handler_t)(zbar_image_t* image); + + /** data handler callback function. + * called when decoded symbol results are available for an image + */ + typedef void (zbar_image_data_handler_t)(zbar_image_t* image, + const void* userdata); + + /** new image constructor. + * @returns a new image object with uninitialized data and format. + * this image should be destroyed (using zbar_image_destroy()) as + * soon as the application is finished with it + */ + extern zbar_image_t* zbar_image_create(void); + + /** image destructor. all images created by or returned to the + * application should be destroyed using this function. when an image + * is destroyed, the associated data cleanup handler will be invoked + * if available + * @note make no assumptions about the image or the data buffer. + * they may not be destroyed/cleaned immediately if the library + * is still using them. if necessary, use the cleanup handler hook + * to keep track of image data buffers + */ + extern void zbar_image_destroy(zbar_image_t* image); + + /** image reference count manipulation. + * increment the reference count when you store a new reference to the + * image. decrement when the reference is no longer used. do not + * refer to the image any longer once the count is decremented. + * zbar_image_ref(image, -1) is the same as zbar_image_destroy(image) + * @since 0.5 + */ + extern void zbar_image_ref(zbar_image_t* image, + int refs); + + /** image format conversion. refer to the documentation for supported + * image formats + * @returns a @em new image with the sample data from the original image + * converted to the requested format. the original image is + * unaffected. + * @note the converted image size may be rounded (up) due to format + * constraints + */ + extern zbar_image_t* zbar_image_convert(const zbar_image_t* image, + unsigned long format); + + /** image format conversion with crop/pad. + * if the requested size is larger than the image, the last row/column + * are duplicated to cover the difference. if the requested size is + * smaller than the image, the extra rows/columns are dropped from the + * right/bottom. + * @returns a @em new image with the sample data from the original + * image converted to the requested format and size. + * @note the image is @em not scaled + * @see zbar_image_convert() + * @since 0.4 + */ + extern zbar_image_t* zbar_image_convert_resize(const zbar_image_t* image, + unsigned long format, + unsigned width, + unsigned height); + + /** retrieve the image format. + * @returns the fourcc describing the format of the image sample data + */ + extern unsigned long zbar_image_get_format(const zbar_image_t* image); + + /** retrieve a "sequence" (page/frame) number associated with this image. + * @since 0.6 + */ + extern unsigned zbar_image_get_sequence(const zbar_image_t* image); + + /** retrieve the width of the image. + * @returns the width in sample columns + */ + extern unsigned zbar_image_get_width(const zbar_image_t* image); + + /** retrieve the height of the image. + * @returns the height in sample rows + */ + extern unsigned zbar_image_get_height(const zbar_image_t* image); + + /** retrieve both dimensions of the image. + * fills in the width and height in samples + */ + extern void zbar_image_get_size(const zbar_image_t* image, + unsigned* width, + unsigned* height); + + /** retrieve the crop rectangle. + * fills in the image coordinates of the upper left corner and size + * of an axis-aligned rectangular area of the image that will be scanned. + * defaults to the full image + * @since 0.11 + */ + extern void zbar_image_get_crop(const zbar_image_t* image, + unsigned* x, + unsigned* y, + unsigned* width, + unsigned* height); + + /** return the image sample data. the returned data buffer is only + * valid until zbar_image_destroy() is called + */ + extern const void* zbar_image_get_data(const zbar_image_t* image); + + /** return the size of image data. + * @since 0.6 + */ + extern unsigned long zbar_image_get_data_length(const zbar_image_t* img); + + /** retrieve the decoded results. + * @returns the (possibly empty) set of decoded symbols + * @returns NULL if the image has not been scanned + * @since 0.10 + */ + extern const zbar_symbol_set_t* + zbar_image_get_symbols(const zbar_image_t* image); + + /** associate the specified symbol set with the image, replacing any + * existing results. use NULL to release the current results from the + * image. + * @see zbar_image_scanner_recycle_image() + * @since 0.10 + */ + extern void zbar_image_set_symbols(zbar_image_t* image, + const zbar_symbol_set_t* symbols); + + /** image_scanner decode result iterator. + * @returns the first decoded symbol result for an image + * or NULL if no results are available + */ + extern const zbar_symbol_t* + zbar_image_first_symbol(const zbar_image_t* image); + + /** specify the fourcc image format code for image sample data. + * refer to the documentation for supported formats. + * @note this does not convert the data! + * (see zbar_image_convert() for that) + */ + extern void zbar_image_set_format(zbar_image_t* image, + unsigned long format); + + /** associate a "sequence" (page/frame) number with this image. + * @since 0.6 + */ + extern void zbar_image_set_sequence(zbar_image_t* image, + unsigned sequence_num); + + /** specify the pixel size of the image. + * @note this also resets the crop rectangle to the full image + * (0, 0, width, height) + * @note this does not affect the data! + */ + extern void zbar_image_set_size(zbar_image_t* image, + unsigned width, + unsigned height); + + /** specify a rectangular region of the image to scan. + * the rectangle will be clipped to the image boundaries. + * defaults to the full image specified by zbar_image_set_size() + */ + extern void zbar_image_set_crop(zbar_image_t* image, + unsigned x, + unsigned y, + unsigned width, + unsigned height); + + /** specify image sample data. when image data is no longer needed by + * the library the specific data cleanup handler will be called + * (unless NULL) + * @note application image data will not be modified by the library + */ + extern void zbar_image_set_data(zbar_image_t* image, + const void* data, + unsigned long data_byte_length, + zbar_image_cleanup_handler_t* cleanup_hndlr); + + /** built-in cleanup handler. + * passes the image data buffer to free() + */ + extern void zbar_image_free_data(zbar_image_t* image); + + /** associate user specified data value with an image. + * @since 0.5 + */ + extern void zbar_image_set_userdata(zbar_image_t* image, + void* userdata); + + /** return user specified data value associated with the image. + * @since 0.5 + */ + extern void* zbar_image_get_userdata(const zbar_image_t* image); + + /** dump raw image data to a file for debug. + * the data will be prefixed with a 16 byte header consisting of: + * - 4 bytes uint = 0x676d697a ("zimg") + * - 4 bytes format fourcc + * - 2 bytes width + * - 2 bytes height + * - 4 bytes size of following image data in bytes + * this header can be dumped w/eg: + * @verbatim + od -Ax -tx1z -N16 -w4 [file] + @endverbatim + * for some formats the image can be displayed/converted using + * ImageMagick, eg: + * @verbatim + display -size 640x480+16 [-depth ?] [-sampling-factor ?x?] \ + {GRAY,RGB,UYVY,YUV}:[file] + @endverbatim + * + * @param image the image object to dump + * @param filebase base filename, appended with ".XXXX.zimg" where + * XXXX is the format fourcc + * @returns 0 on success or a system error code on failure + */ + extern int zbar_image_write(const zbar_image_t* image, + const char* filebase); + + /** read back an image in the format written by zbar_image_write() + * @note TBD + */ + extern zbar_image_t* zbar_image_read(char* filename); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Processor interface + * @anchor c-processor + * high-level self-contained image processor. + * processes video and images for barcodes, optionally displaying + * images to a library owned output window + */ + /*@{*/ + + struct zbar_processor_s; + /** opaque standalone processor object. */ + typedef struct zbar_processor_s zbar_processor_t; + + /** constructor. + * if threaded is set and threading is available the processor + * will spawn threads where appropriate to avoid blocking and + * improve responsiveness + */ + extern zbar_processor_t* zbar_processor_create(int threaded); + + /** destructor. cleans up all resources associated with the processor + */ + extern void zbar_processor_destroy(zbar_processor_t* processor); + + /** (re)initialization. + * opens a video input device and/or prepares to display output + */ + extern int zbar_processor_init(zbar_processor_t* processor, + const char* video_device, + int enable_display); + + /** request a preferred size for the video image from the device. + * the request may be adjusted or completely ignored by the driver. + * @note must be called before zbar_processor_init() + * @since 0.6 + */ + extern int zbar_processor_request_size(zbar_processor_t* processor, + unsigned width, + unsigned height); + + /** request a preferred video driver interface version for + * debug/testing. + * @note must be called before zbar_processor_init() + * @since 0.6 + */ + extern int zbar_processor_request_interface(zbar_processor_t* processor, + int version); + + /** request a preferred video I/O mode for debug/testing. You will + * get errors if the driver does not support the specified mode. + * @verbatim + 0 = auto-detect + 1 = force I/O using read() + 2 = force memory mapped I/O using mmap() + 3 = force USERPTR I/O (v4l2 only) + @endverbatim + * @note must be called before zbar_processor_init() + * @since 0.7 + */ + extern int zbar_processor_request_iomode(zbar_processor_t* video, + int iomode); + + /** force specific input and output formats for debug/testing. + * @note must be called before zbar_processor_init() + */ + extern int zbar_processor_force_format(zbar_processor_t* processor, + unsigned long input_format, + unsigned long output_format); + + /** setup result handler callback. + * the specified function will be called by the processor whenever + * new results are available from the video stream or a static image. + * pass a NULL value to disable callbacks. + * @param processor the object on which to set the handler. + * @param handler the function to call when new results are available. + * @param userdata is set as with zbar_processor_set_userdata(). + * @returns the previously registered handler + */ + extern zbar_image_data_handler_t* + zbar_processor_set_data_handler(zbar_processor_t* processor, + zbar_image_data_handler_t* handler, + const void* userdata); + + /** associate user specified data value with the processor. + * @since 0.6 + */ + extern void zbar_processor_set_userdata(zbar_processor_t* processor, + void* userdata); + + /** return user specified data value associated with the processor. + * @since 0.6 + */ + extern void* zbar_processor_get_userdata(const zbar_processor_t* processor); + + /** set config for indicated symbology (0 for all) to specified value. + * @returns 0 for success, non-0 for failure (config does not apply to + * specified symbology, or value out of range) + * @see zbar_decoder_set_config() + * @since 0.4 + */ + extern int zbar_processor_set_config(zbar_processor_t* processor, + zbar_symbol_type_t symbology, + zbar_config_t config, + int value); + + /** parse configuration string using zbar_parse_config() + * and apply to processor using zbar_processor_set_config(). + * @returns 0 for success, non-0 for failure + * @see zbar_parse_config() + * @see zbar_processor_set_config() + * @since 0.4 + */ + static __inline int zbar_processor_parse_config(zbar_processor_t* processor, + const char* config_string) + { + zbar_symbol_type_t sym; + zbar_config_t cfg; + int val; + return(zbar_parse_config(config_string, &sym, &cfg, &val) || + zbar_processor_set_config(processor, sym, cfg, val)); + } + + /** retrieve the current state of the ouput window. + * @returns 1 if the output window is currently displayed, 0 if not. + * @returns -1 if an error occurs + */ + extern int zbar_processor_is_visible(zbar_processor_t* processor); + + /** show or hide the display window owned by the library. + * the size will be adjusted to the input size + */ + extern int zbar_processor_set_visible(zbar_processor_t* processor, + int visible); + + /** control the processor in free running video mode. + * only works if video input is initialized. if threading is in use, + * scanning will occur in the background, otherwise this is only + * useful wrapping calls to zbar_processor_user_wait(). if the + * library output window is visible, video display will be enabled. + */ + extern int zbar_processor_set_active(zbar_processor_t* processor, + int active); + + /** retrieve decode results for last scanned image/frame. + * @returns the symbol set result container or NULL if no results are + * available + * @note the returned symbol set has its reference count incremented; + * ensure that the count is decremented after use + * @since 0.10 + */ + extern const zbar_symbol_set_t* + zbar_processor_get_results(const zbar_processor_t* processor); + + /** wait for input to the display window from the user + * (via mouse or keyboard). + * @returns >0 when input is received, 0 if timeout ms expired + * with no input or -1 in case of an error + */ + extern int zbar_processor_user_wait(zbar_processor_t* processor, + int timeout); + + /** process from the video stream until a result is available, + * or the timeout (in milliseconds) expires. + * specify a timeout of -1 to scan indefinitely + * (zbar_processor_set_active() may still be used to abort the scan + * from another thread). + * if the library window is visible, video display will be enabled. + * @note that multiple results may still be returned (despite the + * name). + * @returns >0 if symbols were successfully decoded, + * 0 if no symbols were found (ie, the timeout expired) + * or -1 if an error occurs + */ + extern int zbar_process_one(zbar_processor_t* processor, + int timeout); + + /** process the provided image for barcodes. + * if the library window is visible, the image will be displayed. + * @returns >0 if symbols were successfully decoded, + * 0 if no symbols were found or -1 if an error occurs + */ + extern int zbar_process_image(zbar_processor_t* processor, + zbar_image_t* image); + + /** display detail for last processor error to stderr. + * @returns a non-zero value suitable for passing to exit() + */ + static __inline int + zbar_processor_error_spew(const zbar_processor_t* processor, + int verbosity) + { + return(_zbar_error_spew(processor, verbosity)); + } + + /** retrieve the detail string for the last processor error. */ + static __inline const char* + zbar_processor_error_string(const zbar_processor_t* processor, + int verbosity) + { + return(_zbar_error_string(processor, verbosity)); + } + + /** retrieve the type code for the last processor error. */ + static __inline zbar_error_t + zbar_processor_get_error_code(const zbar_processor_t* processor) + { + return(_zbar_get_error_code(processor)); + } + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Video interface + * @anchor c-video + * mid-level video source abstraction. + * captures images from a video device + */ + /*@{*/ + + struct zbar_video_s; + /** opaque video object. */ + typedef struct zbar_video_s zbar_video_t; + + /** constructor. */ + extern zbar_video_t* zbar_video_create(void); + + /** destructor. */ + extern void zbar_video_destroy(zbar_video_t* video); + + /** open and probe a video device. + * the device specified by platform specific unique name + * (v4l device node path in *nix eg "/dev/video", + * DirectShow DevicePath property in windows). + * @returns 0 if successful or -1 if an error occurs + */ + extern int zbar_video_open(zbar_video_t* video, + const char* device); + + /** retrieve file descriptor associated with open *nix video device + * useful for using select()/poll() to tell when new images are + * available (NB v4l2 only!!). + * @returns the file descriptor or -1 if the video device is not open + * or the driver only supports v4l1 + */ + extern int zbar_video_get_fd(const zbar_video_t* video); + + /** request a preferred size for the video image from the device. + * the request may be adjusted or completely ignored by the driver. + * @returns 0 if successful or -1 if the video device is already + * initialized + * @since 0.6 + */ + extern int zbar_video_request_size(zbar_video_t* video, + unsigned width, + unsigned height); + + /** request a preferred driver interface version for debug/testing. + * @note must be called before zbar_video_open() + * @since 0.6 + */ + extern int zbar_video_request_interface(zbar_video_t* video, + int version); + + /** request a preferred I/O mode for debug/testing. You will get + * errors if the driver does not support the specified mode. + * @verbatim + 0 = auto-detect + 1 = force I/O using read() + 2 = force memory mapped I/O using mmap() + 3 = force USERPTR I/O (v4l2 only) + @endverbatim + * @note must be called before zbar_video_open() + * @since 0.7 + */ + extern int zbar_video_request_iomode(zbar_video_t* video, + int iomode); + + /** retrieve current output image width. + * @returns the width or 0 if the video device is not open + */ + extern int zbar_video_get_width(const zbar_video_t* video); + + /** retrieve current output image height. + * @returns the height or 0 if the video device is not open + */ + extern int zbar_video_get_height(const zbar_video_t* video); + + /** initialize video using a specific format for debug. + * use zbar_negotiate_format() to automatically select and initialize + * the best available format + */ + extern int zbar_video_init(zbar_video_t* video, + unsigned long format); + + /** start/stop video capture. + * all buffered images are retired when capture is disabled. + * @returns 0 if successful or -1 if an error occurs + */ + extern int zbar_video_enable(zbar_video_t* video, + int enable); + + /** retrieve next captured image. blocks until an image is available. + * @returns NULL if video is not enabled or an error occurs + */ + extern zbar_image_t* zbar_video_next_image(zbar_video_t* video); + + /** display detail for last video error to stderr. + * @returns a non-zero value suitable for passing to exit() + */ + static __inline int zbar_video_error_spew(const zbar_video_t* video, + int verbosity) + { + return(_zbar_error_spew(video, verbosity)); + } + + /** retrieve the detail string for the last video error. */ + static __inline const char* zbar_video_error_string(const zbar_video_t* video, + int verbosity) + { + return(_zbar_error_string(video, verbosity)); + } + + /** retrieve the type code for the last video error. */ + static __inline zbar_error_t + zbar_video_get_error_code(const zbar_video_t* video) + { + return(_zbar_get_error_code(video)); + } + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Window interface + * @anchor c-window + * mid-level output window abstraction. + * displays images to user-specified platform specific output window + */ + /*@{*/ + + struct zbar_window_s; + /** opaque window object. */ + typedef struct zbar_window_s zbar_window_t; + + /** constructor. */ + extern zbar_window_t* zbar_window_create(void); + + /** destructor. */ + extern void zbar_window_destroy(zbar_window_t* window); + + /** associate reader with an existing platform window. + * This can be any "Drawable" for X Windows or a "HWND" for windows. + * input images will be scaled into the output window. + * pass NULL to detach from the resource, further input will be + * ignored + */ + extern int zbar_window_attach(zbar_window_t* window, + void* x11_display_w32_hwnd, + unsigned long x11_drawable); + + /** control content level of the reader overlay. + * the overlay displays graphical data for informational or debug + * purposes. higher values increase the level of annotation (possibly + * decreasing performance). @verbatim + 0 = disable overlay + 1 = outline decoded symbols (default) + 2 = also track and display input frame rate + @endverbatim + */ + extern void zbar_window_set_overlay(zbar_window_t* window, + int level); + + /** retrieve current content level of reader overlay. + * @see zbar_window_set_overlay() + * @since 0.10 + */ + extern int zbar_window_get_overlay(const zbar_window_t* window); + + /** draw a new image into the output window. */ + extern int zbar_window_draw(zbar_window_t* window, + zbar_image_t* image); + + /** redraw the last image (exposure handler). */ + extern int zbar_window_redraw(zbar_window_t* window); + + /** resize the image window (reconfigure handler). + * this does @em not update the contents of the window + * @since 0.3, changed in 0.4 to not redraw window + */ + extern int zbar_window_resize(zbar_window_t* window, + unsigned width, + unsigned height); + + /** display detail for last window error to stderr. + * @returns a non-zero value suitable for passing to exit() + */ + static __inline int zbar_window_error_spew(const zbar_window_t* window, + int verbosity) + { + return(_zbar_error_spew(window, verbosity)); + } + + /** retrieve the detail string for the last window error. */ + static __inline const char* + zbar_window_error_string(const zbar_window_t* window, + int verbosity) + { + return(_zbar_error_string(window, verbosity)); + } + + /** retrieve the type code for the last window error. */ + static __inline zbar_error_t + zbar_window_get_error_code(const zbar_window_t* window) + { + return(_zbar_get_error_code(window)); + } + + + /** select a compatible format between video input and output window. + * the selection algorithm attempts to use a format shared by + * video input and window output which is also most useful for + * barcode scanning. if a format conversion is necessary, it will + * heuristically attempt to minimize the cost of the conversion + */ + extern int zbar_negotiate_format(zbar_video_t* video, + zbar_window_t* window); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Image Scanner interface + * @anchor c-imagescanner + * mid-level image scanner interface. + * reads barcodes from 2-D images + */ + /*@{*/ + + struct zbar_image_scanner_s; + /** opaque image scanner object. */ + typedef struct zbar_image_scanner_s zbar_image_scanner_t; + + /** constructor. */ + extern zbar_image_scanner_t* zbar_image_scanner_create(void); + + /** destructor. */ + extern void zbar_image_scanner_destroy(zbar_image_scanner_t* scanner); + + /** setup result handler callback. + * the specified function will be called by the scanner whenever + * new results are available from a decoded image. + * pass a NULL value to disable callbacks. + * @returns the previously registered handler + */ + extern zbar_image_data_handler_t* + zbar_image_scanner_set_data_handler(zbar_image_scanner_t* scanner, + zbar_image_data_handler_t* handler, + const void* userdata); + + + /** set config for indicated symbology (0 for all) to specified value. + * @returns 0 for success, non-0 for failure (config does not apply to + * specified symbology, or value out of range) + * @see zbar_decoder_set_config() + * @since 0.4 + */ + extern int zbar_image_scanner_set_config(zbar_image_scanner_t* scanner, + zbar_symbol_type_t symbology, + zbar_config_t config, + int value); + + /** parse configuration string using zbar_parse_config() + * and apply to image scanner using zbar_image_scanner_set_config(). + * @returns 0 for success, non-0 for failure + * @see zbar_parse_config() + * @see zbar_image_scanner_set_config() + * @since 0.4 + */ + static __inline int + zbar_image_scanner_parse_config(zbar_image_scanner_t* scanner, + const char* config_string) + { + zbar_symbol_type_t sym; + zbar_config_t cfg; + int val; + return(zbar_parse_config(config_string, &sym, &cfg, &val) || + zbar_image_scanner_set_config(scanner, sym, cfg, val)); + } + + /** enable or disable the inter-image result cache (default disabled). + * mostly useful for scanning video frames, the cache filters + * duplicate results from consecutive images, while adding some + * consistency checking and hysteresis to the results. + * this interface also clears the cache + */ + extern void zbar_image_scanner_enable_cache(zbar_image_scanner_t* scanner, + int enable); + + /** remove any previously decoded results from the image scanner and the + * specified image. somewhat more efficient version of + * zbar_image_set_symbols(image, NULL) which may retain memory for + * subsequent decodes + * @since 0.10 + */ + extern void zbar_image_scanner_recycle_image(zbar_image_scanner_t* scanner, + zbar_image_t* image); + + /** retrieve decode results for last scanned image. + * @returns the symbol set result container or NULL if no results are + * available + * @note the symbol set does not have its reference count adjusted; + * ensure that the count is incremented if the results may be kept + * after the next image is scanned + * @since 0.10 + */ + extern const zbar_symbol_set_t* + zbar_image_scanner_get_results(const zbar_image_scanner_t* scanner); + + /** scan for symbols in provided image. The image format must be + * "Y800" or "GRAY". + * @returns >0 if symbols were successfully decoded from the image, + * 0 if no symbols were found or -1 if an error occurs + * @see zbar_image_convert() + * @since 0.9 - changed to only accept grayscale images + */ + extern int zbar_scan_image(zbar_image_scanner_t* scanner, + zbar_image_t* image); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Decoder interface + * @anchor c-decoder + * low-level bar width stream decoder interface. + * identifies symbols and extracts encoded data + */ + /*@{*/ + + struct zbar_decoder_s; + /** opaque decoder object. */ + typedef struct zbar_decoder_s zbar_decoder_t; + + /** decoder data handler callback function. + * called by decoder when new data has just been decoded + */ + typedef void (zbar_decoder_handler_t)(zbar_decoder_t* decoder); + + /** constructor. */ + extern zbar_decoder_t* zbar_decoder_create(void); + + /** destructor. */ + extern void zbar_decoder_destroy(zbar_decoder_t* decoder); + + /** set config for indicated symbology (0 for all) to specified value. + * @returns 0 for success, non-0 for failure (config does not apply to + * specified symbology, or value out of range) + * @since 0.4 + */ + extern int zbar_decoder_set_config(zbar_decoder_t* decoder, + zbar_symbol_type_t symbology, + zbar_config_t config, + int value); + + /** parse configuration string using zbar_parse_config() + * and apply to decoder using zbar_decoder_set_config(). + * @returns 0 for success, non-0 for failure + * @see zbar_parse_config() + * @see zbar_decoder_set_config() + * @since 0.4 + */ + static __inline int zbar_decoder_parse_config(zbar_decoder_t* decoder, + const char* config_string) + { + zbar_symbol_type_t sym; + zbar_config_t cfg; + int val; + return(zbar_parse_config(config_string, &sym, &cfg, &val) || + zbar_decoder_set_config(decoder, sym, cfg, val)); + } + + /** retrieve symbology boolean config settings. + * @returns a bitmask indicating which configs are currently set for the + * specified symbology. + * @since 0.11 + */ + extern unsigned int zbar_decoder_get_configs(const zbar_decoder_t* decoder, + zbar_symbol_type_t symbology); + + /** clear all decoder state. + * any partial symbols are flushed + */ + extern void zbar_decoder_reset(zbar_decoder_t* decoder); + + /** mark start of a new scan pass. + * clears any intra-symbol state and resets color to ::ZBAR_SPACE. + * any partially decoded symbol state is retained + */ + extern void zbar_decoder_new_scan(zbar_decoder_t* decoder); + + /** process next bar/space width from input stream. + * the width is in arbitrary relative units. first value of a scan + * is ::ZBAR_SPACE width, alternating from there. + * @returns appropriate symbol type if width completes + * decode of a symbol (data is available for retrieval) + * @returns ::ZBAR_PARTIAL as a hint if part of a symbol was decoded + * @returns ::ZBAR_NONE (0) if no new symbol data is available + */ + extern zbar_symbol_type_t zbar_decode_width(zbar_decoder_t* decoder, + unsigned width); + + /** retrieve color of @em next element passed to + * zbar_decode_width(). */ + extern zbar_color_t zbar_decoder_get_color(const zbar_decoder_t* decoder); + + /** retrieve last decoded data. + * @returns the data string or NULL if no new data available. + * the returned data buffer is owned by library, contents are only + * valid between non-0 return from zbar_decode_width and next library + * call + */ + extern const char* zbar_decoder_get_data(const zbar_decoder_t* decoder); + + /** retrieve length of binary data. + * @returns the length of the decoded data or 0 if no new data + * available. + */ + extern unsigned int + zbar_decoder_get_data_length(const zbar_decoder_t* decoder); + + /** retrieve last decoded symbol type. + * @returns the type or ::ZBAR_NONE if no new data available + */ + extern zbar_symbol_type_t + zbar_decoder_get_type(const zbar_decoder_t* decoder); + + /** retrieve modifier flags for the last decoded symbol. + * @returns a bitmask indicating which characteristics were detected + * during decoding. + * @since 0.11 + */ + extern unsigned int zbar_decoder_get_modifiers(const zbar_decoder_t* decoder); + + /** retrieve last decode direction. + * @returns 1 for forward and -1 for reverse + * @returns 0 if the decode direction is unknown or does not apply + * @since 0.11 + */ + extern int zbar_decoder_get_direction(const zbar_decoder_t* decoder); + + /** setup data handler callback. + * the registered function will be called by the decoder + * just before zbar_decode_width() returns a non-zero value. + * pass a NULL value to disable callbacks. + * @returns the previously registered handler + */ + extern zbar_decoder_handler_t* + zbar_decoder_set_handler(zbar_decoder_t* decoder, + zbar_decoder_handler_t* handler); + + /** associate user specified data value with the decoder. */ + extern void zbar_decoder_set_userdata(zbar_decoder_t* decoder, + void* userdata); + + /** return user specified data value associated with the decoder. */ + extern void* zbar_decoder_get_userdata(const zbar_decoder_t* decoder); + + /*@}*/ + + /*------------------------------------------------------------*/ + /** @name Scanner interface + * @anchor c-scanner + * low-level linear intensity sample stream scanner interface. + * identifies "bar" edges and measures width between them. + * optionally passes to bar width decoder + */ + /*@{*/ + + struct zbar_scanner_s; + /** opaque scanner object. */ + typedef struct zbar_scanner_s zbar_scanner_t; + + /** constructor. + * if decoder is non-NULL it will be attached to scanner + * and called automatically at each new edge + * current color is initialized to ::ZBAR_SPACE + * (so an initial BAR->SPACE transition may be discarded) + */ + extern zbar_scanner_t* zbar_scanner_create(zbar_decoder_t* decoder); + + /** destructor. */ + extern void zbar_scanner_destroy(zbar_scanner_t* scanner); + + /** clear all scanner state. + * also resets an associated decoder + */ + extern zbar_symbol_type_t zbar_scanner_reset(zbar_scanner_t* scanner); + + /** mark start of a new scan pass. resets color to ::ZBAR_SPACE. + * also updates an associated decoder. + * @returns any decode results flushed from the pipeline + * @note when not using callback handlers, the return value should + * be checked the same as zbar_scan_y() + * @note call zbar_scanner_flush() at least twice before calling this + * method to ensure no decode results are lost + */ + extern zbar_symbol_type_t zbar_scanner_new_scan(zbar_scanner_t* scanner); + + /** flush scanner processing pipeline. + * forces current scanner position to be a scan boundary. + * call multiple times (max 3) to completely flush decoder. + * @returns any decode/scan results flushed from the pipeline + * @note when not using callback handlers, the return value should + * be checked the same as zbar_scan_y() + * @since 0.9 + */ + extern zbar_symbol_type_t zbar_scanner_flush(zbar_scanner_t* scanner); + + /** process next sample intensity value. + * intensity (y) is in arbitrary relative units. + * @returns result of zbar_decode_width() if a decoder is attached, + * otherwise @returns (::ZBAR_PARTIAL) when new edge is detected + * or 0 (::ZBAR_NONE) if no new edge is detected + */ + extern zbar_symbol_type_t zbar_scan_y(zbar_scanner_t* scanner, + int y); + + /** process next sample from RGB (or BGR) triple. */ + static __inline zbar_symbol_type_t zbar_scan_rgb24(zbar_scanner_t* scanner, + unsigned char* rgb) + { + return(zbar_scan_y(scanner, rgb[0] + rgb[1] + rgb[2])); + } + + /** retrieve last scanned width. */ + extern unsigned zbar_scanner_get_width(const zbar_scanner_t* scanner); + + /** retrieve sample position of last edge. + * @since 0.10 + */ + extern unsigned zbar_scanner_get_edge(const zbar_scanner_t* scn, + unsigned offset, + int prec); + + /** retrieve last scanned color. */ + extern zbar_color_t zbar_scanner_get_color(const zbar_scanner_t* scanner); + + /*@}*/ + +#ifdef __cplusplus + } +} + +# include "zbar/Exception.h" +# include "zbar/Decoder.h" +# include "zbar/Scanner.h" +# include "zbar/Symbol.h" +# include "zbar/Image.h" +# include "zbar/ImageScanner.h" +# include "zbar/Video.h" +# include "zbar/Window.h" +# include "zbar/Processor.h" +#endif + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Decoder.h b/hgdriver/ImageProcess/include/zbar/Decoder.h new file mode 100755 index 0000000..b3bad96 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Decoder.h @@ -0,0 +1,202 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_DECODER_H_ +#define _ZBAR_DECODER_H_ + +/// @file +/// Decoder C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Decoder.h" +#endif + +#include + +namespace zbar { + +/// low-level bar width stream decoder interface. +/// identifies symbols and extracts encoded data + +class Decoder { + public: + + /// Decoder result handler. + /// applications should subtype this and pass an instance to + /// set_handler() to implement result processing + class Handler { + public: + virtual ~Handler() { } + + /// invoked by the Decoder as decode results become available. + virtual void decode_callback(Decoder &decoder) = 0; + }; + + /// constructor. + Decoder () + : _handler(NULL) + { + _decoder = zbar_decoder_create(); + } + + ~Decoder () + { + zbar_decoder_destroy(_decoder); + } + + /// clear all decoder state. + /// see zbar_decoder_reset() + void reset () + { + zbar_decoder_reset(_decoder); + } + + /// mark start of a new scan pass. + /// see zbar_decoder_new_scan() + void new_scan () + { + zbar_decoder_new_scan(_decoder); + } + + /// process next bar/space width from input stream. + /// see zbar_decode_width() + zbar_symbol_type_t decode_width (unsigned width) + { + return(zbar_decode_width(_decoder, width)); + } + + /// process next bar/space width from input stream. + /// see zbar_decode_width() + Decoder& operator<< (unsigned width) + { + zbar_decode_width(_decoder, width); + return(*this); + } + + /// retrieve color of @em next element passed to Decoder. + /// see zbar_decoder_get_color() + zbar_color_t get_color () const + { + return(zbar_decoder_get_color(_decoder)); + } + + /// retrieve last decoded symbol type. + /// see zbar_decoder_get_type() + zbar_symbol_type_t get_type () const + { + return(zbar_decoder_get_type(_decoder)); + } + + /// retrieve string name of last decoded symbol type. + /// see zbar_get_symbol_name() + const char *get_symbol_name () const + { + return(zbar_get_symbol_name(zbar_decoder_get_type(_decoder))); + } + + /// retrieve string name for last decode addon. + /// see zbar_get_addon_name() + /// @deprecated in 0.11 + const char *get_addon_name () const + { + return(zbar_get_addon_name(zbar_decoder_get_type(_decoder))); + } + + /// retrieve last decoded data in ASCII format as a char array. + /// see zbar_decoder_get_data() + const char *get_data_chars() const + { + return(zbar_decoder_get_data(_decoder)); + } + + /// retrieve last decoded data as a std::string. + /// see zbar_decoder_get_data() + const std::string get_data_string() const + { + return(std::string(zbar_decoder_get_data(_decoder), + zbar_decoder_get_data_length(_decoder))); + } + + /// retrieve last decoded data as a std::string. + /// see zbar_decoder_get_data() + const std::string get_data() const + { + return(get_data_string()); + } + + /// retrieve length of decoded binary data. + /// see zbar_decoder_get_data_length() + int get_data_length() const + { + return(zbar_decoder_get_data_length(_decoder)); + } + + /// retrieve last decode direction. + /// see zbar_decoder_get_direction() + /// @since 0.11 + int get_direction() const + { + return(zbar_decoder_get_direction(_decoder)); + } + + /// setup callback to handle result data. + void set_handler (Handler &handler) + { + _handler = &handler; + zbar_decoder_set_handler(_decoder, _cb); + zbar_decoder_set_userdata(_decoder, this); + } + + /// set config for indicated symbology (0 for all) to specified value. + /// @see zbar_decoder_set_config() + /// @since 0.4 + int set_config (zbar_symbol_type_t symbology, + zbar_config_t config, + int value) + { + return(zbar_decoder_set_config(_decoder, symbology, config, value)); + } + + /// set config parsed from configuration string. + /// @see zbar_decoder_parse_config() + /// @since 0.4 + int set_config (std::string cfgstr) + { + return(zbar_decoder_parse_config(_decoder, cfgstr.c_str())); + } + + private: + friend class Scanner; + zbar_decoder_t *_decoder; + Handler *_handler; + + static void _cb (zbar_decoder_t *cdcode) + { + Decoder *dcode = (Decoder*)zbar_decoder_get_userdata(cdcode); + if(dcode && dcode->_handler) + dcode->_handler->decode_callback(*dcode); + } +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Exception.h b/hgdriver/ImageProcess/include/zbar/Exception.h new file mode 100755 index 0000000..ebe7020 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Exception.h @@ -0,0 +1,187 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_EXCEPTION_H_ +#define _ZBAR_EXCEPTION_H_ + +/// @file +/// C++ Exception definitions + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Exception.h" +#endif + +#include +#include + +namespace zbar { + +/// base class for exceptions defined by this API. +class Exception : public std::exception { + +public: + /// create exception from C library error + Exception (const void *obj = NULL) + : std::exception(), + _obj(obj) + { } + + ~Exception () throw() { } + + /// retrieve error message + virtual const char* what () const throw() + { + if(!_obj) + return("zbar library unspecified generic error"); + return(_zbar_error_string(_obj, 0)); + } + +private: + const void *_obj; +}; + +/// internal library error. +class InternalError : public Exception { +public: + /// create exception from C library error + InternalError (const void *obj) + : Exception(obj) + { } +}; + +/// unsupported request. +class UnsupportedError : public Exception { +public: + /// create exception from C library error + UnsupportedError (const void *obj) + : Exception(obj) + { } +}; + +/// invalid request. +class InvalidError : public Exception { +public: + /// create exception from C library error + InvalidError (const void *obj) + : Exception(obj) + { } +}; + +/// failed system call. +class SystemError : public Exception { +public: + /// create exception from C library error + SystemError (const void *obj) + : Exception(obj) + { } +}; + +/// locking error. +class LockingError : public Exception { +public: + /// create exception from C library error + LockingError (const void *obj) + : Exception(obj) + { } +}; + +/// all resources busy. +class BusyError : public Exception { +public: + /// create exception from C library error + BusyError (const void *obj) + : Exception(obj) + { } +}; + +/// X11 display error. +class XDisplayError : public Exception { +public: + /// create exception from C library error + XDisplayError (const void *obj) + : Exception(obj) + { } +}; + +/// X11 protocol error. +class XProtoError : public Exception { +public: + /// create exception from C library error + XProtoError (const void *obj) + : Exception(obj) + { } +}; + +/// output window is closed. +class ClosedError : public Exception { +public: + /// create exception from C library error + ClosedError (const void *obj) + : Exception(obj) + { } +}; + +/// image format error +class FormatError : public Exception { + // FIXME needs c equivalent + + virtual const char* what () const throw() + { + // FIXME what format? + return("unsupported format"); + } +}; + +/// @internal + +/// extract error information and create exception. +static __inline std::exception throw_exception (const void *obj) +{ + switch(_zbar_get_error_code(obj)) { + case ZBAR_ERR_NOMEM: + throw std::bad_alloc(); + case ZBAR_ERR_INTERNAL: + throw InternalError(obj); + case ZBAR_ERR_UNSUPPORTED: + throw UnsupportedError(obj); + case ZBAR_ERR_INVALID: + throw InvalidError(obj); + case ZBAR_ERR_SYSTEM: + throw SystemError(obj); + case ZBAR_ERR_LOCKING: + throw LockingError(obj); + case ZBAR_ERR_BUSY: + throw BusyError(obj); + case ZBAR_ERR_XDISPLAY: + throw XDisplayError(obj); + case ZBAR_ERR_XPROTO: + throw XProtoError(obj); + case ZBAR_ERR_CLOSED: + throw ClosedError(obj); + default: + throw Exception(obj); + } +} + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Image.h b/hgdriver/ImageProcess/include/zbar/Image.h new file mode 100755 index 0000000..5fa7c32 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Image.h @@ -0,0 +1,329 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_IMAGE_H_ +#define _ZBAR_IMAGE_H_ + +/// @file +/// Image C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Image.h" +#endif + +#include +#include +#include "Symbol.h" +#include "Exception.h" + +namespace zbar { + +class Video; + +/// stores image data samples along with associated format and size +/// metadata + +class Image { +public: + + /// general Image result handler. + /// applications should subtype this and pass an instance to + /// eg. ImageScanner::set_handler() to implement result processing + class Handler { + public: + virtual ~Handler() { } + + /// invoked by library when Image should be processed + virtual void image_callback(Image &image) = 0; + + /// cast this handler to the C handler + operator zbar_image_data_handler_t* () const + { + return(_cb); + } + + private: + static void _cb (zbar_image_t *zimg, + const void *userdata) + { + if(userdata) { + Image *image = (Image*)zbar_image_get_userdata(zimg); + if(image) + ((Handler*)userdata)->image_callback(*image); + else { + Image tmp(zimg, 1); + ((Handler*)userdata)->image_callback(tmp); + } + } + } + }; + + class SymbolIterator : public zbar::SymbolIterator { + public: + /// default constructor. + SymbolIterator () + : zbar::SymbolIterator() + { } + + /// constructor. + SymbolIterator (const SymbolSet &syms) + : zbar::SymbolIterator(syms) + { } + + /// copy constructor. + SymbolIterator (const SymbolIterator& iter) + : zbar::SymbolIterator(iter) + { } + }; + + /// constructor. + /// create a new Image with the specified parameters + Image (unsigned width = 0, + unsigned height = 0, + const std::string& format = "", + const void *data = NULL, + unsigned long length = 0) + : _img(zbar_image_create()) + { + zbar_image_set_userdata(_img, this); + if(width && height) + set_size(width, height); + if(format.length()) + set_format(format); + if(data && length) + set_data(data, length); + } + + ~Image () + { + if(zbar_image_get_userdata(_img) == this) + zbar_image_set_userdata(_img, NULL); + zbar_image_ref(_img, -1); + } + + /// cast to C image object + operator const zbar_image_t* () const + { + return(_img); + } + + /// cast to C image object + operator zbar_image_t* () + { + return(_img); + } + + /// retrieve the image format. + /// see zbar_image_get_format() + unsigned long get_format () const + { + return(zbar_image_get_format(_img)); + } + + /// specify the fourcc image format code for image sample data. + /// see zbar_image_set_format() + void set_format (unsigned long format) + { + zbar_image_set_format(_img, format); + } + + /// specify the fourcc image format code for image sample data. + /// see zbar_image_set_format() + void set_format (const std::string& format) + { + unsigned long fourcc = zbar_fourcc_parse(format.c_str()); + zbar_image_set_format(_img, fourcc); + } + + /// retrieve a "sequence" (page/frame) number associated with this + /// image. + /// see zbar_image_get_sequence() + /// @since 0.6 + unsigned get_sequence () const + { + return(zbar_image_get_sequence(_img)); + } + + /// associate a "sequence" (page/frame) number with this image. + /// see zbar_image_set_sequence() + /// @since 0.6 + void set_sequence (unsigned sequence_num) + { + zbar_image_set_sequence(_img, sequence_num); + } + + /// retrieve the width of the image. + /// see zbar_image_get_width() + unsigned get_width () const + { + return(zbar_image_get_width(_img)); + } + + /// retrieve the height of the image. + /// see zbar_image_get_height() + unsigned get_height () const + { + return(zbar_image_get_height(_img)); + } + + /// retrieve both dimensions of the image. + /// see zbar_image_get_size() + /// @since 0.11 + void get_size (unsigned &width, + unsigned &height) const + { + zbar_image_get_size(_img, &width, &height); + } + + /// specify the pixel size of the image. + /// see zbar_image_set_size() + void set_size (unsigned width, + unsigned height) + { + zbar_image_set_size(_img, width, height); + } + + /// retrieve the scan crop rectangle. + /// see zbar_image_get_crop() + void get_crop (unsigned &x, + unsigned &y, + unsigned &width, + unsigned &height) const + { + zbar_image_get_crop(_img, &x, &y, &width, &height); + } + + /// set the scan crop rectangle. + /// see zbar_image_set_crop() + void set_crop (unsigned x, + unsigned y, + unsigned width, + unsigned height) + { + zbar_image_set_crop(_img, x, y, width, height); + } + + /// return the image sample data. + /// see zbar_image_get_data() + const void *get_data () const + { + return(zbar_image_get_data(_img)); + } + + /// return the size of the image sample data. + /// see zbar_image_get_data_length() + /// @since 0.6 + unsigned long get_data_length () const + { + return(zbar_image_get_data_length(_img)); + } + + /// specify image sample data. + /// see zbar_image_set_data() + void set_data (const void *data, + unsigned long length) + { + zbar_image_set_data(_img, data, length, _cleanup); + } + + /// image format conversion. + /// see zbar_image_convert() + Image convert (unsigned long format) const + { + zbar_image_t *img = zbar_image_convert(_img, format); + if(img) + return(Image(img)); + throw FormatError(); + } + + /// image format conversion. + /// see zbar_image_convert() + /// @since 0.11 + Image convert (std::string format) const + { + unsigned long fourcc = zbar_fourcc_parse(format.c_str()); + return(convert(fourcc)); + } + + /// image format conversion with crop/pad. + /// see zbar_image_convert_resize() + /// @since 0.4 + Image convert (unsigned long format, + unsigned width, + unsigned height) const + { + zbar_image_t *img = + zbar_image_convert_resize(_img, format, width, height); + if(img) + return(Image(img)); + throw FormatError(); + } + + const SymbolSet get_symbols () const { + return(SymbolSet(zbar_image_get_symbols(_img))); + } + + void set_symbols (const SymbolSet &syms) { + zbar_image_set_symbols(_img, syms); + } + + /// create a new SymbolIterator over decoded results. + SymbolIterator symbol_begin () const { + return(SymbolIterator(get_symbols())); + } + + /// return a SymbolIterator suitable for ending iteration. + SymbolIterator symbol_end () const { + return(SymbolIterator()); + } + +protected: + + friend class Video; + + /// constructor. + /// @internal + /// create a new Image from a zbar_image_t C object + Image (zbar_image_t *src, + int refs = 0) + : _img(src) + { + if(refs) + zbar_image_ref(_img, refs); + zbar_image_set_userdata(_img, this); + } + + /// default data cleanup (noop) + /// @internal + static void _cleanup (zbar_image_t *img) + { + // by default nothing is cleaned + assert(img); + } + +private: + zbar_image_t *_img; +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/ImageScanner.h b/hgdriver/ImageProcess/include/zbar/ImageScanner.h new file mode 100755 index 0000000..2c9350d --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/ImageScanner.h @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_IMAGE_SCANNER_H_ +#define _ZBAR_IMAGE_SCANNER_H_ + +/// @file +/// Image Scanner C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/ImageScanner.h" +#endif + +#include "Image.h" + +namespace zbar { + +/// mid-level image scanner interface. +/// reads barcodes from a 2-D Image + +class ImageScanner { +public: + /// constructor. + ImageScanner (zbar_image_scanner_t *scanner = NULL) + { + if(scanner) + _scanner = scanner; + else + _scanner = zbar_image_scanner_create(); + } + + ~ImageScanner () + { + zbar_image_scanner_destroy(_scanner); + } + + /// cast to C image_scanner object + operator zbar_image_scanner_t* () const + { + return(_scanner); + } + + /// setup result handler callback. + void set_handler (Image::Handler &handler) + { + zbar_image_scanner_set_data_handler(_scanner, handler, &handler); + } + + /// set config for indicated symbology (0 for all) to specified value. + /// @see zbar_image_scanner_set_config() + /// @since 0.4 + int set_config (zbar_symbol_type_t symbology, + zbar_config_t config, + int value) + { + return(zbar_image_scanner_set_config(_scanner, symbology, + config, value)); + } + + /// set config parsed from configuration string. + /// @see zbar_image_scanner_parse_config() + /// @since 0.4 + int set_config (std::string cfgstr) + { + return(zbar_image_scanner_parse_config(_scanner, cfgstr.c_str())); + } + + /// enable or disable the inter-image result cache. + /// see zbar_image_scanner_enable_cache() + void enable_cache (bool enable = true) + { + zbar_image_scanner_enable_cache(_scanner, enable); + } + + /// remove previous results from scanner and image. + /// @see zbar_image_scanner_recycle_image() + /// @since 0.10 + void recycle_image (Image &image) + { + zbar_image_scanner_recycle_image(_scanner, image); + } + + /// retrieve decode results for last scanned image. + /// @see zbar_image_scanner_get_results() + /// @since 0.10 + const SymbolSet get_results () const { + return(SymbolSet(zbar_image_scanner_get_results(_scanner))); + } + + /// scan for symbols in provided image. + /// see zbar_scan_image() + int scan (Image& image) + { + return(zbar_scan_image(_scanner, image)); + } + + /// scan for symbols in provided image. + /// see zbar_scan_image() + ImageScanner& operator<< (Image& image) + { + scan(image); + return(*this); + } + +private: + zbar_image_scanner_t *_scanner; +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Processor.h b/hgdriver/ImageProcess/include/zbar/Processor.h new file mode 100755 index 0000000..cf1e783 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Processor.h @@ -0,0 +1,223 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_PROCESSOR_H_ +#define _ZBAR_PROCESSOR_H_ + +/// @file +/// Processor C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Processor.h" +#endif + +#include "Exception.h" +#include "Image.h" + +namespace zbar { + +/// high-level self-contained image processor. +/// processes video and images for barcodes, optionally displaying +/// images to a library owned output window + +class Processor { + public: + /// value to pass for no timeout. + static const int FOREVER = -1; + + /// constructor. + Processor (bool threaded = true, + const char *video_device = "", + bool enable_display = true) + { + _processor = zbar_processor_create(threaded); + if(!_processor) + throw std::bad_alloc(); + init(video_device, enable_display); + } + + ~Processor () + { + zbar_processor_destroy(_processor); + } + + /// cast to C processor object. + operator zbar_processor_t* () + { + return(_processor); + } + + /// opens a video input device and/or prepares to display output. + /// see zbar_processor_init() + void init (const char *video_device = "", + bool enable_display = true) + { + if(zbar_processor_init(_processor, video_device, enable_display)) + throw_exception(_processor); + } + + /// setup result handler callback. + /// see zbar_processor_set_data_handler() + void set_handler (Image::Handler& handler) + { + zbar_processor_set_data_handler(_processor, handler, &handler); + } + + /// set config for indicated symbology (0 for all) to specified value. + /// @see zbar_processor_set_config() + /// @since 0.4 + int set_config (zbar_symbol_type_t symbology, + zbar_config_t config, + int value) + { + return(zbar_processor_set_config(_processor, symbology, + config, value)); + } + + /// set config parsed from configuration string. + /// @see zbar_processor_parse_config() + /// @since 0.4 + int set_config (std::string cfgstr) + { + return(zbar_processor_parse_config(_processor, cfgstr.c_str())); + } + + /// retrieve the current state of the ouput window. + /// see zbar_processor_is_visible() + bool is_visible () + { + int rc = zbar_processor_is_visible(_processor); + if(rc < 0) + throw_exception(_processor); + return(rc != 0); + } + + /// show or hide the display window owned by the library. + /// see zbar_processor_set_visible() + void set_visible (bool visible = true) + { + if(zbar_processor_set_visible(_processor, visible) < 0) + throw_exception(_processor); + } + + /// control the processor in free running video mode. + /// see zbar_processor_set_active() + void set_active (bool active = true) + { + if(zbar_processor_set_active(_processor, active) < 0) + throw_exception(_processor); + } + + /// retrieve decode results for last scanned image. + /// @see zbar_processor_get_results() + /// @since 0.10 + const SymbolSet get_results () const { + return(SymbolSet(zbar_processor_get_results(_processor))); + } + + /// wait for input to the display window from the user. + /// see zbar_processor_user_wait() + int user_wait (int timeout = FOREVER) + { + int rc = zbar_processor_user_wait(_processor, timeout); + if(rc < 0) + throw_exception(_processor); + return(rc); + } + + /// process from the video stream until a result is available. + /// see zbar_process_one() + void process_one (int timeout = FOREVER) + { + if(zbar_process_one(_processor, timeout) < 0) + throw_exception(_processor); + } + + /// process the provided image for barcodes. + /// see zbar_process_image() + void process_image (Image& image) + { + if(zbar_process_image(_processor, image) < 0) + throw_exception(_processor); + } + + /// process the provided image for barcodes. + /// see zbar_process_image() + Processor& operator<< (Image& image) + { + process_image(image); + return(*this); + } + + /// force specific input and output formats for debug/testing. + /// see zbar_processor_force_format() + void force_format (unsigned long input_format, + unsigned long output_format) + { + if(zbar_processor_force_format(_processor, input_format, + output_format)) + throw_exception(_processor); + } + + /// force specific input and output formats for debug/testing. + /// see zbar_processor_force_format() + void force_format (std::string& input_format, + std::string& output_format) + { + unsigned long ifourcc = zbar_fourcc_parse(input_format.c_str()); + unsigned long ofourcc = zbar_fourcc_parse(output_format.c_str()); + if(zbar_processor_force_format(_processor, ifourcc, ofourcc)) + throw_exception(_processor); + } + + /// request a preferred size for the video image from the device. + /// see zbar_processor_request_size() + /// @since 0.6 + void request_size (int width, int height) + { + zbar_processor_request_size(_processor, width, height); + } + + /// request a preferred driver interface version for debug/testing. + /// see zbar_processor_request_interface() + /// @since 0.6 + void request_interface (int version) + { + zbar_processor_request_interface(_processor, version); + } + + /// request a preferred I/O mode for debug/testing. + /// see zbar_processor_request_iomode() + /// @since 0.7 + void request_iomode (int iomode) + { + if(zbar_processor_request_iomode(_processor, iomode)) + throw_exception(_processor); + } + + private: + zbar_processor_t *_processor; +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/QZBar.h b/hgdriver/ImageProcess/include/zbar/QZBar.h new file mode 100755 index 0000000..db7147a --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/QZBar.h @@ -0,0 +1,169 @@ +//------------------------------------------------------------------------ +// Copyright 2008-2009 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _QZBAR_H_ +#define _QZBAR_H_ + +/// @file +/// Barcode Reader Qt4 Widget + +#include + +namespace zbar { + +class QZBarThread; + +/// barcode reader Qt4 widget. +/// embeds a barcode reader directly into a Qt4 based GUI. the widget +/// can process barcodes from a video source (using the QZBar::videoDevice +/// and QZBar::videoEnabled properties) or from individual QImages +/// supplied to the QZBar::scanImage() slot +/// @since 1.5 + +class QZBar : public QWidget +{ + Q_OBJECT + + /// the currently opened video device. + /// + /// setting a new device opens it and automatically sets + /// QZBar::videoEnabled + /// + /// @see videoDevice(), setVideoDevice() + Q_PROPERTY(QString videoDevice + READ videoDevice + WRITE setVideoDevice + DESIGNABLE false) + + /// video device streaming state. + /// + /// use to pause/resume video scanning. + /// + /// @see isVideoEnabled(), setVideoEnabled() + Q_PROPERTY(bool videoEnabled + READ isVideoEnabled + WRITE setVideoEnabled + DESIGNABLE false) + + /// video device opened state. + /// + /// (re)setting QZBar::videoDevice should eventually cause it + /// to be opened or closed. any errors while streaming/scanning + /// will also cause the device to be closed + /// + /// @see isVideoOpened() + Q_PROPERTY(bool videoOpened + READ isVideoOpened + DESIGNABLE false) + +public: + + /// constructs a barcode reader widget with the given @a parent + QZBar(QWidget *parent = NULL); + + ~QZBar(); + + /// retrieve the currently opened video device. + /// @returns the current video device or the empty string if no + /// device is opened + QString videoDevice() const; + + /// retrieve the current video enabled state. + /// @returns true if video scanning is currently enabled, false + /// otherwise + bool isVideoEnabled() const; + + /// retrieve the current video opened state. + /// @returns true if video device is currently opened, false otherwise + bool isVideoOpened() const; + + /// @{ + /// @internal + + QSize sizeHint() const; + int heightForWidth(int) const; + QPaintEngine *paintEngine() const; + + /// @} + +public Q_SLOTS: + + /// open a new video device. + /// + /// use an empty string to close a currently opened device. + /// + /// @note since opening a device may take some time, this call will + /// return immediately and the device will be opened asynchronously + void setVideoDevice(const QString &videoDevice); + + /// enable/disable video scanning. + /// has no effect unless a video device is opened + void setVideoEnabled(bool videoEnabled = true); + + /// scan for barcodes in a QImage. + void scanImage(const QImage &image); + +Q_SIGNALS: + /// emitted when when a video device is opened or closed. + /// + /// (re)setting QZBar::videoDevice should eventually cause it + /// to be opened or closed. any errors while streaming/scanning + /// will also cause the device to be closed + void videoOpened(bool videoOpened); + + /// emitted when a barcode is decoded from an image. + /// the symbol type and contained data are provided as separate + /// parameters. + void decoded(int type, const QString &data); + + /// emitted when a barcode is decoded from an image. + /// the symbol type name is prefixed to the data, separated by a + /// colon + void decodedText(const QString &text); + + /// @{ + /// @internal + +protected: + void attach(); + void showEvent(QShowEvent*); + void paintEvent(QPaintEvent*); + void resizeEvent(QResizeEvent*); + void changeEvent(QEvent*); + void dragEnterEvent(QDragEnterEvent*); + void dropEvent(QDropEvent*); + +protected Q_SLOTS: + void sizeChange(); + + /// @} + +private: + QZBarThread *thread; + QString _videoDevice; + bool _videoEnabled; + bool _attached; +}; + +}; + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/QZBarImage.h b/hgdriver/ImageProcess/include/zbar/QZBarImage.h new file mode 100755 index 0000000..dbd506e --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/QZBarImage.h @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------ +// Copyright 2008-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _QZBARIMAGE_H_ +#define _QZBARIMAGE_H_ + +/// @file +/// QImage to Image type conversion wrapper + +#include +#include + +namespace zbar { + +/// wrap a QImage and convert into a format suitable for scanning. + +class QZBarImage + : public Image +{ +public: + + /// construct a zbar library image based on an existing QImage. + + QZBarImage (const QImage &qimg) + : qimg(qimg) + { + QImage::Format fmt = qimg.format(); + if(fmt != QImage::Format_RGB32 && + fmt != QImage::Format_ARGB32 && + fmt != QImage::Format_ARGB32_Premultiplied) + throw FormatError(); + + unsigned bpl = qimg.bytesPerLine(); + unsigned width = bpl / 4; + unsigned height = qimg.height(); + set_size(width, height); + set_format(zbar_fourcc('B','G','R','4')); + unsigned long datalen = qimg.numBytes(); + set_data(qimg.bits(), datalen); + + if((width * 4 != bpl) || + (width * height * 4 > datalen)) + throw FormatError(); + } + +private: + QImage qimg; +}; + +}; + + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Scanner.h b/hgdriver/ImageProcess/include/zbar/Scanner.h new file mode 100755 index 0000000..ae367c6 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Scanner.h @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_SCANNER_H_ +#define _ZBAR_SCANNER_H_ + +/// @file +/// Scanner C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Scanner.h" +#endif + +#include + +namespace zbar { + +/// low-level linear intensity sample stream scanner interface. +/// identifies "bar" edges and measures width between them. +/// optionally passes to bar width Decoder + +class Scanner { + public: + + /// constructor. + /// @param decoder reference to a Decoder instance which will + /// be passed scan results automatically + Scanner (Decoder& decoder) + { + _scanner = zbar_scanner_create(decoder._decoder); + } + + /// constructor. + /// @param decoder pointer to a Decoder instance which will + /// be passed scan results automatically + Scanner (Decoder* decoder = NULL) + { + zbar_decoder_t *zdcode = NULL; + if(decoder) + zdcode = decoder->_decoder; + _scanner = zbar_scanner_create(zdcode); + } + + ~Scanner () + { + zbar_scanner_destroy(_scanner); + } + + /// clear all scanner state. + /// see zbar_scanner_reset() + void reset () + { + zbar_scanner_reset(_scanner); + } + + /// mark start of a new scan pass. + /// see zbar_scanner_new_scan() + zbar_symbol_type_t new_scan () + { + _type = zbar_scanner_new_scan(_scanner); + return(_type); + } + + /// flush scanner pipeline. + /// see zbar_scanner_flush() + zbar_symbol_type_t flush () + { + _type = zbar_scanner_flush(_scanner); + return(_type); + } + + /// process next sample intensity value. + /// see zbar_scan_y() + zbar_symbol_type_t scan_y (int y) + { + _type = zbar_scan_y(_scanner, y); + return(_type); + } + + /// process next sample intensity value. + /// see zbar_scan_y() + Scanner& operator<< (int y) + { + _type = zbar_scan_y(_scanner, y); + return(*this); + } + + /// process next sample from RGB (or BGR) triple. + /// see zbar_scan_rgb24() + zbar_symbol_type_t scan_rgb24 (unsigned char *rgb) + { + _type = zbar_scan_rgb24(_scanner, rgb); + return(_type); + } + + /// process next sample from RGB (or BGR) triple. + /// see zbar_scan_rgb24() + Scanner& operator<< (unsigned char *rgb) + { + _type = zbar_scan_rgb24(_scanner, rgb); + return(*this); + } + + /// retrieve last scanned width. + /// see zbar_scanner_get_width() + unsigned get_width () const + { + return(zbar_scanner_get_width(_scanner)); + } + + /// retrieve last scanned color. + /// see zbar_scanner_get_color() + zbar_color_t get_color () const + { + return(zbar_scanner_get_color(_scanner)); + } + + /// retrieve last scan result. + zbar_symbol_type_t get_type () const + { + return(_type); + } + + /// cast to C scanner + operator zbar_scanner_t* () const + { + return(_scanner); + } + + /// retrieve C scanner + const zbar_scanner_t *get_c_scanner () const + { + return(_scanner); + } + + private: + zbar_scanner_t *_scanner; + zbar_symbol_type_t _type; +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Symbol.h b/hgdriver/ImageProcess/include/zbar/Symbol.h new file mode 100755 index 0000000..6ed2842 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Symbol.h @@ -0,0 +1,541 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_SYMBOL_H_ +#define _ZBAR_SYMBOL_H_ + +/// @file +/// Symbol C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Symbol.h" +#endif + +#include +#include +#include +#include + +namespace zbar { + +class SymbolIterator; + +/// container for decoded result symbols associated with an image +/// or a composite symbol. + +class SymbolSet { +public: + /// constructor. + SymbolSet (const zbar_symbol_set_t *syms = NULL) + : _syms(syms) + { + ref(); + } + + /// copy constructor. + SymbolSet (const SymbolSet& syms) + : _syms(syms._syms) + { + ref(); + } + + /// destructor. + ~SymbolSet () + { + ref(-1); + } + + /// assignment. + SymbolSet& operator= (const SymbolSet& syms) + { + syms.ref(); + ref(-1); + _syms = syms._syms; + return(*this); + } + + /// truth testing. + bool operator! () const + { + return(!_syms || !get_size()); + } + + /// manipulate reference count. + void ref (int delta = 1) const + { + if(_syms) + zbar_symbol_set_ref((zbar_symbol_set_t*)_syms, delta); + } + + /// cast to C symbol set. + operator const zbar_symbol_set_t* () const + { + return(_syms); + } + + int get_size () const + { + return((_syms) ? zbar_symbol_set_get_size(_syms) : 0); + } + + /// create a new SymbolIterator over decoded results. + SymbolIterator symbol_begin() const; + + /// return a SymbolIterator suitable for ending iteration. + const SymbolIterator symbol_end() const; + +private: + const zbar_symbol_set_t *_syms; +}; + +/// decoded barcode symbol result object. stores type, data, and +/// image location of decoded symbol + +class Symbol { +public: + + /// image pixel location (x, y) coordinate tuple. + class Point { + public: + int x; ///< x-coordinate. + int y; ///< y-coordinate. + + Point () { } + + Point(int x, int y) + : x(x), y(y) + { } + + /// copy constructor. + Point (const Point& pt) + : x(pt.x), + y(pt.y) + { } + + /// assignment. + Point& operator= (const Point& pt) + { + x = pt.x; + y = pt.y; + return(*this); + } + }; + + /// iteration over Point objects in a symbol location polygon. + class PointIterator + : public std::iterator { + + public: + /// constructor. + PointIterator (const Symbol *sym = NULL, + int index = 0) + : _sym(sym), + _index(index) + { + if(sym) + sym->ref(1); + if(!sym || + (unsigned)_index >= zbar_symbol_get_loc_size(*_sym)) + _index = -1; + } + + /// copy constructor. + PointIterator (const PointIterator& iter) + : _sym(iter._sym), + _index(iter._index) + { + if(_sym) + _sym->ref(); + } + + /// destructor. + ~PointIterator () + { + if(_sym) + _sym->ref(-1); + } + + /// assignment. + PointIterator& operator= (const PointIterator& iter) + { + if(iter._sym) + iter._sym->ref(); + if(_sym) + _sym->ref(-1); + _sym = iter._sym; + _index = iter._index; + return(*this); + } + + /// truth testing. + bool operator! () const + { + return(!_sym || _index < 0); + } + + /// advance iterator to next Point. + PointIterator& operator++ () + { + unsigned int i = ++_index; + if(!_sym || i >= zbar_symbol_get_loc_size(*_sym)) + _index = -1; + return(*this); + } + + /// retrieve currently referenced Point. + const Point operator* () const + { + assert(!!*this); + if(!*this) + return(Point()); + return(Point(zbar_symbol_get_loc_x(*_sym, _index), + zbar_symbol_get_loc_y(*_sym, _index))); + } + + /// test if two iterators refer to the same Point in the same + /// Symbol. + bool operator== (const PointIterator& iter) const + { + return(_index == iter._index && + ((_index < 0) || _sym == iter._sym)); + } + + /// test if two iterators refer to the same Point in the same + /// Symbol. + bool operator!= (const PointIterator& iter) const + { + return(!(*this == iter)); + } + + private: + const Symbol *_sym; + int _index; + }; + + /// constructor. + Symbol (const zbar_symbol_t *sym = NULL) + : _xmlbuf(NULL), + _xmllen(0) + { + init(sym); + ref(); + } + + /// copy constructor. + Symbol (const Symbol& sym) + : _sym(sym._sym), + _type(sym._type), + _data(sym._data), + _xmlbuf(NULL), + _xmllen(0) + { + ref(); + } + + /// destructor. + ~Symbol () { + if(_xmlbuf) + free(_xmlbuf); + ref(-1); + } + + /// assignment. + Symbol& operator= (const Symbol& sym) + { + sym.ref(1); + ref(-1); + _sym = sym._sym; + _type = sym._type; + _data = sym._data; + return(*this); + } + + Symbol& operator= (const zbar_symbol_t *sym) + { + if(sym) + zbar_symbol_ref(sym, 1); + ref(-1); + init(sym); + return(*this); + } + + /// truth testing. + bool operator! () const + { + return(!_sym); + } + + void ref (int delta = 1) const + { + if(_sym) + zbar_symbol_ref((zbar_symbol_t*)_sym, delta); + } + + /// cast to C symbol. + operator const zbar_symbol_t* () const + { + return(_sym); + } + + /// test if two Symbol objects refer to the same C symbol. + bool operator== (const Symbol& sym) const + { + return(_sym == sym._sym); + } + + /// test if two Symbol objects refer to the same C symbol. + bool operator!= (const Symbol& sym) const + { + return(!(*this == sym)); + } + + /// retrieve type of decoded symbol. + zbar_symbol_type_t get_type () const + { + return(_type); + } + + /// retrieve the string name of the symbol type. + const std::string get_type_name () const + { + return(zbar_get_symbol_name(_type)); + } + + /// retrieve the string name for any addon. + /// @deprecated in 0.11 + const std::string get_addon_name () const + { + return(zbar_get_addon_name(_type)); + } + + /// retrieve data decoded from symbol. + const std::string get_data () const + { + return(_data); + } + + /// retrieve length of binary data + unsigned get_data_length () const + { + return((_sym) ? zbar_symbol_get_data_length(_sym) : 0); + } + + /// retrieve inter-frame coherency count. + /// see zbar_symbol_get_count() + /// @since 0.5 + int get_count () const + { + return((_sym) ? zbar_symbol_get_count(_sym) : -1); + } + + /// retrieve loosely defined relative quality metric. + /// see zbar_symbol_get_quality() + /// @since 0.11 + int get_quality () const + { + return((_sym) ? zbar_symbol_get_quality(_sym) : 0); + } + + SymbolSet get_components () const + { + return(SymbolSet((_sym) ? zbar_symbol_get_components(_sym) : NULL)); + } + + /// create a new PointIterator at the start of the location + /// polygon. + PointIterator point_begin() const + { + return(PointIterator(this)); + } + + /// return a PointIterator suitable for ending iteration. + const PointIterator point_end() const + { + return(PointIterator()); + } + + /// see zbar_symbol_get_loc_size(). + int get_location_size () const + { + return((_sym) ? zbar_symbol_get_loc_size(_sym) : 0); + } + + /// see zbar_symbol_get_loc_x(). + int get_location_x (unsigned index) const + { + return((_sym) ? zbar_symbol_get_loc_x(_sym, index) : -1); + } + + /// see zbar_symbol_get_loc_y(). + int get_location_y (unsigned index) const + { + return((_sym) ? zbar_symbol_get_loc_y(_sym, index) : -1); + } + + /// see zbar_symbol_get_orientation(). + /// @since 0.11 + int get_orientation () const + { + return(zbar_symbol_get_orientation(_sym)); + } + + /// see zbar_symbol_xml(). + const std::string xml () const + { + if(!_sym) + return(""); + return(zbar_symbol_xml(_sym, (char**)&_xmlbuf, (unsigned*)&_xmllen)); + } + +protected: + /// (re)initialize Symbol from C symbol object. + void init (const zbar_symbol_t *sym = NULL) + { + _sym = sym; + if(sym) { + _type = zbar_symbol_get_type(sym); + _data = std::string(zbar_symbol_get_data(sym), + zbar_symbol_get_data_length(sym)); + } + else { + _type = ZBAR_NONE; + _data = ""; + } + } + +private: + const zbar_symbol_t *_sym; + zbar_symbol_type_t _type; + std::string _data; + char *_xmlbuf; + unsigned _xmllen; +}; + +/// iteration over Symbol result objects in a scanned Image or SymbolSet. +class SymbolIterator + : public std::iterator { + +public: + /// default constructor. + SymbolIterator () + { } + + /// constructor. + SymbolIterator (const SymbolSet &syms) + : _syms(syms) + { + const zbar_symbol_set_t *zsyms = _syms; + if(zsyms) + _sym = zbar_symbol_set_first_symbol(zsyms); + } + + /// copy constructor. + SymbolIterator (const SymbolIterator& iter) + : _syms(iter._syms) + { + const zbar_symbol_set_t *zsyms = _syms; + if(zsyms) + _sym = zbar_symbol_set_first_symbol(zsyms); + } + + ~SymbolIterator () + { + } + + /// assignment. + SymbolIterator& operator= (const SymbolIterator& iter) + { + _syms = iter._syms; + _sym = iter._sym; + return(*this); + } + + bool operator! () const + { + return(!_syms || !_sym); + } + + /// advance iterator to next Symbol. + SymbolIterator& operator++ () + { + if(!!_sym) + _sym = zbar_symbol_next(_sym); + else if(!!_syms) + _sym = zbar_symbol_set_first_symbol(_syms); + return(*this); + } + + /// retrieve currently referenced Symbol. + const Symbol operator* () const + { + return(_sym); + } + + /// access currently referenced Symbol. + const Symbol* operator-> () const + { + return(&_sym); + } + + /// test if two iterators refer to the same Symbol + bool operator== (const SymbolIterator& iter) const + { + // it is enough to test the symbols, as they belong + // to only one set (also simplifies invalid case) + return(_sym == iter._sym); + } + + /// test if two iterators refer to the same Symbol + bool operator!= (const SymbolIterator& iter) const + { + return(!(*this == iter)); + } + + const SymbolIterator end () const { + return(SymbolIterator()); + } + +private: + SymbolSet _syms; + Symbol _sym; +}; + +__inline SymbolIterator SymbolSet::symbol_begin () const { + return(SymbolIterator(*this)); +} + +__inline const SymbolIterator SymbolSet::symbol_end () const { + return(SymbolIterator()); +} + +/// @relates Symbol +/// stream the string representation of a Symbol. +static __inline std::ostream& operator<< (std::ostream& out, + const Symbol& sym) +{ + out << sym.get_type_name() << ":" << sym.get_data(); + return(out); +} + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Video.h b/hgdriver/ImageProcess/include/zbar/Video.h new file mode 100755 index 0000000..48d1f46 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Video.h @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2010 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_VIDEO_H_ +#define _ZBAR_VIDEO_H_ + +/// @file +/// Video Input C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Video.h" +#endif + +#include "Image.h" + +namespace zbar { + +/// mid-level video source abstraction. +/// captures images from a video device + +class Video { +public: + /// constructor. + Video (zbar_video_t *video = NULL) + { + if(video) + _video = video; + else + _video = zbar_video_create(); + } + + /// constructor. + Video (std::string& device) + { + _video = zbar_video_create(); + open(device); + } + + ~Video () + { + zbar_video_destroy(_video); + } + + /// cast to C video object. + operator zbar_video_t* () const + { + return(_video); + } + + /// open and probe a video device. + void open (std::string& device) + { + if(zbar_video_open(_video, device.c_str())) + throw_exception(_video); + } + + /// close video device if open. + void close () + { + if(zbar_video_open(_video, NULL)) + throw_exception(_video); + } + + /// initialize video using a specific format for debug. + /// see zbar_video_init() + void init (unsigned long fourcc) + { + if(zbar_video_init(_video, fourcc)) + throw_exception(_video); + } + + /// initialize video using a specific format for debug. + /// see zbar_video_init() + void init (std::string& format) + { + unsigned int fourcc = zbar_fourcc_parse(format.c_str()); + if(zbar_video_init(_video, fourcc)) + throw_exception(_video); + } + + /// retrieve file descriptor associated with open *nix video device. + /// see zbar_video_get_fd() + int get_fd () + { + return(zbar_video_get_fd(_video)); + } + + /// retrieve current output image width. + /// see zbar_video_get_width() + int get_width () + { + return(zbar_video_get_width(_video)); + } + + /// retrieve current output image height. + /// see zbar_video_get_height() + int get_height () + { + return(zbar_video_get_height(_video)); + } + + /// start/stop video capture. + /// see zbar_video_enable() + void enable (bool enable = true) + { + if(zbar_video_enable(_video, enable)) + throw_exception(_video); + } + + /// retrieve next captured image. + /// see zbar_video_next_image() + Image next_image () + { + zbar_image_t *img = zbar_video_next_image(_video); + if(!img) + throw_exception(_video); + return(Image(img)); + } + + /// request a preferred size for the video image from the device. + /// see zbar_video_request_size() + /// @since 0.6 + void request_size (int width, int height) + { + zbar_video_request_size(_video, width, height); + } + + /// request a preferred driver interface version for debug/testing. + /// see zbar_video_request_interface() + /// @since 0.6 + void request_interface (int version) + { + zbar_video_request_interface(_video, version); + } + + /// request a preferred I/O mode for debug/testing. + /// see zbar_video_request_iomode() + /// @since 0.7 + void request_iomode (int iomode) + { + if(zbar_video_request_iomode(_video, iomode)) + throw_exception(_video); + } + +private: + zbar_video_t *_video; +}; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/Window.h b/hgdriver/ImageProcess/include/zbar/Window.h new file mode 100755 index 0000000..6c40488 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/Window.h @@ -0,0 +1,136 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ +#ifndef _ZBAR_WINDOW_H_ +#define _ZBAR_WINDOW_H_ + +/// @file +/// Output Window C++ wrapper + +#ifndef _ZBAR_H_ +# error "include zbar.h in your application, **not** zbar/Window.h" +#endif + +#include "Image.h" + +namespace zbar { + +/// mid-level output window abstraction. +/// displays images to user-specified platform specific output window + +class Window { +public: + /// constructor. + Window (zbar_window_t *window = NULL) + { + if(window) + _window = window; + else + _window = zbar_window_create(); + } + + /// constructor. + Window (void *x11_display_w32_hwnd, + unsigned long x11_drawable) + { + _window = zbar_window_create(); + attach(x11_display_w32_hwnd, x11_drawable); + } + + ~Window () + { + zbar_window_destroy(_window); + } + + /// cast to C window object. + operator zbar_window_t* () const + { + return(_window); + } + + /// associate reader with an existing platform window. + /// see zbar_window_attach() + void attach (void *x11_display_w32_hwnd, + unsigned long x11_drawable = 0) + { + if(zbar_window_attach(_window, + x11_display_w32_hwnd, x11_drawable) < 0) + throw_exception(_window); + } + + /// control content level of the reader overlay. + /// see zbar_window_set_overlay() + void set_overlay (int level) + { + zbar_window_set_overlay(_window, level); + } + + /// retrieve current content level of reader overlay. + /// see zbar_window_get_overlay() + + /// draw a new image into the output window. + /// see zbar_window_draw() + void draw (Image& image) + { + if(zbar_window_draw(_window, image) < 0) + throw_exception(_window); + } + + /// clear the image from the output window. + /// see zbar_window_draw() + void clear () + { + if(zbar_window_draw(_window, NULL) < 0) + throw_exception(_window); + } + + /// redraw the last image. + /// zbar_window_redraw() + void redraw () + { + if(zbar_window_redraw(_window) < 0) + throw_exception(_window); + } + + /// resize the image window. + /// zbar_window_resize() + void resize (unsigned width, unsigned height) + { + if(zbar_window_resize(_window, width, height) < 0) + throw_exception(_window); + } + +private: + zbar_window_t *_window; +}; + +/// select a compatible format between video input and output window. +/// see zbar_negotiate_format() +static inline void negotiate_format (Video& video, Window& window) +{ + if(zbar_negotiate_format(video, window) < 0) + throw_exception(video); +} + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zbar/zbargtk.h b/hgdriver/ImageProcess/include/zbar/zbargtk.h new file mode 100755 index 0000000..d3d7440 --- /dev/null +++ b/hgdriver/ImageProcess/include/zbar/zbargtk.h @@ -0,0 +1,215 @@ +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ +#ifndef __ZBAR_GTK_H__ +#define __ZBAR_GTK_H__ + +/** SECTION:ZBarGtk + * @short_description: barcode reader GTK+ 2.x widget + * @include: zbar/zbargtk.h + * + * embeds a barcode reader directly into a GTK+ based GUI. the widget + * can process barcodes from a video source (using the + * #ZBarGtk:video-device and #ZBarGtk:video-enabled properties) or + * from individual GdkPixbufs supplied to zbar_gtk_scan_image() + * + * Since: 1.5 + */ + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define ZBAR_TYPE_GTK (zbar_gtk_get_type()) +#define ZBAR_GTK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), ZBAR_TYPE_GTK, ZBarGtk)) +#define ZBAR_GTK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), ZBAR_TYPE_GTK, ZBarGtkClass)) +#define ZBAR_IS_GTK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), ZBAR_TYPE_GTK)) +#define ZBAR_IS_GTK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), ZBAR_TYPE_GTK)) +#define ZBAR_GTK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), ZBAR_TYPE_GTK, ZBarGtkClass)) + +typedef struct _ZBarGtk ZBarGtk; +typedef struct _ZBarGtkClass ZBarGtkClass; + +struct _ZBarGtk { + GtkWidget widget; + gpointer *_private; + + /* properties */ + + /** + * ZBarGtk:video-device: + * + * the currently set video device. + * + * setting a new device opens it and automatically sets + * #ZBarGtk:video-enabled. set the empty string ("") or NULL to + * close. + */ + + /** + * ZBarGtk:video-enabled: + * + * video device streaming state. + * + * use to pause/resume video scanning. + */ + + /** + * ZBarGtk:video-opened: + * + * video device opened state. + * + * (re)setting #ZBarGtk:video-device should eventually cause it + * to be opened or closed. any errors while streaming/scanning + * will also cause the device to be closed + */ +}; + +struct _ZBarGtkClass { + GtkWidgetClass parent_class; + + /* signals */ + + /** + * ZBarGtk::decoded: + * @widget: the object that received the signal + * @symbol_type: the type of symbol decoded (a zbar_symbol_type_t) + * @data: the data decoded from the symbol + * + * emitted when a barcode is decoded from an image. + * the symbol type and contained data are provided as separate + * parameters + */ + void (*decoded) (ZBarGtk *zbar, + zbar_symbol_type_t symbol_type, + const char *data); + + /** + * ZBarGtk::decoded-text: + * @widget: the object that received the signal + * @text: the decoded data prefixed by the string name of the + * symbol type (separated by a colon) + * + * emitted when a barcode is decoded from an image. + * the symbol type name is prefixed to the data, separated by a + * colon + */ + void (*decoded_text) (ZBarGtk *zbar, + const char *text); + + /** + * ZBarGtk::scan-image: + * @widget: the object that received the signal + * @image: the image to scan for barcodes + */ + void (*scan_image) (ZBarGtk *zbar, + GdkPixbuf *image); +}; + +GType zbar_gtk_get_type(void) G_GNUC_CONST; + +/** + * zbar_gtk_new: + * create a new barcode reader widget instance. + * initially has no associated video device or image. + * + * Returns: a new #ZBarGtk widget instance + */ +GtkWidget *zbar_gtk_new(void); + +/** + * zbar_gtk_scan_image: + * + */ +void zbar_gtk_scan_image(ZBarGtk *zbar, + GdkPixbuf *image); + +/** retrieve the currently opened video device. + * + * Returns: the current video device or NULL if no device is opened + */ +const char *zbar_gtk_get_video_device(ZBarGtk *zbar); + +/** open a new video device. + * + * @video_device: the platform specific name of the device to open. + * use NULL to close a currently opened device. + * + * @note since opening a device may take some time, this call will + * return immediately and the device will be opened asynchronously + */ +void zbar_gtk_set_video_device(ZBarGtk *zbar, + const char *video_device); + +/** retrieve the current video enabled state. + * + * Returns: true if video scanning is currently enabled, false otherwise + */ +gboolean zbar_gtk_get_video_enabled(ZBarGtk *zbar); + +/** enable/disable video scanning. + * @video_enabled: true to enable video scanning, false to disable + * + * has no effect unless a video device is opened + */ +void zbar_gtk_set_video_enabled(ZBarGtk *zbar, + gboolean video_enabled); + +/** retrieve the current video opened state. + * + * Returns: true if video device is currently opened, false otherwise + */ +gboolean zbar_gtk_get_video_opened(ZBarGtk *zbar); + +/** set video camera resolution. + * @width: width in pixels + * @height: height in pixels + * + * @note this call must be made before video is initialized + */ +void zbar_gtk_request_video_size(ZBarGtk *zbar, + int width, + int height); + +/** + * utility function to populate a zbar_image_t from a GdkPixbuf. + * @image: the zbar library image destination to populate + * @pixbuf: the GdkPixbuf source + * + * Returns: TRUE if successful or FALSE if the conversion could not be + * performed for some reason + */ +gboolean zbar_gtk_image_from_pixbuf(zbar_image_t *image, + GdkPixbuf *pixbuf); + +G_END_DECLS + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/BarcodeFormat.h b/hgdriver/ImageProcess/include/zxing/BarcodeFormat.h new file mode 100755 index 0000000..faea173 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/BarcodeFormat.h @@ -0,0 +1,58 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __BARCODE_FORMAT_H__ +#define __BARCODE_FORMAT_H__ + +/* + * BarcodeFormat.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace zxing { + class BarcodeFormat { + public: + // if you update the enum, update BarcodeFormat.cpp + + enum Value { + NONE, + AZTEC, + CODABAR, + CODE_39, + CODE_93, + CODE_128, + DATA_MATRIX, + EAN_8, + EAN_13, + ITF, + MAXICODE, + PDF_417, + QR_CODE, + RSS_14, + RSS_EXPANDED, + UPC_A, + UPC_E, + UPC_EAN_EXTENSION + }; + + BarcodeFormat(Value v) : value(v) {} + const Value value; + operator Value () const { return value; } + + static char const* barcodeFormatNames[]; + }; +} + +#endif // __BARCODE_FORMAT_H__ diff --git a/hgdriver/ImageProcess/include/zxing/Binarizer.h b/hgdriver/ImageProcess/include/zxing/Binarizer.h new file mode 100755 index 0000000..4d30afb --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/Binarizer.h @@ -0,0 +1,49 @@ +#ifndef BINARIZER_H_ +#define BINARIZER_H_ + +/* + * Binarizer.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class Binarizer : public Counted { + private: + Ref source_; + + public: + Binarizer(Ref source); + virtual ~Binarizer(); + + virtual Ref getBlackRow(int y, Ref row) = 0; + virtual Ref getBlackMatrix() = 0; + + Ref getLuminanceSource() const; + virtual Ref createBinarizer(Ref source) = 0; + + int getWidth() const; + int getHeight() const; + }; + +} +#endif /* BINARIZER_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/BinaryBitmap.h b/hgdriver/ImageProcess/include/zxing/BinaryBitmap.h new file mode 100755 index 0000000..bbdb68f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/BinaryBitmap.h @@ -0,0 +1,55 @@ +#ifndef __BINARYBITMAP_H__ +#define __BINARYBITMAP_H__ + +/* + * BinaryBitmap.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class BinaryBitmap : public Counted { + private: + Ref binarizer_; + + public: + BinaryBitmap(Ref binarizer); + virtual ~BinaryBitmap(); + + Ref getBlackRow(int y, Ref row); + Ref getBlackMatrix(); + + Ref getLuminanceSource() const; + + int getWidth() const; + int getHeight() const; + + bool isRotateSupported() const; + Ref rotateCounterClockwise(); + + bool isCropSupported() const; + Ref crop(int left, int top, int width, int height); + }; + +} + +#endif /* BINARYBITMAP_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/ChecksumException.h b/hgdriver/ImageProcess/include/zxing/ChecksumException.h new file mode 100755 index 0000000..3188973 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/ChecksumException.h @@ -0,0 +1,34 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __CHECKSUM_EXCEPTION_H__ +#define __NOT_FOUND_EXCEPTION_H__ + +/* + * Copyright 20011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + class ChecksumException : public ReaderException { + typedef ReaderException Base; + public: + ChecksumException() throw(); + ChecksumException(const char* msg) throw(); + ~ChecksumException() throw(); + }; +} + +#endif // __CHECKSUM_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/DecodeHints.h b/hgdriver/ImageProcess/include/zxing/DecodeHints.h new file mode 100755 index 0000000..946b75d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/DecodeHints.h @@ -0,0 +1,85 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DECODEHINTS_H_ +#define __DECODEHINTS_H_ +/* + * DecodeHintType.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + + typedef unsigned int DecodeHintType; + class DecodeHints; + DecodeHints operator | (DecodeHints const&, DecodeHints const&); + + class DecodeHints { + private: + DecodeHintType hints; + Ref callback; + + public: + static const DecodeHintType AZTEC_HINT = 1 << BarcodeFormat::AZTEC; + static const DecodeHintType CODABAR_HINT = 1 << BarcodeFormat::CODABAR; + static const DecodeHintType CODE_39_HINT = 1 << BarcodeFormat::CODE_39; + static const DecodeHintType CODE_93_HINT = 1 << BarcodeFormat::CODE_93; + static const DecodeHintType CODE_128_HINT = 1 << BarcodeFormat::CODE_128; + static const DecodeHintType DATA_MATRIX_HINT = 1 << BarcodeFormat::DATA_MATRIX; + static const DecodeHintType EAN_8_HINT = 1 << BarcodeFormat::EAN_8; + static const DecodeHintType EAN_13_HINT = 1 << BarcodeFormat::EAN_13; + static const DecodeHintType ITF_HINT = 1 << BarcodeFormat::ITF; + static const DecodeHintType MAXICODE_HINT = 1 << BarcodeFormat::MAXICODE; + static const DecodeHintType PDF_417_HINT = 1 << BarcodeFormat::PDF_417; + static const DecodeHintType QR_CODE_HINT = 1 << BarcodeFormat::QR_CODE; + static const DecodeHintType RSS_14_HINT = 1 << BarcodeFormat::RSS_14; + static const DecodeHintType RSS_EXPANDED_HINT = 1 << BarcodeFormat::RSS_EXPANDED; + static const DecodeHintType UPC_A_HINT = 1 << BarcodeFormat::UPC_A; + static const DecodeHintType UPC_E_HINT = 1 << BarcodeFormat::UPC_E; + static const DecodeHintType UPC_EAN_EXTENSION_HINT = 1 << BarcodeFormat::UPC_EAN_EXTENSION; + + static const DecodeHintType TRYHARDER_HINT = 1 << 31; + static const DecodeHintType CHARACTER_SET = 1 << 30; + // static const DecodeHintType ALLOWED_LENGTHS = 1 << 29; + // static const DecodeHintType ASSUME_CODE_39_CHECK_DIGIT = 1 << 28; + static const DecodeHintType ASSUME_GS1 = 1 << 27; + // static const DecodeHintType NEED_RESULT_POINT_CALLBACK = 1 << 26; + + static const DecodeHints PRODUCT_HINT; + static const DecodeHints ONED_HINT; + static const DecodeHints DEFAULT_HINT; + + DecodeHints(); + DecodeHints(DecodeHintType init); + + void addFormat(BarcodeFormat toadd); + bool containsFormat(BarcodeFormat tocheck) const; + bool isEmpty() const { return (hints == 0); } + void clear() { hints = 0; } + void setTryHarder(bool toset); + bool getTryHarder() const; + + void setResultPointCallback(Ref const&); + Ref getResultPointCallback() const; + + friend DecodeHints operator | (DecodeHints const&, DecodeHints const&); + }; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/Exception.h b/hgdriver/ImageProcess/include/zxing/Exception.h new file mode 100755 index 0000000..c749197 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/Exception.h @@ -0,0 +1,51 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +/* + * Exception.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + + class Exception : public std::exception { + private: + char const* const message; + + public: + Exception() throw() : message(0) {} + Exception(const char* msg) throw() : message(copy(msg)) {} + Exception(Exception const& that) throw() : std::exception(that), message(copy(that.message)) {} + ~Exception() throw() { + if (message) { + deleteMessage(); + } + } + char const* what() const throw() { return message ? message : ""; } + + private: + static char const* copy(char const*); + void deleteMessage(); + }; + +} + +#endif // __EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/FormatException.h b/hgdriver/ImageProcess/include/zxing/FormatException.h new file mode 100755 index 0000000..cdb5ff9 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/FormatException.h @@ -0,0 +1,37 @@ +#ifndef __FORMAT_EXCEPTION_H__ +#define __FORMAT_EXCEPTION_H__ + +/* + * FormatException.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class FormatException : public ReaderException { + public: + FormatException(); + FormatException(const char* msg); + ~FormatException() throw(); + + static FormatException const& getFormatInstance(); + }; + +} +#endif // __FORMAT_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/IllegalStateException.h b/hgdriver/ImageProcess/include/zxing/IllegalStateException.h new file mode 100755 index 0000000..0162b61 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/IllegalStateException.h @@ -0,0 +1,35 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __ILLEGAL_STATE_EXCEPTION_H__ +#define __ILLEGAL_STATE_EXCEPTION_H__ + +/* + * Copyright 20011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may illegal use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class IllegalStateException : public ReaderException { + public: + IllegalStateException() throw() {} + IllegalStateException(const char* msg) throw() : ReaderException(msg) {} + ~IllegalStateException() throw() {} + }; + +} + +#endif // __ILLEGAL_STATE_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/InvertedLuminanceSource.h b/hgdriver/ImageProcess/include/zxing/InvertedLuminanceSource.h new file mode 100755 index 0000000..cd48b6d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/InvertedLuminanceSource.h @@ -0,0 +1,48 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __INVERTEDLUMINANCESOURCE_H__ +#define __INVERTEDLUMINANCESOURCE_H__ +/* + * Copyright 2013 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + + class InvertedLuminanceSource : public LuminanceSource { + private: + typedef LuminanceSource Super; + const Ref delegate; + + public: + InvertedLuminanceSource(Ref const&); + + ArrayRef getRow(int y, ArrayRef row) const; + ArrayRef getMatrix() const; + + boolean isCropSupported() const; + Ref crop(int left, int top, int width, int height) const; + + boolean isRotateSupported() const; + + virtual Ref invert() const; + + Ref rotateCounterClockwise() const; + }; + +} + +#endif /* INVERTEDLUMINANCESOURCE_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/LuminanceSource.h b/hgdriver/ImageProcess/include/zxing/LuminanceSource.h new file mode 100755 index 0000000..92f9e32 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/LuminanceSource.h @@ -0,0 +1,59 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __LUMINANCESOURCE_H__ +#define __LUMINANCESOURCE_H__ +/* + * LuminanceSource.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + + class LuminanceSource : public Counted { + private: + const int width; + const int height; + + public: + LuminanceSource(int width, int height); + virtual ~LuminanceSource(); + + int getWidth() const { return width; } + int getHeight() const { return height; } + + // Callers take ownership of the returned memory and must call delete [] on it themselves. + virtual ArrayRef getRow(int y, ArrayRef row) const = 0; + virtual ArrayRef getMatrix() const = 0; + + virtual bool isCropSupported() const; + virtual Ref crop(int left, int top, int width, int height) const; + + virtual bool isRotateSupported() const; + + virtual Ref invert() const; + + virtual Ref rotateCounterClockwise() const; + + operator std::string() const; + }; + +} + +#endif /* LUMINANCESOURCE_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/MultiFormatReader.h b/hgdriver/ImageProcess/include/zxing/MultiFormatReader.h new file mode 100755 index 0000000..f1dc93a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/MultiFormatReader.h @@ -0,0 +1,48 @@ +#ifndef __MULTI_FORMAT_READER_H__ +#define __MULTI_FORMAT_READER_H__ + +/* + * MultiFormatBarcodeReader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include + +namespace zxing { + class MultiFormatReader : public Reader { + private: + Ref decodeInternal(Ref image); + + std::vector > readers_; + DecodeHints hints_; + + public: + MultiFormatReader(); + + Ref decode(Ref image); + Ref decode(Ref image, DecodeHints hints); + Ref decodeWithState(Ref image); + void setHints(DecodeHints hints); + ~MultiFormatReader(); + }; +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/NotFoundException.h b/hgdriver/ImageProcess/include/zxing/NotFoundException.h new file mode 100755 index 0000000..47b3896 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/NotFoundException.h @@ -0,0 +1,35 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __NOT_FOUND_EXCEPTION_H__ +#define __NOT_FOUND_EXCEPTION_H__ + +/* + * Copyright 20011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class NotFoundException : public ReaderException { + public: + NotFoundException() throw() {} + NotFoundException(const char* msg) throw() : ReaderException(msg) {} + ~NotFoundException() throw() {} + }; + +} + +#endif // __NOT_FOUND_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/Reader.h b/hgdriver/ImageProcess/include/zxing/Reader.h new file mode 100755 index 0000000..264ec06 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/Reader.h @@ -0,0 +1,40 @@ +#ifndef __READER_H__ +#define __READER_H__ + +/* + * Reader.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + + class Reader : public Counted { + protected: + Reader() {} + public: + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints) = 0; + virtual ~Reader(); + }; + +} + +#endif // __READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/ReaderException.h b/hgdriver/ImageProcess/include/zxing/ReaderException.h new file mode 100755 index 0000000..c46a91e --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/ReaderException.h @@ -0,0 +1,37 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __READER_EXCEPTION_H__ +#define __READER_EXCEPTION_H__ + +/* + * ReaderException.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class ReaderException : public Exception { + public: + ReaderException() throw() {} + ReaderException(char const* msg) throw() : Exception(msg) {} + ~ReaderException() throw() {} + }; + +} + +#endif // __READER_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/Result.h b/hgdriver/ImageProcess/include/zxing/Result.h new file mode 100755 index 0000000..59a3d0d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/Result.h @@ -0,0 +1,55 @@ +#ifndef __RESULT_H__ +#define __RESULT_H__ + +/* + * Result.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + + class Result : public Counted { + private: + Ref text_; + ArrayRef rawBytes_; + ArrayRef< Ref > resultPoints_; + BarcodeFormat format_; + + public: + Result(Ref text, + ArrayRef rawBytes, + ArrayRef< Ref > resultPoints, + BarcodeFormat format); + ~Result(); + Ref getText(); + ArrayRef getRawBytes(); + ArrayRef< Ref > const& getResultPoints() const; + ArrayRef< Ref >& getResultPoints(); + BarcodeFormat getBarcodeFormat() const; + + friend std::ostream& operator<<(std::ostream& out, Result& result); + }; + +} +#endif // __RESULT_H__ diff --git a/hgdriver/ImageProcess/include/zxing/ResultPoint.h b/hgdriver/ImageProcess/include/zxing/ResultPoint.h new file mode 100755 index 0000000..d160c84 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/ResultPoint.h @@ -0,0 +1,55 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __RESULT_POINT_H__ +#define __RESULT_POINT_H__ + +/* + * ResultPoint.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + + class ResultPoint : public Counted { + protected: + const float posX_; + const float posY_; + + public: + ResultPoint(); + ResultPoint(float x, float y); + ResultPoint(int x, int y); + virtual ~ResultPoint(); + + virtual float getX() const; + virtual float getY() const; + + bool equals(Ref other); + + static void orderBestPatterns(std::vector >& patterns); + static float distance(Ref point1, Ref point2); + static float distance(float x1, float x2, float y1, float y2); + + private: + static float crossProductZ(Ref pointA, Ref pointB, Ref pointC); + }; + +} + +#endif // __RESULT_POINT_H__ diff --git a/hgdriver/ImageProcess/include/zxing/ResultPointCallback.h b/hgdriver/ImageProcess/include/zxing/ResultPointCallback.h new file mode 100755 index 0000000..d643c10 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/ResultPointCallback.h @@ -0,0 +1,39 @@ +#ifndef __RESULT_POINT_CALLBACK_H__ +#define __RESULT_POINT_CALLBACK_H__ + +/* + * ResultPointCallback.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class ResultPoint; + + class ResultPointCallback : public Counted { + protected: + ResultPointCallback() {} + public: + virtual void foundPossibleResultPoint(ResultPoint const& point) = 0; + virtual ~ResultPointCallback(); + }; + +} + +#endif // __RESULT_POINT_CALLBACK_H__ diff --git a/hgdriver/ImageProcess/include/zxing/ZXing.h b/hgdriver/ImageProcess/include/zxing/ZXing.h new file mode 100755 index 0000000..05b51f3 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/ZXing.h @@ -0,0 +1,134 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 2013 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ZXING_H_ +#define __ZXING_H_ + +#define ZXING_ARRAY_LEN(v) ((int)(sizeof(v)/sizeof(v[0]))) +#define ZX_LOG_DIGITS(digits) \ + ((digits == 8) ? 3 : \ + ((digits == 16) ? 4 : \ + ((digits == 32) ? 5 : \ + ((digits == 64) ? 6 : \ + ((digits == 128) ? 7 : \ + (-1)))))) + +#ifndef ZXING_DEBUG +#define ZXING_DEBUG 0 +#endif + +namespace zxing { + typedef char byte; + typedef bool boolean; +} + +#include + +#if defined(_WIN32) || defined(_WIN64) + +#include + +namespace zxing { + inline bool isnan(float v) { return _isnan(v) != 0; } + inline bool isnan(double v) { return _isnan(v) != 0; } + inline float nan() { return std::numeric_limits::quiet_NaN(); } +} + +#else + +#include + +namespace zxing { + inline bool isnan(float v) { return std::isnan(v); } + inline bool isnan(double v) { return std::isnan(v); } + inline float nan() { return std::numeric_limits::quiet_NaN(); } +} + +#endif + +#if ZXING_DEBUG + +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::flush; +using std::string; +using std::ostream; + +#if ZXING_DEBUG_TIMER + +#include + +namespace zxing { + + class DebugTimer { + public: + DebugTimer(char const* string_) : chars(string_) { + gettimeofday(&start, 0); + } + + DebugTimer(std::string const& string_) : chars(0), string(string_) { + gettimeofday(&start, 0); + } + + void mark(char const* string) { + struct timeval end; + gettimeofday(&end, 0); + int diff = + (end.tv_sec - start.tv_sec) * 1000 * 1000 + (end.tv_usec - start.tv_usec); + + cerr << diff << " " << string << '\n'; + } + + void mark(std::string string) { + mark(string.c_str()); + } + + ~DebugTimer() { + if (chars) { + mark(chars); + } + else { + mark(string.c_str()); + } + } + + private: + char const* const chars; + std::string string; + struct timeval start; + }; + +} + +#define ZXING_TIME(string) DebugTimer __timer__ (string) +#define ZXING_TIME_MARK(string) __timer__.mark(string) + +#endif + +#endif // ZXING_DEBUG + +#ifndef ZXING_TIME +#define ZXING_TIME(string) (void)0 +#endif +#ifndef ZXING_TIME_MARK +#define ZXING_TIME_MARK(string) (void)0 +#endif + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/aztec/AztecDetectorResult.h b/hgdriver/ImageProcess/include/zxing/aztec/AztecDetectorResult.h new file mode 100755 index 0000000..c4410ae --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/aztec/AztecDetectorResult.h @@ -0,0 +1,47 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * AtztecDetecorResult.h + * zxing + * + * Created by Lukas Stabe on 08/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifndef ZXingWidget_AtztecDetecorResult_h +#define ZXingWidget_AtztecDetecorResult_h + +namespace zxing { + namespace aztec { + class AztecDetectorResult : public DetectorResult { + private: + bool compact_; + int nbDatablocks_, nbLayers_; + public: + AztecDetectorResult(Ref bits, + ArrayRef< Ref > points, + bool compact, + int nbDatablocks, + int nbLayers); + bool isCompact(); + int getNBDatablocks(); + int getNBLayers(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/aztec/AztecReader.h b/hgdriver/ImageProcess/include/zxing/aztec/AztecReader.h new file mode 100755 index 0000000..2ef102a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/aztec/AztecReader.h @@ -0,0 +1,49 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * AztecReader.h + * zxing + * + * Created by Lukas Stabe on 08/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#ifndef ZXingWidget_AztecReader_h +#define ZXingWidget_AztecReader_h + +namespace zxing { + namespace aztec { + + class AztecReader : public Reader { + private: + Decoder decoder_; + + protected: + Decoder& getDecoder(); + + public: + AztecReader(); + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints); + virtual ~AztecReader(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/aztec/decoder/Decoder.h b/hgdriver/ImageProcess/include/zxing/aztec/decoder/Decoder.h new file mode 100755 index 0000000..ebe0c25 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/aztec/decoder/Decoder.h @@ -0,0 +1,69 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Decoder.h + * zxing + * + * Created by Lukas Stabe on 08/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ZXING_AZTEC_DECODER_DECODER_H__ +#define __ZXING_AZTEC_DECODER_DECODER_H__ + +#include +#include +#include + +namespace zxing { + + class DecoderResult; + + namespace aztec { + + class Decoder : public Counted { + private: + enum Table { + UPPER, + LOWER, + MIXED, + DIGIT, + PUNCT, + BINARY + }; + + static Table getTable(char t); + static const char* getCharacter(Table table, int code); + + int numCodewords_; + int codewordSize_; + Ref ddata_; + int invertedBitCount_; + + Ref getEncodedData(Ref correctedBits); + Ref correctBits(Ref rawbits); + Ref extractBits(Ref matrix); + static Ref removeDashedLines(Ref matrix); + static int readCode(Ref rawbits, int startIndex, int length); + + + public: + Decoder(); + Ref decode(Ref detectorResult); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/aztec/detector/Detector.h b/hgdriver/ImageProcess/include/zxing/aztec/detector/Detector.h new file mode 100755 index 0000000..5fb1f14 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/aztec/detector/Detector.h @@ -0,0 +1,92 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Detector.h + * zxing + * + * Created by Lukas Stabe on 08/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ZXING_AZTEC_DETECTOR_DETECTOR_H__ +#define __ZXING_AZTEC_DETECTOR_DETECTOR_H__ + +#include + +#include +#include +#include +#include +#include + +namespace zxing { + namespace aztec { + + class Point : public Counted { + private: + const int x; + const int y; + + public: + Ref toResultPoint() { + return Ref(new ResultPoint(float(x), float(y))); + } + + Point(int ax, int ay) : x(ax), y(ay) {} + + int getX() const { return x; } + int getY() const { return y; } + }; + + class Detector : public Counted { + + private: + Ref image_; + + bool compact_; + int nbLayers_; + int nbDataBlocks_; + int nbCenterLayers_; + int shift_; + + void extractParameters(std::vector > bullEyeCornerPoints); + ArrayRef< Ref > getMatrixCornerPoints(std::vector > bullEyeCornerPoints); + static void correctParameterData(Ref parameterData, bool compact); + std::vector > getBullEyeCornerPoints(Ref pCenter); + Ref getMatrixCenter(); + Ref sampleGrid(Ref image, + Ref topLeft, + Ref bottomLeft, + Ref bottomRight, + Ref topRight); + void getParameters(Ref parameterData); + Ref sampleLine(Ref p1, Ref p2, int size); + bool isWhiteOrBlackRectangle(Ref p1, + Ref p2, + Ref p3, + Ref p4); + int getColor(Ref p1, Ref p2); + Ref getFirstDifferent(Ref init, bool color, int dx, int dy); + bool isValid(int x, int y); + static float distance(Ref a, Ref b); + + public: + Detector(Ref image); + Ref detect(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/Array.h b/hgdriver/ImageProcess/include/zxing/common/Array.h new file mode 100755 index 0000000..e9cdc1f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/Array.h @@ -0,0 +1,170 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ARRAY_H__ +#define __ARRAY_H__ + +/* + * Array.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace zxing { + + template class Array : public Counted { + protected: + public: + std::vector values_; + Array() {} + Array(int n) : + Counted(), values_(n, T()) { + } + Array(T const* ts, int n) : + Counted(), values_(ts, ts + n) { + } + Array(T const* ts, T const* te) : + Counted(), values_(ts, te) { + } + Array(T v, int n) : + Counted(), values_(n, v) { + } + Array(std::vector& v) : + Counted(), values_(v) { + } + Array(Array& other) : + Counted(), values_(other.values_) { + } + Array(Array* other) : + Counted(), values_(other->values_) { + } + virtual ~Array() { + } + Array& operator=(const Array& other) { + values_ = other.values_; + return *this; + } + Array& operator=(const std::vector& array) { + values_ = array; + return *this; + } + T const& operator[](int i) const { + return values_[i]; + } + T& operator[](int i) { + return values_[i]; + } + int size() const { + return values_.size(); + } + bool empty() const { + return values_.size() == 0; + } + std::vector const& values() const { + return values_; + } + std::vector& values() { + return values_; + } + }; + + template class ArrayRef : public Counted { + private: + public: + Array* array_; + ArrayRef() : + array_(0) { + } + explicit ArrayRef(int n) : + array_(0) { + reset(new Array(n)); + } + ArrayRef(T* ts, int n) : + array_(0) { + reset(new Array(ts, n)); + } + ArrayRef(Array* a) : + array_(0) { + reset(a); + } + ArrayRef(const ArrayRef& other) : + Counted(), array_(0) { + reset(other.array_); + } + + template + ArrayRef(const ArrayRef& other) : + array_(0) { + reset(static_cast*>(other.array_)); + } + + ~ArrayRef() { + if (array_) { + array_->release(); + } + array_ = 0; + } + + T const& operator[](int i) const { + return (*array_)[i]; + } + + T& operator[](int i) { + return (*array_)[i]; + } + + void reset(Array* a) { + if (a) { + a->retain(); + } + if (array_) { + array_->release(); + } + array_ = a; + } + void reset(const ArrayRef& other) { + reset(other.array_); + } + ArrayRef& operator=(const ArrayRef& other) { + reset(other); + return *this; + } + ArrayRef& operator=(Array* a) { + reset(a); + return *this; + } + + Array& operator*() const { + return *array_; + } + + Array* operator->() const { + return array_; + } + + operator bool() const { + return array_ != 0; + } + bool operator ! () const { + return array_ == 0; + } + }; + +} // namespace zxing + +#endif // __ARRAY_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/BitArray.h b/hgdriver/ImageProcess/include/zxing/common/BitArray.h new file mode 100755 index 0000000..f95dfcc --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/BitArray.h @@ -0,0 +1,81 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __BIT_ARRAY_H__ +#define __BIT_ARRAY_H__ + +/* + * Copyright 2010 ZXing authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + + class BitArray : public Counted { + public: + static const int bitsPerWord = std::numeric_limits::digits; + + private: + int size; + ArrayRef bits; + static const int logBits = ZX_LOG_DIGITS(bitsPerWord); + static const int bitsMask = (1 << logBits) - 1; + + public: + BitArray(int size); + ~BitArray(); + int getSize() const; + + bool get(int i) const { + return (bits[i >> logBits] & (1 << (i & bitsMask))) != 0; + } + + void set(int i) { + bits[i >> logBits] |= 1 << (i & bitsMask); + } + + int getNextSet(int from); + int getNextUnset(int from); + + void setBulk(int i, int newBits); + void setRange(int start, int end); + void clear(); + bool isRange(int start, int end, bool value); + std::vector& getBitArray(); + + void reverse(); + + class Reverse { + private: + Ref array; + public: + Reverse(Ref array); + ~Reverse(); + }; + + private: + static int makeArraySize(int size); + }; + + std::ostream& operator << (std::ostream&, BitArray const&); + +} + +#endif // __BIT_ARRAY_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/BitMatrix.h b/hgdriver/ImageProcess/include/zxing/common/BitMatrix.h new file mode 100755 index 0000000..e106813 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/BitMatrix.h @@ -0,0 +1,91 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __BIT_MATRIX_H__ +#define __BIT_MATRIX_H__ + +/* + * BitMatrix.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class BitMatrix : public Counted { + public: + static const int bitsPerWord = std::numeric_limits::digits; + + private: + int width; + int height; + int rowSize; + ArrayRef bits; + +#define ZX_LOG_DIGITS(digits) \ + ((digits == 8) ? 3 : \ + ((digits == 16) ? 4 : \ + ((digits == 32) ? 5 : \ + ((digits == 64) ? 6 : \ + ((digits == 128) ? 7 : \ + (-1)))))) + + static const int logBits = ZX_LOG_DIGITS(bitsPerWord); + static const int bitsMask = (1 << logBits) - 1; + + public: + BitMatrix(int dimension); + BitMatrix(int width, int height); + + ~BitMatrix(); + + bool get(int x, int y) const { + int offset = y * rowSize + (x >> logBits); + return ((((unsigned)bits[offset]) >> (x & bitsMask)) & 1) != 0; + } + + void set(int x, int y) { + int offset = y * rowSize + (x >> logBits); + bits[offset] |= 1 << (x & bitsMask); + } + + void flip(int x, int y); + void clear(); + void setRegion(int left, int top, int width, int height); + Ref getRow(int y, Ref row); + + int getWidth() const; + int getHeight() const; + + ArrayRef getTopLeftOnBit() const; + ArrayRef getBottomRightOnBit() const; + + friend std::ostream& operator<<(std::ostream& out, const BitMatrix& bm); + const char* description(); + + private: + inline void init(int, int); + + BitMatrix(const BitMatrix&); + BitMatrix& operator =(const BitMatrix&); + }; + +} + +#endif // __BIT_MATRIX_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/BitSource.h b/hgdriver/ImageProcess/include/zxing/common/BitSource.h new file mode 100755 index 0000000..02f5677 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/BitSource.h @@ -0,0 +1,74 @@ +#ifndef __BIT_SOURCE_H__ +#define __BIT_SOURCE_H__ + +/* + * BitSource.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + /** + *

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the + * number of bits read is not often a multiple of 8.

+ * + *

This class is not thread-safe.

+ * + * @author srowen@google.com (Sean Owen) + * @author christian.brunschen@gmail.com (Christian Brunschen) + */ + class BitSource : public Counted { + typedef char byte; + private: + ArrayRef bytes_; + int byteOffset_; + int bitOffset_; + public: + /** + * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. + * Bits are read within a byte from most-significant to least-significant bit. + */ + BitSource(ArrayRef& bytes) : + bytes_(bytes), byteOffset_(0), bitOffset_(0) { + } + + int getBitOffset() { + return bitOffset_; + } + + int getByteOffset() { + return byteOffset_; + } + + /** + * @param numBits number of bits to read + * @return int representing the bits read. The bits will appear as the least-significant + * bits of the int + * @throws IllegalArgumentException if numBits isn't in [1,32] + */ + int readBits(int numBits); + + /** + * @return number of bits that can be read successfully + */ + int available(); + }; + +} + +#endif // __BIT_SOURCE_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/CharacterSetECI.h b/hgdriver/ImageProcess/include/zxing/common/CharacterSetECI.h new file mode 100755 index 0000000..e46584a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/CharacterSetECI.h @@ -0,0 +1,53 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __CHARACTERSET_ECI__ +#define __CHARACTERSET_ECI__ + +/* + * Copyright 2008-2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace common { + + class CharacterSetECI { + private: + static std::map VALUE_TO_ECI; + static std::map NAME_TO_ECI; + static const bool inited; + static bool init_tables(); + + int const* const values_; + char const* const* const names_; + + CharacterSetECI(int const* values, char const* const* names); + + static void addCharacterSet(int const* value, char const* const* encodingNames); + + public: + char const* name() const; + int getValue() const; + + static CharacterSetECI* getCharacterSetECIByValue(int value); + static CharacterSetECI* getCharacterSetECIByName(std::string const& name); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/Counted.h b/hgdriver/ImageProcess/include/zxing/common/Counted.h new file mode 100755 index 0000000..8ce667e --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/Counted.h @@ -0,0 +1,140 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __COUNTED_H__ +#define __COUNTED_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + /* base class for reference-counted objects */ + class Counted { + private: + unsigned int count_; + public: + Counted() : + count_(0) { + } + virtual ~Counted() { + } + Counted* retain() { + count_++; + return this; + } + void release() { + count_--; + if (count_ == 0) { + count_ = 0xDEADF001; + delete this; + } + } + + + /* return the current count for denugging purposes or similar */ + int count() const { + return count_; + } + }; + + /* counting reference to reference-counted objects */ + template class Ref { + private: + public: + T* object_; + explicit Ref(T* o = 0) : + object_(0) { + reset(o); + } + Ref(const Ref& other) : + object_(0) { + reset(other.object_); + } + + template + Ref(const Ref& other) : + object_(0) { + reset(other.object_); + } + + ~Ref() { + if (object_) { + object_->release(); + } + } + + void reset(T* o) { + if (o) { + o->retain(); + } + if (object_ != 0) { + object_->release(); + } + object_ = o; + } + Ref& operator=(const Ref& other) { + reset(other.object_); + return *this; + } + template + Ref& operator=(const Ref& other) { + reset(other.object_); + return *this; + } + Ref& operator=(T* o) { + reset(o); + return *this; + } + template + Ref& operator=(Y* o) { + reset(o); + return *this; + } + + T& operator*() { + return *object_; + } + T* operator->() const { + return object_; + } + operator T* () const { + return object_; + } + + bool operator==(const T* that) { + return object_ == that; + } + bool operator==(const Ref& other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + template + bool operator==(const Ref& other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + + bool operator!=(const T* that) { + return !(*this == that); + } + + bool empty() const { + return object_ == 0; + } + }; + +} + +#endif // __COUNTED_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/DecoderResult.h b/hgdriver/ImageProcess/include/zxing/common/DecoderResult.h new file mode 100755 index 0000000..d5311e9 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/DecoderResult.h @@ -0,0 +1,51 @@ +#ifndef __DECODER_RESULT_H__ +#define __DECODER_RESULT_H__ + +/* + * DecoderResult.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class DecoderResult : public Counted { + private: + ArrayRef rawBytes_; + Ref text_; + ArrayRef< ArrayRef > byteSegments_; + std::string ecLevel_; + + public: + DecoderResult(ArrayRef rawBytes, + Ref text, + ArrayRef< ArrayRef >& byteSegments, + std::string const& ecLevel); + + DecoderResult(ArrayRef rawBytes, Ref text); + + ArrayRef getRawBytes(); + Ref getText(); + }; + +} + +#endif // __DECODER_RESULT_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/DetectorResult.h b/hgdriver/ImageProcess/include/zxing/common/DetectorResult.h new file mode 100755 index 0000000..567f29b --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/DetectorResult.h @@ -0,0 +1,43 @@ +#ifndef __DETECTOR_RESULT_H__ +#define __DETECTOR_RESULT_H__ + +/* + * DetectorResult.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class DetectorResult : public Counted { + private: + Ref bits_; + ArrayRef< Ref > points_; + + public: + DetectorResult(Ref bits, ArrayRef< Ref > points); + Ref getBits(); + ArrayRef< Ref > getPoints(); + }; + +} + +#endif // __DETECTOR_RESULT_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/GlobalHistogramBinarizer.h b/hgdriver/ImageProcess/include/zxing/common/GlobalHistogramBinarizer.h new file mode 100755 index 0000000..c81981d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/GlobalHistogramBinarizer.h @@ -0,0 +1,48 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __GLOBALHISTOGRAMBINARIZER_H__ +#define __GLOBALHISTOGRAMBINARIZER_H__ +/* + * GlobalHistogramBinarizer.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + + class GlobalHistogramBinarizer : public Binarizer { + private: + ArrayRef luminances; + ArrayRef buckets; + public: + GlobalHistogramBinarizer(Ref source); + virtual ~GlobalHistogramBinarizer(); + + virtual Ref getBlackRow(int y, Ref row); + virtual Ref getBlackMatrix(); + static int estimateBlackPoint(ArrayRef const& buckets); + Ref createBinarizer(Ref source); + private: + void initArrays(int luminanceSize); + }; + +} + +#endif /* GLOBALHISTOGRAMBINARIZER_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/common/GreyscaleLuminanceSource.h b/hgdriver/ImageProcess/include/zxing/common/GreyscaleLuminanceSource.h new file mode 100755 index 0000000..d0620f2 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/GreyscaleLuminanceSource.h @@ -0,0 +1,53 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __GREYSCALE_LUMINANCE_SOURCE__ +#define __GREYSCALE_LUMINANCE_SOURCE__ +/* + * GreyscaleLuminanceSource.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class GreyscaleLuminanceSource : public LuminanceSource { + + private: + typedef LuminanceSource Super; + ArrayRef greyData_; + const int dataWidth_; + const int dataHeight_; + const int left_; + const int top_; + + public: + GreyscaleLuminanceSource(ArrayRef greyData, int dataWidth, int dataHeight, int left, + int top, int width, int height); + + ArrayRef getRow(int y, ArrayRef row) const; + ArrayRef getMatrix() const; + + bool isRotateSupported() const { + return true; + } + + Ref rotateCounterClockwise() const; + }; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/GreyscaleRotatedLuminanceSource.h b/hgdriver/ImageProcess/include/zxing/common/GreyscaleRotatedLuminanceSource.h new file mode 100755 index 0000000..5c6496a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/GreyscaleRotatedLuminanceSource.h @@ -0,0 +1,46 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ +#define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__ +/* + * GreyscaleRotatedLuminanceSource.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +namespace zxing { + + class GreyscaleRotatedLuminanceSource : public LuminanceSource { + private: + typedef LuminanceSource Super; + ArrayRef greyData_; + const int dataWidth_; + const int left_; + const int top_; + + public: + GreyscaleRotatedLuminanceSource(ArrayRef greyData, int dataWidth, int dataHeight, + int left, int top, int width, int height); + + ArrayRef getRow(int y, ArrayRef row) const; + ArrayRef getMatrix() const; + }; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/GridSampler.h b/hgdriver/ImageProcess/include/zxing/common/GridSampler.h new file mode 100755 index 0000000..8ba9ebf --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/GridSampler.h @@ -0,0 +1,45 @@ +#ifndef __GRID_SAMPLER_H__ +#define __GRID_SAMPLER_H__ + +/* + * GridSampler.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + class GridSampler { + private: + static GridSampler gridSampler; + GridSampler(); + + public: + Ref sampleGrid(Ref image, int dimension, Ref transform); + Ref sampleGrid(Ref image, int dimensionX, int dimensionY, Ref transform); + + Ref sampleGrid(Ref image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, + float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, + float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); + static void checkAndNudgePoints(Ref image, std::vector& points); + static GridSampler& getInstance(); + }; +} + +#endif // __GRID_SAMPLER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/HybridBinarizer.h b/hgdriver/ImageProcess/include/zxing/common/HybridBinarizer.h new file mode 100755 index 0000000..b40c7b2 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/HybridBinarizer.h @@ -0,0 +1,67 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __HYBRIDBINARIZER_H__ +#define __HYBRIDBINARIZER_H__ +/* + * HybridBinarizer.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + + class HybridBinarizer : public GlobalHistogramBinarizer { + private: + Ref matrix_; + Ref cached_row_; + + public: + HybridBinarizer(Ref source); + virtual ~HybridBinarizer(); + + virtual Ref getBlackMatrix(); + Ref createBinarizer(Ref source); + private: + // We'll be using one-D arrays because C++ can't dynamically allocate 2D + // arrays + ArrayRef calculateBlackPoints(ArrayRef luminances, + int subWidth, + int subHeight, + int width, + int height); + void calculateThresholdForBlock(ArrayRef luminances, + int subWidth, + int subHeight, + int width, + int height, + ArrayRef blackPoints, + Ref const& matrix); + void thresholdBlock(ArrayRefluminances, + int xoffset, + int yoffset, + int threshold, + int stride, + Ref const& matrix); + }; + +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/IllegalArgumentException.h b/hgdriver/ImageProcess/include/zxing/common/IllegalArgumentException.h new file mode 100755 index 0000000..9f05f6d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/IllegalArgumentException.h @@ -0,0 +1,36 @@ +#ifndef __ILLEGAL_ARGUMENT_EXCEPTION_H__ +#define __ILLEGAL_ARGUMENT_EXCEPTION_H__ + +/* + * IllegalArgumentException.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + class IllegalArgumentException : public Exception { + public: + IllegalArgumentException(); + IllegalArgumentException(const char* msg); + ~IllegalArgumentException() throw(); + }; + +} + +#endif // __ILLEGAL_ARGUMENT_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/PerspectiveTransform.h b/hgdriver/ImageProcess/include/zxing/common/PerspectiveTransform.h new file mode 100755 index 0000000..fd300b7 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/PerspectiveTransform.h @@ -0,0 +1,49 @@ +#ifndef __PERSPECTIVE_TANSFORM_H__ +#define __PERSPECTIVE_TANSFORM_H__ + +/* + * PerspectiveTransform.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + class PerspectiveTransform : public Counted { + private: + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, + float a33); + + public: + static Ref + quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, + float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p); + static Ref squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + static Ref quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + Ref buildAdjoint(); + Ref times(Ref other); + void transformPoints(std::vector& points); + + friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform& pt); + }; +} + +#endif // __PERSPECTIVE_TANSFORM_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/Point.h b/hgdriver/ImageProcess/include/zxing/common/Point.h new file mode 100755 index 0000000..2f489ee --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/Point.h @@ -0,0 +1,47 @@ +#ifndef __POINT_H__ +#define __POINT_H__ + +/* + * Point.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace zxing { + class PointI { + public: + int x; + int y; + }; + + class Point { + public: + Point() : x(0.0f), y(0.0f) {}; + Point(float x_, float y_) : x(x_), y(y_) {}; + + float x; + float y; + }; + + class Line { + public: + Line(Point start_, Point end_) : start(start_), end(end_) {}; + + Point start; + Point end; + }; +} +#endif // POINT_H_ diff --git a/hgdriver/ImageProcess/include/zxing/common/Str.h b/hgdriver/ImageProcess/include/zxing/common/Str.h new file mode 100755 index 0000000..d1dbc6f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/Str.h @@ -0,0 +1,51 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __STR_H__ +#define __STR_H__ + +/* + * Str.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + + class String; + std::ostream& operator << (std::ostream& out, String const& s); + + class String : public Counted { + private: + std::string text_; + public: + explicit String(const std::string& text); + explicit String(int); + char charAt(int) const; + Ref substring(int) const; + const std::string& getText() const; + int size() const; + void append(std::string const& tail); + void append(char c); + int length() const; + friend std::ostream& zxing::operator << (std::ostream& out, String const& s); + }; + +} + +#endif // __COMMON__STRING_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/StringUtils.h b/hgdriver/ImageProcess/include/zxing/common/StringUtils.h new file mode 100755 index 0000000..8784574 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/StringUtils.h @@ -0,0 +1,52 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __STRING_UTILS__ +#define __STRING_UTILS__ + +/* + * Copyright (C) 2010-2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace common { + + class StringUtils { + private: + static char const* const PLATFORM_DEFAULT_ENCODING; + + StringUtils() {} + + public: + static char const* const ASCII; + static char const* const SHIFT_JIS; + static char const* const GB2312; + static char const* const EUC_JP; + static char const* const UTF8; + static char const* const ISO88591; + static const bool ASSUME_SHIFT_JIS; + + typedef std::map Hashtable; + + static std::string guessEncoding(char* bytes, int length, Hashtable const& hints); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/detector/JavaMath.h b/hgdriver/ImageProcess/include/zxing/common/detector/JavaMath.h new file mode 100755 index 0000000..010cf04 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/detector/JavaMath.h @@ -0,0 +1,43 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ZXING_COMMON_DETECTOR_MATH_H__ +#define __ZXING_COMMON_DETECTOR_MATH_H__ +/* + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace common { + namespace detector { + + class Math { + private: + Math(); + ~Math(); + public: + + // Java standard Math.round + static inline int round(float a) { + return (int)std::floor(a + 0.5f); + } + + }; + + } + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/detector/MathUtils.h b/hgdriver/ImageProcess/include/zxing/common/detector/MathUtils.h new file mode 100755 index 0000000..da787b0 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/detector/MathUtils.h @@ -0,0 +1,57 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ZXING_COMMON_DETECTOR_MATHUTILS_H__ +#define __ZXING_COMMON_DETECTOR_MATHUTILS_H__ +/* + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace common { + namespace detector { + + class MathUtils { + private: + MathUtils(); + ~MathUtils(); + public: + + /** + * Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its + * argument to the nearest int, where x.5 rounds up to x+1. + */ + static inline int round(float d) { + return (int)(d + 0.5f); + } + + static inline float distance(float aX, float aY, float bX, float bY) { + float xDiff = aX - bX; + float yDiff = aY - bY; + return sqrt(xDiff * xDiff + yDiff * yDiff); + } + + static inline float distance(int aX, int aY, int bX, int bY) { + int xDiff = aX - bX; + int yDiff = aY - bY; + return sqrt(float(xDiff * xDiff + yDiff * yDiff)); + } + }; + + } + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/detector/MonochromeRectangleDetector.h b/hgdriver/ImageProcess/include/zxing/common/detector/MonochromeRectangleDetector.h new file mode 100755 index 0000000..6c2d56b --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/detector/MonochromeRectangleDetector.h @@ -0,0 +1,62 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __MONOCHROMERECTANGLEDETECTOR_H__ +#define __MONOCHROMERECTANGLEDETECTOR_H__ + +/* + * MonochromeRectangleDetector.h + * y_wmk + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 y_wmk authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + + struct TwoInts : public Counted { + int start; + int end; + }; + + class MonochromeRectangleDetector : public Counted { + private: + static const int MAX_MODULES = 32; + Ref image_; + + public: + MonochromeRectangleDetector(Ref image) : image_(image) { }; + + std::vector > detect(); + + private: + Ref findCornerFromCenter(int centerX, int deltaX, int left, int right, + int centerY, int deltaY, int top, int bottom, int maxWhiteRun); + + Ref blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, + bool horizontal); + + int max(int a, float b) { return (float)a > b ? a : (int)b; }; + }; + +} + +#endif // __MONOCHROMERECTANGLEDETECTOR_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/detector/WhiteRectangleDetector.h b/hgdriver/ImageProcess/include/zxing/common/detector/WhiteRectangleDetector.h new file mode 100755 index 0000000..f7b2b6e --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/detector/WhiteRectangleDetector.h @@ -0,0 +1,59 @@ +#ifndef __WHITERECTANGLEDETECTOR_H__ +#define __WHITERECTANGLEDETECTOR_H__ + +/* + * WhiteRectangleDetector.h + * + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + + +namespace zxing { + + class WhiteRectangleDetector : public Counted { + private: + static int INIT_SIZE; + static int CORR; + Ref image_; + int width_; + int height_; + int leftInit_; + int rightInit_; + int downInit_; + int upInit_; + + public: + WhiteRectangleDetector(Ref image); + WhiteRectangleDetector(Ref image, int initSize, int x, int y); + std::vector > detect(); + + private: + Ref getBlackPointOnSegment(int aX, int aY, int bX, int bY); + std::vector > centerEdges(Ref y, Ref z, + Ref x, Ref t); + bool containsBlackPoint(int a, int b, int fixed, bool horizontal); + }; +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGF.h b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGF.h new file mode 100755 index 0000000..7cd81ea --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGF.h @@ -0,0 +1,73 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * GenericGF.h + * zxing + * + * Created by Lukas Stabe on 13/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GENERICGF_H +#define GENERICGF_H + +#include +#include + +namespace zxing { + class GenericGFPoly; + + class GenericGF : public Counted { + + private: + std::vector expTable; + std::vector logTable; + Ref zero; + Ref one; + int size; + int primitive; + int generatorBase; + bool initialized; + + void initialize(); + void checkInit(); + + public: + static Ref AZTEC_DATA_12; + static Ref AZTEC_DATA_10; + static Ref AZTEC_DATA_8; + static Ref AZTEC_DATA_6; + static Ref AZTEC_PARAM; + static Ref QR_CODE_FIELD_256; + static Ref DATA_MATRIX_FIELD_256; + static Ref MAXICODE_FIELD_64; + + GenericGF(int primitive, int size, int b); + + Ref getZero(); + Ref getOne(); + int getSize(); + int getGeneratorBase(); + Ref buildMonomial(int degree, int coefficient); + + static int addOrSubtract(int a, int b); + int exp(int a); + int log(int a); + int inverse(int a); + int multiply(int a, int b); + }; +} + +#endif //GENERICGF_H + diff --git a/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGFPoly.h b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGFPoly.h new file mode 100755 index 0000000..960e622 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/GenericGFPoly.h @@ -0,0 +1,56 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * GenericGFPoly.h + * zxing + * + * Created by Lukas Stabe on 13/02/2012. + * Copyright 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GENERICGFPOLY_H +#define GENERICGFPOLY_H + +#include +#include +#include + +namespace zxing { + + class GenericGF; + + class GenericGFPoly : public Counted { + private: + Ref field_; + ArrayRef coefficients_; + + public: + GenericGFPoly(Ref field, ArrayRef coefficients); + ArrayRef getCoefficients(); + int getDegree(); + bool isZero(); + int getCoefficient(int degree); + int evaluateAt(int a); + Ref addOrSubtract(Ref other); + Ref multiply(Ref other); + Ref multiply(int scalar); + Ref multiplyByMonomial(int degree, int coefficient); + std::vector > divide(Ref other); + + + }; + +} + +#endif //GENERICGFPOLY_H diff --git a/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonDecoder.h b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonDecoder.h new file mode 100755 index 0000000..867c4d7 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonDecoder.h @@ -0,0 +1,49 @@ +#ifndef __REED_SOLOMON_DECODER_H__ +#define __REED_SOLOMON_DECODER_H__ + +/* + * ReedSolomonDecoder.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + class GenericGFPoly; + class GenericGF; + + class ReedSolomonDecoder { + private: + Ref field; + public: + ReedSolomonDecoder(Ref fld); + ~ReedSolomonDecoder(); + void decode(ArrayRef received, int twoS); + std::vector > runEuclideanAlgorithm(Ref a, Ref b, int R); + + private: + ArrayRef findErrorLocations(Ref errorLocator); + ArrayRef findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations); + }; +} + +#endif // __REED_SOLOMON_DECODER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonException.h b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonException.h new file mode 100755 index 0000000..9d6707e --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/common/reedsolomon/ReedSolomonException.h @@ -0,0 +1,33 @@ +#ifndef __REED_SOLOMON_EXCEPTION_H__ +#define __REED_SOLOMON_EXCEPTION_H__ + +/* + * ReedSolomonException.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + class ReedSolomonException : public Exception { + public: + ReedSolomonException(const char* msg) throw(); + ~ReedSolomonException() throw(); + }; +} + +#endif // __REED_SOLOMON_EXCEPTION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/DataMatrixReader.h b/hgdriver/ImageProcess/include/zxing/datamatrix/DataMatrixReader.h new file mode 100755 index 0000000..3b2cd54 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/DataMatrixReader.h @@ -0,0 +1,45 @@ +#ifndef __DATA_MATRIX_READER_H__ +#define __DATA_MATRIX_READER_H__ + +/* + * DataMatrixReader.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace datamatrix { + + class DataMatrixReader : public Reader { + private: + Decoder decoder_; + + public: + DataMatrixReader(); + virtual Ref decode(Ref image, DecodeHints hints); + virtual ~DataMatrixReader(); + + }; + + } +} + +#endif // __DATA_MATRIX_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/Version.h b/hgdriver/ImageProcess/include/zxing/datamatrix/Version.h new file mode 100755 index 0000000..ad4505c --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/Version.h @@ -0,0 +1,87 @@ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +/* + * Version.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace datamatrix { + + class ECB { + private: + int count_; + int dataCodewords_; + public: + ECB(int count, int dataCodewords); + int getCount(); + int getDataCodewords(); + }; + + class ECBlocks { + private: + int ecCodewords_; + std::vector ecBlocks_; + public: + ECBlocks(int ecCodewords, ECB* ecBlocks); + ECBlocks(int ecCodewords, ECB* ecBlocks1, ECB* ecBlocks2); + int getECCodewords(); + std::vector& getECBlocks(); + ~ECBlocks(); + }; + + class Version : public Counted { + private: + int versionNumber_; + int symbolSizeRows_; + int symbolSizeColumns_; + int dataRegionSizeRows_; + int dataRegionSizeColumns_; + ECBlocks* ecBlocks_; + int totalCodewords_; + Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, + int dataRegionSizeColumns, ECBlocks* ecBlocks); + + public: + static std::vector > VERSIONS; + + ~Version(); + int getVersionNumber(); + int getSymbolSizeRows(); + int getSymbolSizeColumns(); + int getDataRegionSizeRows(); + int getDataRegionSizeColumns(); + int getTotalCodewords(); + ECBlocks* getECBlocks(); + static int buildVersions(); + Ref getVersionForDimensions(int numRows, int numColumns); + + private: + Version(const Version&); + Version& operator=(const Version&); + }; + } +} + +#endif // __VERSION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/BitMatrixParser.h b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/BitMatrixParser.h new file mode 100755 index 0000000..0b182d2 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/BitMatrixParser.h @@ -0,0 +1,59 @@ +#ifndef __BIT_MATRIX_PARSER_DM_H__ +#define __BIT_MATRIX_PARSER_DM_H__ + +/* + * BitMatrixParser.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace datamatrix { + + class BitMatrixParser : public Counted { + private: + Ref bitMatrix_; + Ref parsedVersion_; + Ref readBitMatrix_; + + int copyBit(size_t x, size_t y, int versionBits); + + public: + BitMatrixParser(Ref bitMatrix); + Ref readVersion(Ref bitMatrix); + ArrayRef readCodewords(); + bool readModule(int row, int column, int numRows, int numColumns); + + private: + int readUtah(int row, int column, int numRows, int numColumns); + int readCorner1(int numRows, int numColumns); + int readCorner2(int numRows, int numColumns); + int readCorner3(int numRows, int numColumns); + int readCorner4(int numRows, int numColumns); + Ref extractDataRegion(Ref bitMatrix); + }; + + } +} + +#endif // __BIT_MATRIX_PARSER_DM_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DataBlock.h b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DataBlock.h new file mode 100755 index 0000000..d85f94f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DataBlock.h @@ -0,0 +1,49 @@ +#ifndef __DATA_BLOCK_DM_H__ +#define __DATA_BLOCK_DM_H__ + +/* + * DataBlock.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace datamatrix { + + class DataBlock : public Counted { + private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + + public: + static std::vector > getDataBlocks(ArrayRef rawCodewords, Version* version); + + int getNumDataCodewords(); + ArrayRef getCodewords(); + }; + + } +} + +#endif // __DATA_BLOCK_DM_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DecodedBitStreamParser.h b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DecodedBitStreamParser.h new file mode 100755 index 0000000..f59193d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/DecodedBitStreamParser.h @@ -0,0 +1,104 @@ +#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__ +#define __DECODED_BIT_STREAM_PARSER_DM_H__ + +/* + * DecodedBitStreamParser.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + + +namespace zxing { + namespace datamatrix { + + class DecodedBitStreamParser { + private: + static const int PAD_ENCODE = 0; // Not really an encoding + static const int ASCII_ENCODE = 1; + static const int C40_ENCODE = 2; + static const int TEXT_ENCODE = 3; + static const int ANSIX12_ENCODE = 4; + static const int EDIFACT_ENCODE = 5; + static const int BASE256_ENCODE = 6; + + /** + * See ISO 16022:2006, Annex C Table C.1 + * The C40 Basic Character Set (*'s used for placeholders for the shift values) + */ + static const char C40_BASIC_SET_CHARS[]; + + static const char C40_SHIFT2_SET_CHARS[]; + /** + * See ISO 16022:2006, Annex C Table C.2 + * The Text Basic Character Set (*'s used for placeholders for the shift values) + */ + static const char TEXT_BASIC_SET_CHARS[]; + + static const char TEXT_SHIFT3_SET_CHARS[]; + /** + * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 + */ + int decodeAsciiSegment(Ref bits, std::ostringstream& result, std::ostringstream& resultTrailer); + /** + * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + */ + void decodeC40Segment(Ref bits, std::ostringstream& result); + /** + * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + */ + void decodeTextSegment(Ref bits, std::ostringstream& result); + /** + * See ISO 16022:2006, 5.2.7 + */ + void decodeAnsiX12Segment(Ref bits, std::ostringstream& result); + /** + * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 + */ + void decodeEdifactSegment(Ref bits, std::ostringstream& result); + /** + * See ISO 16022:2006, 5.2.9 and Annex B, B.2 + */ + void decodeBase256Segment(Ref bits, std::ostringstream& result, std::vector byteSegments); + + void parseTwoBytes(int firstByte, int secondByte, int* result); + /** + * See ISO 16022:2006, Annex B, B.2 + */ + char unrandomize255State(int randomizedBase256Codeword, + int base256CodewordPosition) { + int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; + int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; + return (char)(tempVariable >= 0 ? tempVariable : (tempVariable + 256)); + }; + void append(std::ostream& ost, const char* bufIn, size_t nIn, const char* src); + + public: + DecodedBitStreamParser() { }; + Ref decode(ArrayRef bytes); + }; + + } +} + +#endif // __DECODED_BIT_STREAM_PARSER_DM_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/Decoder.h b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/Decoder.h new file mode 100755 index 0000000..388275a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/decoder/Decoder.h @@ -0,0 +1,49 @@ +#ifndef __DECODER_DM_H__ +#define __DECODER_DM_H__ + +/* + * Decoder.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + + +namespace zxing { + namespace datamatrix { + + class Decoder { + private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + + public: + Decoder(); + + Ref decode(Ref bits); + }; + + } +} + +#endif // __DECODER_DM_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/detector/CornerPoint.h b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/CornerPoint.h new file mode 100755 index 0000000..8977eae --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/CornerPoint.h @@ -0,0 +1,43 @@ +#ifndef __CORNER_FINDER_H__ +#define __CORNER_FINDER_H__ + +/* + * CornerPoint.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace datamatrix { + + class CornerPoint : public ResultPoint { + private: + int counter_; + + public: + CornerPoint(float posX, float posY); + int getCount() const; + void incrementCount(); + bool equals(Ref other) const; + }; + } +} + +#endif // __CORNER_FINDER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/detector/Detector.h b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/Detector.h new file mode 100755 index 0000000..905b2a5 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/Detector.h @@ -0,0 +1,94 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Created by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace datamatrix { + + class ResultPointsAndTransitions : public Counted { + private: + Ref to_; + Ref from_; + int transitions_; + + public: + ResultPointsAndTransitions(); + ResultPointsAndTransitions(Ref from, Ref to, int transitions); + Ref getFrom(); + Ref getTo(); + int getTransitions(); + }; + + class Detector : public Counted { + private: + Ref image_; + + protected: + Ref sampleGrid(Ref image, int dimensionX, int dimensionY, + Ref transform); + + void insertionSort(std::vector >& vector); + + Ref correctTopRightRectangular(Ref bottomLeft, + Ref bottomRight, Ref topLeft, Ref topRight, + int dimensionTop, int dimensionRight); + Ref correctTopRight(Ref bottomLeft, Ref bottomRight, + Ref topLeft, Ref topRight, int dimension); + bool isValid(Ref p); + int distance(Ref a, Ref b); + Ref transitionsBetween(Ref from, Ref to); + int min(int a, int b) { + return a > b ? b : a; + } + /** + * Ends up being a bit faster than round(). This merely rounds its + * argument to the nearest int, where x.5 rounds up. + */ + int round(float d) { + return (int)(d + 0.5f); + } + + public: + Ref getImage(); + Detector(Ref image); + + virtual Ref createTransform(Ref topLeft, + Ref topRight, Ref bottomLeft, Ref bottomRight, + int dimensionX, int dimensionY); + + Ref detect(); + + private: + int compare(Ref a, Ref b); + }; + + } +} + +#endif // __DETECTOR_H__ diff --git a/hgdriver/ImageProcess/include/zxing/datamatrix/detector/DetectorException.h b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/DetectorException.h new file mode 100755 index 0000000..d2058be --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/datamatrix/detector/DetectorException.h @@ -0,0 +1,23 @@ +/* + * DetectorException.h + * + * Created on: Aug 26, 2011 + * Author: luiz + */ + +#ifndef DETECTOREXCEPTION_H_ +#define DETECTOREXCEPTION_H_ + +#include + +namespace zxing { + namespace datamatrix { + + class DetectorException : public Exception { + public: + DetectorException(const char* msg); + virtual ~DetectorException() throw(); + }; + } /* namespace nexxera */ +} /* namespace zxing */ +#endif /* DETECTOREXCEPTION_H_ */ diff --git a/hgdriver/ImageProcess/include/zxing/multi/ByQuadrantReader.h b/hgdriver/ImageProcess/include/zxing/multi/ByQuadrantReader.h new file mode 100755 index 0000000..e91baa4 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/ByQuadrantReader.h @@ -0,0 +1,42 @@ +#ifndef __BY_QUADRANT_READER_H__ +#define __BY_QUADRANT_READER_H__ + +/* + * Copyright 2011 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace multi { + + class ByQuadrantReader : public Reader { + private: + Reader& delegate_; + + public: + ByQuadrantReader(Reader& delegate); + virtual ~ByQuadrantReader(); + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints); + }; + + } +} + +#endif // __BY_QUADRANT_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/multi/GenericMultipleBarcodeReader.h b/hgdriver/ImageProcess/include/zxing/multi/GenericMultipleBarcodeReader.h new file mode 100755 index 0000000..8919ea6 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/GenericMultipleBarcodeReader.h @@ -0,0 +1,51 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __GENERIC_MULTIPLE_BARCODE_READER_H__ +#define __GENERIC_MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 2011 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace multi { + + class GenericMultipleBarcodeReader : public MultipleBarcodeReader { + private: + static Ref translateResultPoints(Ref result, + int xOffset, + int yOffset); + void doDecodeMultiple(Ref image, + DecodeHints hints, + std::vector >& results, + int xOffset, + int yOffset, + int currentDepth); + Reader& delegate_; + static const int MIN_DIMENSION_TO_RECUR = 100; + static const int MAX_DEPTH = 4; + + public: + GenericMultipleBarcodeReader(Reader& delegate); + virtual ~GenericMultipleBarcodeReader(); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints); + }; + + } +} + +#endif // __GENERIC_MULTIPLE_BARCODE_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/multi/MultipleBarcodeReader.h b/hgdriver/ImageProcess/include/zxing/multi/MultipleBarcodeReader.h new file mode 100755 index 0000000..616376b --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/MultipleBarcodeReader.h @@ -0,0 +1,41 @@ +#ifndef __MULTIPLE_BARCODE_READER_H__ +#define __MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 2011 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace multi { + + class MultipleBarcodeReader : public Counted { + protected: + MultipleBarcodeReader() {} + public: + virtual std::vector > decodeMultiple(Ref image); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints) = 0; + virtual ~MultipleBarcodeReader(); + }; + + } +} + +#endif // __MULTIPLE_BARCODE_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/multi/qrcode/QRCodeMultiReader.h b/hgdriver/ImageProcess/include/zxing/multi/qrcode/QRCodeMultiReader.h new file mode 100755 index 0000000..8d166e7 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/qrcode/QRCodeMultiReader.h @@ -0,0 +1,36 @@ +#ifndef __QRCODE_MULTI_READER_H__ +#define __QRCODE_MULTI_READER_H__ + +/* + * Copyright 2011 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace multi { + + class QRCodeMultiReader : public zxing::qrcode::QRCodeReader, public MultipleBarcodeReader { + public: + QRCodeMultiReader(); + virtual ~QRCodeMultiReader(); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints); + }; + + } +} + +#endif // __QRCODE_MULTI_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiDetector.h b/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiDetector.h new file mode 100755 index 0000000..f3dfc5a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiDetector.h @@ -0,0 +1,37 @@ +#ifndef __MULTI_DETECTOR_H__ +#define __MULTI_DETECTOR_H__ + +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +namespace multi { + +class MultiDetector : public zxing::qrcode::Detector { + public: + MultiDetector(Ref image); + virtual ~MultiDetector(); + virtual std::vector > detectMulti(DecodeHints hints); +}; + +} +} + +#endif // __MULTI_DETECTOR_H__ diff --git a/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h b/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h new file mode 100755 index 0000000..116be39 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h @@ -0,0 +1,47 @@ +#ifndef __MULTI_FINDER_PATTERN_FINDER_H__ +#define __MULTI_FINDER_PATTERN_FINDER_H__ + +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace multi { + + class MultiFinderPatternFinder : zxing::qrcode::FinderPatternFinder { + private: + std::vector > > selectBestPatterns(); + + static const float MAX_MODULE_COUNT_PER_EDGE; + static const float MIN_MODULE_COUNT_PER_EDGE; + static const float DIFF_MODSIZE_CUTOFF_PERCENT; + static const float DIFF_MODSIZE_CUTOFF; + + public: + MultiFinderPatternFinder(Ref image, Ref resultPointCallback); + virtual ~MultiFinderPatternFinder(); + virtual std::vector > findMulti(DecodeHints const& hints); + + + }; + + } +} + +#endif // __MULTI_FINDER_PATTERN_FINDER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/oned/CodaBarReader.h b/hgdriver/ImageProcess/include/zxing/oned/CodaBarReader.h new file mode 100755 index 0000000..2d93e9c --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/CodaBarReader.h @@ -0,0 +1,57 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODA_BAR_READER_H__ +#define __CODA_BAR_READER_H__ +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + class CodaBarReader : public OneDReader { + private: + static const int MAX_ACCEPTABLE; + static const int PADDING; + + // Keep some instance variables to avoid reallocations + std::string decodeRowResult; + std::vector counters; + int counterLength; + + public: + CodaBarReader(); + + Ref decodeRow(int rowNumber, Ref row); + + void validatePattern(int start); + + private: + void setCounters(Ref row); + void counterAppend(int e); + int findStartPattern(); + + static bool arrayContains(char const array[], char key); + + int toNarrowWidePattern(int position); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/Code128Reader.h b/hgdriver/ImageProcess/include/zxing/oned/Code128Reader.h new file mode 100755 index 0000000..d969511 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/Code128Reader.h @@ -0,0 +1,48 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODE_128_READER_H__ +#define __CODE_128_READER_H__ +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + class Code128Reader : public OneDReader { + private: + static const int MAX_AVG_VARIANCE; + static const int MAX_INDIVIDUAL_VARIANCE; + + static std::vector findStartPattern(Ref row); + static int decodeCode(Ref row, + std::vector& counters, + int rowOffset); + + public: + Ref decodeRow(int rowNumber, Ref row); + Code128Reader(); + ~Code128Reader(); + + BarcodeFormat getBarcodeFormat(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/Code39Reader.h b/hgdriver/ImageProcess/include/zxing/oned/Code39Reader.h new file mode 100755 index 0000000..87c6975 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/Code39Reader.h @@ -0,0 +1,63 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODE_39_READER_H__ +#define __CODE_39_READER_H__ +/* + * Code39Reader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + /** + *

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ + class Code39Reader : public OneDReader { + private: + bool usingCheckDigit; + bool extendedMode; + std::string decodeRowResult; + std::vector counters; + + void init(bool usingCheckDigit = false, bool extendedMode = false); + + static std::vector findAsteriskPattern(Ref row, + std::vector& counters); + static int toNarrowWidePattern(std::vector& counters); + static char patternToChar(int pattern); + static Ref decodeExtended(std::string encoded); + + void append(char* s, char c); + + public: + Code39Reader(); + Code39Reader(bool usingCheckDigit_); + Code39Reader(bool usingCheckDigit_, bool extendedMode_); + + Ref decodeRow(int rowNumber, Ref row); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/Code93Reader.h b/hgdriver/ImageProcess/include/zxing/oned/Code93Reader.h new file mode 100755 index 0000000..50d1c1a --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/Code93Reader.h @@ -0,0 +1,58 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __CODE_93_READER_H__ +#define __CODE_93_READER_H__ +/* + * Code93Reader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + /** + *

Decodes Code 93 barcodes. This does not support "Full ASCII Code 93" yet.

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ + class Code93Reader : public OneDReader { + public: + Code93Reader(); + Ref decodeRow(int rowNumber, Ref row); + + private: + std::string decodeRowResult; + std::vector counters; + + Range findAsteriskPattern(Ref row); + + static int toPattern(std::vector& counters); + static char patternToChar(int pattern); + static Ref decodeExtended(std::string const& encoded); + static void checkChecksums(std::string const& result); + static void checkOneChecksum(std::string const& result, + int checkPosition, + int weightMax); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/EAN13Reader.h b/hgdriver/ImageProcess/include/zxing/oned/EAN13Reader.h new file mode 100755 index 0000000..b68550f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/EAN13Reader.h @@ -0,0 +1,49 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __EAN_13_READER_H__ +#define __EAN_13_READER_H__ + +/* + * EAN13Reader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + + class EAN13Reader : public UPCEANReader { + private: + std::vector decodeMiddleCounters; + static void determineFirstDigit(std::string& resultString, + int lgPatternFound); + + public: + EAN13Reader(); + + int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/EAN8Reader.h b/hgdriver/ImageProcess/include/zxing/oned/EAN8Reader.h new file mode 100755 index 0000000..91dbcfc --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/EAN8Reader.h @@ -0,0 +1,47 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __EAN_8_READER_H__ +#define __EAN_8_READER_H__ + +/* + * EAN8Reader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + + class EAN8Reader : public UPCEANReader { + private: + std::vector decodeMiddleCounters; + + public: + EAN8Reader(); + + int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString); + + BarcodeFormat getBarcodeFormat(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/ITFReader.h b/hgdriver/ImageProcess/include/zxing/oned/ITFReader.h new file mode 100755 index 0000000..ba869be --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/ITFReader.h @@ -0,0 +1,54 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ITF_READER_H__ +#define __ITF_READER_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + class ITFReader : public OneDReader { + private: + enum { MAX_AVG_VARIANCE = (unsigned int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 420 / 1000) }; + enum { MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 780 / 1000) }; + // Stores the actual narrow line width of the image being decoded. + int narrowLineWidth; + + Range decodeStart(Ref row); + Range decodeEnd(Ref row); + static void decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString); + void validateQuietZone(Ref row, int startPattern); + static int skipWhiteSpace(Ref row); + + static Range findGuardPattern(Ref row, int rowOffset, std::vector const& pattern); + static int decodeDigit(std::vector& counters); + + void append(char* s, char c); + public: + Ref decodeRow(int rowNumber, Ref row); + ITFReader(); + ~ITFReader(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/MultiFormatOneDReader.h b/hgdriver/ImageProcess/include/zxing/oned/MultiFormatOneDReader.h new file mode 100755 index 0000000..5d48103 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/MultiFormatOneDReader.h @@ -0,0 +1,38 @@ +#ifndef __MULTI_FORMAT_ONED_READER_H__ +#define __MULTI_FORMAT_ONED_READER_H__ +/* + * MultiFormatOneDReader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace oned { + class MultiFormatOneDReader : public OneDReader { + + private: + std::vector > readers; + public: + MultiFormatOneDReader(DecodeHints hints); + + Ref decodeRow(int rowNumber, Ref row); + }; + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/MultiFormatUPCEANReader.h b/hgdriver/ImageProcess/include/zxing/oned/MultiFormatUPCEANReader.h new file mode 100755 index 0000000..f0916da --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/MultiFormatUPCEANReader.h @@ -0,0 +1,41 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __MULTI_FORMAT_UPC_EAN_READER_H__ +#define __MULTI_FORMAT_UPC_EAN_READER_H__ +/* + * MultiFormatUPCEANReader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace oned { + + class UPCEANReader; + + class MultiFormatUPCEANReader : public OneDReader { + private: + std::vector< Ref > readers; + public: + MultiFormatUPCEANReader(DecodeHints hints); + Ref decodeRow(int rowNumber, Ref row); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/OneDReader.h b/hgdriver/ImageProcess/include/zxing/oned/OneDReader.h new file mode 100755 index 0000000..0ab7729 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/OneDReader.h @@ -0,0 +1,81 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __ONED_READER_H__ +#define __ONED_READER_H__ + +/* + * OneDReader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace oned { + + class OneDReader : public Reader { + private: + Ref doDecode(Ref image, DecodeHints hints); + + protected: + static const int INTEGER_MATH_SHIFT = 8; + + struct Range { + private: + int data[2]; + public: + Range() {} + Range(int zero, int one) { + data[0] = zero; + data[1] = one; + } + int& operator [] (int index) { + return data[index]; + } + int const& operator [] (int index) const { + return data[index]; + } + }; + + static int patternMatchVariance(std::vector& counters, + std::vector const& pattern, + int maxIndividualVariance); + static int patternMatchVariance(std::vector& counters, + int const pattern[], + int maxIndividualVariance); + + protected: + static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + + public: + + OneDReader(); + virtual Ref decode(Ref image, DecodeHints hints); + + // Implementations must not throw any exceptions. If a barcode is not found on this row, + // a empty ref should be returned e.g. return Ref(); + virtual Ref decodeRow(int rowNumber, Ref row) = 0; + + static void recordPattern(Ref row, + int start, + std::vector& counters); + virtual ~OneDReader(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/OneDResultPoint.h b/hgdriver/ImageProcess/include/zxing/oned/OneDResultPoint.h new file mode 100755 index 0000000..17c270f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/OneDResultPoint.h @@ -0,0 +1,35 @@ +#ifndef __ONED_RESULT_POINT_H__ +#define __ONED_RESULT_POINT_H__ +/* + * OneDResultPoint.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +namespace zxing { + namespace oned { + + class OneDResultPoint : public ResultPoint { + + public: + OneDResultPoint(float posX, float posY); + }; + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/UPCAReader.h b/hgdriver/ImageProcess/include/zxing/oned/UPCAReader.h new file mode 100755 index 0000000..bf40521 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/UPCAReader.h @@ -0,0 +1,50 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __UPCA_READER_H__ +#define __UPCA_READER_H__ +/* + * UPCAReader.h + * ZXing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + + class UPCAReader : public UPCEANReader { + + private: + EAN13Reader ean13Reader; + static Ref maybeReturnResult(Ref result); + + public: + UPCAReader(); + + int decodeMiddle(Ref row, Range const& startRange, std::string& resultString); + + Ref decodeRow(int rowNumber, Ref row); + Ref decodeRow(int rowNumber, Ref row, Range const& startGuardRange); + Ref decode(Ref image, DecodeHints hints); + + BarcodeFormat getBarcodeFormat(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/UPCEANReader.h b/hgdriver/ImageProcess/include/zxing/oned/UPCEANReader.h new file mode 100755 index 0000000..429d7e8 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/UPCEANReader.h @@ -0,0 +1,88 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __UPC_EAN_READER_H__ +#define __UPC_EAN_READER_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + class UPCEANReader : public OneDReader { + private: + std::string decodeRowStringBuffer; + // UPCEANExtensionSupport extensionReader; + // EANManufacturerOrgSupport eanManSupport; + + static const int MAX_AVG_VARIANCE; + static const int MAX_INDIVIDUAL_VARIANCE; + + static Range findStartGuardPattern(Ref row); + + virtual Range decodeEnd(Ref row, int endStart); + + static bool checkStandardUPCEANChecksum(Ref const& s); + + static Range findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + std::vector const& pattern, + std::vector& counters); + + + protected: + static const std::vector START_END_PATTERN; + static const std::vector MIDDLE_PATTERN; + + static const std::vector L_PATTERNS; + static const std::vector L_AND_G_PATTERNS; + + static Range findGuardPattern(Ref row, + int rowOffset, + bool whiteFirst, + std::vector const& pattern); + + public: + UPCEANReader(); + + virtual int decodeMiddle(Ref row, + Range const& startRange, + std::string& resultString) = 0; + + virtual Ref decodeRow(int rowNumber, Ref row); + virtual Ref decodeRow(int rowNumber, Ref row, Range const& range); + + static int decodeDigit(Ref row, + std::vector& counters, + int rowOffset, + std::vector const& patterns); + + virtual bool checkChecksum(Ref const& s); + + virtual BarcodeFormat getBarcodeFormat() = 0; + virtual ~UPCEANReader(); + + friend class MultiFormatUPCEANReader; + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/oned/UPCEReader.h b/hgdriver/ImageProcess/include/zxing/oned/UPCEReader.h new file mode 100755 index 0000000..bc2d726 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/oned/UPCEReader.h @@ -0,0 +1,47 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __UPC_E_READER_H__ +#define __UPC_E_READER_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + + class UPCEReader : public UPCEANReader { + private: + std::vector decodeMiddleCounters; + static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); + + protected: + Range decodeEnd(Ref row, int endStart); + bool checkChecksum(Ref const& s); + public: + UPCEReader(); + + int decodeMiddle(Ref row, Range const& startRange, std::string& resultString); + static Ref convertUPCEtoUPCA(Ref const& upce); + + BarcodeFormat getBarcodeFormat(); + }; + + } +} + +#endif diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/PDF417Reader.h b/hgdriver/ImageProcess/include/zxing/pdf417/PDF417Reader.h new file mode 100755 index 0000000..1d6d05f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/PDF417Reader.h @@ -0,0 +1,49 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __PDF417_READER_H__ +#define __PDF417_READER_H__ + +/* + * PDF417Reader.h + * zxing + * + * Copyright 2010,2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace pdf417 { + + + class PDF417Reader : public Reader { + private: + decoder::Decoder decoder; + + static Ref extractPureBits(Ref image); + static int moduleSize(ArrayRef leftTopBlack, Ref image); + static int findPatternStart(int x, int y, Ref image); + static int findPatternEnd(int x, int y, Ref image); + + public: + Ref decode(Ref image, DecodeHints hints); + void reset(); + }; + + } +} + +#endif // __PDF417_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/BitMatrixParser.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/BitMatrixParser.h new file mode 100755 index 0000000..7b2a626 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/BitMatrixParser.h @@ -0,0 +1,84 @@ +#ifndef __BIT_MATRIX_PARSER__PDF_H__ +#define __BIT_MATRIX_PARSER__PDF_H__ + +/* + * BitMatrixParser.h / PDF417 + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace decoder { + + class BitMatrixParser : public Counted { + private: + static const int MAX_ROWS; + // Maximum Codewords (Data + Error) + static const int MAX_CW_CAPACITY; + static const int MODULES_IN_SYMBOL; + + Ref bitMatrix_; + int rows_; /* = 0 */ + int leftColumnECData_; /* = 0 */ + int rightColumnECData_; /* = 0 */ + /* added 2012-06-22 HFN */ + int aLeftColumnTriple_[3]; + int aRightColumnTriple_[3]; + int eraseCount_; /* = 0 */ + ArrayRef erasures_; + int ecLevel_; /* = -1 */ + + public: + static const int SYMBOL_TABLE[]; + static const int SYMBOL_TABLE_LENGTH; + static const int CODEWORD_TABLE[]; + + public: + BitMatrixParser(Ref bitMatrix); + ArrayRef getErasures() const { return erasures_; } + int getECLevel() const { return ecLevel_; } + int getEraseCount() const { return eraseCount_; } + ArrayRef readCodewords(); /* throw(FormatException) */ + static int getCodeword(int64_t symbol, int* pi = NULL); + + private: + bool VerifyOuterColumns(int rownumber); + static ArrayRef trimArray(ArrayRef array, int size); + static int findCodewordIndex(int64_t symbol); + + + int processRow(int rowNumber, + ArrayRef codewords, int next); + + int processRow(ArrayRef rowCounters, int rowNumber, int rowHeight, + ArrayRef codewords, int next); /* throw(FormatException) */ + protected: + bool IsEqual(int& a, int& b, int rownumber); + }; + + } + } +} + +#endif // __BIT_MATRIX_PARSER__PDF_H__ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/DecodedBitStreamParser.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/DecodedBitStreamParser.h new file mode 100755 index 0000000..2e51ea2 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/DecodedBitStreamParser.h @@ -0,0 +1,84 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DECODED_BIT_STREAM_PARSER_PD_H__ +#define __DECODED_BIT_STREAM_PARSER_PD_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + + class DecodedBitStreamParser { + protected: + enum Mode { + ALPHA, + LOWER, + MIXED, + PUNCT, + ALPHA_SHIFT, + PUNCT_SHIFT + }; + + private: + + static const int TEXT_COMPACTION_MODE_LATCH; + static const int BYTE_COMPACTION_MODE_LATCH; + static const int NUMERIC_COMPACTION_MODE_LATCH; + static const int BYTE_COMPACTION_MODE_LATCH_6; + static const int BEGIN_MACRO_PDF417_CONTROL_BLOCK; + static const int BEGIN_MACRO_PDF417_OPTIONAL_FIELD; + static const int MACRO_PDF417_TERMINATOR; + static const int MODE_SHIFT_TO_BYTE_COMPACTION_MODE; + static const int MAX_NUMERIC_CODEWORDS; + + static const int PL; + static const int LL; + static const int AS; + static const int ML; + static const int AL; + static const int PS; + static const int PAL; + static const int EXP900_SIZE; + + static const char PUNCT_CHARS[]; + static const char MIXED_CHARS[]; + + static ArrayRef EXP900; + static ArrayRef initEXP900(); + + static int textCompaction(ArrayRef codewords, int codeIndex, Ref result); + static void decodeTextCompaction(ArrayRef textCompactionData, + ArrayRef byteCompactionData, + int length, + Ref result); + static int byteCompaction(int mode, ArrayRef codewords, int codeIndex, Ref result); + static int numericCompaction(ArrayRef codewords, int codeIndex, Ref result); + static Ref decodeBase900toBase10(ArrayRef codewords, int count); + + public: + DecodedBitStreamParser(); + static Ref decode(ArrayRef codewords); + }; + + } /* namespace pdf417 */ +} /* namespace zxing */ + +#endif // __DECODED_BIT_STREAM_PARSER_PD_H__ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.cpp b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.cpp new file mode 100755 index 0000000..65509d0 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.cpp @@ -0,0 +1,118 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 2010, 2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * 2012-06-27 hfn: PDF417 Reed-Solomon error correction, using following Java + * source code: + * http://code.google.com/p/zxing/issues/attachmentText?id=817&aid=8170033000&name=pdf417-java-reed-solomon-error-correction-2.patch&token=0819f5d7446ae2814fd91385eeec6a11 + */ + +#include +#include +#include +#include +#include +#include + +using zxing::pdf417::decoder::Decoder; +using zxing::pdf417::decoder::ec::ErrorCorrection; +using zxing::Ref; +using zxing::DecoderResult; + +// VC++ + +using zxing::BitMatrix; +using zxing::DecodeHints; +using zxing::ArrayRef; + +const int Decoder::MAX_ERRORS = 3; +const int Decoder::MAX_EC_CODEWORDS = 512; + +Ref Decoder::decode(Ref bits, DecodeHints const& hints) { + (void)hints; + // Construct a parser to read the data codewords and error-correction level + BitMatrixParser parser(bits); + ArrayRef codewords(parser.readCodewords()); + if (codewords->size() == 0) { + throw FormatException("PDF:Decoder:decode: cannot read codewords"); + } + + int ecLevel = parser.getECLevel(); + int numECCodewords = 1 << (ecLevel + 1); + ArrayRef erasures = parser.getErasures(); + + correctErrors(codewords, erasures, numECCodewords); + verifyCodewordCount(codewords, numECCodewords); + + // Decode the codewords + return DecodedBitStreamParser::decode(codewords); +} + +/** + * Verify that all is OK with the codeword array. + * + * @param codewords + * @return an index to the first data codeword. + * @throws FormatException + */ +void Decoder::verifyCodewordCount(ArrayRef codewords, int numECCodewords) { + int cwsize = codewords->size(); + if (cwsize < 4) { + // Codeword array size should be at least 4 allowing for + // Count CW, At least one Data CW, Error Correction CW, Error Correction CW + throw FormatException("PDF:Decoder:verifyCodewordCount: codeword array too small!"); + } + // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data + // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad + // codewords, but excluding the number of error correction codewords. + int numberOfCodewords = codewords[0]; + if (numberOfCodewords > cwsize) { + throw FormatException("PDF:Decoder:verifyCodewordCount: bad codeword number descriptor!"); + } + if (numberOfCodewords == 0) { + // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords) + if (numECCodewords < cwsize) { + codewords[0] = cwsize - numECCodewords; + } else { + throw FormatException("PDF:Decoder:verifyCodewordCount: bad error correction cw number!"); + } + } +} + +/** + * Correct errors whenever it is possible using Reed-Solomom algorithm + * + * @param codewords, erasures, numECCodewords + * @return 0. + * @throws FormatException + */ +void Decoder::correctErrors(ArrayRef codewords, + ArrayRef erasures, int numECCodewords) { + if (erasures->size() > numECCodewords / 2 + MAX_ERRORS || + numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS) { + throw FormatException("PDF:Decoder:correctErrors: Too many errors or EC Codewords corrupted"); + } + + Ref errorCorrection(new ErrorCorrection); + errorCorrection->decode(codewords, numECCodewords, erasures); + + // 2012-06-27 HFN if, despite of error correction, there are still codewords with invalid + // value, throw an exception here: + for (int i = 0; i < codewords->size(); i++) { + if (codewords[i]<0) { + throw FormatException("PDF:Decoder:correctErrors: Error correction did not succeed!"); + } + } +} diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.h new file mode 100755 index 0000000..4b2fa66 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/Decoder.h @@ -0,0 +1,62 @@ +#ifndef __DECOCER_PDF_H__ +#define __DECOCER_PDF_H__ + +/* + * Decoder.h + * zxing + * + * Created by Hartmut Neubauer, 2012-05-25 + * Copyright 2010,2012 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + + +namespace zxing { + namespace pdf417 { + namespace decoder { + + /** + *

The main class which implements PDF417 Code decoding -- as + * opposed to locating and extracting the PDF417 Code from an image.

+ * + *

2012-06-27 HFN Reed-Solomon error correction activated, see class PDF417RSDecoder.

+ *

2012-09-19 HFN Reed-Solomon error correction via ErrorCorrection/ModulusGF/ModulusPoly.

+ */ + + class Decoder { + private: + static const int MAX_ERRORS; + static const int MAX_EC_CODEWORDS; + + void correctErrors(ArrayRef codewords, + ArrayRef erasures, int numECCodewords); + static void verifyCodewordCount(ArrayRef codewords, int numECCodewords); + + public: + + Ref decode(Ref bits, DecodeHints const& hints); + }; + + } + } +} + +#endif // __DECOCER_PDF_H__ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ErrorCorrection.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ErrorCorrection.h new file mode 100755 index 0000000..e0e9574 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ErrorCorrection.h @@ -0,0 +1,71 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __ERROR_CORRECTION_PDF_H__ +#define __ERROR_CORRECTION_PDF_H__ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * 2012-09-17 HFN translation from Java into C++ + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace decoder { + namespace ec { + + + /** + *

PDF417 error correction implementation.

+ * + *

This example + * is quite useful in understanding the algorithm.

+ * + * @author Sean Owen + * @see com.google.zxing.common.reedsolomon.ReedSolomonDecoder + */ + class ErrorCorrection : public Counted { + + private: + ModulusGF& field_; + + public: + ErrorCorrection(); + void decode(ArrayRef received, + int numECCodewords, + ArrayRef erasures); + + private: + std::vector > runEuclideanAlgorithm(Ref a, Ref b, int R); + + ArrayRef findErrorLocations(Ref errorLocator); + ArrayRef findErrorMagnitudes(Ref errorEvaluator, + Ref errorLocator, + ArrayRef errorLocations); + }; + + } + } + } +} + +#endif /* __ERROR_CORRECTION_PDF_H__ */ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusGF.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusGF.h new file mode 100755 index 0000000..bdaa020 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusGF.h @@ -0,0 +1,72 @@ +#ifndef __MODULUS_GF_PDF_H__ +#define __MODULUS_GF_PDF_H__ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * 2012-09-17 HFN translation from Java into C++ + */ + +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace decoder { + namespace ec { + + class ModulusPoly; + + /** + *

A field based on powers of a generator integer, modulo some modulus.

+ * + * @author Sean Owen + * @see com.google.zxing.common.reedsolomon.GenericGF + */ + class ModulusGF { + + public: + static ModulusGF PDF417_GF; + + private: + ArrayRef expTable_; + ArrayRef logTable_; + Ref zero_; + Ref one_; + int modulus_; + + public: + ModulusGF(int modulus, int generator); + Ref getZero(); + Ref getOne(); + Ref buildMonomial(int degree, int coefficient); + + int add(int a, int b); + int subtract(int a, int b); + int exp(int a); + int log(int a); + int inverse(int a); + int multiply(int a, int b); + int getSize(); + + }; + + } + } + } +} + +#endif /* __MODULUS_GF_PDF_H__ */ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusPoly.h b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusPoly.h new file mode 100755 index 0000000..1b4f1a4 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/decoder/ec/ModulusPoly.h @@ -0,0 +1,68 @@ +#ifndef __MODULUS_GFPOLY_PDF_H__ +#define __MODULUS_GFPOLY_PDF_H__ + +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * 2012-09-17 HFN translation from Java into C++ + */ + +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace decoder { + namespace ec { + + class ModulusGF; + + /** + * @author Sean Owen + * @see com.google.zxing.common.reedsolomon.GenericGFPoly + */ + class ModulusPoly : public Counted { + + private: + ModulusGF& field_; + ArrayRef coefficients_; + public: + ModulusPoly(ModulusGF& field, ArrayRef coefficients); + ~ModulusPoly(); + ArrayRef getCoefficients(); + int getDegree(); + bool isZero(); + int getCoefficient(int degree); + int evaluateAt(int a); + Ref add(Ref other); + Ref subtract(Ref other); + Ref multiply(Ref other); + Ref negative(); + Ref multiply(int scalar); + Ref multiplyByMonomial(int degree, int coefficient); + std::vector > divide(Ref other); +#if 0 + public String toString(); +#endif + }; + + } + } + } +} + +#endif /* __MODULUS_GFPOLY_PDF_H__ */ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/detector/Detector.h b/hgdriver/ImageProcess/include/zxing/pdf417/detector/Detector.h new file mode 100755 index 0000000..c5b0dfa --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/detector/Detector.h @@ -0,0 +1,106 @@ +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace detector { + + class Detector { + private: + static const int INTEGER_MATH_SHIFT = 8; + static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + static const int MAX_AVG_VARIANCE; + static const int MAX_INDIVIDUAL_VARIANCE; + + static const int START_PATTERN[]; + static const int START_PATTERN_LENGTH; + static const int START_PATTERN_REVERSE[]; + static const int START_PATTERN_REVERSE_LENGTH; + static const int STOP_PATTERN[]; + static const int STOP_PATTERN_LENGTH; + static const int STOP_PATTERN_REVERSE[]; + static const int STOP_PATTERN_REVERSE_LENGTH; + + Ref image_; + + static ArrayRef< Ref > findVertices(Ref matrix, int rowStep); + static ArrayRef< Ref > findVertices180(Ref matrix, int rowStep); + + static ArrayRef findGuardPattern(Ref matrix, + int column, + int row, + int width, + bool whiteFirst, + const int pattern[], + int patternSize, + ArrayRef& counters); + static int patternMatchVariance(ArrayRef& counters, const int pattern[], + int maxIndividualVariance); + + static void correctVertices(Ref matrix, + ArrayRef< Ref >& vertices, + bool upsideDown); + static void findWideBarTopBottom(Ref matrix, + ArrayRef< Ref >& vertices, + int offsetVertice, + int startWideBar, + int lenWideBar, + int lenPattern, + int nIncrement); + static void findCrossingPoint(ArrayRef< Ref >& vertices, + int idxResult, + int idxLineA1, int idxLineA2, + int idxLineB1, int idxLineB2, + Ref& matrix); + static Point intersection(Line a, Line b); + static float computeModuleWidth(ArrayRef< Ref >& vertices); + static int computeDimension(Ref const& topLeft, + Ref const& topRight, + Ref const& bottomLeft, + Ref const& bottomRight, + float moduleWidth); + int computeYDimension(Ref const& topLeft, + Ref const& topRight, + Ref const& bottomLeft, + Ref const& bottomRight, + float moduleWidth); + + Ref sampleLines(ArrayRef< Ref > const& vertices, int dimensionY, int dimension); + + public: + Detector(Ref image); + Ref getImage(); + Ref detect(); + Ref detect(DecodeHints const& hints); + }; + + } + } +} + +#endif // __DETECTOR_H__ diff --git a/hgdriver/ImageProcess/include/zxing/pdf417/detector/LinesSampler.h b/hgdriver/ImageProcess/include/zxing/pdf417/detector/LinesSampler.h new file mode 100755 index 0000000..c0521fe --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/pdf417/detector/LinesSampler.h @@ -0,0 +1,122 @@ +#ifndef __LINESSAMPLER_H__ +#define __LINESSAMPLER_H__ + +/* + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace pdf417 { + namespace detector { + + class LinesSampler { + private: + static const int MODULES_IN_SYMBOL = 17; + static const int BARS_IN_SYMBOL = 8; + static const int POSSIBLE_SYMBOLS = 2787; + static const std::vector RATIOS_TABLE; + static std::vector init_ratios_table(); + static const int BARCODE_START_OFFSET = 2; + + Ref linesMatrix_; + int symbolsPerLine_; + int dimension_; + + static std::vector > findVertices(Ref matrix, int rowStep); + static std::vector > findVertices180(Ref matrix, int rowStep); + + static ArrayRef findGuardPattern(Ref matrix, + int column, + int row, + int width, + bool whiteFirst, + const int pattern[], + int patternSize, + ArrayRef counters); + static int patternMatchVariance(ArrayRef counters, const int pattern[], + int maxIndividualVariance); + + static void correctVertices(Ref matrix, + std::vector >& vertices, + bool upsideDown); + static void findWideBarTopBottom(Ref matrix, + std::vector >& vertices, + int offsetVertice, + int startWideBar, + int lenWideBar, + int lenPattern, + int nIncrement); + static void findCrossingPoint(std::vector >& vertices, + int idxResult, + int idxLineA1, int idxLineA2, + int idxLineB1, int idxLineB2, + Ref matrix); + static float computeModuleWidth(std::vector >& vertices); + static int computeDimension(Ref topLeft, + Ref topRight, + Ref bottomLeft, + Ref bottomRight, + float moduleWidth); + int computeYDimension(Ref topLeft, + Ref topRight, + Ref bottomLeft, + Ref bottomRight, + float moduleWidth); + + Ref sampleLines(std::vector > const& vertices, + int dimensionY, + int dimension); + + static void codewordsToBitMatrix(std::vector >& codewords, + Ref& matrix); + static int calculateClusterNumber(int codeword); + static Ref sampleGrid(Ref image, + int dimension); + static void computeSymbolWidths(std::vector& symbolWidths, + const int symbolsPerLine, Ref linesMatrix); + static void linesMatrixToCodewords(std::vector >& clusterNumbers, + const int symbolsPerLine, + const std::vector& symbolWidths, + Ref linesMatrix, + std::vector >& codewords); + static std::vector > > + distributeVotes(const int symbolsPerLine, + const std::vector >& codewords, + const std::vector >& clusterNumbers); + static std::vector + findMissingLines(const int symbolsPerLine, + std::vector >& detectedCodeWords); + static int decodeRowCount(const int symbolsPerLine, + std::vector >& detectedCodeWords, + std::vector& insertLinesAt); + + static int round(float d); + static Point intersection(Line a, Line b); + + public: + LinesSampler(Ref linesMatrix, int dimension); + Ref sample(); + }; + + } + } +} + +#endif // __LINESSAMPLER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/ErrorCorrectionLevel.h b/hgdriver/ImageProcess/include/zxing/qrcode/ErrorCorrectionLevel.h new file mode 100755 index 0000000..5202a9d --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/ErrorCorrectionLevel.h @@ -0,0 +1,52 @@ +#ifndef __ERROR_CORRECTION_LEVEL_H__ +#define __ERROR_CORRECTION_LEVEL_H__ + +/* + * ErrorCorrectionLevel.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace qrcode { + + class ErrorCorrectionLevel { + private: + int ordinal_; + int bits_; + std::string name_; + ErrorCorrectionLevel(int inOrdinal, int bits, char const* name); + static ErrorCorrectionLevel* FOR_BITS[]; + static int N_LEVELS; + public: + static ErrorCorrectionLevel L; + static ErrorCorrectionLevel M; + static ErrorCorrectionLevel Q; + static ErrorCorrectionLevel H; + + int ordinal() const; + int bits() const; + std::string const& name() const; + operator std::string const& () const; + + static ErrorCorrectionLevel& forBits(int bits); + }; + } +} + +#endif // __ERROR_CORRECTION_LEVEL_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/FormatInformation.h b/hgdriver/ImageProcess/include/zxing/qrcode/FormatInformation.h new file mode 100755 index 0000000..5ea74c7 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/FormatInformation.h @@ -0,0 +1,54 @@ +#ifndef __FORMAT_INFORMATION_H__ +#define __FORMAT_INFORMATION_H__ + +/* + * FormatInformation.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class FormatInformation : public Counted { + private: + static int FORMAT_INFO_MASK_QR; + static int FORMAT_INFO_DECODE_LOOKUP[][2]; + static int N_FORMAT_INFO_DECODE_LOOKUPS; + static int BITS_SET_IN_HALF_BYTE[]; + + ErrorCorrectionLevel& errorCorrectionLevel_; + char dataMask_; + + FormatInformation(int formatInfo); + + public: + static int numBitsDiffering(int a, int b); + static Ref decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); + static Ref doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2); + ErrorCorrectionLevel& getErrorCorrectionLevel(); + char getDataMask(); + friend bool operator==(const FormatInformation& a, const FormatInformation& b); + friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi); + }; + } +} + +#endif // __FORMAT_INFORMATION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/QRCodeReader.h b/hgdriver/ImageProcess/include/zxing/qrcode/QRCodeReader.h new file mode 100755 index 0000000..c14c5ed --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/QRCodeReader.h @@ -0,0 +1,48 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __QR_CODE_READER_H__ +#define __QR_CODE_READER_H__ + +/* + * QRCodeReader.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class QRCodeReader : public Reader { + private: + Decoder decoder_; + + protected: + Decoder& getDecoder(); + + public: + QRCodeReader(); + virtual ~QRCodeReader(); + + Ref decode(Ref image, DecodeHints hints); + }; + + } +} + +#endif // __QR_CODE_READER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/Version.h b/hgdriver/ImageProcess/include/zxing/qrcode/Version.h new file mode 100755 index 0000000..321f844 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/Version.h @@ -0,0 +1,85 @@ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +/* + * Version.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class ECB { + private: + int count_; + int dataCodewords_; + public: + ECB(int count, int dataCodewords); + int getCount(); + int getDataCodewords(); + }; + + class ECBlocks { + private: + int ecCodewords_; + std::vector ecBlocks_; + public: + ECBlocks(int ecCodewords, ECB* ecBlocks); + ECBlocks(int ecCodewords, ECB* ecBlocks1, ECB* ecBlocks2); + int getECCodewords(); + std::vector& getECBlocks(); + ~ECBlocks(); + }; + + class Version : public Counted { + + private: + int versionNumber_; + std::vector& alignmentPatternCenters_; + std::vector ecBlocks_; + int totalCodewords_; + Version(int versionNumber, std::vector* alignmentPatternCenters, ECBlocks* ecBlocks1, ECBlocks* ecBlocks2, + ECBlocks* ecBlocks3, ECBlocks* ecBlocks4); + + public: + static unsigned int VERSION_DECODE_INFO[]; + static int N_VERSION_DECODE_INFOS; + static std::vector > VERSIONS; + + ~Version(); + int getVersionNumber(); + std::vector& getAlignmentPatternCenters(); + int getTotalCodewords(); + int getDimensionForVersion(); + ECBlocks& getECBlocksForLevel(ErrorCorrectionLevel& ecLevel); + static Version* getProvisionalVersionForDimension(int dimension); + static Version* getVersionForNumber(int versionNumber); + static Version* decodeVersionInformation(unsigned int versionBits); + Ref buildFunctionPattern(); + static int buildVersions(); + }; + } +} + +#endif // __VERSION_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/BitMatrixParser.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/BitMatrixParser.h new file mode 100755 index 0000000..8e36292 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/BitMatrixParser.h @@ -0,0 +1,56 @@ +#ifndef __BIT_MATRIX_PARSER_H__ +#define __BIT_MATRIX_PARSER_H__ + +/* + * BitMatrixParser.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class BitMatrixParser : public Counted { + private: + Ref bitMatrix_; + Version* parsedVersion_; + Ref parsedFormatInfo_; + + int copyBit(size_t x, size_t y, int versionBits); + + public: + BitMatrixParser(Ref bitMatrix); + Ref readFormatInformation(); + Version* readVersion(); + ArrayRef readCodewords(); + + private: + BitMatrixParser(const BitMatrixParser&); + BitMatrixParser& operator =(const BitMatrixParser&); + + }; + + } +} + +#endif // __BIT_MATRIX_PARSER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataBlock.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataBlock.h new file mode 100755 index 0000000..f029c90 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataBlock.h @@ -0,0 +1,50 @@ +#ifndef __DATA_BLOCK_H__ +#define __DATA_BLOCK_H__ + +/* + * DataBlock.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class DataBlock : public Counted { + private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + + public: + static std::vector > + getDataBlocks(ArrayRef rawCodewords, Version* version, ErrorCorrectionLevel& ecLevel); + + int getNumDataCodewords(); + ArrayRef getCodewords(); + }; + + } +} + +#endif // __DATA_BLOCK_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataMask.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataMask.h new file mode 100755 index 0000000..ce2e364 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DataMask.h @@ -0,0 +1,50 @@ +#ifndef __DATA_MASK_H__ +#define __DATA_MASK_H__ + +/* + * DataMask.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +namespace zxing { + namespace qrcode { + + class DataMask : public Counted { + private: + static std::vector > DATA_MASKS; + + protected: + + public: + static int buildDataMasks(); + DataMask(); + virtual ~DataMask(); + void unmaskBitMatrix(BitMatrix& matrix, size_t dimension); + virtual bool isMasked(size_t x, size_t y) = 0; + static DataMask& forReference(int reference); + }; + + } +} + +#endif // __DATA_MASK_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DecodedBitStreamParser.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DecodedBitStreamParser.h new file mode 100755 index 0000000..0f17e0b --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/DecodedBitStreamParser.h @@ -0,0 +1,72 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __DECODED_BIT_STREAM_PARSER_H__ +#define __DECODED_BIT_STREAM_PARSER_H__ + +/* + * DecodedBitStreamParser.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class DecodedBitStreamParser { + public: + typedef std::map Hashtable; + + private: + static char const ALPHANUMERIC_CHARS[]; + static char toAlphaNumericChar(size_t value); + + static void decodeHanziSegment(Ref bits, std::string& result, int count); + static void decodeKanjiSegment(Ref bits, std::string& result, int count); + static void decodeByteSegment(Ref bits, std::string& result, int count); + static void decodeByteSegment(Ref bits_, + std::string& result, + int count, + zxing::common::CharacterSetECI* currentCharacterSetECI, + ArrayRef< ArrayRef >& byteSegments, + Hashtable const& hints); + static void decodeAlphanumericSegment(Ref bits, std::string& result, int count, bool fc1InEffect); + static void decodeNumericSegment(Ref bits, std::string& result, int count); + + static void append(std::string& ost, const char* bufIn, size_t nIn, const char* src); + static void append(std::string& ost, std::string const& in, const char* src); + + public: + static Ref decode(ArrayRef bytes, + Version* version, + ErrorCorrectionLevel const& ecLevel, + Hashtable const& hints); + }; + + } +} + +#endif // __DECODED_BIT_STREAM_PARSER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Decoder.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Decoder.h new file mode 100755 index 0000000..617ce2b --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Decoder.h @@ -0,0 +1,46 @@ +#ifndef __DECODER_H__ +#define __DECODER_H__ + +/* + * Decoder.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class Decoder { + private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + + public: + Decoder(); + Ref decode(Ref bits); + }; + + } +} + +#endif // __DECODER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Mode.h b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Mode.h new file mode 100755 index 0000000..04aabe8 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/decoder/Mode.h @@ -0,0 +1,57 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __MODE_H__ +#define __MODE_H__ + +/* + * Mode.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class Mode { + private: + int characterCountBitsForVersions0To9_; + int characterCountBitsForVersions10To26_; + int characterCountBitsForVersions27AndHigher_; + std::string name_; + + Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name); + + public: + static Mode TERMINATOR; + static Mode NUMERIC; + static Mode ALPHANUMERIC; + static Mode STRUCTURED_APPEND; + static Mode BYTE; + static Mode ECI; + static Mode KANJI; + static Mode FNC1_FIRST_POSITION; + static Mode FNC1_SECOND_POSITION; + static Mode HANZI; + + static Mode& forBits(int bits); + int getCharacterCountBits(Version* version); + }; + } +} + +#endif // __MODE_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPattern.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPattern.h new file mode 100755 index 0000000..b7d125e --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPattern.h @@ -0,0 +1,45 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __ALIGNMENT_PATTERN_H__ +#define __ALIGNMENT_PATTERN_H__ + +/* + * AlignmentPattern.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class AlignmentPattern : public ResultPoint { + private: + float estimatedModuleSize_; + + public: + AlignmentPattern(float posX, float posY, float estimatedModuleSize); + bool aboutEquals(float moduleSize, float i, float j) const; + Ref combineEstimate(float i, float j, + float newModuleSize) const; + }; + + } +} + +#endif // __ALIGNMENT_PATTERN_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPatternFinder.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPatternFinder.h new file mode 100755 index 0000000..fe8a990 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/AlignmentPatternFinder.h @@ -0,0 +1,68 @@ +#ifndef __ALIGNMENT_PATTERN_FINDER_H__ +#define __ALIGNMENT_PATTERN_FINDER_H__ + +/* + * AlignmentPatternFinder.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AlignmentPattern.h" +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class AlignmentPatternFinder : public Counted { + private: + static int CENTER_QUORUM; + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector* possibleCenters_; + int startX_; + int startY_; + int width_; + int height_; + float moduleSize_; + + static float centerFromEnd(std::vector& stateCount, int end); + bool foundPatternCross(std::vector& stateCount); + + float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal); + + Ref handlePossibleCenter(std::vector& stateCount, int i, int j); + + public: + AlignmentPatternFinder(Ref image, int startX, int startY, int width, int height, + float moduleSize, Refconst& callback); + ~AlignmentPatternFinder(); + Ref find(); + + private: + AlignmentPatternFinder(const AlignmentPatternFinder&); + AlignmentPatternFinder& operator =(const AlignmentPatternFinder&); + + Ref callback_; + }; + } +} + +#endif // __ALIGNMENT_PATTERN_FINDER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/Detector.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/Detector.h new file mode 100755 index 0000000..f90bcb6 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/Detector.h @@ -0,0 +1,69 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + + class DecodeHints; + + namespace qrcode { + + class Detector : public Counted { + private: + Ref image_; + Ref callback_; + + protected: + Ref getImage() const; + Ref getResultPointCallback() const; + + static Ref sampleGrid(Ref image, int dimension, Ref); + static int computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize); + float calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft); + float calculateModuleSizeOneWay(Ref pattern, Ref otherPattern); + float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY); + float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); + Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor); + Ref processFinderPatternInfo(Ref info); + public: + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + + Detector(Ref image); + Ref detect(DecodeHints const& hints); + + + }; + } +} + +#endif // __DETECTOR_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPattern.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPattern.h new file mode 100755 index 0000000..51fca5f --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPattern.h @@ -0,0 +1,48 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __FINDER_PATTERN_H__ +#define __FINDER_PATTERN_H__ + +/* + * FinderPattern.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class FinderPattern : public ResultPoint { + private: + float estimatedModuleSize_; + int count_; + + FinderPattern(float posX, float posY, float estimatedModuleSize, int count); + + public: + FinderPattern(float posX, float posY, float estimatedModuleSize); + int getCount() const; + float getEstimatedModuleSize() const; + void incrementCount(); + bool aboutEquals(float moduleSize, float i, float j) const; + Ref combineEstimate(float i, float j, float newModuleSize) const; + }; + } +} + +#endif // __FINDER_PATTERN_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternFinder.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternFinder.h new file mode 100755 index 0000000..5e80561 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternFinder.h @@ -0,0 +1,76 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __FINDER_PATTERN_FINDER_H__ +#define __FINDER_PATTERN_FINDER_H__ + +/* + * FinderPatternFinder.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + + class DecodeHints; + + namespace qrcode { + + class FinderPatternFinder { + private: + static int CENTER_QUORUM; + + protected: + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector > possibleCenters_; + bool hasSkipped_; + + Ref callback_; + + /** stateCount must be int[5] */ + static float centerFromEnd(int* stateCount, int end); + static bool foundPatternCross(int* stateCount); + + float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); + float crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, int originalStateCountTotal); + + /** stateCount must be int[5] */ + bool handlePossibleCenter(int* stateCount, size_t i, size_t j); + int findRowSkip(); + bool haveMultiplyConfirmedCenters(); + std::vector > selectBestPatterns(); + static std::vector > orderBestPatterns(std::vector > patterns); + + Ref getImage(); + std::vector >& getPossibleCenters(); + + public: + static float distance(Ref p1, Ref p2); + FinderPatternFinder(Ref image, Refconst&); + Ref find(DecodeHints const& hints); + }; + } +} + +#endif // __FINDER_PATTERN_FINDER_H__ diff --git a/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternInfo.h b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternInfo.h new file mode 100755 index 0000000..2b373c7 --- /dev/null +++ b/hgdriver/ImageProcess/include/zxing/qrcode/detector/FinderPatternInfo.h @@ -0,0 +1,47 @@ +#ifndef __FINDER_PATTERN_INFO_H__ +#define __FINDER_PATTERN_INFO_H__ + +/* + * FinderPatternInfo.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + namespace qrcode { + + class FinderPatternInfo : public Counted { + private: + Ref bottomLeft_; + Ref topLeft_; + Ref topRight_; + + public: + FinderPatternInfo(std::vector > patternCenters); + + Ref getBottomLeft(); + Ref getTopLeft(); + Ref getTopRight(); + }; + } +} + +#endif // __FINDER_PATTERN_INFO_H__ diff --git a/hgdriver/ImageProcess/lib/debug/zbar.lib b/hgdriver/ImageProcess/lib/debug/zbar.lib new file mode 100755 index 0000000..8fe4d8a Binary files /dev/null and b/hgdriver/ImageProcess/lib/debug/zbar.lib differ diff --git a/hgdriver/ImageProcess/lib/debug/zxing.lib b/hgdriver/ImageProcess/lib/debug/zxing.lib new file mode 100755 index 0000000..f16ad3b Binary files /dev/null and b/hgdriver/ImageProcess/lib/debug/zxing.lib differ diff --git a/hgdriver/ImageProcess/lib/release/zbar.lib b/hgdriver/ImageProcess/lib/release/zbar.lib new file mode 100755 index 0000000..b9a60a7 Binary files /dev/null and b/hgdriver/ImageProcess/lib/release/zbar.lib differ diff --git a/hgdriver/ImageProcess/lib/release/zxing.lib b/hgdriver/ImageProcess/lib/release/zxing.lib new file mode 100755 index 0000000..1342b06 Binary files /dev/null and b/hgdriver/ImageProcess/lib/release/zxing.lib differ diff --git a/hgdriver/ImageProcess_test/CMakeLists.txt b/hgdriver/ImageProcess_test/CMakeLists.txt new file mode 100644 index 0000000..dc55d60 --- /dev/null +++ b/hgdriver/ImageProcess_test/CMakeLists.txt @@ -0,0 +1,18 @@ +project(gimgproc) +add_compile_options(-std=c++11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS) +file(GLOB DIR_HEADS "${PROJECT_SOURCE_DIR}/*.h" "${PROJECT_SOURCE_DIR}/*.hpp") +set(DIR_SRCS ${DIR_SRCS} ${DIR_HEADS}) + +add_library(${PROJECT_NAME} STATIC ${DIR_SRCS}) + + +target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/../3rdparty/nick + ${PROJECT_SOURCE_DIR}/../hgimgproc + ${PROJECT_SOURCE_DIR}/../3rdparty/opencv/include + ${PROJECT_SOURCE_DIR}/../3rdparty/tiff/include + ) +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../build/) diff --git a/hgdriver/ImageProcess_test/G4Tiff.cpp b/hgdriver/ImageProcess_test/G4Tiff.cpp new file mode 100644 index 0000000..ec9b7fe --- /dev/null +++ b/hgdriver/ImageProcess_test/G4Tiff.cpp @@ -0,0 +1,178 @@ +#include "G4Tiff.h" +#if defined(WIN32) || defined(_WIN64) +#include +#else +#include +#include +#include +#define _access access +#define _fileno fileno +#define _lseek lseek +#endif + +G4Tiff::G4Tiff(cv::Mat & mat, Mode mode,std::string path + , int threshold,int res, int compression) + : m_threshold(threshold), m_res(res), m_mode(mode) + , compression_(compression) +{ + m_tmppath = mode == Mode::MemoryMode ? cv::tempfile(".tif").c_str() : path; + m_mat = mat; + if (mode == Mode::MemoryMode) + save(mat); +} + +G4Tiff::~G4Tiff() +{ + if (m_mode == Mode::MemoryMode) + { + if (_access(m_tmppath.c_str(), 0) == 0) + { + if (!std::remove(m_tmppath.c_str())) {}//ɾɹ + else + throw std::runtime_error("File is not exist"); + } + } +} + +uchar* G4Tiff::load_mini_file(const char* file, size_t* bytes, void* (*mem_alloc)(size_t, const char*)) +{ + uchar* buf = nullptr; + + if (bytes) + *bytes = 0; + + FILE* src = fopen(file, "rb"); + if (src) + { + int filesize = _lseek(_fileno(src), 0, SEEK_END); // seek to EOF + fseek(src, 0, SEEK_SET); + std::vector ifh(8, 0); + fread(ifh.data(), 1, ifh.size(), src); + int size = (int)(*(int*)(ifh.data() + 4)); + fseek(src, 8, SEEK_SET); + if (filesize) + { + if (bytes) + *bytes = size; + buf = (uchar*)mem_alloc(size, ""); + if (buf) + fread(buf, 1, size, src); + } + fclose(src); + } + + return buf; +} + +void G4Tiff::GetCompressedData(std::vector& cmpeddata) +{ + if (m_tmppath.empty()) + throw std::runtime_error("file is not exist"); + FILE* file = fopen(m_tmppath.c_str(), "rb"); + if (file) + { + + int filesize = _lseek(_fileno(file), 0, SEEK_END); // seek to EOF + fseek(file, 0, SEEK_SET); + std::vector ifh(8, 0); + fread(ifh.data(), 1, ifh.size(), file); + int size = (int)(*(int*)(ifh.data() + 4)); + fseek(file, 8, SEEK_SET); + if (filesize) + { + cmpeddata.resize(size); + fread(cmpeddata.data(), 1, size, file); + } + } + fclose(file); +} +uchar* G4Tiff::get_compressed_data(size_t* bytes, void* (*mem_alloc)(size_t, const char*)) +{ + if (m_tmppath.empty()) + throw std::runtime_error("file is not exist"); + + return G4Tiff::load_mini_file(m_tmppath.c_str(), bytes, mem_alloc); +} +void G4Tiff::SaveG4Tiff() +{ + save(m_mat); +} + +void G4Tiff::save(cv::Mat& mat) +{ + if (compression_ == COMPRESSION_CCITT_T6 && mat.channels() != 1) + throw std::runtime_error("mat channel error"); + TIFF* pTiffHandle = TIFFOpen(m_tmppath.c_str(), "w"); + if (!pTiffHandle) + { + printf("can't open TIFF descriptor\n"); + } + int width = mat.cols; + int height = mat.rows; + try + { + except(TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width), "width"); + except(TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height), "length"); + if (compression_ == COMPRESSION_CCITT_T6) + { + except(TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, 1), "bits per sample"); + except(TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, 1), "samples per pixel"); + } + else + { + except(TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, /*mat.depth()*/8), "bits per sample"); + except(TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, mat.channels()), "samples per pixel"); + } + except(TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, height), "rows per strip"); + except(TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression_), "compression"); + except(TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE), "photometric"); + except(TIFFSetField(pTiffHandle, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB), "photometric"); + except(TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG), "planar config"); + // not necessary + except(TIFFSetField(pTiffHandle, TIFFTAG_XRESOLUTION, (float)m_res), "res x"); + except(TIFFSetField(pTiffHandle, TIFFTAG_YRESOLUTION, (float)m_res), "res y"); + except(TIFFSetField(pTiffHandle, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH), "res unit"); + + if (compression_ == COMPRESSION_CCITT_T6) + { + std::vector _buffer(width / 8 + 8, 0); + //std::vector _buffer(width / 8 + 1, 0); + uchar* buffer = &_buffer[0]; + //int bytes = int(width / 8.0 + 0.5); + for (int y = 0; y < height; ++y) + { + uint8_t* src_row = mat.ptr(y); + for (int x = 0; x < width; ++x, ++src_row) + { + uint8_t eight_pixels = buffer[x / 8]; + eight_pixels = eight_pixels << 1; + if (*src_row < m_threshold) + eight_pixels = eight_pixels | 1; // + buffer[x / 8] = eight_pixels; + } + except(TIFFWriteScanline(pTiffHandle, buffer, y, 0) != -1, "write scanline"); + } + } + else + { + int l = mat.total() / mat.rows * mat.channels(); + for (int y = 0; y < height; ++y) + { + uint8_t* src = mat.ptr(y); + except(TIFFWriteScanline(pTiffHandle, src, y, 0) != -1, "write scanline"); + } + } + } + catch (const std::runtime_error& e) + { + printf("TIFF writing: %s\n", e.what()); + // TIFFClose(pTiffHandle); + } + TIFFClose(pTiffHandle); +} + +void G4Tiff::except(bool condition, const std::string & message) +{ + if (!condition) + throw std::runtime_error("Error " + message); +} diff --git a/hgdriver/ImageProcess_test/G4Tiff.h b/hgdriver/ImageProcess_test/G4Tiff.h new file mode 100644 index 0000000..f94e884 --- /dev/null +++ b/hgdriver/ImageProcess_test/G4Tiff.h @@ -0,0 +1,41 @@ +#ifndef HUAGO_TIFF_H +#define HUAGO_TIFF_H +#include +#include +#include + +class G4Tiff +{ +public: + enum class Mode + { + FileMode, + MemoryMode + }; + G4Tiff(cv::Mat& mat, Mode mode, std::string path, int threshold=120,int res=200, int compression = COMPRESSION_CCITT_T6); + ~G4Tiff(); + + static uchar* load_mini_file(const char* file, size_t* bytes, void* (*mem_alloc)(size_t, const char*)); + +public: + /* + *ڴ洫ģʽʱѹͼȥ + */ + void GetCompressedData(std::vector& cmpeddata); + uchar* get_compressed_data(size_t* bytes, void* (*mem_alloc)(size_t, const char*)); + /* + * ļģʽʱʹ + */ + void SaveG4Tiff(); +private: + void save(cv::Mat& mat); +private: + void except(bool condition, const std::string& message = ""); + std::string m_tmppath; + int m_threshold; + int m_res; + int compression_; + Mode m_mode; + cv::Mat m_mat; +}; +#endif // !HUAGO_TIFF_H diff --git a/hgdriver/ImageProcess_test/IMulti.cpp b/hgdriver/ImageProcess_test/IMulti.cpp new file mode 100644 index 0000000..442cf4c --- /dev/null +++ b/hgdriver/ImageProcess_test/IMulti.cpp @@ -0,0 +1,10 @@ +#include "IMulti.h" + +IMulti::IMulti(void) +{ +} + +IMulti::~IMulti(void) +{ +} + diff --git a/hgdriver/ImageProcess_test/IMulti.h b/hgdriver/ImageProcess_test/IMulti.h new file mode 100644 index 0000000..df7ef35 --- /dev/null +++ b/hgdriver/ImageProcess_test/IMulti.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include "imgprocdefs.h" + +class IMulti +{ +public: + IMulti(void); + virtual ~IMulti(void); + virtual std::vector apply(cv::Mat& pDib) = 0; +}; diff --git a/hgdriver/ImageProcess_test/ImageApply.cpp b/hgdriver/ImageProcess_test/ImageApply.cpp new file mode 100644 index 0000000..80f5fbf --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApply.cpp @@ -0,0 +1,9 @@ +#include "ImageApply.h" + +CImageApply::CImageApply(void) +{ +} + +CImageApply::~CImageApply(void) +{ +} diff --git a/hgdriver/ImageProcess_test/ImageApply.h b/hgdriver/ImageProcess_test/ImageApply.h new file mode 100644 index 0000000..c94c0bc --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApply.h @@ -0,0 +1,21 @@ +#ifndef IMAGE_APPLY_H +#define IMAGE_APPLY_H + +#include +#include +#include + +class CImageApply +{ +public: + CImageApply(void); + virtual ~CImageApply(void); + + virtual void apply(cv::Mat& pDib,int side) = 0; + + virtual void apply(std::vector& mats, bool isTwoSide) = 0; +}; + +typedef std::shared_ptr ImageApplyPtr; + +#endif //!IMAGE_APPLY_H diff --git a/hgdriver/ImageProcess_test/ImageApplyAdjustColors.cpp b/hgdriver/ImageProcess_test/ImageApplyAdjustColors.cpp new file mode 100644 index 0000000..3e6cd5a --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAdjustColors.cpp @@ -0,0 +1,90 @@ +#include "ImageApplyAdjustColors.h" + +CImageApplyAdjustColors::CImageApplyAdjustColors(void) + : m_brightness(0) + , m_contrast(0) + , m_gamma(1.0f) + , lut(1, 256, CV_8UC1) +{ + update_lutData(); +} + +CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma) + : lut(1, 256, CV_8UC1) +{ + setAdjustColors(brightness, contrast, gamma); +} + +CImageApplyAdjustColors::~CImageApplyAdjustColors(void) +{ + +} + +void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side) +{ + (void)side; + if (pDib.empty()) return; + + if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f) + cv::LUT(pDib, lut, pDib); +} + +void CImageApplyAdjustColors::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if(!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + m_contrast = cv::max(-127, cv::min(contrast, 127)); + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::setBrightness(int brightness) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + update_lutData(); +} + +void CImageApplyAdjustColors::setContrast(int contrast) +{ + m_contrast = cv::max(-127, cv::min(contrast, 127)); + update_lutData(); +} + +void CImageApplyAdjustColors::setGamma(float gamma) +{ + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::update_lutData() +{ + unsigned char* ptr = lut.data; + + uchar buffer[256]; + for (int i = 0; i < 256; i++) + { + //update brightness + ptr[i] = static_cast(cv::max(0, cv::min(i + m_brightness, 255))); + + //update contrast + if (ptr[i] < 128) + ptr[i] = static_cast(cv::max(0, cv::min(ptr[i] - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(ptr[i] + m_contrast, 255))); + } + float g = 1.0f / m_gamma; + for (int i = 0; i < 256; i++) + ptr[i] = static_cast(cv::min(255, static_cast(cv::pow(static_cast(ptr[i]) / 255.0f, g) * 255.0f + 0.5f))); +} diff --git a/hgdriver/ImageProcess_test/ImageApplyAdjustColors.h b/hgdriver/ImageProcess_test/ImageApplyAdjustColors.h new file mode 100644 index 0000000..83ea595 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAdjustColors.h @@ -0,0 +1,53 @@ +#ifndef IMAGE_APPLY_ADJUST_COLOR_H +#define IMAGE_APPLY_ADJUST_COLOR_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors : public CImageApply +{ +public: + + CImageApplyAdjustColors(void); + + /* + * brightness [in]: ȵڣȡֵΧ[-255, 255] + * constrast [in]: ԱȶȵڣȡֵΧ[-128 127] + * gamma [in]: ٤ڣȡֵΧ[0.1, 5.0] + */ + CImageApplyAdjustColors(int brightness, int contrast, float gamma); + + virtual ~CImageApplyAdjustColors(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + void setAdjustColors(int brightness, int contrast, float gamma); + + int getContrast() { return m_contrast; } + + int getBrightness() { return m_brightness; } + + double getGamma() { return m_gamma; } + + void setBrightness(int brightness); + + void setContrast(int contrast); + + void setGamma(float gamma); + +private: + + void update_lutData(); + +private: + + int m_brightness; + int m_contrast; + float m_gamma; + cv::Mat lut; +}; + +#endif // !IMAGE_APPLY_ADJUST_COLOR_H + + diff --git a/hgdriver/ImageProcess_test/ImageApplyAutoContrast.cpp b/hgdriver/ImageProcess_test/ImageApplyAutoContrast.cpp new file mode 100644 index 0000000..4cd0d5f --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAutoContrast.cpp @@ -0,0 +1,43 @@ +#include "ImageApplyAutoContrast.h" +#include +using namespace std; +using namespace cv; + +CImageApplyAutoContrast::CImageApplyAutoContrast() +{ +} + +CImageApplyAutoContrast::~CImageApplyAutoContrast() +{ +} + +void CImageApplyAutoContrast::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if(pDib.channels() == 1) + cv::equalizeHist(pDib,pDib); + else + { + std::vector mats(3); + cv::split(pDib,mats); + for(size_t i = 0; i < mats.size(); i++) + if(!mats[i].empty()) + cv::equalizeHist(mats[i], mats[i]); + cv::merge(mats,pDib); + } +} + +void CImageApplyAutoContrast::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyAutoContrast.h b/hgdriver/ImageProcess_test/ImageApplyAutoContrast.h new file mode 100644 index 0000000..d8abf05 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAutoContrast.h @@ -0,0 +1,32 @@ +/* + * ==================================================== + + * ܣԶɫУʵԭΪֱͼ⻯ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_AUTO_CONTRAST_H +#define IMAGE_APPLY_AUTO_CONTRAST_H + +#include "ImageApply.h" + +class CImageApplyAutoContrast : public CImageApply +{ +public: + + CImageApplyAutoContrast(); + + virtual ~CImageApplyAutoContrast(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + +}; +#endif // !IMAGE_APPLY_AUTO_CONTRAST_H diff --git a/hgdriver/ImageProcess_test/ImageApplyAutoCrop.cpp b/hgdriver/ImageProcess_test/ImageApplyAutoCrop.cpp new file mode 100644 index 0000000..6c4be07 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAutoCrop.cpp @@ -0,0 +1,393 @@ +#include "ImageApplyAutoCrop.h" +#include "ImageProcess_Public.h" + +CImageApplyAutoCrop::CImageApplyAutoCrop() + : m_isCrop(false) + , m_isDesaskew(false) + , m_isFillBlank(false) + , m_isConvexHull(true) + , m_isFillColor(false) + , m_threshold(40) + , m_noise(8) + , m_indent(5) + , m_normalCrop(false) +{ +} + +CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor, + double threshold, int noise, int indent, bool normalCrop) + : m_isCrop(isCrop) + , m_isDesaskew(isDesaskew) + , m_isFillBlank(isFillBlank) + , m_isConvexHull(isConvex) + , m_isFillColor(isFillColor) + , m_threshold(threshold) + , m_noise(noise) + , m_indent(indent) + , m_fixedSize(fixedSize) + , m_normalCrop(normalCrop) +{ +} + +CImageApplyAutoCrop::~CImageApplyAutoCrop() +{ +} + +void matmul(double* mul1, double* mul2, double* dst) +{ + dst[0] = mul1[0] * mul2[0] + mul1[1] * mul2[3] + mul1[2] * mul2[6]; + dst[1] = mul1[0] * mul2[1] + mul1[1] * mul2[4] + mul1[2] * mul2[7]; + dst[2] = mul1[0] * mul2[2] + mul1[1] * mul2[5] + mul1[2] * mul2[8]; + dst[3] = mul1[3] * mul2[0] + mul1[4] * mul2[3] + mul1[5] * mul2[6]; + dst[4] = mul1[3] * mul2[1] + mul1[4] * mul2[4] + mul1[5] * mul2[7]; + dst[5] = mul1[3] * mul2[2] + mul1[4] * mul2[5] + mul1[5] * mul2[8]; + dst[6] = mul1[6] * mul2[0] + mul1[7] * mul2[3] + mul1[8] * mul2[6]; + dst[7] = mul1[6] * mul2[1] + mul1[7] * mul2[4] + mul1[8] * mul2[7]; + dst[8] = mul1[6] * mul2[2] + mul1[7] * mul2[5] + mul1[8] * mul2[8]; +} + +cv::Mat concatenateMatrix(const cv::Mat& first, const cv::Mat& second) +{ + double buffer1[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ; + double buffer2[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ; + cv::Mat mul1(3, 3, CV_64FC1, buffer1); //cv::Mat::eye(3, 3, CV_64F); + cv::Mat mul2(3, 3, CV_64FC1, buffer2); //cv::Mat::eye(3, 3, CV_64F); + cv::Mat mul_r; + first.convertTo(mul_r, CV_64F); + mul_r.row(0).copyTo(mul1.row(0)); + mul_r.row(1).copyTo(mul1.row(1)); + + second.convertTo(mul_r, CV_64F); + mul_r.row(0).copyTo(mul2.row(0)); + mul_r.row(1).copyTo(mul2.row(1)); + + //mul1 = mul2 * mul1; + cv::Mat temp(3, 3, CV_64FC1); + matmul(buffer2, buffer1, (double*)temp.data); + mul1 = temp; + mul_r = first.clone(); + mul1.row(0).copyTo(mul_r.row(0)); + mul1.row(1).copyTo(mul_r.row(1)); + return mul_r; +} + +std::vector comMat() +{ + std::vector mats; + cv::Point2f srcTri[3]; + srcTri[0] = cv::Point2f(1, 1); + srcTri[1] = cv::Point2f(1, 0); + srcTri[2] = cv::Point2f(0, 1); + const float fact = 0.33f; + + float pos[] = { 0, 2 * fact, fact }; + cv::Point2f dstTri[3]; + dstTri[0] = cv::Point2f(1, 1); + dstTri[1] = cv::Point2f(1, 0.5); + dstTri[2] = cv::Point2f(0, 1); + + for (int i = 0; i < 3; i++) + { + dstTri[0] = cv::Point2f(1, 1 + pos[i]); + dstTri[1] = cv::Point2f(1, pos[i]); + dstTri[2] = cv::Point2f(0, 1 + pos[i]); + + mats.push_back(cv::getAffineTransform(srcTri, dstTri)); + } + return mats; +} + +void brightSharp(cv::Mat& src) +{ + const float a = -0.49f; + const float b = 3.0f; + //float kernel_data[] = { + // a, 0, 0, 0, a, + // 0, 0, a, 0, 0, + // 0, a, b, a, 0, + // 0, 0, a, 0, 0, + // a, 0, 0, 0, a }; + + float kernel_data[] = { + 0, a, 0, + a, b, a, + 0, a, 0 + }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if (m_normalCrop) + { + cv::Rect roi = cv::Rect((pDib.cols - m_fixedSize.width) / 2, side == 0 ? 75 : 145, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows); + pDib = pDib(roi).clone(); + m_rect = cv::RotatedRect(cv::Point2f(roi.x + roi.width / 2, roi.y + roi.height / 2), cv::Size2f(roi.width, roi.height), 0.0f); + return; + } + + if (!m_isCrop && !m_isDesaskew && !m_isFillBlank && m_fixedSize.empty()) return; + + cv::Mat src = pDib; + cv::Mat thre; + cv::Mat dst; + hg::threshold_Mat(src, thre, m_threshold); + + if (m_noise > 0) + { + cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(m_noise, 1)); + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element); + } + + if (m_indent > 0) + { + cv::Mat element = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(m_indent, m_indent)); + cv::morphologyEx(thre, thre, cv::MORPH_ERODE, element); + } + + std::vector hierarchy; + std::vector> contours; + + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + m_maxContour = hg::getMaxContour(contours, hierarchy); + + if (m_maxContour.size() == 0) + { + thre.release(); + // + if (!m_isCrop) + pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone(); +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply"); +#endif // LOG + return; + } + + thre.release(); + dst.release(); + + cv::RotatedRect rect = hg::getBoundingRect(m_maxContour); + m_rect = rect; + cv::Rect boudingRect = cv::boundingRect(m_maxContour); + boudingRect.x -= 1; + boudingRect.y -= 1; + boudingRect.width += 2; + boudingRect.height += 2; + + if (m_isDesaskew && rect.angle != 0) + { + cv::Point2f srcTri[4], srcTri_temp[3], dstTri[3]; + rect.points(srcTri); + + dstTri[0] = cv::Point2f(0, rect.size.height - 1); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(rect.size.width - 1, 0); + + srcTri_temp[0] = dstTri[0]; + srcTri_temp[1] = dstTri[1]; + srcTri_temp[2] = dstTri[2]; + cv::Mat warp_mat; + warp_mat = cv::getAffineTransform(srcTri, dstTri); + if (src.channels() == 1) + { + cv::warpAffine(src, dst, warp_mat, rect.size, cv::INTER_LINEAR); + } + else + { + cv::Mat bgr[3]; + cv::split(src, bgr); + auto mats = comMat(); + warp_mat = cv::getAffineTransform(srcTri, dstTri); + warp_mat = concatenateMatrix(mats[0], warp_mat); + + cv::warpAffine(bgr[0], bgr[0], warp_mat, rect.size, cv::INTER_LINEAR); + + warp_mat = cv::getAffineTransform(srcTri, dstTri); + warp_mat = concatenateMatrix(mats[1], warp_mat); + cv::warpAffine(bgr[1], bgr[1], warp_mat, rect.size, cv::INTER_LINEAR); + + warp_mat = cv::getAffineTransform(srcTri, dstTri); + warp_mat = concatenateMatrix(mats[2], warp_mat); + cv::warpAffine(bgr[2], bgr[2], warp_mat, rect.size, cv::INTER_LINEAR); + + cv::merge(bgr, 3, dst); + } + + double* ptr_m = reinterpret_cast(warp_mat.data); + double a = ptr_m[0]; + double b = ptr_m[1]; + double c = ptr_m[2]; + double d = ptr_m[3]; + double e = ptr_m[4]; + double f = ptr_m[5]; + + for (cv::Point& p : m_maxContour) + { + p.x = static_cast(a * p.x + b * p.y + c); + p.y = static_cast(d * p.x + e * p.y + f); + } + + for (std::vector& sub : contours) + for (cv::Point& p : sub) + { + p.x = static_cast(a * p.x + b * p.y + c); + p.y = static_cast(d * p.x + e * p.y + f); + } + } + else + { + auto t_rect = boudingRect & cv::Rect(0, 0, src.cols, src.rows); + dst = src(t_rect); + if (dst.channels() == 3) + { + cv::Mat bgr[3]; + cv::split(dst, bgr); + auto mats = comMat(); + for (int i = 0; i < 3; i++) + cv::warpAffine(bgr[i], bgr[i], mats[i], t_rect.size(), cv::INTER_LINEAR); + cv::merge(bgr, 3, dst); + } + } + + cv::Scalar autoBGColor; + if (m_isFillBlank) + { + if (m_isConvexHull) + { + if (m_maxContour.size() == 0) + { + thre.release(); + //����ǹ̶����棬�뷵�ز��к�ijߴ� + if (!m_isCrop) + pDib = pDib(cv::Rect((pDib.cols - m_fixedSize.width) / 2, (pDib.rows - m_fixedSize.height) / 2, m_fixedSize.width, m_fixedSize.height) & cv::Rect(0, 0, pDib.cols, pDib.rows)).clone(); + return; + } + hg::convexHull(m_maxContour, m_maxContour); + contours.clear(); + contours.push_back(m_maxContour); + } + + contours.push_back(std::vector()); + contours[contours.size() - 1].push_back(cv::Point(-1, dst.rows - 1)); + contours[contours.size() - 1].push_back(cv::Point(-1, -1)); + contours[contours.size() - 1].push_back(cv::Point(dst.cols, -1)); + contours[contours.size() - 1].push_back(cv::Point(dst.cols, dst.rows)); + + autoBGColor = m_isFillColor ? getBackGroudColor(pDib, rect.size.area()) : cv::Scalar(255, 255, 255); + hg::fillPolys(dst, contours, autoBGColor); + } + else + { + m_maxContour.clear(); + m_maxContour.push_back(cv::Point(-1, dst.rows)); + m_maxContour.push_back(cv::Point(-1, -1)); + m_maxContour.push_back(cv::Point(dst.cols, -1)); + m_maxContour.push_back(cv::Point(dst.cols, dst.rows)); + } + + pDib.release(); + if (/*(m_isCrop && side == 0) || (side == 1 && m_fixedSize.width * m_fixedSize.height == 0)*/ m_isCrop) + pDib = dst.clone(); + else + { + pDib = cv::Mat(m_fixedSize, dst.type(), m_isFillBlank ? autoBGColor : cv::Scalar(0, 0, 0)); + + cv::Rect roi; + roi.x = dst.cols > pDib.cols ? (dst.cols - pDib.cols) / 2 : 0; + roi.width = cv::min(pDib.cols, dst.cols); + roi.y = dst.rows > pDib.rows ? (dst.rows - pDib.rows) / 2 : 0; + roi.height = cv::min(pDib.rows, dst.rows); + cv::Rect rect((pDib.cols - roi.width) / 2, (pDib.rows - roi.height) / 2, roi.width, roi.height); + + for (cv::Point& p : m_maxContour) + p += roi.tl(); + dst(roi).copyTo(pDib(rect)); + } +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply8"); +#endif // LOG +} + +void CImageApplyAutoCrop::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + if (!mats[0].empty()) { + apply(mats[0], 0); + m_rects.push_back(m_rect); + //brightSharp(mats[0]); + } + + if (isTwoSide && mats.size() > 1) + { + cv::Size dSize = m_fixedSize; + if (!mats[0].empty()) + m_fixedSize = mats[0].size(); + if (!mats[1].empty()) { + apply(mats[1], 1); + m_rects.push_back(m_rect); + //brightSharp(mats[1]); + } + + if (!mats[0].empty()) + m_fixedSize = dSize; + } +} + +cv::Scalar CImageApplyAutoCrop::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 CImageApplyAutoCrop::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 - m_threshold; + while (length < length_max) + { + for (size_t i = m_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; +} diff --git a/hgdriver/ImageProcess_test/ImageApplyAutoCrop.h b/hgdriver/ImageProcess_test/ImageApplyAutoCrop.h new file mode 100644 index 0000000..d09d365 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyAutoCrop.h @@ -0,0 +1,112 @@ +/* + * ==================================================== + + * 功能:自动裁剪、纠偏、除黑底 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用) + 2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度。 + 2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG。 + 2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG。 + 2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏) + 2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底。 + * 版本号:v1.3.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_AUTO_CROP_H +#define IMAGE_APPLY_AUTO_CROP_H + +#include "ImageApply.h" + +class CImageApplyAutoCrop : public CImageApply +{ +public: + CImageApplyAutoCrop(); + + + /* + * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剪 + * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 + * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 + * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像素 + * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true + * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false + * threshold [in]:二值化阈值,取值范围(0, 255),默认40 + * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默认2 + * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5 + * normalCrop [in]:为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式,默认false + */ + 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); + + virtual ~CImageApplyAutoCrop(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + bool isAutoCrop() { return m_isCrop; } + + bool isFillBlank() { return m_isFillBlank; } + + bool isDesaskew() { return m_isDesaskew; } + + bool isConvexHull() { return m_isConvexHull; } + + double threshold() { return m_threshold; } + + const cv::RotatedRect& rotatedROI() { return m_rect; } + + const std::vector& rotatedROIs() { return m_rects; } + + int noise() { return m_noise; } + + int indent() { return m_indent; } + + cv::Size fixedSize() { return m_fixedSize; } + + const std::vector& maxContour() { return m_maxContour; } + + void setAutoCrop(bool enabled) { m_isCrop = enabled; } + + void setFillBlank(bool enabled) { m_isFillBlank = enabled; } + + void setDesaskew(bool enabled) { m_isDesaskew = enabled; } + + void setConvexHull(bool convex) { m_isConvexHull = convex; } + + void setThreshold(double value) { m_threshold = value; } + + void setNoise(int value) { m_noise = value; } + + void setIndent(int value) { m_indent = value; } + + void setFixedSize(cv::Size size) { m_fixedSize = size; } + +private: + cv::Scalar getBackGroudColor(const cv::Mat& image, int total); + + uchar getBackGroudChannelMean(const cv::Mat& gray, int total); + +private: + bool m_isCrop; + bool m_isDesaskew; + bool m_isFillBlank; + bool m_isConvexHull; + bool m_isFillColor; + + double m_threshold; + int m_noise; + int m_indent; + bool m_normalCrop; //为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式 + cv::Size m_fixedSize; + cv::RotatedRect m_rect; + std::vector m_maxContour; + std::vector m_rects; +}; + +#endif // !IMAGE_APPLY_AUTO_CROP_H + diff --git a/hgdriver/ImageProcess_test/ImageApplyBWBinaray.cpp b/hgdriver/ImageProcess_test/ImageApplyBWBinaray.cpp new file mode 100644 index 0000000..7995a25 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyBWBinaray.cpp @@ -0,0 +1,164 @@ +#include "ImageApplyBWBinaray.h" + +CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant) + : m_threshold(threshold) + , m_type(type) + , m_blockSize(blockSize) + , m_constant(constant) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::CImageApplyBWBinaray() + : m_threshold(120) + , m_type(ThresholdType::THRESH_BINARY) + , m_blockSize(25) + , m_constant(5) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::~CImageApplyBWBinaray(void) +{ + delete[] m_table; +} + +void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if (pDib.channels() == 3) + cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + //20.12.29 ޸IJΪ51 10 30 235 + //20.12.30 ޸IJΪ51 20 30 235 + // ޸IJΪ17 20 110 235 + cv::Mat integ; + int blockSize = 17;//ߴ + int threshold = 20; + int low = 110; + int up = 235; + int halfSize = blockSize / 2; + int square_blockSize = blockSize * blockSize; + switch (m_type) + { + case ThresholdType::THRESH_BINARY: + cv::integral(pDib, integ, CV_32S); + + for (int j = halfSize; j < integ.rows - halfSize - 1; j++) + { + uchar* data = pDib.ptr(j); + int* idata1 = integ.ptr(j - halfSize); + int* idata2 = integ.ptr(j + halfSize + 1); + for (int i = halfSize; i < integ.cols - halfSize - 1; i++) + { + if (data[i] < low) + data[i] = 0; + else if (data[i] > up) + data[i] = 255; + else + data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255; + } + } + + cv::threshold(pDib(cv::Rect(0, 0, halfSize, pDib.rows)), pDib(cv::Rect(0, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, 0, pDib.cols, halfSize)), pDib(cv::Rect(0, 0, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + break; + case ThresholdType::THRESH_OTSU: + cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU); + break; + case ThresholdType::ADAPTIVE_GAUSSIAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ADAPTIVE_MEAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ERROR_DIFFUSION: + errorDiffuse(pDib); + break; + default: + break; + } +} + +void CImageApplyBWBinaray::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image) +{ + if (image.rows < 3 || image.cols < 3) + { + cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY); + return; + } + + cv::Mat dst; + image.convertTo(dst, CV_16S); + + size_t rows = static_cast(image.rows) - 1; + size_t cols = static_cast(image.cols) - 1; + + short** pixels_dst = new short* [static_cast(image.rows)]; + for (int i = 0; i < image.rows; i++) + pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(dst.step)); + + short error; + for (size_t y = 0; y < rows; y++) + for (size_t x = 1; x < cols; x++) + { + short dstPix = pixels_dst[y][x]; + if (dstPix >= m_threshold) + { + pixels_dst[y][x] = 255; + error = dstPix - 255; + } + else + { + pixels_dst[y][x] = 0; + error = dstPix; + } + + pixels_dst[y][x + 1] += error * 1 / 16; + pixels_dst[y + 1][x - 1] += error * 1 / 16; + pixels_dst[y + 1][x] += error * 1 / 16; + pixels_dst[y + 1][x + 1] += error * 1 / 16; + } + image.release(); + dst.convertTo(image, CV_8U); + + rows++; + uchar* ptr = image.data; + size_t step = image.step; + size_t offset; + for (size_t y = 0; y < rows; y++) + { + offset = y * step; + ptr[offset] = m_table[ptr[offset]]; + offset += cols; + ptr[offset] = m_table[ptr[offset]]; + } + + cols++; + ptr = image.data + step * (rows - 1); + for (size_t x = 0; x < cols; x++) + ptr[x] = m_table[ptr[x]]; + + delete[] pixels_dst; +} \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageApplyBWBinaray.h b/hgdriver/ImageProcess_test/ImageApplyBWBinaray.h new file mode 100644 index 0000000..59001a4 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyBWBinaray.h @@ -0,0 +1,86 @@ +/* + * ==================================================== + + * 功能:二值化处理 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法 + 2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果 + 2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果 + 2020/12/21 v1.3.1 调整自适应阈值上下限 + 2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25 + * 版本号:v1.3.2 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_BW_BINARAY_H +#define IMAGE_APPLY_BW_BINARAY_H + +#include "ImageApply.h" + +class CImageApplyBWBinaray:public CImageApply +{ +public: + + enum class ThresholdType + { + THRESH_BINARY = 0, //传统二值化 + THRESH_OTSU, //大津阈值 + + ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值 + ADAPTIVE_MEAN, //均值局部自适应阈值 + + ERROR_DIFFUSION //错误扩散 + }; + + /* + * type [in]:二值化模式 + * threshold [in]:阈值,当选择THRESH_OTSU时无效 + * blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,表示局部观察块的宽度 + * constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,与blockSize形成比例关系,作为局部筛选阈值 + */ + CImageApplyBWBinaray(ThresholdType type, int threshold = 120, int blockSize = 25, int constant = 5); + + CImageApplyBWBinaray(); + + virtual ~CImageApplyBWBinaray(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + double getThreshold() { return m_threshold; } + + ThresholdType getThresholdType() { return m_type; } + + int getBlockSize() { return m_blockSize; } + + double getConstant() { return m_constant; } + + void setThreshold(double value) { m_threshold = value; } + + void setThresholdType(ThresholdType type) { m_type = type; } + + void setBlockSize(int value) { m_blockSize = value; } + + void setConstant(double value) { m_constant = value; } + +private: + + void errorDiffuse(cv::Mat& image); + +private: + double m_threshold; + + ThresholdType m_type; + + int m_blockSize; + + double m_constant; + + uchar* m_table; +}; + +#endif //!IMAGE_APPLY_BW_BINARAY_H + diff --git a/hgdriver/ImageProcess_test/ImageApplyChannel.cpp b/hgdriver/ImageProcess_test/ImageApplyChannel.cpp new file mode 100644 index 0000000..1b9180c --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyChannel.cpp @@ -0,0 +1,127 @@ +#include "ImageApplyChannel.h" +#include "ImageApplyAdjustColors.h" + +CImageApplyChannel::CImageApplyChannel() + : m_channel(Invalid) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::CImageApplyChannel(Channel channel) + : m_channel(channel) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::~CImageApplyChannel() +{ + if (colors != nullptr) delete colors; +} + +void CImageApplyChannel::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1); + switch (m_channel) + { + case Red: + cv::extractChannel(pDib, dst, 2); + colors->apply(pDib, side); + break; + case Green: + cv::extractChannel(pDib, dst, 1); + break; + case Blue: + cv::extractChannel(pDib, dst, 0); + break; + case All: + colourless(pDib, dst, 80); + break; + case Except_Red: + except_channel(pDib, dst, 2); + break; + case Except_Green: + except_channel(pDib, dst, 1); + break; + case Except_Blue: + except_channel(pDib, dst, 0); + break; + default: + break; + } + pDib.release(); + pDib = dst; + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply"); +#endif // LOG +} + +void CImageApplyChannel::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel) +{ + cv::Mat mv[3]; + cv::split(src, mv); + cv::Mat mask, mask1, mask2; + switch (channel) + { + case 0: + mask1 = mv[0] - mv[1]; + mask2 = mv[0] - mv[2]; + break; + case 1: + mask1 = mv[1] - mv[0]; + mask2 = mv[1] - mv[2]; + break; + case 2: + mask1 = mv[2] - mv[1]; + mask2 = mv[2] - mv[0]; + break; + default: + break; + } + cv::min(mask1, mask2, mask); + + cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY); + dst -= mask; +} + +void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold) +{ + if (src.channels() != 3) + { + dst = src; + return; + } + + cv::Mat hsv; + cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL); + cv::Mat mv_hsv[3]; + cv::split(hsv, mv_hsv); + size_t total = mv_hsv[1].total(); + uchar* ptr_s = mv_hsv[1].data; + uchar* ptr_v = mv_hsv[2].data; + for (size_t i = 0; i < total; i++) + if (ptr_s[i] > threshold) + { + ptr_s[i] = 0; + ptr_v[i] = 255; + } + cv::merge(mv_hsv, 3, hsv); + cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL); + cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY); +} diff --git a/hgdriver/ImageProcess_test/ImageApplyChannel.h b/hgdriver/ImageProcess_test/ImageApplyChannel.h new file mode 100644 index 0000000..1e52fa9 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyChannel.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + + * 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:v1.0 2020/4/21 + v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。 + v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。 + v1.3 2021/5/24 替换红色增强算法方案。 + * 版本号:v1.3 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CHANNEL_H +#define IMAGE_APPLY_CHANNEL_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class CImageApplyChannel : public CImageApply +{ +public: + + typedef enum channel + { + Red, //红色通道 + Green, //绿色通道 + Blue, //蓝色通道 + All, //去除所有HSV色彩结构中,S大于80的色彩 + Invalid, //无效 + Except_Red, //绿蓝色通道混合 + Except_Green, //红蓝色通道混合 + Except_Blue //红绿色通道混合 + }Channel; + +public: + + CImageApplyChannel(); + + /* + * channel [in]:通道模式 + * */ + CImageApplyChannel(Channel channel); + + virtual ~CImageApplyChannel(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + void except_channel(const cv::Mat& src, cv::Mat& dst, int channel); + + void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80); + +private: + + Channel m_channel; + CImageApplyAdjustColors* colors; +}; + +#endif // !IMAGE_APPLY_CHANNEL_H diff --git a/hgdriver/ImageProcess_test/ImageApplyColorRecognition.cpp b/hgdriver/ImageProcess_test/ImageApplyColorRecognition.cpp new file mode 100644 index 0000000..d85896b --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyColorRecognition.cpp @@ -0,0 +1,126 @@ +#include "ImageApplyColorRecognition.h" +#include "ImageApplyHeaders.h" + +static CImageApplyBWBinaray m_bw; +static CImageApplyAdjustColors m_ac(0, 50, 1.0f); + +/// +/// ͼǷDzɫǰ߼ԺɫؽжϣںɫΪɫΪDzɫ +/// +/// ͼ +/// trueΪɫfalseΪDzɫ +bool isColor(const cv::Mat& image) +{ + if (image.channels() != 3) return false; + + cv::Mat pDib_resize; + cv::resize(image, pDib_resize, cv::Size(image.cols / 9, image.rows / 9), 0, 0, cv::INTER_AREA); + + cv::Mat hsv; + cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL); + std::vector hsv_channels; + cv::split(hsv, hsv_channels); + + cv::Mat range_h1, range_h2, range_s, range_v; + cv::inRange(hsv_channels[0], 0, 85, range_h1); + cv::inRange(hsv_channels[0], 170, 255, range_h2); + cv::inRange(hsv_channels[1], 60, 255, range_s); + cv::inRange(hsv_channels[2], 100, 255, range_v); + + cv::Mat thre = (range_h1 | range_h2) & range_s & range_v; + return (cv::sum(thre)[0] / 255)> 4; +} + +bool isGray(const cv::Mat& image) +{ + if (image.channels() == 3) return true; + + cv::Mat image_clone; + cv::resize(image, image_clone, cv::Size(), 0.25, 0.25); + int channels[] = { 0 }; + int histsize[] = { 256 }; + float range[] = { 0, 256 }; + const float* histRanges[] = { range }; + cv::Mat hist; + cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, histsize, histRanges, true, false); + + float pixel_count0 = hist.at(0, 0); + float pixel_count255 = hist.at(255, 0); + float total = image_clone.total(); + + return ((pixel_count0 + pixel_count255) / total) > 0.95; +} + +CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode) + : m_mode(mode) +{ +} + +CImageApplyColorRecognition::~CImageApplyColorRecognition(void) +{ +} + +void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side) +{ + //жǷҪжDzɫ + if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono) + { + //Dzɫֱ˳ + if (isColor(pDib)) + { + m_result = Color; + return; + } + } + + if (pDib.channels() == 3) + cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + if (m_mode == Color_Gray) + { + m_result = Gray; + return; + } + + if (m_mode == Color_Mono) + { + m_bw.apply(pDib, side); + m_result = Mono; + return; + } + + if (isGray(pDib)) + m_result = Gray; + else + { + m_bw.apply(pDib, side); + m_result = Mono; + } +} + +void CImageApplyColorRecognition::apply(std::vector& mats, bool isTwoSide) +{ + m_results.clear(); + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + m_results.push_back(m_result); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); + + m_results.push_back(m_result); +} + +CImageApplyColorRecognition::ColorType CImageApplyColorRecognition::getResult() +{ + return m_result; +} + +std::vector CImageApplyColorRecognition::getResults() +{ + return m_results; +} diff --git a/hgdriver/ImageProcess_test/ImageApplyColorRecognition.h b/hgdriver/ImageProcess_test/ImageApplyColorRecognition.h new file mode 100644 index 0000000..e1361f3 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyColorRecognition.h @@ -0,0 +1,68 @@ +/* + * ==================================================== + + * 功能:色彩识别,将识别会“灰度”的24位图转化为256色8位图, 把识别为“黑白”图转化为二值化的8位图 + * 作者:刘丁维 + * 生成时间:2020/7/17 + * 最近修改时间:2021/04/19 + * 版本号:v1.0 2020/7/17 + * v1.1 2020/12/15 调整策略,仅判断红色像素,存在红色像素为彩色,否则为灰度;删除输出结果,直接转换图像。 + * v1.2 2020/12/16 增加颜色限制模式(输出结果只可能两种),增加结果访问接口 + * v1.3 2021/04/19 修改识别策略,能够识别占比1‰的彩色图像。只区分彩色和灰度图。 + * v1.4 2021/06/18 调整二级色彩区间,从原来的[90, 200]调整为[50, 200]。 + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H +#define IMAGE_APPLY_COLOR_RECOGNITION_H + +#include "ImageApply.h" + +class CImageApplyColorRecognition : public CImageApply +{ +public: + + //色彩识别模式 + enum ColorRecognitionMode + { + AllColor, //全色模式 识别结果可能会是彩色、灰度、黑白 + Color_Gray, //彩色灰度模式 识别结果只会是彩色或者灰度 + Color_Mono, //彩色黑白模式 识别结果只会是彩色或者黑白 + Gray_Mono //灰度黑白模式 识别结果只会是灰度或者黑白 + }; + + //色彩类型 + enum ColorType + { + Color, //彩色 + Gray, //灰度 + Mono //黑白 + }; +public: + CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor); + + virtual ~CImageApplyColorRecognition(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /// + /// 获取图片色彩类型。配合void apply(cv::Mat&, int)接口使用 + /// + /// 色彩类型 + ColorType getResult(); + + /// + /// 获取图片色彩类型。配合void apply(std::vector&, int)接口使用 + /// + /// 色彩类型数组 + std::vector getResults(); + +private: + ColorType m_result; + std::vector m_results; + ColorRecognitionMode m_mode; +}; + +#endif // !IMAGE_APPLY_CONCATENATION_H diff --git a/hgdriver/ImageProcess_test/ImageApplyConcatenation.cpp b/hgdriver/ImageProcess_test/ImageApplyConcatenation.cpp new file mode 100644 index 0000000..be8bd0a --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyConcatenation.cpp @@ -0,0 +1,108 @@ +#include "ImageApplyConcatenation.h" + +CImageApplyConcatenation::CImageApplyConcatenation() + : m_direction(autoDirection) + , m_BG_color(0, 0, 0) +{ +} + +CImageApplyConcatenation::CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& background) + : m_direction(dir) + , m_BG_color(background) +{ +} + +CImageApplyConcatenation::~CImageApplyConcatenation(void) +{ +} + +void CImageApplyConcatenation::apply(cv::Mat& pDib, int side) +{ + (void)pDib; + (void)side; +} + +void CImageApplyConcatenation::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + if (mats.size() < 2) + { + mats.clear(); + return; + } + + ConcatMode direction; + if (m_direction == ConcatMode::autoDirection) + direction = (mats[0].cols > mats[0].rows) ? ConcatMode::vertical : ConcatMode::horizontal; + else + direction = m_direction; + cv::Mat dst = concat(mats[0], mats[1], direction); + mats.clear(); + mats.push_back(dst); +} + +cv::Mat CImageApplyConcatenation::concat(cv::Mat &front, cv::Mat &back, ConcatMode direction) +{ + cv::Mat dst; + if (direction == horizontal) + { +#if 0 + int top, bottom; + if (front.rows > back.rows) + { + top = (front.rows - back.rows) / 2; + bottom = front.rows - back.rows - top; + cv::copyMakeBorder(back, back, top, bottom, 0, 0, cv::BORDER_CONSTANT); + } + else if (front.rows < back.rows) + { + top = (back.rows - front.rows) / 2; + bottom = back.rows - front.rows - top; + cv::copyMakeBorder(front, front, top, bottom, 0, 0, cv::BORDER_CONSTANT); + } + cv::hconcat(front, back, dst); +#else + int width = cv::max(front.cols, back.cols) * 2; + int height = cv::max(front.rows, back.rows); + + dst = cv::Mat(height, width, front.type(), m_BG_color); + front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); + int offset = front.cols; + front.release(); + back.copyTo(dst(cv::Rect(offset, 0, back.cols, back.rows))); + back.release(); +#endif + } + else if (direction == vertical) + { +#if 0 + int left, right; + if (front.cols > back.cols) + { + left = (front.cols - back.cols) / 2; + right = front.cols - back.cols - left; + cv::copyMakeBorder(back, back, 0, 0, left, right, cv::BORDER_CONSTANT); + } + else if (front.cols < back.cols) + { + left = (back.cols - front.cols) / 2; + right = back.cols - front.cols - left; + cv::copyMakeBorder(front, front, 0, 0, left, right, cv::BORDER_CONSTANT); + } + cv::vconcat(front, back, dst); +#else + int width = cv::max(front.cols, back.cols); + int height = cv::max(front.rows, back.rows) * 2; + + dst = cv::Mat(height, width, front.type(), m_BG_color); + front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows))); + int offset = front.rows; + front.release(); + back.copyTo(dst(cv::Rect(0, offset, back.cols, back.rows))); + back.release(); +#endif + } + //front.release(); + //back.release(); + return dst; +} diff --git a/hgdriver/ImageProcess_test/ImageApplyConcatenation.h b/hgdriver/ImageProcess_test/ImageApplyConcatenation.h new file mode 100644 index 0000000..c4ec540 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyConcatenation.h @@ -0,0 +1,61 @@ +/* + * ==================================================== + + * ܣƴӣ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/29 + * 汾ţv1.0 2020/4/21 + * 汾ţv1.1 2020/4/29 : 1m_BG_colorӿڣͼƬ2Żڴ + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CONCATENATION_H +#define IMAGE_APPLY_CONCATENATION_H + +#include "ImageApply.h" + + class CImageApplyConcatenation : public CImageApply +{ +public: + //۷ + enum ConcatMode + { + horizontal = 0, //ƴ + vertical, //ƴ + autoDirection + + }; +public: + CImageApplyConcatenation(); //Ĭm_direction = autoDirection; + + /* + * dir [in]:ƴӷ + * backgroud [in]:ɫĬΪɫ + * */ + CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& backgroud = cv::Scalar(0, 0, 0)); + + virtual ~CImageApplyConcatenation(void); + + virtual void apply(std::vector& mats, bool isTwoSide); + + inline ConcatMode getConcatDirection() { return m_direction; } + + inline void setFildDirection(ConcatMode dir) { m_direction = dir; } + + inline cv::Scalar getBackGroundColor() const { return m_BG_color; } + + inline void setBackGroundColor(const cv::Scalar& color) { m_BG_color = color; } + +private: + + virtual void apply(cv::Mat& pDib, int side); + + cv::Mat concat(cv::Mat& front, cv::Mat& back, ConcatMode direction = autoDirection); + +private: + ConcatMode m_direction; + cv::Scalar m_BG_color; +}; + +#endif // !IMAGE_APPLY_CONCATENATION_H diff --git a/hgdriver/ImageProcess_test/ImageApplyCrop.cpp b/hgdriver/ImageProcess_test/ImageApplyCrop.cpp new file mode 100644 index 0000000..ca08427 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCrop.cpp @@ -0,0 +1,40 @@ +#include "ImageApplyCrop.h" + +CImageApplyCrop::CImageApplyCrop(void) +{ +} + + +CImageApplyCrop::~CImageApplyCrop(void) +{ +} + +void CImageApplyCrop::apply(cv::Mat& pDib,int side) +{ + + if (pDib.empty()) + { + return; + } + + if (m_roi.x < 0 || m_roi.y < 0 || m_roi.br().x >= pDib.cols || m_roi.br().y >= pDib.rows || m_roi.width == 0 || m_roi.height == 0) + { + return; + } + + pDib = pDib(m_roi).clone(); +} + +void CImageApplyCrop::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + + if (!mats[0].empty()) { + apply(mats[0], 0); + } + + if (isTwoSide && mats.size() > 1) { + if (!mats[1].empty()) + apply(mats[1], 1); + } +} \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageApplyCrop.h b/hgdriver/ImageProcess_test/ImageApplyCrop.h new file mode 100644 index 0000000..366d262 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCrop.h @@ -0,0 +1,28 @@ +#ifndef IMAGE_APPLY_CROP_H +#define IMAGE_APPLY_CROP_H + +#include "ImageApply.h" + +class CImageApplyCrop : public CImageApply +{ + +public: + + CImageApplyCrop(void); + + virtual ~CImageApplyCrop(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + cv::Rect getROI() { return m_roi; } + + void setROI(const cv::Rect& rect) { m_roi = rect; } + +private: + + cv::Rect m_roi; +}; + +#endif // !IMAGE_APPLY_CROP_H \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageApplyCustomCrop.cpp b/hgdriver/ImageProcess_test/ImageApplyCustomCrop.cpp new file mode 100644 index 0000000..9875e38 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCustomCrop.cpp @@ -0,0 +1,32 @@ +#include "ImageApplyCustomCrop.h" + +CImageApplyCustomCrop::CImageApplyCustomCrop(const cv::Rect &rect) + : m_rect(rect) +{ + +} + +CImageApplyCustomCrop::~CImageApplyCustomCrop() +{ + +} + +void CImageApplyCustomCrop::apply(cv::Mat &pDib, int side) +{ + (void)side; + if(pDib.empty()) return; + pDib = pDib(cv::Rect(0, 0, pDib.cols, pDib.rows) & m_rect).clone(); +} + +void CImageApplyCustomCrop::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyCustomCrop.h b/hgdriver/ImageProcess_test/ImageApplyCustomCrop.h new file mode 100644 index 0000000..3993a51 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCustomCrop.h @@ -0,0 +1,40 @@ +/* + * ==================================================== + + * ܣԶü + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CUSTOM_CROP_H +#define IMAGE_APPLY_CUSTOM_CROP_H + +#include "ImageApply.h" + +class CImageApplyCustomCrop : public CImageApply +{ +public: + + /* + * rect [in]:ü + * */ + CImageApplyCustomCrop(const cv::Rect& rect); + + virtual~ CImageApplyCustomCrop(void); + + inline cv::Rect getROI() const { return m_rect; } + + inline void setROI(const cv::Rect& roi) { m_rect = roi; } + + virtual void apply(cv::Mat &pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + cv::Rect m_rect; +}; + +#endif // IMAGE_APPLY_CUSTOM_CROP_H diff --git a/hgdriver/ImageProcess_test/ImageApplyCustomGamma.cpp b/hgdriver/ImageProcess_test/ImageApplyCustomGamma.cpp new file mode 100644 index 0000000..8132682 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCustomGamma.cpp @@ -0,0 +1,63 @@ +#include "ImageApplyCustomGamma.h" + +CImageApplyCustomGamma::CImageApplyCustomGamma(unsigned char* table,int length) + : emptyPtr(false) +{ + if(table==nullptr) + emptyPtr = true; + + init_gamma_table(); + setLUT(table,length == 256 ? 1 : 3); +} + +CImageApplyCustomGamma::~CImageApplyCustomGamma() +{ +} + +void CImageApplyCustomGamma::setLUT(const unsigned char* table, int byteCount) +{ + if (emptyPtr) + return; + + if (byteCount == 1) + memcpy(m_table_bit8, table, 256); + else if (byteCount == 3) + memcpy(m_table_bit24, table, 768); +} + +void CImageApplyCustomGamma::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (emptyPtr) + return; + int numOfChannels = pDib.channels(); + cv::Mat mat_table(1, 256, CV_8UC(numOfChannels), (numOfChannels == 3) ? m_table_bit24 : m_table_bit8); + cv::LUT(pDib, mat_table, pDib); +} + +void CImageApplyCustomGamma::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyCustomGamma::setTableData(const unsigned char* data, int length) +{ + setLUT(data, length == 256 ? 1 : 3); +} + +void CImageApplyCustomGamma::init_gamma_table() +{ + for (size_t i = 0; i < 256; ++i) + { + m_table_bit8[i] = static_cast(i); + m_table_bit24[i * 3] = m_table_bit24[i * 3 + 1] = m_table_bit24[i * 3 + 2] = static_cast(i); + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyCustomGamma.h b/hgdriver/ImageProcess_test/ImageApplyCustomGamma.h new file mode 100644 index 0000000..d51949b --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCustomGamma.h @@ -0,0 +1,44 @@ +/* + * ==================================================== + + * 功能:自定义伽马校正。原理为哈希表查值 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CUSTOM_CAMMA_H +#define IMAGE_APPLY_CUSTOM_CAMMA_H + +#include "ImageApply.h" + +class CImageApplyCustomGamma : public CImageApply +{ +public: + /* + * table [in]:自定义查值表 + * length [in]:表的长度,灰度表256,彩色表768 + * */ + CImageApplyCustomGamma(unsigned char* table,int length); + + virtual ~CImageApplyCustomGamma(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + void setTableData(const unsigned char* data, int length); +private: + void init_gamma_table(); + void setLUT(const unsigned char* table, int byteCount); + bool emptyPtr; +private: + unsigned char m_table_bit8[256]; + + unsigned char m_table_bit24[768]; +}; + +#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H diff --git a/hgdriver/ImageProcess_test/ImageApplyCvtColor.cpp b/hgdriver/ImageProcess_test/ImageApplyCvtColor.cpp new file mode 100644 index 0000000..d69979a --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCvtColor.cpp @@ -0,0 +1,57 @@ +#include "ImageApplyCvtColor.h" + +CImageApplyCvtColor::CImageApplyCvtColor(ConversionCodes type) + : m_code(type) +{ +} + +CImageApplyCvtColor::~CImageApplyCvtColor() +{ +} + +void CImageApplyCvtColor::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.channels() == 1) return; + if (m_code > 3) + cv::cvtColor(pDib, pDib, static_cast(m_code)); + else + { + cv::Mat gray(pDib.size(), CV_8UC1); + if (m_code == BGR_MAX) + { + for (size_t y = 0, rows = pDib.rows; y < rows; y++) + { + uchar* ptr_y = pDib.ptr(y); + uchar* gray_y = gray.ptr(y); + for (size_t x = 0, cols = pDib.cols; x < cols; x++) + gray_y[x] = cv::max(ptr_y[x * 3], cv::max(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); + } + } + else if (m_code == BGR_MIN) + { + for (size_t y = 0, rows = pDib.rows; y < rows; y++) + { + uchar* ptr_y = pDib.ptr(y); + uchar* gray_y = gray.ptr(y); + for (size_t x = 0, cols = pDib.cols; x < cols; x++) + gray_y[x] = cv::min(ptr_y[x * 3], cv::min(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2])); + } + } + pDib.release(); + pDib = gray; + } +} + +void CImageApplyCvtColor::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyCvtColor.h b/hgdriver/ImageProcess_test/ImageApplyCvtColor.h new file mode 100644 index 0000000..2010430 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyCvtColor.h @@ -0,0 +1,52 @@ +/* + * ==================================================== + + * ܣɫʱ任 + * ߣά + * ʱ䣺2020/6/19 + * ޸ʱ䣺v1.0 2020/6/19 + v1.1 2020/6/20 BGRתHSV,BGR_MAXBGR_MIN + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CONVERT_COLOR_H +#define IMAGE_APPLY_CONVERT_COLOR_H + +#include "ImageApply.h" + +class CImageApplyCvtColor : public CImageApply +{ +public: + + //תģʽ + enum ConversionCodes + { + BGR_MAX = 1, //BGRȡֵתGRAY + BGR_MIN = 2, //BGRȡСֵתGRAY + BGR2GRAY = 6, //BGRתGRAY + BGR2HSV = 40 //BGRתHSV + }; + + /* + * type [in]:ɫתģʽĬBGRתGray + * */ + CImageApplyCvtColor(ConversionCodes type = BGR2GRAY); + + virtual ~CImageApplyCvtColor(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + inline ConversionCodes getConversionCode() { return m_code; } + + inline void setConversionCode(ConversionCodes code) { m_code = code; } + +private: + ConversionCodes m_code; + +}; + +#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H diff --git a/hgdriver/ImageProcess_test/ImageApplyDetachNoise.cpp b/hgdriver/ImageProcess_test/ImageApplyDetachNoise.cpp new file mode 100644 index 0000000..d32951b --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDetachNoise.cpp @@ -0,0 +1,42 @@ +#include "ImageApplyDetachNoise.h" +#include "ImageProcess_Public.h" + +CImageApplyDetachNoise::CImageApplyDetachNoise(int noise) + : m_noise(noise) +{ +} + +CImageApplyDetachNoise::~CImageApplyDetachNoise(void) +{ +} + +void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()||pDib.channels() != 1) + return; + + cv::Mat mask; + cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV); + + std::vector> contours; + std::vector h; + hg::findContours(mask, contours, h); + + for (const std::vector& contour : contours) + if (contourArea(contour) < m_noise) + fillConvexPoly(pDib, contour, cv::Scalar(255)); +} + +void CImageApplyDetachNoise::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyDetachNoise.h b/hgdriver/ImageProcess_test/ImageApplyDetachNoise.h new file mode 100644 index 0000000..200985f --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDetachNoise.h @@ -0,0 +1,46 @@ +/* + * ==================================================== + + * ܣ룬3*3ڵص㣬ҪԺڰͼ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + 2020/5/29 v1.1 ӽӿڣʹСֵɵ + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DETACH_NOISE_H +#define IMAGE_APPLY_DETACH_NOISE_H + +#include "ImageApply.h" + +class CImageApplyDetachNoise : public CImageApply +{ +public: + CImageApplyDetachNoise(int + + + + + + + + = 1); + + inline int getNoise() { return m_noise; } + + inline void setNoise(int noise) { m_noise = noise; } + + virtual ~CImageApplyDetachNoise(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + int m_noise; +}; +#endif // !IMAGE_APPLY_DETACH_NOISE_H + diff --git a/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.cpp b/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.cpp new file mode 100644 index 0000000..f9863cf --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.cpp @@ -0,0 +1,114 @@ +#include "ImageApplyDiscardBlank.h" +#include "ImageProcess_Public.h" + +CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh) + : m_threshold(threshold) + , m_edge(edge) + , m_devTh(devTh) + , m_meanTh(meanTh) +{ +} + +CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void) +{ +} + +void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side) +{ + if (apply(pDib, m_threshold, m_edge, m_devTh)) + pDib.release(); +} + +void CImageApplyDiscardBlank::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2) +{ + for (int i = 0; i < 3; i++) + if (val1[i] > val2[i]) + return false; + return true; +} + +bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh) +{ + double min, max; + cv::minMaxLoc(img, &min, &max, 0, 0, mask); + if (cv::mean(img, mask)[0] < meanTh) + return false; + return (max - min) < devTh; +} + +bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh) +{ + if (pDib.empty()) + return true; + + cv::Mat img_resize; + cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2); + + cv::Mat threshold_img; + if (img_resize.channels() == 3) + cv::cvtColor(img_resize, threshold_img, cv::COLOR_BGR2GRAY); + cv::threshold(img_resize.channels() == 3 ? threshold_img : img_resize, threshold_img, threshold, 255, CV_THRESH_BINARY); + + std::vector> contours; + std::vector h1; + hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); + + std::vector contour; + for (const std::vector& sub : contours) + for (const cv::Point& p : sub) + contour.push_back(p); + + cv::RotatedRect rect = hg::getBoundingRect(contour); + rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5); + cv::Point2f box[4]; + rect.points(box); + contour.clear(); + contours.clear(); + + for (size_t i = 0; i < 4; i++) + contour.push_back(box[i]); + contours.push_back(contour); + cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1); + hg::fillPolys(mask, contours, cv::Scalar::all(255)); + cv::blur(img_resize, img_resize, cv::Size(3, 3)); + + bool b = true; + if (img_resize.channels() == 3) + { + cv::Mat bgr[3]; + cv::split(img_resize, bgr); + for (size_t i = 0; i < 3; i++) + { + b &= maxMinCompare(bgr[i], mask, devTh, meanTh); + if (!b) break; + } + } + else + b &= maxMinCompare(img_resize, mask, devTh, meanTh); + /* + if (b) + { + cv::imwrite("�հ�ҳ/img1/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("�հ�ҳ/mask1/" + std::to_string(index) + ".bmp", mask); + } + else + { + cv::imwrite("�հ�ҳ/img2/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("�հ�ҳ/mask2/" + std::to_string(index) + ".bmp", mask); + }*/ + + return b; +} diff --git a/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.h b/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.h new file mode 100644 index 0000000..9b1fa19 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDiscardBlank.h @@ -0,0 +1,48 @@ +/* + * ==================================================== + + * 功能:空白页识别。 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/8/12 v1.1 开放setIntensity和setMinArea;取消isNormal标识位;扩大setIntensity的设置范围,从[2, 20]扩大到[1, 100] + 2020/8/25 v1.1.1 纸张检测缩进,从100像素调整到20像素 + 2020/10/16 v1.2 添加新接口,能够高效便捷判断图片是否为空白页 + 2020/10/19 v1.2.1 修复静态空白页判断识别误判的BUG + 2021/04/13 v1.3.0 增加标准/票据标识位 + 2021/08/12 v1.3.1 添加防止不同opencv版本导致计算结果存在差异的代码。 + 2021/12/14 v1.3.2 重构算法。 + 2021/12/15 v1.3.3 微调参数。 + 2021/12/17 v1.3.4 增加背景色接口,实现对纯色纸张的空白页判定 + * 版本号:v1.3.4 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DISCARD_BLANK_H +#define IMAGE_APPLY_DISCARD_BLANK_H + +#include "ImageApply.h" + +class CImageApplyDiscardBlank : public CImageApply +{ +public: + + CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200); + + virtual ~CImageApplyDiscardBlank(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + static bool apply(const cv::Mat& pDib, double threshold = 40, int edge = 150, int blockSize = 10, double devTh = 50, double meanTh = 200); + +private: + double m_threshold; + int m_edge; + double m_devTh; + double m_meanTh; +}; + +#endif // !IMAGE_APPLY_DISCARD_BLANK_H \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.cpp b/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.cpp new file mode 100644 index 0000000..40ef3a7 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.cpp @@ -0,0 +1,67 @@ +#include "ImageApplyDogEarDetection.h" +#include "ImageProcess_Public.h" + +CImageApplyDogEarDetection::CImageApplyDogEarDetection() + : m_threshold(40) + , m_zoom(1.0) + , m_distance(50) + , m_result(false) +{ + +} + +CImageApplyDogEarDetection::CImageApplyDogEarDetection(double threshlod, double zoom, double distance) + : m_threshold(threshlod) + , m_zoom(zoom) + , m_distance(distance) + , m_result(false) +{ + +} + +CImageApplyDogEarDetection::~CImageApplyDogEarDetection() +{ + +} + +void CImageApplyDogEarDetection::apply(cv::Mat &pDib, int side) +{ + m_result = false; + (void)side; + if (pDib.empty()) return; + cv::Mat src; + if (m_zoom != 1.0) + cv::resize(pDib, src, cv::Size(), m_zoom, m_zoom, cv::INTER_NEAREST); + else + src = pDib; + + cv::Mat thre; + hg::threshold_Mat(src, thre, m_threshold); + std::vector hierarchy; + std::vector> contours; + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + if (maxContour.size() == 0) + { + m_result = true; + return; + } + hg::convexHull(maxContour, maxContour); + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + cv::Point2f vertexes[4]; + rect.points(vertexes); + + for (int i = 0; i < 4; i++) + if ((-cv::pointPolygonTest(maxContour, vertexes[i], true)) > (m_distance * m_zoom)) + { + m_result = true; + return; + } +} + +void CImageApplyDogEarDetection::apply(std::vector &mats, bool isTwoSide) +{ + (void)mats; + (void)isTwoSide; +} diff --git a/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.h b/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.h new file mode 100644 index 0000000..46dff8c --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyDogEarDetection.h @@ -0,0 +1,56 @@ +/* + * ==================================================== + + * 功能:折角检测。检测原理:计算纸张的理论四角顶点,到实际轮廓最小距离。当任意顶点到轮廓最小距离超过阈值,则判定为折角 + * 作者:刘丁维 + * 生成时间:2020/10/30 + * 最近修改时间:2020/10/30 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DOGEAR_DETECTION_H +#define IMAGE_APPLY_DOGEAR_DETECTION_H + +#include "ImageApply.h" + +class CImageApplyDogEarDetection :public CImageApply +{ +public: + + /// + /// 折角检测默认构造函数,threshold = 40, zoom = 1.0, distance = 50 + /// + CImageApplyDogEarDetection(); + + /// + /// 折角检测构造函数 + /// + /// 二值化阈值 + /// 原图缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放) + /// 理论顶点到实际轮廓最小距离的阈值,大于该阈值则判定为折角,默认值50(像素) + CImageApplyDogEarDetection(double threshlod, double zoom = 1.0, double distance = 50); + + virtual ~CImageApplyDogEarDetection(void); + + /// + /// 获取检测结果。该函数须在调用apply之后使用。 + /// + /// true为折角,false为不折角 + inline bool getResult() { return m_result; } + + virtual void apply(cv::Mat& pDib, int side); + +private: + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + double m_threshold; + double m_zoom; + double m_distance; + + bool m_result; +}; + +#endif // IMAGE_APPLY_DOGEAR_DETECTION_H diff --git a/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.cpp b/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.cpp new file mode 100644 index 0000000..d66e986 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.cpp @@ -0,0 +1,150 @@ +#include "ImageApplyFadeBackGroundColor.h" + + +CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range) + : m_threshold(threshold) + , m_offset(offset) + , m_range(range) +{ + memset(m_table1, 255, 768); + memset(m_table1, 0, m_threshold * 3); + + memset(m_table2, 255, 256 * 3); + for (size_t i = 0; i < 256; i++) + m_table2[i] = i; +} + +CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor() +{ +} + +void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side) +{ + if (pDib.channels() != 3) + return; + +#if 0 + cv::Mat mask; + cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY); + //cv::imwrite("mask.jpg", mask); + cv::Mat bgr[3]; + cv::split(pDib, bgr); + + int histSize = 255; + float range[] = { 0, 255 }; + const float* histRange = { range }; + + cv::Mat hist_bgr[3]; + cv::Scalar mean_bgr; + for (size_t i = 0; i < 3; i++) + { + cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange); + double maxVal = 0; + cv::Point maxLoc; + cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc); + mean_bgr[i] = maxLoc.y; + } + + cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask); +#else + fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range); +#endif +} + +void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range) +{ + int hist_bgr[3][256] = { 0 }; + + int width = bytesPerLine / 3; + unsigned char* mask = new unsigned char[width * height]; + unsigned char* ptr_data = data; + unsigned char* ptr_mask = mask; + + //ģmaskͳֱͨͼ + for (size_t i = 0; i < height; i++) + { + int x = 0; + unsigned char b = 0; + for (size_t j = 0; j < width; j++) + { + b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]]; + ptr_mask[j] = b; + for (size_t k = 0; k < 3; k++) + hist_bgr[k][ptr_data[x + k] & b]++; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //ͳƱɫ + int max_vals[3] = { 0 }; + int max_indexes[3]; + + for (size_t i = 1; i < 256; i++) + for (size_t j = 0; j < 3; j++) + if (hist_bgr[j][i] > max_vals[j]) + { + max_vals[j] = hist_bgr[j][i]; + max_indexes[j] = i; + } + + //ɫֵrangeΧڵɫͬΪɫ + for (size_t i = 0; i < 3; i++) + { + memset(m_table_rgb[i], 0, 256); + int start = cv::max(max_indexes[i] - range, 0); + int end = cv::min(max_indexes[i] + range, 255); + memset(m_table_rgb[i] + start, 255, end - start + 1); + } + + //ݱɫֵģųɫ + ptr_data = data; + ptr_mask = mask; + for (size_t i = 0; i < height; i++) + { + int x = 0; + for (size_t j = 0; j < width; j++) + { + ptr_mask[j] &= m_table_rgb[0][ptr_data[x]] & m_table_rgb[1][ptr_data[x + 1]] & m_table_rgb[2][ptr_data[x + 2]]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //ģɫ + unsigned char offset_rgb[3]; + for (size_t i = 0; i < 3; i++) + offset_rgb[i] = 255 + offset - max_indexes[i]; + + ptr_data = data; + ptr_mask = mask; + for (size_t i = 0; i < height; i++) + { + int x = 0; + for (size_t j = 0; j < width; j++) + { + for (size_t k = 0; k < 3; k++) + ptr_data[x + k] = m_table2[(int)ptr_data[x + k] + (offset_rgb[k] & ptr_mask[j])]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + delete[] mask; +} + +void CImageApplyFadeBackGroudColor::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) + if (!var.empty()) + { + apply(var, i); + i++; + } +} + diff --git a/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.h b/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.h new file mode 100644 index 0000000..493883a --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyFadeBackGroundColor.h @@ -0,0 +1,64 @@ +/* + * ==================================================== + + * ܣĸֽŵɫ + * ߣά + * ʱ䣺2020/11/30 + * ޸ʱ䣺2021/04/14 v2.0 Ϊλ + * 2021/04/14 v2.1 LINUXһ¡ + * 2021/08/03 v2.2 ԶȡͶ㷨ⲻͬopencv汾ƫ + * 2021/10/12 v2.3 ع㷨ȥԭֵ趨ΪԶʶɫȥɫ + * 2021/10/23 v3.0 ع㷨ܿɫģĸƽɫס + * 2021/10/26 v3.1 캯Ӳģʱֵ + * 2021/10/28 v3.2 ع㷨ôC++ʵֹܣߴٶȡ + * 2021/10/29 v3.3 Ż㷨rangeԸݵͼܹЧ𱳾ͷDZݡ + * 汾ţv3.2 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H +#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class CImageApplyFadeBackGroudColor : public CImageApply +{ +public: + /// + /// 캯 + /// + /// ԶʶײĻϣӵƫȡֵΧ[-255, 255] + CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40); + + virtual ~CImageApplyFadeBackGroudColor(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + /// + /// ĸɫ㷨֧24λͼ + /// + /// ͼͷָ + /// ÿݴС + /// ͼ߶ + /// ֵοֵΪ100 + /// ĸɫƫĬΪ0ֵԽ󣬱Խף֮Խ + /// ɫΧɫʶ𵽵ĵɫ[-range, range]ΧڣΪɫ򲻻ᱻ + void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range); + +private: + int m_threshold; + int m_offset; + int m_range; + uchar m_table1[768]; + uchar m_table2[512]; + uchar m_table_rgb[3][256]; +}; + +#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H diff --git a/hgdriver/ImageProcess_test/ImageApplyFilter.cpp b/hgdriver/ImageProcess_test/ImageApplyFilter.cpp new file mode 100644 index 0000000..80e40b9 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyFilter.cpp @@ -0,0 +1,97 @@ +#include "ImageApplyFilter.h" + +CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize) + : m_type(type) + , m_kernel(kSize) +{ + m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9; +} + +CImageApplyFilter::~CImageApplyFilter() +{ +} + +void CImageApplyFilter::apply(cv::Mat& pDib, int side) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply"); +#endif // LOG + + switch (m_type) + { + case FilterMode::Sharpen: + case FilterMode::Sharpen_More: + sharpen(pDib, m_kSize); + break; + case FilterMode::AverBlur: + case FilterMode::AverBlur_More: + averblur(pDib, static_cast(m_kSize)); + break; + case FilterMode::BilateralFilter: + bilateralFilter(pDib, m_kernel); + break; + case FilterMode::GaussianBlur: + gaussianBlur(pDib, m_kernel); + break; + case FilterMode::BrightSharp: + brightSharp(pDib); + break; + } + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply"); +#endif // LOG +} + +void CImageApplyFilter::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); +} + +void CImageApplyFilter::averblur(cv::Mat& src, int kSize) +{ + cv::blur(src, src, cv::Size(kSize, kSize)); +} + +void CImageApplyFilter::sharpen(cv::Mat& src, float kSize) +{ + float other = (1.0f - kSize) / 4; + float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::brightSharp(cv::Mat& src) +{ + const float a = -0.49f; + const float b = 3.0f; + float kernel_data[] = + { + 0, a, 0, + a, b, a, + 0, a, 0 + }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel) +{ + cv::Mat dst; + cv::bilateralFilter(src, dst, static_cast(kernel), kernel * 2, kernel / 2); + src.release(); + src = dst; +} + +void CImageApplyFilter::gaussianBlur(cv::Mat src, int kSize) +{ + cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0); +} diff --git a/hgdriver/ImageProcess_test/ImageApplyFilter.h b/hgdriver/ImageProcess_test/ImageApplyFilter.h new file mode 100644 index 0000000..09e4675 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyFilter.h @@ -0,0 +1,64 @@ +/* + * ==================================================== + + * ܣ˾Ŀǰ񻯡ǿ񻯡ģͼǿģ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 v1.0 + 2020/7/17 v1.1 ˫˲BilateralFilterЧʵ֡ƽ; + 2020/11/30 v1.2 Ӹ˹ģGaussianBlur + 2021/07/21 v1.2.1 񻯣BrightSharp + 2021/10/19 v1.2.2 񻯲 + * 汾ţv1.2.2 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FILTER_H +#define IMAGE_APPLY_FILTER_H + +#include "ImageApply.h" + +class CImageApplyFilter : public CImageApply +{ +public: + enum FilterMode + { + None, + Sharpen, // + Sharpen_More, //һ + AverBlur, //ģ + AverBlur_More, //һģ + BilateralFilter, //˫˲--ƽٸӱɫjpgѹ + GaussianBlur, + BrightSharp //5 * 5 + }; + + /* + * sharpentype [in]:˾ģʽ + */ + CImageApplyFilter(FilterMode type, int kSize = 30); + + virtual ~CImageApplyFilter(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + void averblur(cv::Mat& src, int kSize); + + void sharpen(cv::Mat& src, float kSize); + + void brightSharp(cv::Mat& src); + + void bilateralFilter(cv::Mat& src, double kernel); + + void gaussianBlur(cv::Mat src, int kSize); +private: + int m_type; + float m_kSize; + double m_kernel; +}; + +#endif // !IMAGE_APPLY_SHARPEN_H diff --git a/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.cpp b/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.cpp new file mode 100644 index 0000000..4b558a8 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.cpp @@ -0,0 +1,144 @@ +#include "ImageApplyHSVCorrect.h" +#include + +CImageApplyHSVCorrect::CImageApplyHSVCorrect() + : m_table(new uint[256 * 256 * 256]) +{ + initLUT(); +} + +CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode) + : m_table(new uint[256 * 256 * 256]) +{ + initLUT(); + switch (mode) + { + case CImageApplyHSVCorrect::Red_Removal: + set_HSV_value(std::pair(0, 63), std::pair(20, 255), std::pair(160, 255), 0x00FFFFFF); + set_HSV_value(std::pair(191, 255), std::pair(20, 255), std::pair(160, 255), 0x00FFFFFF); + break; + default: + break; + } +} + +CImageApplyHSVCorrect::~CImageApplyHSVCorrect() +{ + delete [] m_table; +} + +void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side) +{ + (void)side; + if (pDib.empty() || pDib.channels() != 3) return; + + uchar* src = pDib.data; + cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3); + uchar* dst = z.data; + + int total = pDib.total(); +#pragma omp parallel for + for (int i = 0; i < total; i++) + { + int offset = i * 3; + int index = *reinterpret_cast(src + offset) & 0x00ffffff; + uint color = m_table[index]; + *reinterpret_cast(dst + offset) |= color; + } + pDib = z; +} + +void CImageApplyHSVCorrect::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyHSVCorrect::initLUT() +{ +#if 0 + uchar h, s, v; +#endif + for (uint b = 0; b < 256; b++) + for (uint g = 0; g < 256; g++) + for (uint r = 0; r < 256; r++) + { +#if 0 + RGB_2_HSV_full(r, g, b, h, s, v); + + uint index = b | (g << 8) | (r << 16); + if (h < 12 || h > 245) + m_table[index] = index & 0x00ffffff; + else + m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff; +#else + m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16); +#endif + } +} + +void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r) +{ + m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16); +} + +void CImageApplyHSVCorrect::set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr) +{ + uchar h, s, v; + for (int b = 0; b < 256; b++) + for (int g = 0; g < 256; g++) + for (int r = 0; r < 256; r++) + { + RGB_2_HSV_full(r, g, b, h, s, v); + if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v)) + m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff; + } +} + +void CImageApplyHSVCorrect::set_table(const uint* table) +{ + memcpy(m_table, table, 256 * 256 * 256); +} + +bool CImageApplyHSVCorrect::contained(uchar value, const std::pair &range) +{ + return value >= range.first && value <= range.second; +} + +void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v) +{ + int minn = cv::min(r, cv::min(g, b)); + int maxx = cv::max(r, cv::max(g, b)); + v = static_cast(maxx); //V + + int delta = maxx - minn; + float _h; + if (maxx == 0) + { + h = s = v = 0; + return; + } + else + s = static_cast(delta * 255 / maxx); + + if (r == maxx) + _h = static_cast(g - b) / static_cast(delta); + else if (g == maxx) + _h = 2 + static_cast(b - r) / static_cast(delta); + else + _h = 4 + static_cast(r - g) / static_cast(delta); + + float __h = _h * 42.6666666667f; + h = (__h >= 0) ? static_cast(__h) : static_cast(__h + 256); +} diff --git a/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.h b/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.h new file mode 100644 index 0000000..8816d13 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyHSVCorrect.h @@ -0,0 +1,87 @@ +/* + * ==================================================== + + * ܣɫͼɫУLUTʵ֣ԤBGRֵHVSBGRԭͼвֵУ + * ߣά + * ʱ䣺2020/3/21 + * ޸ʱ䣺v1.0 2020/3/21 + v1.1 2020/6/15 ЧHSVȡֵΧ + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_CORRECT_H +#define IMAGE_APPLY_COLOR_CORRECT_H + +#include "ImageApply.h" + +class CImageApplyHSVCorrect : public CImageApply +{ +public: + enum CorrectOption + { + Red_Removal //ɫɫH:[0, 85][170, 255],S:[10, 255],V:[120,255] + }; +public: + + CImageApplyHSVCorrect(); + + /* + * mode [in]:Ԥɫģʽ + */ + CImageApplyHSVCorrect(CorrectOption mode); + + virtual ~CImageApplyHSVCorrect(); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /* + * ܣʼֵRGBRڸλBڵλ32λݽֵһ¡ + Χ[00x00FFFFFF]ڹ캯лĬϵøú + */ + void initLUT(); + + /* + * ܣֵָRGBֵΪĿֵ + = src_b | (src_g << 8) | (src_r << 16) + ֵ = dst_b | (dst_g << 8) | (dst_r << 16) + * src_b:[in] ԭֵBͨ + * src_g:[in] ԭֵGͨ + * src_r:[in] ԭֵRͨ + * dst_b:[in] ĿֵBֵͨ + * dst_g:[in] ĿֵGֵͨ + * dst_r:[in] ĿֵRֵͨ + */ + void set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r); + /* + * ܣHSVɫʿռɫʷΧ÷ΧӦBGRΪ0x00FFFFFF(Ĭϰɫ + * range_h:[in] HΧȡֵΧ[0, 255] + * range_s:[in] SΧȡֵΧ[0, 255] + * range_v:[in] VΧȡֵΧ[0, 255] + * bgr:[in] uintʾBGRֵBڵλRڸλ + */ + void set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr = 0x00FFFFFF); + + /* + * ܣⲿֵĬϳΪ 256 * 256 * 256 * sizeof(uint + * table:[in] ָ + */ + void set_table(const uint* table); + +private: + static bool contained(uchar value, const std::pair& range); + + static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v); + +private: + uint* m_table; +}; + +#endif diff --git a/hgdriver/ImageProcess_test/ImageApplyHeaders.h b/hgdriver/ImageProcess_test/ImageApplyHeaders.h new file mode 100644 index 0000000..a4a77a5 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyHeaders.h @@ -0,0 +1,34 @@ +#ifndef IMAGE_APPLY_HEADER_H +#define IMAGE_APPLY_HEADER_H + +#include "ImageApply.h" +#include "ImageApplyAdjustColors.h" +#include "ImageApplyAutoCrop.h" +#include "ImageApplyBWBinaray.h" +#include "ImageApplyChannel.h" +#include "ImageApplyCrop.h" +#include "ImageApplyDiscardBlank.h" +#include "ImageApplyOutHole.h" +#include "ImageApplyDogEarDetection.h" +#include "ImageApplyResize.h" +#include "ImageApplyRotation.h" +#include "ImageApplySharpen.h" +#include "ImageApplyConcatenation.h" +#include "ImageApplyHSVCorrect.h" +#include "ImageApplyDetachNoise.h" +#include "ImageApplyColorRecognition.h" +#include "ImageApplyUV.h" +#include "ImageApplyAutoContrast.h" +#include "ImageApplyCustomCrop.h" +#include "ImageApplyCustomGamma.h" +#include "ImageApplyCvtColor.h" +#include "ImageApplyFadeBackGroundColor.h" +#include "ImageApplyFilter.h" +#include "ImageApplyRefuseInflow.h" +#include "ImageApplySplit.h" +#include "ImageApplyTextureRemoval.h" +#include "ImageMulti.h" +#include "ImageMultiOutputRed.h" +#include "ImageApplySplit.h" +#include "ImageApplySizeDetection.h" +#endif diff --git a/hgdriver/ImageProcess_test/ImageApplyOutHole.cpp b/hgdriver/ImageProcess_test/ImageApplyOutHole.cpp new file mode 100644 index 0000000..3baeeff --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyOutHole.cpp @@ -0,0 +1,323 @@ +#include "ImageApplyOutHole.h" +#include "ImageProcess_Public.h" + +#ifdef LOG +#include "Device/filetools.h" +#endif // LOG + +CImageApplyOutHole::CImageApplyOutHole(void) + : CImageApply() + , m_borderSize(600) + , m_edgeScale(0.1f) + , m_threshold(100) +{ +} + +CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold) + : CImageApply() + , m_borderSize(borderSize) + , m_edgeScale(edgeScale) + , m_threshold(threshold) +{ +} + +CImageApplyOutHole::~CImageApplyOutHole(void) +{ +} + +void CImageApplyOutHole::apply(cv::Mat& pDib, int side) +{ + (void)pDib; + (void)side; +} + +void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter ImageOutHole apply"); +#endif // LOG + + if (mats.size() < 2) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + if (mats[0].empty() || mats[1].empty()) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + //二值化正反面图像 + cv::Mat front = mats[0]; + cv::Mat 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::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 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::flip(back_thre, back_thre, 1); //1:Horizontal + + //正反面图像寻边 + 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); + + //提取正反面图像最大轮廓 + std::vector maxContour_front = hg::getMaxContour(contours_front, b1_front); + std::vector maxContour_back = hg::getMaxContour(contours_back, b1_back); + + cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //提取正面最大轮廓的最小外接矩形 + cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //提取反面最大轮廓的最小外接矩形 + + //如果正反面图像尺寸差异超过20个像素,直接放弃处理 + if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 || + cv::abs(rrect_front.size.height - rrect_back.size.height) > 20) + return; + + //提取正反面图像重叠部分区域 + cv::Rect roi_front, roi_back; + cv::RotatedRect mask_rotatedRect; + getRoi(rrect_front, rrect_back, cv::Size(front.cols, front.rows), roi_front, roi_back, mask_rotatedRect); + + cv::Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分 + cv::Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分 + + //正反面二值图像做或运算,真正镂空区域保留0,其他地方填充为255 + cv::Mat mask; + cv::bitwise_or(roiMat_front, roiMat_back, mask); //或运算,正反面二值图像重叠 + + //cv::imwrite("roiMat_front.jpg", roiMat_front); + //cv::imwrite("roiMat_back.jpg", roiMat_back); + + //二值图像重叠图像颜色取反,膨胀,提取轮廓 + cv::bitwise_not(mask, 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), 15); //绘制纸张矩形边缘 + + std::vector> contours_mask; + std::vector b1_mask; + 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); + //for (size_t i = 0; i < hole_contours.size(); i++) + // cv::drawContours(mask, hole_contours, static_cast(i), cv::Scalar(127), 2); + //cv::imwrite("mask.jpg", mask); + cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area()); + 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); + hg::fillPolys(front_temp, contourss_temp, color); + } + + if (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()); + 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)); + + std::vector> contours_temp; + contours_temp.push_back(hole_contour); + cv::Mat back_temp = back(roi_back); + hg::fillPolys(back_temp, contours_temp, color); + } + } +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG +} + +void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize, + cv::Rect& roi_front, cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect) +{ + cv::Size size(static_cast(rrect_front.size.width + rrect_back.size.width) / 2, static_cast(rrect_front.size.height + rrect_back.size.height) / 2); + float angle = (rrect_front.angle + rrect_back.angle) / 2; + + rrect_front.size = rrect_back.size = size; + rrect_front.angle = rrect_back.angle = angle; + + roi_front = rrect_front.boundingRect(); + roi_back = rrect_back.boundingRect(); + + if (roi_front.width != roi_back.width || roi_front.height != roi_back.height) + { + roi_front.height = roi_back.height; + roi_front.width = roi_back.width; + } + + cv::Point offset(0, 0); + int top = std::min(roi_front.y, roi_back.y); + if (top < 0) + { + roi_front.y -= top; + roi_back.y -= top; + roi_front.height += top; + roi_back.height += top; + offset.y += top; + } + + int left = std::min(roi_front.x, roi_back.x); + if (left < 0) + { + roi_front.x -= left; + roi_back.x -= left; + roi_front.width += left; + roi_back.width += left; + offset.x += left; + } + + int right = std::max(roi_front.x + roi_front.width, roi_back.x + roi_back.width); + if (right >= srcSize.width) + { + roi_front.width -= (right - srcSize.width + 1); + roi_back.width -= (right - srcSize.width + 1); + } + + int bottom = std::max(roi_front.y + roi_front.height, roi_back.y + roi_back.height); + if (bottom >= srcSize.height) + { + roi_front.height -= (bottom - srcSize.height + 1); + roi_back.height -= (bottom - srcSize.height + 1); + } + + mask_rotatedRect.center = cv::Point((roi_front.width + offset.x) / 2, (roi_front.height + offset.y) / 2); + mask_rotatedRect.size = size; + mask_rotatedRect.angle = angle; +} + +std::vector> CImageApplyOutHole::filterPoly(std::vector>& contours, const std::vector& m, + cv::RotatedRect roi, float edgeScale, float areaThreshold) +{ + edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f)); + cv::RotatedRect roi2(roi.center, cv::Size(static_cast(roi.size.width * (1 - edgeScale * 2)), + static_cast(roi.size.height * (1 - edgeScale * 2))), roi.angle); + + std::vector vertices_roi1 = hg::getVertices(roi); + std::vector vertices_roi2 = hg::getVertices(roi2); + + std::vector> hole_contours; + for (size_t i = 0, length = contours.size(); i < length; i++) + { + if (m[i][2] != -1) continue; + + cv::RotatedRect rrect = hg::getBoundingRect(contours[i]); + if (rrect.size.area() < areaThreshold) continue; + + bool enabled = true; + for (size_t j = 0, count = contours[i].size(); j < count; j++) + { + cv::Point p(contours[i][j]); + double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外 + double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外 + //如果在纸张外,或者边缘内,视为非孔洞 + if (temp1 < 0 || temp2 > 0) + { + enabled = false; + break; + } + } + + if (enabled) + hole_contours.push_back(contours[i]); + } + return hole_contours; +} + +cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const 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 - m_threshold; + while (length < length_max) + { + for (size_t i = m_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; +} \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageApplyOutHole.h b/hgdriver/ImageProcess_test/ImageApplyOutHole.h new file mode 100644 index 0000000..4d0feaf --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyOutHole.h @@ -0,0 +1,74 @@ +/* + * ==================================================== + + * 功能:装订孔填充 + * 作者:刘丁维 + * 生成时间: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。 + * 版本号:v1.5 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_OUT_HOLE_H +#define IMAGE_APPLY_OUT_HOLE_H + +#include "ImageApply.h" + +class CImageApplyOutHole : public CImageApply +{ +public: + + CImageApplyOutHole(); + + /* + * borderSize [in]:孔洞面积阈值 + * edgeScale [in]:纸张边缘区域比例,取值范围(0,0.5),默认值0.1 + * threshold [in]:二值化阈值 + */ + CImageApplyOutHole(float borderSize, float edgeScale, double threshold); + + ~CImageApplyOutHole(void); + + virtual void apply(std::vector& mats, bool isTwoSide); + + float getBorderSize() { return m_borderSize; } + + float getEdgeScale() { return m_edgeScale; } + + double getThreshold() { return m_threshold; } + + void setBorderSize(float size) { m_borderSize = size; } + + void setEdgeScale(float scale) { m_edgeScale = scale; } + + void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); } + +private: + + virtual void apply(cv::Mat& pDib, int side); + + void getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize, cv::Rect& roi_front, + cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect); + + std::vector > filterPoly(std::vector>& contours, const std::vector& m, cv::RotatedRect roi, + float edgeScale, float areaThreshold); + + 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); + +private: + float m_borderSize; + float m_edgeScale; + double m_threshold; +}; + +#endif // !IMAGE_APPLY_OUT_HOLE_H diff --git a/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.cpp b/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.cpp new file mode 100644 index 0000000..45f91e0 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.cpp @@ -0,0 +1,64 @@ +#include "ImageApplyRefuseInflow.h" +#include "ImageApplyAdjustColors.h" + +CImageApplyRefuseInflow::CImageApplyRefuseInflow(int constrast) + : m_adjustColor(new CImageApplyAdjustColors(0, constrast, 1.0f)) +{ +} + +CImageApplyRefuseInflow::~CImageApplyRefuseInflow() +{ + delete m_adjustColor; +} + +void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side) +{ + (void)side; +#if 0 + static unsigned char table_contrast[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255 }; + static cv::Mat mat_table(1, 256, CV_8UC1, table_contrast); + cv::LUT(pDib, mat_table, pDib); +#else + m_adjustColor->apply(pDib, side); +#endif +} + +void CImageApplyRefuseInflow::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.h b/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.h new file mode 100644 index 0000000..672cd0d --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyRefuseInflow.h @@ -0,0 +1,34 @@ +/* + * ==================================================== + + * ܣ͸ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺v1.0 2020/04/21 + * v1.1 2022/05/04 ع㷨߶Աȶʵַ͸ + * 汾ţv1.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_REFUSE_INFLOW_H +#define IMAGE_APPLY_REFUSE_INFLOW_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class CImageApplyRefuseInflow : public CImageApply +{ +public: + CImageApplyRefuseInflow(int constrast = 15); + + virtual ~CImageApplyRefuseInflow(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + CImageApplyAdjustColors* m_adjustColor; +}; +#endif // !IMAGE_APPLY_REFUSE_INFLOW_H diff --git a/hgdriver/ImageProcess_test/ImageApplyResize.cpp b/hgdriver/ImageProcess_test/ImageApplyResize.cpp new file mode 100644 index 0000000..7411eee --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyResize.cpp @@ -0,0 +1,45 @@ +#include "ImageApplyResize.h" + +CImageApplyResize::CImageApplyResize() + : m_fx(1.0) + , m_fy(1.0) + , m_type(ResizeType::RATIO) +{ +} + +CImageApplyResize::CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy) + : m_type(type) + , m_dSize(size) + , m_fx(fx) + , m_fy(fy) +{ +} + + +CImageApplyResize::~CImageApplyResize(void) +{ +} + + +void CImageApplyResize::apply(cv::Mat& pDib,int side) +{ + (void)side; + if (pDib.empty()) return; + if (m_type == ResizeType::RATIO) + cv::resize(pDib, pDib, cv::Size(0, 0), m_fx, m_fy); + else + cv::resize(pDib, pDib, m_dSize); +} + +void CImageApplyResize::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyResize.h b/hgdriver/ImageProcess_test/ImageApplyResize.h new file mode 100644 index 0000000..f7dfc21 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyResize.h @@ -0,0 +1,69 @@ +/* + * ==================================================== + + * 功能:自定义伽马校正。原理为哈希表查值 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_RESIZE_H +#define IMAGE_APPLY_RESIZE_H + +#include "ImageApply.h" + +class CImageApplyResize : public CImageApply +{ +public: + + enum class ResizeType + { + RATIO, //比例缩放 + DSIZE //尺寸缩放 + }; + +public: + CImageApplyResize(); + + /* + * type [in]:缩放类型 + * size [in]:目标尺寸,当type为DSIZE时生效 + * fx [in]:横向目标比例,当type为RATIO时生效 + * fy [in]:纵向目标比例,当type为RATIO时生效 + */ + CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy); + + virtual ~CImageApplyResize(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + + double getFX() { return m_fx; } + + double getFY() { return m_fy; } + + cv::Size getDSize() { return m_dSize; } + + ResizeType getType() { return m_type; } + + void setFX(double value) { m_fx = value; } + + void setFY(double value) { m_fy = value; } + + void setDSize(const cv::Size& size) { m_dSize = size; } + + void setType(ResizeType type) { m_type = type; } + +private: + double m_fx; + double m_fy; + cv::Size m_dSize; + ResizeType m_type; +}; + +#endif // !IMAGE_APPLY_RESIZE_H diff --git a/hgdriver/ImageProcess_test/ImageApplyRotation.cpp b/hgdriver/ImageProcess_test/ImageApplyRotation.cpp new file mode 100644 index 0000000..782d6c0 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyRotation.cpp @@ -0,0 +1,172 @@ +#include "ImageApplyRotation.h" +//#define USE_TESSERCAT + +//#define USE_HANWANG + +//#define HG_GPDF_API_BUILD +#include "hg_ocr.h" + +CImageApplyRotation::CImageApplyRotation(RotationType rotation, bool isBackTransposed, int dpi, const char* tessdataPath) + : m_rotation(rotation) + , m_backTranspose(isBackTransposed) + , m_dpi(dpi) + , osd(nullptr) +{ + if (rotation == RotationType::AutoTextOrientation) + { +#ifdef USE_TESSERCAT + osd = new HG_OCR(); + std::string strpath(tessdataPath); + reinterpret_cast(osd)->init(strpath.c_str(), HG_OCR::PSM_TYPE::Orientation); +#endif + } +} + +CImageApplyRotation::~CImageApplyRotation() +{ +#ifdef USE_TESSERCAT + if (osd) delete reinterpret_cast(osd); +#endif +} + +void CImageApplyRotation::apply(cv::Mat& pDib, int side) +{ + m_angleResult = 0; + if (pDib.empty()) + { + return; + } + + if (m_rotation == RotationType::AutoTextOrientation) //�Զ��ı�����ʶ�� + { +#ifdef USE_HANWANG + cv::Mat temp; + if (m_dpi != 200) + { + double scale = 200 / static_cast(m_dpi); + int new_w = static_cast(pDib.cols * scale) / 4 * 4; + int new_h = pDib.rows * scale; + cv::resize(pDib, temp, cv::Size(new_w, new_h)); + } + else + temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); + + if (temp.channels() == 3) + cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); + cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU); + + int orientation = HG_OCR::orientation(temp.data, temp.cols, temp.rows, temp.channels()); + + switch (orientation) + { + case 90: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 0); + break; + case 180: + cv::flip(pDib, pDib, 0); + cv::flip(pDib, pDib, 1); + break; + case 270: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 1); + break; + default: + break; + } +#endif +#ifdef USE_TESSERCAT + if (osd) + { + cv::Mat temp; + if (m_dpi != 200) + { + double scale = 200 / static_cast(m_dpi); + int new_w = (static_cast(pDib.cols * scale) + 3) / 4 * 4; + int new_h = pDib.rows * scale; + cv::resize(pDib, temp, cv::Size(new_w, new_h)); + } + else + temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); + + + HG_OCR* ptr_osd = reinterpret_cast(osd); + int ori = -1; + int direction = -1; + int order = -1; + float angle = -1; + ptr_osd->getOrientation(temp.data, temp.cols, temp.rows, temp.channels(), temp.step1(), + ori, direction, order, angle); + + switch (ori) + { + case 1: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 0); + m_angleResult = 90; + break; + case 2: + cv::flip(pDib, pDib, 0); + cv::flip(pDib, pDib, 1); + m_angleResult = 180; + break; + case 3: + cv::transpose(pDib, pDib); + cv::flip(pDib, pDib, 1); + m_angleResult = 270; + break; + default: + m_angleResult = 0; + break; + } + } +#endif + } + else if (m_backTranspose && side == 1) //������ת180 + { + if (m_rotation != RotationType::Rotate_180) //��ת180�� + { + if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� + { + transpose(pDib, pDib); + flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1); + m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 270 : 90; + } + else + { + flip(pDib, pDib, 0); + flip(pDib, pDib, 1); + m_angleResult = 180; + } + } + } + else //zh + { + if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90�� -90�� + { + transpose(pDib, pDib); + flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 1 : 0); + m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 90 : 270; + } + else if (m_rotation == RotationType::Rotate_180) + { + flip(pDib, pDib, 0); + flip(pDib, pDib, 1); + m_angleResult = 180; + } + } +} + +void CImageApplyRotation::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + m_angleResults.clear(); + int i = 0; + for (cv::Mat& var : mats) { + if (!var.empty()) { + apply(var, i); + m_angleResults.push_back(m_angleResult); + i++; + } + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyRotation.h b/hgdriver/ImageProcess_test/ImageApplyRotation.h new file mode 100644 index 0000000..5412dd9 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyRotation.h @@ -0,0 +1,56 @@ +#ifndef IMAGE_APPLY_ROTATION_H +#define IMAGE_APPLY_ROTATION_H + +#include "ImageApply.h" + +class CImageApplyRotation : public CImageApply +{ +public: + enum class RotationType + { + Invalid, + Rotate_90_clockwise, + Rotate_180, + Rotate_90_anti_clockwise, + + AutoTextOrientation + }; + +public: + + CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr); + + virtual ~CImageApplyRotation(); + + virtual void apply(cv::Mat& pDib, int side) override; + + virtual void apply(std::vector& mats, bool isTwoSide); + + bool isBackTransposed() { return m_backTranspose; } + + int getDPI() { return m_dpi; } + + int angleResult() { return m_angleResult; } + + const std::vector& angleResults() { return m_angleResults; } + + RotationType getRotationType() { return m_rotation; } + + void setBackTransposed(bool enabled) { m_backTranspose = enabled; } + + void setDPI(int dpi) { m_dpi = dpi; } + + void setRotationType(RotationType type) { m_rotation = type; } + +private: + RotationType m_rotation; + bool m_backTranspose; + int m_dpi; + + void* osd; + + int m_angleResult; + std::vector m_angleResults; +}; + +#endif // !IMAGE_APPLY_ROTATION_H diff --git a/hgdriver/ImageProcess_test/ImageApplySharpen.cpp b/hgdriver/ImageProcess_test/ImageApplySharpen.cpp new file mode 100644 index 0000000..34eeef9 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySharpen.cpp @@ -0,0 +1,53 @@ +#include "ImageApplySharpen.h" +using namespace cv; +CImageApplySharpen::CImageApplySharpen(int sharpentype) +{ + sharpenType = sharpentype; + kSize = (sharpentype == FilterMethod::Sharpen || sharpentype == FilterMethod::AverBlur) ? 5 : 9; +} + +CImageApplySharpen::~CImageApplySharpen() +{ +} + +void CImageApplySharpen::apply(cv::Mat & pDib, int side) +{ + switch (sharpenType) + { + case CImageApplySharpen::Sharpen: + case CImageApplySharpen::Sharpen_More: + sharpen(pDib, kSize); + break; + case CImageApplySharpen::AverBlur: + case CImageApplySharpen::AverBlur_More: + averblur(pDib, static_cast(kSize)); + break; + } +} + +void CImageApplySharpen::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + if (isTwoSide && mats.size() > 1) { + if (!mats[1].empty()) + apply(mats[1], 1); + } +} + +void CImageApplySharpen::averblur(Mat& src, int kSize) +{ + blur(src, src, Size(kSize, kSize)); +} + +void CImageApplySharpen::sharpen(Mat& src, float kSize) +{ + float other = (1.0f - kSize) / 4; + float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 }; + Mat kernel(3, 3, CV_32FC1, kernel_data); + + filter2D(src, src, src.depth(), kernel); +} diff --git a/hgdriver/ImageProcess_test/ImageApplySharpen.h b/hgdriver/ImageProcess_test/ImageApplySharpen.h new file mode 100644 index 0000000..9401b9e --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySharpen.h @@ -0,0 +1,32 @@ +#ifndef IMAGE_APPLY_SHARPEN_H +#define IMAGE_APPLY_SHARPEN_H + +#include "ImageApply.h" + +class CImageApplySharpen : + public CImageApply +{ +public: + enum FilterMethod + { + None, + Sharpen, + Sharpen_More, + AverBlur, + AverBlur_More + }; + CImageApplySharpen(int sharpentype); + virtual ~CImageApplySharpen(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + void averblur(cv::Mat& src, int kSize); + void sharpen(cv::Mat& src, float kSize); +private: + int sharpenType; + float kSize; +}; + +#endif // !IMAGE_APPLY_SHARPEN_H diff --git a/hgdriver/ImageProcess_test/ImageApplySizeDetection.cpp b/hgdriver/ImageProcess_test/ImageApplySizeDetection.cpp new file mode 100644 index 0000000..4a9da84 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySizeDetection.cpp @@ -0,0 +1,47 @@ +#include "ImageApplySizeDetection.h" +#include "ImageProcess_Public.h" + +CImageApplySizeDetection::CImageApplySizeDetection(int paperType, int thre_x, int thre_y) + : m_paperType(paperType) + , m_thre_x(thre_x) + , m_thre_y(thre_y) +{ + printf("\n paperType =%d \r\n", paperType); +} + +CImageApplySizeDetection::~CImageApplySizeDetection() +{ +} + +#define THRESHOLD 40 +#define ELEMNT_K 8 +int CImageApplySizeDetection::apply(const cv::Mat& pDib) +{ + if (pDib.empty()) return 0; + + float width, height; + cv::Mat thre; + hg::threshold_Mat(pDib, thre, THRESHOLD); + cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(ELEMNT_K, 1)); + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + std::vector> contours; + std::vector hierarchy; + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + width = rect.size.width; + height = rect.size.height; + printf("\n width =%f ,height = %f ", width, height); + + HGSize dstSize; + if (m_supportPaper.count((PaperSize)m_paperType) > 0)//包含设置的幅面 + { + dstSize = m_supportPaper[(PaperSize)m_paperType]; + if ((width > (dstSize.width + m_thre_x)) || + (width < (dstSize.width - m_thre_x)) || + (height > (dstSize.height + m_thre_y)) || + (height < (dstSize.height - m_thre_y))) + return 1; + } + return 0; +} diff --git a/hgdriver/ImageProcess_test/ImageApplySizeDetection.h b/hgdriver/ImageProcess_test/ImageApplySizeDetection.h new file mode 100644 index 0000000..75c5023 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySizeDetection.h @@ -0,0 +1,84 @@ +/* + * ==================================================== + + * ܣߴ + * ߣά + * ʱ䣺2022/05/11 + * ޸ʱ䣺2022/05/11 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_SIZE_DETECTION_H +#define IMAGE_APPLY_SIZE_DETECTION_H + +#include "ImageApply.h" +#include + +class CImageApplySizeDetection +{ +public: + enum PaperSize + { + G400_A3, + G400_A4, + G400_A4R, + G400_A5, + G400_A5R, + G400_A6, + G400_A6R, + G400_B4, + G400_B5, + G400_B5R, + G400_B6R, + G400_B6, + G400_DOUBLELETTER, + G400_LEGAL, + G400_LETTER, + G400_LONGLETTER, + G400_MAXSIZE + }; + + struct HGSize + { + int width; + int height; + }; + +public: + + CImageApplySizeDetection(int paperType, int thre_x = 70, int thre_y = 80); + + ~CImageApplySizeDetection(); + + virtual int apply(const cv::Mat& pDib); + + inline void setPaperType(int paperType) { m_paperType = paperType; } + +private: + int m_paperType; + int m_thre_x; + int m_thre_y; + std::map m_supportPaper = { + {PaperSize::G400_A3,HGSize{2338,3307}}, + {PaperSize::G400_A4,HGSize{1653,2338}}, + {PaperSize::G400_A4R,HGSize{2338,1653}}, + {PaperSize::G400_A5,HGSize{1165,1653}}, + {PaperSize::G400_A5R,HGSize{1653,1165}}, + {PaperSize::G400_A6,HGSize{826,1165}}, + {PaperSize::G400_A6R,HGSize{1165,826}}, + {PaperSize::G400_B4,HGSize{1969,2780}}, + {PaperSize::G400_B5,HGSize{1385,1968}}, + {PaperSize::G400_B5R,HGSize{1968,1385}}, + {PaperSize::G400_B6R,HGSize{1433,1007}}, + {PaperSize::G400_B6,HGSize{1007,1433}}, + {PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}}, + {PaperSize::G400_LEGAL,HGSize{1700,2800}}, + {PaperSize::G400_LETTER,HGSize{1700,2198}}, + {PaperSize::G400_LONGLETTER,HGSize{2040,2640}}, + {PaperSize::G400_MAXSIZE,HGSize{2338,6614}} + }; +}; + +#endif // !IMAGE_APPLY_SIZE_DETECTION_H diff --git a/hgdriver/ImageProcess_test/ImageApplySplit.cpp b/hgdriver/ImageProcess_test/ImageApplySplit.cpp new file mode 100644 index 0000000..8d0cc5f --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySplit.cpp @@ -0,0 +1,115 @@ +#include "ImageApplySplit.h" +#include + +#define BPP(type,index) +CImageApplySplit::CImageApplySplit(int multitype,bool split, bool ismulti_filter_red,int colormode) : + m_bmulti_filter_red(ismulti_filter_red) + , m_split(split) + , m_multitype(multitype) + , m_colormode(colormode) +{ +} + +CImageApplySplit::~CImageApplySplit(void) +{ +} + +std::vector CImageApplySplit::SplitMats(std::vector& mats, bool isTwoSide) +{ + std::vector rets; + for (size_t i = 0; i < mats.size(); i++) + { + if (mats[i].empty()) + continue; +// if (i != 0 && isTwoSide == false) +// break; + + int bpp = getBpp(i); + if (m_split)// + { + std::vector retmats = apply(mats[i]); + if (bpp != -1) { + } + else {// + if (m_colormode == 0) bpp = 1;//bw + else if (m_colormode == 1) bpp = 8; + else bpp = 24; + } + + for (size_t j = 0; j < retmats.size(); j++) + { + if (!retmats[j].empty()) { + cv::transpose(retmats[j],retmats[j]); + cv::flip(retmats[j],retmats[j],i==0?1:0); + MatEx matex(retmats[j], bpp); + rets.push_back(matex); + } + } + } + else { + MatEx matex(mats[i], bpp); + rets.push_back(matex); + } + } + return rets; +} + +std::vector CImageApplySplit::apply(cv::Mat& pDib) +{ + if (pDib.empty()) + return std::vector(); + std::vector retMats; + int heigth = pDib.rows; + int width = pDib.cols; + if (heigth > width) + { + cv::Mat matF = pDib(cv::Rect(0, 0, width, (int)(0.5 * heigth))); + cv::Mat matB = pDib(cv::Rect(0, (int)(0.5 * heigth), width, (int)(0.5 * heigth))); + retMats.push_back(matF); + retMats.push_back(matB); + } + else + { + cv::Mat matF = pDib(cv::Rect(0, 0, (int)(width*0.5), heigth)); + cv::Mat matB = pDib(cv::Rect((int)(width*0.5), 0, (int)(width * 0.5), heigth)); + retMats.push_back(matF); + retMats.push_back(matB); + } + return retMats; +} + +int CImageApplySplit::getBpp(int matIndex) +{ + int ret = -1; + if (m_bmulti_filter_red) { + ret = matIndex == 0 ? 24 : 8; + } + else + { + if (m_multitype == -1) + return ret; + switch (m_multitype) + { + case 0://all + if (matIndex == 0) ret = 24; + else if (matIndex == 1) ret = 8; + else ret = 1; + break; + case 1://clolr +gray + if (matIndex == 0) ret = 24; + else ret = 8; + break; + case 2://color+bw + if (matIndex == 0) ret = 24; + else ret = 1; + break; + case 3://gray+bw + if (matIndex == 0) ret = 8; + else ret = 1; + break; + default: + break; + } + } + return ret; +} diff --git a/hgdriver/ImageProcess_test/ImageApplySplit.h b/hgdriver/ImageProcess_test/ImageApplySplit.h new file mode 100644 index 0000000..35103a8 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplySplit.h @@ -0,0 +1,38 @@ +/* + * ==================================================== + + * ܣͼ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_SPLIT_H +#define IMAGE_APPLY_SPLIT_H +#include "MatEx.h" +#include +#include "imgprocdefs.h" + +class CImageApplySplit +{ +public: + CImageApplySplit(int multitype=-1,bool split=false,bool ismulti_filter_red=false,int colormode=1);//Ĭϲ Ҷ + + ~CImageApplySplit(void); + std::vector SplitMats(std::vector& mats, bool isTwoSide); + +//private: + std::vector apply(cv::Mat& pDib); + int getBpp(int matIndex); + +private://field + bool m_bmulti_filter_red; + int m_multitype; + int m_colormode; + bool m_split; +}; + +#endif // !IMAGE_APPLY_SPLIT_H diff --git a/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.cpp b/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.cpp new file mode 100644 index 0000000..5c42622 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.cpp @@ -0,0 +1,172 @@ +#include "ImageApplyTextureRemoval.h" + +//Խ +void zero_to_center(cv::Mat& image, int colToCut, int rowToCut) +{ + cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut)); + cv::Mat q2(image, cv::Rect(colToCut, 0, colToCut, rowToCut)); + cv::Mat q3(image, cv::Rect(0, rowToCut, colToCut, rowToCut)); + cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut)); + + //ڶ޺͵޽н + cv::Mat tmpImg; + q1.copyTo(tmpImg); + q4.copyTo(q1); + tmpImg.copyTo(q4); + + //һ޺͵޽н + q2.copyTo(tmpImg); + q3.copyTo(q2); + tmpImg.copyTo(q3); +} + +// +cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5) +{ + cv::Mat dst; + cv::magnitude(matArray[0], matArray[1], dst); +#if 1 + cv::divide(dst, dst.cols * dst.rows, dst, scale); + //imshow("Ƶ", dst); +#else + dst += Scalar::all(1); + log(dst, dst); + normalize(dst, dst, 1, 0, CV_MINMAX); +#endif + +#if 0 + imshow("Ƶ", dst); +#endif + return dst; +} + +//Ҷ任 +void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst) +{ + cv::Mat complexIDFT; + cv::Mat matArray[2]; + cv::idft(src, complexIDFT); + cv::split(complexIDFT, matArray); + cv::magnitude(matArray[0], matArray[1], dst); + cv::normalize(dst, dst, 0, 1, CV_MINMAX); +} + +//ݲ˲ +cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize) +{ + cv::Mat temp; + spectrum.convertTo(temp, CV_8UC1, 255); + cv::threshold(temp, temp, 0, 255, CV_THRESH_OTSU); + //imshow("ֵ", temp); + + cv::Mat element1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(dilateSize, dilateSize)); + cv::Mat element2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(erodeSize, erodeSize)); + cv::dilate(temp, temp, element1); + cv::erode(temp, temp, element2); + cv::floodFill(temp, cv::Point(temp.cols / 2, temp.rows / 2), cv::Scalar(0)); //ˮ + cv::medianBlur(~temp, temp, 3); //ֵ˲ + //temp = ~temp; + //cv::imshow("ֵ", temp); + + //ݲ˲ + cv::Mat filter; + temp.convertTo(filter, CV_32FC1); + cv::normalize(filter, filter, 1, 0.01, CV_MINMAX); + std::vector mv; + mv.push_back(filter); + mv.push_back(filter); + cv::merge(mv, filter); + + return filter; +} + +void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img) +{ + //õDFTѳߴ磨2ָԼټ + cv::Mat paddedImg; + int m = cv::getOptimalDFTSize(img.rows); + int n = cv::getOptimalDFTSize(img.cols); + + //ͼ¶˺Ҷ + cv::copyMakeBorder(img, paddedImg, 0, m - img.rows, 0, n - img.cols, + cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + //ͼһĶά飨ͨMatDFT + cv::Mat matArray[] = { cv::Mat_(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) }; + cv::Mat complexInput, complexOutput; + cv::merge(matArray, 2, complexInput); + cv::dft(complexInput, complexOutput); + cv::split(complexOutput, matArray); //ףҶף + + //˲ + //ʵ鲿Ƶͼķʽλ + //Ƶͼģ˲ + zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2); + zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2); + cv::Mat spectrum = create_spectrum(matArray); + + //˲ + cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize); + cv::merge(matArray, 2, complexOutput); + cv::multiply(complexOutput, filter, filter); + + //IDFTõ˲ + cv::Size imgSize = img.size(); + inverseFourierTransform(filter, img); + img = img(cv::Rect(cv::Point(0, 0), imgSize)); + img *= 255; + img.convertTo(img, CV_8UC1); +} + +CImageApplyTextureRemoval::CImageApplyTextureRemoval() + : CImageApply() + , m_dilateSize(5) + , m_erodeSize(3) +{ + +} + +CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize) + : CImageApply() + , m_dilateSize(dilateSize) + , m_erodeSize(erodeSize) +{ + +} + +CImageApplyTextureRemoval::~CImageApplyTextureRemoval() +{ + +} + +void CImageApplyTextureRemoval::apply(cv::Mat &pDib, int side) +{ + (void)side; + + if (pDib.channels() == 1) + textureRemovalGray(pDib); + else + { + std::vector rgb(3); + cv::split(pDib, rgb); + for (cv::Mat& var : rgb) + textureRemovalGray(var); + cv::merge(rgb, pDib); + } + + pDib *= 1.15; +} + +void CImageApplyTextureRemoval::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} diff --git a/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.h b/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.h new file mode 100644 index 0000000..f97080d --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyTextureRemoval.h @@ -0,0 +1,50 @@ +/* + * ==================================================== + + * 功能:去除网纹 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_TEXTURE_REMOVAL_H +#define IMAGE_APPLY_TEXTURE_REMOVAL_H + +#include "ImageApply.h" + +class CImageApplyTextureRemoval : public CImageApply +{ +public: + CImageApplyTextureRemoval(void); + + /* + * dilateSize [in]:膨胀像素 + * erodeSize [in]:腐蚀像素 + */ + CImageApplyTextureRemoval(int dilateSize, int erodeSize); + + virtual ~CImageApplyTextureRemoval(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + int getDilateSize() {return m_dilateSize;} + + int getErodeSize() {return m_erodeSize;} + + void setDilateSize(int size) {m_dilateSize = size;} + + void setErodeSize(int size) {m_erodeSize = size;} +private: + void textureRemovalGray(cv::Mat& img); + +private: + int m_dilateSize; + int m_erodeSize; +}; + +#endif diff --git a/hgdriver/ImageProcess_test/ImageApplyUV.cpp b/hgdriver/ImageProcess_test/ImageApplyUV.cpp new file mode 100644 index 0000000..56808fe --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyUV.cpp @@ -0,0 +1,315 @@ +#include "ImageApplyUV.h" +using namespace cv; +#define SCA 50 + +ImageApplyUV::ImageApplyUV() : lut(1, 256, CV_8UC1) +{ +} + +ImageApplyUV::~ImageApplyUV() +{ +} + +void ImageApplyUV::update_lutData(int contrast) +{ + unsigned char* ptr = lut.data; + int m_contrast = cv::max(-127, cv::min(contrast, 127)); + for (int i = 0; i < 256; i++) + { + //update contrast + if (i < 128) + ptr[i] = static_cast(cv::max(0, cv::min(i - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(i + m_contrast, 255))); + } +} + +void ImageApplyUV::Apply(cv::Mat& image, const cv::Mat& uv, int dpi, int thresh) +{ + update_lutData(12); + cv::LUT(uv, lut, uv); + Mat uv_resize; + cv::resize(uv, uv_resize, cv::Size(uv.cols * SCA / dpi, uv.rows * SCA / dpi)); + if (uv_resize.channels() == 3) + cv::cvtColor(uv_resize, uv_resize, cv::COLOR_BGR2GRAY); + cv::threshold(uv_resize, uv_resize, 150, 255, THRESH_BINARY); + cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1500 / dpi, 1500 / dpi)); + cv::dilate(uv_resize, uv_resize, element); + std::vector> contours; + std::vector hierarchy; + findContours1(uv_resize, contours, hierarchy, cv::RETR_EXTERNAL); + + std::map map_color; + for (int i = 0; i < contours.size(); i++) + { + cv::Rect roi = cv::boundingRect(contours[i]); + roi.x *= dpi / SCA; + roi.y *= dpi / SCA; + roi.width *= dpi / SCA; + roi.height *= dpi / SCA; + + purgeQR_kernal(image, roi, map_color, dpi, thresh); + } +} + +cv::Mat ImageApplyUV::Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle, int pixtype) +{ + static int svindex = 0; + if (uvRoi.size.width == 0) + return cv::Mat(); + cv::RotatedRect uvRoi_clone = uvRoi; + cv::Mat dst = cv::Mat::zeros(image.rows > image.cols ? image.rows : (image.rows * 2), image.cols > image.rows ? image.cols : (image.cols * 2), image.type()); + image.copyTo(dst(cv::Rect(0, 0, image.cols, image.rows))); + + cv::Mat dst_uv = dst(cv::Rect(image.rows > image.cols ? image.cols : 0, image.rows > image.cols ? 0 : image.rows, image.cols, image.rows)); + if (isDesaskew) + { + cv::Point2f srcTri[4]; + cv::Point2f dstTri[3]; + uvRoi_clone.points(srcTri); + + if (angle == 90) + { + dstTri[0] = cv::Point2f(0, 0); + dstTri[1] = cv::Point2f(uvRoi_clone.size.width - 1, 0); + dstTri[2] = cv::Point2f(uvRoi_clone.size.width - 1, uvRoi_clone.size.height - 1); + } + else if (angle == 180) + { + dstTri[0] = cv::Point2f(uvRoi_clone.size.width - 1, 0); + dstTri[1] = cv::Point2f(uvRoi_clone.size.width - 1, uvRoi_clone.size.height - 1); + dstTri[2] = cv::Point2f(0, uvRoi_clone.size.height - 1); + } + else if (angle == 270) + { + dstTri[0] = cv::Point2f(uvRoi_clone.size.width - 1, uvRoi_clone.size.height - 1); + dstTri[1] = cv::Point2f(0, uvRoi_clone.size.height - 1); + dstTri[2] = cv::Point2f(0, 0); + } + else + { + dstTri[0] = cv::Point2f(0, uvRoi_clone.size.height - 1); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(uvRoi_clone.size.width - 1, 0); + } + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + cv::Mat uv_temp; + cv::warpAffine(uv, uv_temp, warp_mat, cv::Size(uvRoi_clone.size.width, uvRoi_clone.size.height)); + + //cv::imwrite("uv_temp.jpg", uv_temp); + if (pixtype == 0)//ֵͼ + { + cvtColor(uv_temp, uv_temp, cv::COLOR_BGR2GRAY); + cv::threshold(uv_temp, uv_temp, 150, 255, THRESH_OTSU); + } + + if (uv_temp.channels() == 1 && dst_uv.channels() == 3) + { + cv::cvtColor(uv_temp(cv::Rect( + uv_temp.cols > dst_uv.cols ? (uv_temp.cols - dst_uv.cols) / 2 : 0, + uv_temp.rows > dst_uv.rows ? (uv_temp.rows - dst_uv.rows) / 2 : 0, + uv_temp.cols > dst_uv.cols ? dst_uv.cols : uv_temp.cols, + uv_temp.rows > dst_uv.rows ? dst_uv.rows : uv_temp.rows)), + dst_uv(cv::Rect( + dst_uv.cols > uv_temp.cols ? (dst_uv.cols - uv_temp.cols) / 2 : 0, + dst_uv.rows > uv_temp.rows ? (dst_uv.rows - uv_temp.rows) / 2 : 0, + dst_uv.cols > uv_temp.cols ? uv_temp.cols : dst_uv.cols, + dst_uv.rows > uv_temp.rows ? uv_temp.rows : dst_uv.rows)), cv::COLOR_GRAY2BGR); + } + else if (uv_temp.channels() == 3 && dst_uv.channels() == 1) + { + cv::cvtColor(uv_temp(cv::Rect( + uv_temp.cols > dst_uv.cols ? (uv_temp.cols - dst_uv.cols) / 2 : 0, + uv_temp.rows > dst_uv.rows ? (uv_temp.rows - dst_uv.rows) / 2 : 0, + uv_temp.cols > dst_uv.cols ? dst_uv.cols : uv_temp.cols, + uv_temp.rows > dst_uv.rows ? dst_uv.rows : uv_temp.rows)), + dst_uv(cv::Rect( + dst_uv.cols > uv_temp.cols ? (dst_uv.cols - uv_temp.cols) / 2 : 0, + dst_uv.rows > uv_temp.rows ? (dst_uv.rows - uv_temp.rows) / 2 : 0, + dst_uv.cols > uv_temp.cols ? uv_temp.cols : dst_uv.cols, + dst_uv.rows > uv_temp.rows ? uv_temp.rows : dst_uv.rows)), cv::COLOR_BGR2GRAY); + } + else + { + uv_temp(cv::Rect( + uv_temp.cols > dst_uv.cols ? (uv_temp.cols - dst_uv.cols) / 2 : 0, + uv_temp.rows > dst_uv.rows ? (uv_temp.rows - dst_uv.rows) / 2 : 0, + uv_temp.cols > dst_uv.cols ? dst_uv.cols : uv_temp.cols, + uv_temp.rows > dst_uv.rows ? dst_uv.rows : uv_temp.rows)).copyTo(dst_uv(cv::Rect( + dst_uv.cols > uv_temp.cols ? (dst_uv.cols - uv_temp.cols) / 2 : 0, + dst_uv.rows > uv_temp.rows ? (dst_uv.rows - uv_temp.rows) / 2 : 0, + dst_uv.cols > uv_temp.cols ? uv_temp.cols : dst_uv.cols, + dst_uv.rows > uv_temp.rows ? uv_temp.rows : dst_uv.rows))); + } + + } + else + { + cv::Rect uvBoundingRect = uvRoi_clone.boundingRect(); + + cv::Rect uvBoundingRect_temp; + if (angle == 90 || angle == 270) + { + uvBoundingRect_temp.x = dst_uv.rows > uvBoundingRect.width ? uvBoundingRect.x : uvBoundingRect.x + (uvBoundingRect.width - dst_uv.rows) / 2; + uvBoundingRect_temp.width = cv::min(dst_uv.rows, uvBoundingRect.width); + uvBoundingRect_temp.y = dst_uv.cols > uvBoundingRect.height ? uvBoundingRect.y : uvBoundingRect.y + (uvBoundingRect.height - dst_uv.cols) / 2; + uvBoundingRect_temp.height = cv::min(dst_uv.cols, uvBoundingRect.height); + } + else + { + uvBoundingRect_temp.x = dst_uv.cols > uvBoundingRect.width ? uvBoundingRect.x : uvBoundingRect.x + (uvBoundingRect.width - dst_uv.cols) / 2; + uvBoundingRect_temp.width = cv::min(dst_uv.cols, uvBoundingRect.width); + uvBoundingRect_temp.y = dst_uv.rows > uvBoundingRect.height ? uvBoundingRect.y : uvBoundingRect.y + (uvBoundingRect.height - dst_uv.rows) / 2; + uvBoundingRect_temp.height = cv::min(dst_uv.rows, uvBoundingRect.height); + } + + int offset_left = 0, offset_right = 0, offset_top = 0, offset_bottom = 0; + if (uvBoundingRect_temp.x < 0) + { + offset_left = -uvBoundingRect_temp.x; + uvBoundingRect_temp.x = 0; + uvBoundingRect_temp.width -= offset_left; + } + + if (uvBoundingRect_temp.y < 0) + { + offset_top = -uvBoundingRect_temp.y; + uvBoundingRect_temp.y = 0; + uvBoundingRect_temp.height -= offset_top; + } + + if (uvBoundingRect_temp.br().x >= uv.cols) + { + offset_right = uvBoundingRect_temp.br().x - uv.cols + 1; + uvBoundingRect_temp.width -= offset_right; + } + + if (uvBoundingRect_temp.br().y >= uv.rows) + { + offset_bottom = uvBoundingRect_temp.br().y - uv.rows + 1; + uvBoundingRect_temp.height -= offset_bottom; + } + + cv::Mat uv_roi = uv(uvBoundingRect_temp).clone(); + + if (dst_uv.channels() == 1)//Ҷ + { + cv::cvtColor(uv_roi, uv_roi, cv::COLOR_BGR2GRAY); + if (pixtype == 0)//ֵͼ + cv::threshold(uv_roi, uv_roi, 150, 255, THRESH_OTSU); + } + uv_roi.copyTo(dst_uv(cv::Rect((dst_uv.cols - uv_roi.cols + offset_left) / 2, (dst_uv.rows - uv_roi.rows + offset_top) / 2, uv_roi.cols, uv_roi.rows))); + } + //imwrite("D:\\dst" + std::to_string(svindex) + ".jpg", dst); + return dst; +} + +void ImageApplyUV::purgeQR_kernal(cv::Mat& image, const cv::Rect& roi, std::map map_color, int dpi, int threshold) +{ + cv::Mat image_roi = image(roi); + cv::Mat mask; + cv::cvtColor(image_roi, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, 127, 255, cv::THRESH_OTSU); + cv::Mat image_resize; + cv::resize(image, image_resize, cv::Size(image.cols, 800)); + + for (int i = 0, cols = image_roi.cols, rows = image_roi.rows; i < cols; i++) + { + cv::Scalar color_fill; + if (map_color.find(i + roi.x) == map_color.end()) + { + color_fill = getColor(image_resize, roi.x + i, threshold); + map_color[i + roi.x] = color_fill; + } + else + color_fill = map_color[i + roi.x]; + + for (int j = 0; j < rows; j++) + { + if (*mask.ptr(j, i)) + { + uchar* color = image_roi.ptr(j, i); + color[0] = color_fill[0]; + color[1] = color_fill[1]; + color[2] = color_fill[2]; + } + } + } +} + +void ImageApplyUV::findContours1(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) +{ + CvMat c_image; + CV_DbgAssert(src.dims <= 2); + c_image = cvMat(src.rows, src.dims == 1 ? 1 : src.cols, src.type(), src.data); + c_image.step = (int)src.step[0]; + c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG); + cv::MemStorage storage(cvCreateMemStorage()); + CvSeq* _ccontours = nullptr; + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint({ offset.x,offset.y })); + + if (!_ccontours) + { + contours.clear(); + return; + } + cv::Seq all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); + size_t total = all_contours.size(); + contours.resize(total); + + cv::SeqIterator it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + reinterpret_cast(c)->color = static_cast(i); + int count = c->total; + int* data = new int[static_cast(count * 2)]; + cvCvtSeqToArray(c, data); + for (int j = 0; j < count; j++) + contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); + + delete[] data; + } + + hierarchy.resize(total); + it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; + int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; + int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; + int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; + hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); + } + + storage.release(); +} + +cv::Scalar ImageApplyUV::getColor(const cv::Mat& image, int col, int threshold) +{ + cv::Scalar color(0, 0, 0); + int num = 0; + + for (int i = 0, length = image.rows; i < length; i++) + { + const uchar* ptr = image.ptr(i, col); + int gray = (ptr[0] * 30 + ptr[1] * 59 + ptr[2] * 11) / 100; + if (gray > threshold) + { + color[0] += ptr[0]; + color[1] += ptr[1]; + color[2] += ptr[2]; + num++; + } + } + + if (num) + color /= num; + else + color[0] = color[1] = color[2] = 255; + + return color; +} + diff --git a/hgdriver/ImageProcess_test/ImageApplyUV.h b/hgdriver/ImageProcess_test/ImageApplyUV.h new file mode 100644 index 0000000..14b9e77 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageApplyUV.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include "ImageProcess_Public.h" +#include + +class ImageApplyUV +{ +public: + ImageApplyUV(); + ~ImageApplyUV(); + void Apply(cv::Mat& image, const cv::Mat& uv, int dpi = 200, int thresh = 100); + + static cv::Mat Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle, int pixtype); +private: + void purgeQR_kernal(cv::Mat& image, const cv::Rect& roi, std::map map_color, int dpi, int threshold); + void findContours1(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 getColor(const cv::Mat& image, int col, int threshold); + void update_lutData(int contrast); + cv::Mat lut; +}; + + diff --git a/hgdriver/ImageProcess_test/ImageMulti.cpp b/hgdriver/ImageProcess_test/ImageMulti.cpp new file mode 100644 index 0000000..422f707 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageMulti.cpp @@ -0,0 +1,72 @@ +#include "ImageMulti.h" + +IMageMulti::IMageMulti(int multiType,int thre) +{ + m_multiType = multiType; + m_thre = thre; +} + +IMageMulti::~IMageMulti(void) +{ +} + +std::vector IMageMulti::apply(cv::Mat& pDib) +{ + std::vector retMats; + if (pDib.empty()) + return retMats; + retMats.push_back(pDib); + switch (m_multiType) + { + case ALL: + { + if (pDib.channels() == 3){ + cv::Mat dst; + cv::cvtColor(pDib, dst,cv::COLOR_BGR2GRAY); + retMats.push_back(dst); + } + cv::Mat dstThre; + cv::cvtColor(pDib, dstThre,cv::COLOR_BGR2GRAY); + //cv::threshold(dstThre, dstThre, m_thre, 255, cv::THRESH_BINARY); + cv::adaptiveThreshold(dstThre,dstThre,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + if (!dstThre.empty()) + { + retMats.push_back(dstThre); + } + } + break; + case COLORGRAY: + { + if (pDib.channels() == 3) { + cv::Mat dstGray; + cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); + retMats.push_back(dstGray); + } + } + break; + case COLORBW: + { + if (pDib.channels() == 3) { + cv::Mat dstGray; + cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY); + cv::Mat dstBW; + cv::adaptiveThreshold(dstGray,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + retMats.push_back(dstBW); + } + } + break; + case GRAYBW://pDib should be GreyImage(channels() == 1) + { + cv::Mat dstBW; + cv::adaptiveThreshold(pDib,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5); + if (!dstBW.empty()) + { + retMats.push_back(dstBW); + } + } + break; + default: + break; + } + return retMats; +} diff --git a/hgdriver/ImageProcess_test/ImageMulti.h b/hgdriver/ImageProcess_test/ImageMulti.h new file mode 100644 index 0000000..0a79195 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageMulti.h @@ -0,0 +1,26 @@ +#ifndef IMAGE_MULTI_H +#define IMAGE_MULTI_H +#include "IMulti.h" + +class IMageMulti + :public IMulti +{ +public: + enum MultiOutput + { + NONE=-1, + ALL, + COLORGRAY, + COLORBW, + GRAYBW + }; +public: + IMageMulti(int multiType = 0,int thre = 128); + virtual ~IMageMulti(void); + virtual std::vector apply(cv::Mat& pDib); +private: + int m_multiType; + int m_thre; +}; + +#endif // !IMAGE_MULTI_H \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageMultiOutputRed.cpp b/hgdriver/ImageProcess_test/ImageMultiOutputRed.cpp new file mode 100644 index 0000000..5cc08d2 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageMultiOutputRed.cpp @@ -0,0 +1,63 @@ +#include "ImageMultiOutputRed.h" +#include + +using namespace std; + +ImageMultiOutputRed::ImageMultiOutputRed(short channelIndex) +{ + m_channelIndex = channelIndex; +} + +ImageMultiOutputRed::~ImageMultiOutputRed(void) +{ +} + +std::vector ImageMultiOutputRed::apply(cv::Mat& pDib) +{ + std::vector retMats; + if (pDib.empty()) + return retMats; + retMats.push_back(pDib); + cv::Mat mat = FilterColor(pDib, m_channelIndex); + if (!mat.empty()) + retMats.push_back(mat); + return retMats; +} + +cv::Mat ImageMultiOutputRed::FilterColor(cv::Mat image, short channel) +{ + cv::Mat dstImage(image.rows, image.cols, CV_8UC1); + int channels = image.channels(); + if (channel > channels - 1) + { + return cv::Mat(); + } + if ((channel == 3) && (channels != 4) && (channels != 8)) + { + return cv::Mat(); + } + if (channels <= 4) + { + int srcOffset = image.step - image.cols * channels; + int dstOffset = dstImage.step - dstImage.cols; + unsigned char *src = image.data; + unsigned char *dst = dstImage.data; + src += channel; + + for (int y = 0; y < image.rows; y++) + { + for (int x = 0; x < image.cols; x++, src += channels, dst++) + { + unsigned short pix = *src; + if (pix >= 130) + { + pix = 255; + } + *dst = pix; + } + src += srcOffset; + dst += dstOffset; + } + } + return dstImage; +} diff --git a/hgdriver/ImageProcess_test/ImageMultiOutputRed.h b/hgdriver/ImageProcess_test/ImageMultiOutputRed.h new file mode 100644 index 0000000..a7ed28c --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageMultiOutputRed.h @@ -0,0 +1,17 @@ +#ifndef IMAGE_MULTI_OUTPUT_RED_H +#define IMAGE_MULTI_OUTPUT_RED_H +#include "IMulti.h" + +class ImageMultiOutputRed + :public IMulti +{ +public: + ImageMultiOutputRed(short channelIndex); + virtual ~ImageMultiOutputRed(void); + virtual std::vector apply(cv::Mat& pDib) override; + +private: + short m_channelIndex; + cv::Mat FilterColor(cv::Mat image, short channel); +}; +#endif //!IMAGE_MULTI_OUTPUT_RED_H diff --git a/hgdriver/ImageProcess_test/ImageProcess_Public.cpp b/hgdriver/ImageProcess_test/ImageProcess_Public.cpp new file mode 100644 index 0000000..7096570 --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageProcess_Public.cpp @@ -0,0 +1,336 @@ +#include "ImageProcess_Public.h" + +namespace hg +{ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise) + { + CvMemStorage* storage = cvCreateMemStorage(); // + CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage + + // + for (const cv::Point& item : src) + { + CvPoint p; + p.x = item.x; + p.y = item.y; + cvSeqPush(ptseq, &p); + } + + //hullstorage + CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0); + + //dst + dst.clear(); + for (int i = 0, hullCount = hull->total; i < hullCount; i++) + dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i)); + + //storage + cvReleaseMemStorage(&storage); + } + +#define R_COLOR 255 + void fillConvexHull(cv::Mat& image, const std::vector& points) + { + uint index_top = 0; + uint index_bottom = 0; + for (size_t i = 0, length = points.size(); i < length; i++) + { + if (points[i].y < points[index_top].y) + index_top = i; + if (points[i].y > points[index_bottom].y) + index_bottom = i; + } + + std::vector edge_left; + uint temp = index_top; + while (temp != index_bottom) + { + edge_left.push_back(points[temp]); + temp = (temp + points.size() - 1) % points.size(); + } + edge_left.push_back(points[index_bottom]); + + std::vector edge_right; + temp = index_top; + while (temp != index_bottom) + { + edge_right.push_back(points[temp]); + temp = (temp + points.size() + 1) % points.size(); + } + edge_right.push_back(points[index_bottom]); + + std::vector left_edge_x; + std::vector left_edge_y; + for (size_t i = 0, length = edge_left.size() - 1; i < length; i++) + { + int y_top = edge_left[i].y; + int x_top = edge_left[i].x; + int y_bottom = edge_left[i + 1].y; + int x_bottom = edge_left[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y >= 0 && y_top != y_bottom && y < image.rows) + { + left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + left_edge_y.push_back(y); + } + } + size_t step = image.step; + unsigned char* ptr; + ptr = image.data + static_cast(left_edge_y[0]) * step; + for (size_t i = 0, length = left_edge_x.size(); i < length; i++) + { + int pix = left_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step, R_COLOR, static_cast((pix + 1) * image.channels())); + } + + std::vector right_edge_x; + std::vector right_edge_y; + for (size_t i = 0, length = edge_right.size() - 1; i < length; i++) + { + int y_top = edge_right[i].y; + int x_top = edge_right[i].x; + int y_bottom = edge_right[i + 1].y; + int x_bottom = edge_right[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y_top != y_bottom && y < image.rows && y >= 0) + { + right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + right_edge_y.push_back(y); + } + } + + ptr = image.data + static_cast(right_edge_y[0]) * step; + for (size_t i = 0, length = right_edge_x.size(); i < length; i++) + { + int pix = right_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast(pix * image.channels())); + } + + if (edge_left[0].y > 0) + memset(image.data, R_COLOR, static_cast(edge_left[0].y) * step); + + if (edge_left.back().y < image.rows - 1) + memset(image.data + static_cast(edge_left.back().y) * step, R_COLOR, + static_cast(image.rows - edge_left.back().y) * step); + } + + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color) + { + if (contours.empty()) return; + + size_t count = contours.size(); + cv::Point** pointss = new cv::Point*[count]; + int* npts = new int[count]; + + for (size_t i = 0; i < count; i++) + { + size_t length = contours[i].size(); + npts[i] = length; + pointss[i] = new cv::Point[length]; + for (size_t j = 0; j < length; j++) + pointss[i][j] = contours[i][j]; + } + cv::fillPoly(image, const_cast(pointss), npts, count, color); + + for (size_t i = 0; i < count; i++) + delete[] pointss[i]; + + delete[] pointss; + delete[] npts; + } + + void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) + { + CvMat c_image; + CV_DbgAssert(src.dims <= 2); + c_image = cvMat(src.rows, src.dims == 1 ? 1 : src.cols, src.type(), src.data); + c_image.step = (int)src.step[0]; + c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG); + cv::MemStorage storage(cvCreateMemStorage()); + CvSeq* _ccontours = nullptr; + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint({ offset.x,offset.y })); + + if (!_ccontours) + { + contours.clear(); + return; + } + cv::Seq all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); + size_t total = all_contours.size(); + contours.resize(total); + + cv::SeqIterator it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + reinterpret_cast(c)->color = static_cast(i); + int count = c->total; + int* data = new int[static_cast(count * 2)]; + cvCvtSeqToArray(c, data); + for (int j = 0; j < count; j++) + { + contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); + } + delete[] data; + } + + hierarchy.resize(total); + it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; + int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; + int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; + int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; + hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); + } + + storage.release(); + } + + cv::RotatedRect getBoundingRect(const std::vector& contour) + { + if (contour.empty()) return {}; + + cv::RotatedRect rect = minAreaRect(contour); + if (rect.angle < -45) + { + rect.angle += 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + + if (rect.angle > 45) + { + rect.angle -= 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + + return rect; + } + + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy) + { + std::vector maxContour; + if (contours.size() < 1) return {}; + + for (size_t i = 0, length = hierarchy.size(); i < length; i++) + if (hierarchy[i][3] == -1) + for (const auto &item : contours[i]) + maxContour.push_back(item); + + return maxContour; + } + + std::vector getVertices(const cv::RotatedRect& rect) + { + cv::Point2f box[4]; + rect.points(box); + std::vector points; + for (int i = 0; i < 4; i++) + points.push_back(cv::Point(box[i])); + + return points; + } + + void polyIndent(std::vector& points, const cv::Point& center, int indent) + { + static cv::Point zero(0, 0); + for (cv::Point& item : points) + { +#if 0 + cv::Point vec = item - center; + if (vec != zero) + { + int length = vec.x * vec.x + vec.y * vec.y; + float x = cv::sqrt(static_cast(vec.x * vec.x / length)) * indent; + float y = cv::sqrt(static_cast(vec.y * vec.y / length)) * indent; + + if (vec.x < 0) x *= -1.0f; + if (vec.y < 0) y *= -1.0f; + + item.x -= static_cast(x); + item.y -= static_cast(y); + } +#else + if (item.x > center.x) + item.x -= indent; + else + item.x += indent; + + if (item.y > center.y) + item.y -= indent; + else + item.y += indent; +#endif + } + } + + cv::Mat transforColor(const cv::Mat& src) + { + if (src.channels() == 1) return src.clone(); + + std::vector channels(3); + cv::split(src, channels); + + cv::Mat temp, dst; + bitwise_or(channels[0], channels[1], temp); + bitwise_or(channels[2], temp, dst); + temp.release(); + + for (cv::Mat& index : channels) + index.release(); + return dst; + } + + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) + { + if (src.channels() == 3) + { +#ifdef USE_ONENCL + if (cl_res.context) + transforColor_threshold_opencl(src, dst, static_cast(thre)); + else +#endif + { + cv::Mat gray = transforColor(src); + cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY); + gray.release(); + } + } + else + cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY); + } + + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) + { + double src_data[3] = { static_cast(p.x), static_cast(p.y), 1 }; + cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1 + + cv::Mat dst = warp_mat * src; + double* ptr = reinterpret_cast(dst.data); + return cv::Point(static_cast(ptr[0]), static_cast(ptr[1])); + } + + int distanceP2P(const cv::Point& p1, const cv::Point& p2) + { + return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2)); + } + + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2) + { + //ֱ߷ + int A = 0, B = 0, C = 0; + A = l1.y - l2.y; + B = l2.x - l1.x; + C = l1.x * l2.y - l1.y * l2.x; + //㵽ֱ߾빫ʽ + return ((float)abs(A * p.x + B * p.y + C)) / ((float)sqrtf(A * A + B * B)); + } +} \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/ImageProcess_Public.h b/hgdriver/ImageProcess_test/ImageProcess_Public.h new file mode 100644 index 0000000..b2cfa7d --- /dev/null +++ b/hgdriver/ImageProcess_test/ImageProcess_Public.h @@ -0,0 +1,123 @@ +/* + * ==================================================== + + * ܣͼ㷨ֹܻܿImageProcess෴ʹ + * ߣά + * ʱ䣺2020/4/21 + * ޸ʱ䣺2020/4/21 + * 汾ţv1.0 + + * ==================================================== + */ + +#ifndef IMAGE_PROCESS_PUBLIC_H +#define IMAGE_PROCESS_PUBLIC_H + +#include +#include + +namespace hg +{ + /* + * ܣԴ㼯͹㼯 + * src: Դ㼯 + * dst: Ŀ㼯 + * clockwise: trueΪ˳ʱfalseΪʱ + */ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise = false); + + /* + * ܣ͹ΣĬɫΪɫ + * image: ͼ + * points: ͹㼯ʱ + */ + void fillConvexHull(cv::Mat& image, const std::vector& points); + + /* + * ܣ䰼 + * image: ͼ + * contours: 㼯ʱ + * color: ɫ + */ + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color); + + /* + * ܣȡͨ + * src: Դͼ + * contours: + * hierarchy: ϵcontoursӦretrѡͬб仯 + * retr: ʽĬΪʽ + * method: 㷨ѡĬΪͨ + * offset: ʼ㣬ĬΪ0,0 + */ + 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::RotatedRect getBoundingRect(const std::vector& contour); + + /* + * : ȡС͹ + * contours: ÿɵ㼯ɣ + * hierarchy: У֮ĹϵcontoursӦ + * ֵ: ͹㼯 + */ + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy); + + /* + * : ȡС͹ + * contours: ÿɵ㼯ɣ + * hierarchy: У֮ĹϵcontoursӦ + * ֵ: ͹㼯 + */ + std::vector getVertices(const cv::RotatedRect& rect); + + /* + * : + * points: 㼯 + * center: Χcenter + * indent: + */ + void polyIndent(std::vector& points, const cv::Point& center, int indent); + + /* + * : ֵܹɫͻҶͼsrcΪɫͼʱҶͼȡֵͨ + * src: Դͼ + * dst: Ŀͼ + * thre: ֵ + */ + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre); + + /* + * : ɫתҶȣҶͼȡֵͨ + * src: Դͼ + * ֵ: Ҷͼ + */ + cv::Mat transforColor(const cv::Mat& src); + + /* + * : ȡķ任 + * p: ԭ + * warp_mat: 任ϵ + * ֵ: 任ĵ + */ + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat); + + /* + * : 㵽 + * p1: 1 + * p2: 2 + * ֵ: 㵽 + */ + int distanceP2P(const cv::Point& p1, const cv::Point& p2); + + /* + * : 㵽ֱ߾ + * p: + * l1: ֱ߶˵1 + * l2: ֱ߶˵2 + * ֵ: 㵽ֱ߾ + */ + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2); +} + +#endif // !IMAGE_PROCESS_C_H diff --git a/hgdriver/ImageProcess_test/Makefile b/hgdriver/ImageProcess_test/Makefile new file mode 100644 index 0000000..945e4d2 --- /dev/null +++ b/hgdriver/ImageProcess_test/Makefile @@ -0,0 +1,706 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.13 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/modehua/Desktop/最新版sdk调试/Iibwebscan/ImageProcess + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/modehua/Desktop/最新版sdk调试/Iibwebscan/ImageProcess + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /usr/bin/cmake-gui -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/modehua/Desktop/最新版sdk调试/Iibwebscan/ImageProcess/CMakeFiles /home/modehua/Desktop/最新版sdk调试/Iibwebscan/ImageProcess/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/modehua/Desktop/最新版sdk调试/Iibwebscan/ImageProcess/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named gimgproc + +# Build rule for target. +gimgproc: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 gimgproc +.PHONY : gimgproc + +# fast build rule for target. +gimgproc/fast: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/build +.PHONY : gimgproc/fast + +# target to build an object file +IMulti.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/IMulti.o +.PHONY : IMulti.o + +# target to preprocess a source file +IMulti.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/IMulti.i +.PHONY : IMulti.i + +# target to generate assembly for a file +IMulti.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/IMulti.s +.PHONY : IMulti.s + +# target to build an object file +ImageApply.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApply.o +.PHONY : ImageApply.o + +# target to preprocess a source file +ImageApply.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApply.i +.PHONY : ImageApply.i + +# target to generate assembly for a file +ImageApply.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApply.s +.PHONY : ImageApply.s + +# target to build an object file +ImageApplyAdjustColors.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAdjustColors.o +.PHONY : ImageApplyAdjustColors.o + +# target to preprocess a source file +ImageApplyAdjustColors.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAdjustColors.i +.PHONY : ImageApplyAdjustColors.i + +# target to generate assembly for a file +ImageApplyAdjustColors.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAdjustColors.s +.PHONY : ImageApplyAdjustColors.s + +# target to build an object file +ImageApplyAutoContrast.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoContrast.o +.PHONY : ImageApplyAutoContrast.o + +# target to preprocess a source file +ImageApplyAutoContrast.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoContrast.i +.PHONY : ImageApplyAutoContrast.i + +# target to generate assembly for a file +ImageApplyAutoContrast.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoContrast.s +.PHONY : ImageApplyAutoContrast.s + +# target to build an object file +ImageApplyAutoCrop.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoCrop.o +.PHONY : ImageApplyAutoCrop.o + +# target to preprocess a source file +ImageApplyAutoCrop.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoCrop.i +.PHONY : ImageApplyAutoCrop.i + +# target to generate assembly for a file +ImageApplyAutoCrop.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyAutoCrop.s +.PHONY : ImageApplyAutoCrop.s + +# target to build an object file +ImageApplyBWBinaray.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyBWBinaray.o +.PHONY : ImageApplyBWBinaray.o + +# target to preprocess a source file +ImageApplyBWBinaray.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyBWBinaray.i +.PHONY : ImageApplyBWBinaray.i + +# target to generate assembly for a file +ImageApplyBWBinaray.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyBWBinaray.s +.PHONY : ImageApplyBWBinaray.s + +# target to build an object file +ImageApplyChannel.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyChannel.o +.PHONY : ImageApplyChannel.o + +# target to preprocess a source file +ImageApplyChannel.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyChannel.i +.PHONY : ImageApplyChannel.i + +# target to generate assembly for a file +ImageApplyChannel.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyChannel.s +.PHONY : ImageApplyChannel.s + +# target to build an object file +ImageApplyColorRecognition.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyColorRecognition.o +.PHONY : ImageApplyColorRecognition.o + +# target to preprocess a source file +ImageApplyColorRecognition.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyColorRecognition.i +.PHONY : ImageApplyColorRecognition.i + +# target to generate assembly for a file +ImageApplyColorRecognition.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyColorRecognition.s +.PHONY : ImageApplyColorRecognition.s + +# target to build an object file +ImageApplyConcatenation.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyConcatenation.o +.PHONY : ImageApplyConcatenation.o + +# target to preprocess a source file +ImageApplyConcatenation.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyConcatenation.i +.PHONY : ImageApplyConcatenation.i + +# target to generate assembly for a file +ImageApplyConcatenation.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyConcatenation.s +.PHONY : ImageApplyConcatenation.s + +# target to build an object file +ImageApplyCrop.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCrop.o +.PHONY : ImageApplyCrop.o + +# target to preprocess a source file +ImageApplyCrop.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCrop.i +.PHONY : ImageApplyCrop.i + +# target to generate assembly for a file +ImageApplyCrop.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCrop.s +.PHONY : ImageApplyCrop.s + +# target to build an object file +ImageApplyCustomCrop.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomCrop.o +.PHONY : ImageApplyCustomCrop.o + +# target to preprocess a source file +ImageApplyCustomCrop.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomCrop.i +.PHONY : ImageApplyCustomCrop.i + +# target to generate assembly for a file +ImageApplyCustomCrop.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomCrop.s +.PHONY : ImageApplyCustomCrop.s + +# target to build an object file +ImageApplyCustomGamma.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomGamma.o +.PHONY : ImageApplyCustomGamma.o + +# target to preprocess a source file +ImageApplyCustomGamma.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomGamma.i +.PHONY : ImageApplyCustomGamma.i + +# target to generate assembly for a file +ImageApplyCustomGamma.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCustomGamma.s +.PHONY : ImageApplyCustomGamma.s + +# target to build an object file +ImageApplyCvtColor.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCvtColor.o +.PHONY : ImageApplyCvtColor.o + +# target to preprocess a source file +ImageApplyCvtColor.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCvtColor.i +.PHONY : ImageApplyCvtColor.i + +# target to generate assembly for a file +ImageApplyCvtColor.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyCvtColor.s +.PHONY : ImageApplyCvtColor.s + +# target to build an object file +ImageApplyDetachNoise.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDetachNoise.o +.PHONY : ImageApplyDetachNoise.o + +# target to preprocess a source file +ImageApplyDetachNoise.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDetachNoise.i +.PHONY : ImageApplyDetachNoise.i + +# target to generate assembly for a file +ImageApplyDetachNoise.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDetachNoise.s +.PHONY : ImageApplyDetachNoise.s + +# target to build an object file +ImageApplyDiscardBlank.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDiscardBlank.o +.PHONY : ImageApplyDiscardBlank.o + +# target to preprocess a source file +ImageApplyDiscardBlank.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDiscardBlank.i +.PHONY : ImageApplyDiscardBlank.i + +# target to generate assembly for a file +ImageApplyDiscardBlank.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDiscardBlank.s +.PHONY : ImageApplyDiscardBlank.s + +# target to build an object file +ImageApplyDogEarDetection.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDogEarDetection.o +.PHONY : ImageApplyDogEarDetection.o + +# target to preprocess a source file +ImageApplyDogEarDetection.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDogEarDetection.i +.PHONY : ImageApplyDogEarDetection.i + +# target to generate assembly for a file +ImageApplyDogEarDetection.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyDogEarDetection.s +.PHONY : ImageApplyDogEarDetection.s + +# target to build an object file +ImageApplyFadeBackGroundColor.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFadeBackGroundColor.o +.PHONY : ImageApplyFadeBackGroundColor.o + +# target to preprocess a source file +ImageApplyFadeBackGroundColor.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFadeBackGroundColor.i +.PHONY : ImageApplyFadeBackGroundColor.i + +# target to generate assembly for a file +ImageApplyFadeBackGroundColor.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFadeBackGroundColor.s +.PHONY : ImageApplyFadeBackGroundColor.s + +# target to build an object file +ImageApplyFilter.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFilter.o +.PHONY : ImageApplyFilter.o + +# target to preprocess a source file +ImageApplyFilter.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFilter.i +.PHONY : ImageApplyFilter.i + +# target to generate assembly for a file +ImageApplyFilter.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyFilter.s +.PHONY : ImageApplyFilter.s + +# target to build an object file +ImageApplyHSVCorrect.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyHSVCorrect.o +.PHONY : ImageApplyHSVCorrect.o + +# target to preprocess a source file +ImageApplyHSVCorrect.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyHSVCorrect.i +.PHONY : ImageApplyHSVCorrect.i + +# target to generate assembly for a file +ImageApplyHSVCorrect.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyHSVCorrect.s +.PHONY : ImageApplyHSVCorrect.s + +# target to build an object file +ImageApplyOutHole.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyOutHole.o +.PHONY : ImageApplyOutHole.o + +# target to preprocess a source file +ImageApplyOutHole.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyOutHole.i +.PHONY : ImageApplyOutHole.i + +# target to generate assembly for a file +ImageApplyOutHole.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyOutHole.s +.PHONY : ImageApplyOutHole.s + +# target to build an object file +ImageApplyRefuseInflow.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRefuseInflow.o +.PHONY : ImageApplyRefuseInflow.o + +# target to preprocess a source file +ImageApplyRefuseInflow.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRefuseInflow.i +.PHONY : ImageApplyRefuseInflow.i + +# target to generate assembly for a file +ImageApplyRefuseInflow.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRefuseInflow.s +.PHONY : ImageApplyRefuseInflow.s + +# target to build an object file +ImageApplyResize.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyResize.o +.PHONY : ImageApplyResize.o + +# target to preprocess a source file +ImageApplyResize.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyResize.i +.PHONY : ImageApplyResize.i + +# target to generate assembly for a file +ImageApplyResize.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyResize.s +.PHONY : ImageApplyResize.s + +# target to build an object file +ImageApplyRotation.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRotation.o +.PHONY : ImageApplyRotation.o + +# target to preprocess a source file +ImageApplyRotation.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRotation.i +.PHONY : ImageApplyRotation.i + +# target to generate assembly for a file +ImageApplyRotation.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyRotation.s +.PHONY : ImageApplyRotation.s + +# target to build an object file +ImageApplySharpen.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySharpen.o +.PHONY : ImageApplySharpen.o + +# target to preprocess a source file +ImageApplySharpen.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySharpen.i +.PHONY : ImageApplySharpen.i + +# target to generate assembly for a file +ImageApplySharpen.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySharpen.s +.PHONY : ImageApplySharpen.s + +# target to build an object file +ImageApplySplit.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySplit.o +.PHONY : ImageApplySplit.o + +# target to preprocess a source file +ImageApplySplit.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySplit.i +.PHONY : ImageApplySplit.i + +# target to generate assembly for a file +ImageApplySplit.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplySplit.s +.PHONY : ImageApplySplit.s + +# target to build an object file +ImageApplyTextureRemoval.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyTextureRemoval.o +.PHONY : ImageApplyTextureRemoval.o + +# target to preprocess a source file +ImageApplyTextureRemoval.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyTextureRemoval.i +.PHONY : ImageApplyTextureRemoval.i + +# target to generate assembly for a file +ImageApplyTextureRemoval.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyTextureRemoval.s +.PHONY : ImageApplyTextureRemoval.s + +# target to build an object file +ImageApplyUV.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyUV.o +.PHONY : ImageApplyUV.o + +# target to preprocess a source file +ImageApplyUV.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyUV.i +.PHONY : ImageApplyUV.i + +# target to generate assembly for a file +ImageApplyUV.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageApplyUV.s +.PHONY : ImageApplyUV.s + +# target to build an object file +ImageMulti.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMulti.o +.PHONY : ImageMulti.o + +# target to preprocess a source file +ImageMulti.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMulti.i +.PHONY : ImageMulti.i + +# target to generate assembly for a file +ImageMulti.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMulti.s +.PHONY : ImageMulti.s + +# target to build an object file +ImageMultiOutputRed.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMultiOutputRed.o +.PHONY : ImageMultiOutputRed.o + +# target to preprocess a source file +ImageMultiOutputRed.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMultiOutputRed.i +.PHONY : ImageMultiOutputRed.i + +# target to generate assembly for a file +ImageMultiOutputRed.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageMultiOutputRed.s +.PHONY : ImageMultiOutputRed.s + +# target to build an object file +ImageProcess_Public.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageProcess_Public.o +.PHONY : ImageProcess_Public.o + +# target to preprocess a source file +ImageProcess_Public.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageProcess_Public.i +.PHONY : ImageProcess_Public.i + +# target to generate assembly for a file +ImageProcess_Public.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/ImageProcess_Public.s +.PHONY : ImageProcess_Public.s + +# target to build an object file +hg_ocr.o: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/hg_ocr.o +.PHONY : hg_ocr.o + +# target to preprocess a source file +hg_ocr.i: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/hg_ocr.i +.PHONY : hg_ocr.i + +# target to generate assembly for a file +hg_ocr.s: + $(MAKE) -f CMakeFiles/gimgproc.dir/build.make CMakeFiles/gimgproc.dir/hg_ocr.s +.PHONY : hg_ocr.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... rebuild_cache" + @echo "... gimgproc" + @echo "... edit_cache" + @echo "... IMulti.o" + @echo "... IMulti.i" + @echo "... IMulti.s" + @echo "... ImageApply.o" + @echo "... ImageApply.i" + @echo "... ImageApply.s" + @echo "... ImageApplyAdjustColors.o" + @echo "... ImageApplyAdjustColors.i" + @echo "... ImageApplyAdjustColors.s" + @echo "... ImageApplyAutoContrast.o" + @echo "... ImageApplyAutoContrast.i" + @echo "... ImageApplyAutoContrast.s" + @echo "... ImageApplyAutoCrop.o" + @echo "... ImageApplyAutoCrop.i" + @echo "... ImageApplyAutoCrop.s" + @echo "... ImageApplyBWBinaray.o" + @echo "... ImageApplyBWBinaray.i" + @echo "... ImageApplyBWBinaray.s" + @echo "... ImageApplyChannel.o" + @echo "... ImageApplyChannel.i" + @echo "... ImageApplyChannel.s" + @echo "... ImageApplyColorRecognition.o" + @echo "... ImageApplyColorRecognition.i" + @echo "... ImageApplyColorRecognition.s" + @echo "... ImageApplyConcatenation.o" + @echo "... ImageApplyConcatenation.i" + @echo "... ImageApplyConcatenation.s" + @echo "... ImageApplyCrop.o" + @echo "... ImageApplyCrop.i" + @echo "... ImageApplyCrop.s" + @echo "... ImageApplyCustomCrop.o" + @echo "... ImageApplyCustomCrop.i" + @echo "... ImageApplyCustomCrop.s" + @echo "... ImageApplyCustomGamma.o" + @echo "... ImageApplyCustomGamma.i" + @echo "... ImageApplyCustomGamma.s" + @echo "... ImageApplyCvtColor.o" + @echo "... ImageApplyCvtColor.i" + @echo "... ImageApplyCvtColor.s" + @echo "... ImageApplyDetachNoise.o" + @echo "... ImageApplyDetachNoise.i" + @echo "... ImageApplyDetachNoise.s" + @echo "... ImageApplyDiscardBlank.o" + @echo "... ImageApplyDiscardBlank.i" + @echo "... ImageApplyDiscardBlank.s" + @echo "... ImageApplyDogEarDetection.o" + @echo "... ImageApplyDogEarDetection.i" + @echo "... ImageApplyDogEarDetection.s" + @echo "... ImageApplyFadeBackGroundColor.o" + @echo "... ImageApplyFadeBackGroundColor.i" + @echo "... ImageApplyFadeBackGroundColor.s" + @echo "... ImageApplyFilter.o" + @echo "... ImageApplyFilter.i" + @echo "... ImageApplyFilter.s" + @echo "... ImageApplyHSVCorrect.o" + @echo "... ImageApplyHSVCorrect.i" + @echo "... ImageApplyHSVCorrect.s" + @echo "... ImageApplyOutHole.o" + @echo "... ImageApplyOutHole.i" + @echo "... ImageApplyOutHole.s" + @echo "... ImageApplyRefuseInflow.o" + @echo "... ImageApplyRefuseInflow.i" + @echo "... ImageApplyRefuseInflow.s" + @echo "... ImageApplyResize.o" + @echo "... ImageApplyResize.i" + @echo "... ImageApplyResize.s" + @echo "... ImageApplyRotation.o" + @echo "... ImageApplyRotation.i" + @echo "... ImageApplyRotation.s" + @echo "... ImageApplySharpen.o" + @echo "... ImageApplySharpen.i" + @echo "... ImageApplySharpen.s" + @echo "... ImageApplySplit.o" + @echo "... ImageApplySplit.i" + @echo "... ImageApplySplit.s" + @echo "... ImageApplyTextureRemoval.o" + @echo "... ImageApplyTextureRemoval.i" + @echo "... ImageApplyTextureRemoval.s" + @echo "... ImageApplyUV.o" + @echo "... ImageApplyUV.i" + @echo "... ImageApplyUV.s" + @echo "... ImageMulti.o" + @echo "... ImageMulti.i" + @echo "... ImageMulti.s" + @echo "... ImageMultiOutputRed.o" + @echo "... ImageMultiOutputRed.i" + @echo "... ImageMultiOutputRed.s" + @echo "... ImageProcess_Public.o" + @echo "... ImageProcess_Public.i" + @echo "... ImageProcess_Public.s" + @echo "... hg_ocr.o" + @echo "... hg_ocr.i" + @echo "... hg_ocr.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/hgdriver/ImageProcess_test/MatEx.h b/hgdriver/ImageProcess_test/MatEx.h new file mode 100644 index 0000000..ab0c469 --- /dev/null +++ b/hgdriver/ImageProcess_test/MatEx.h @@ -0,0 +1,22 @@ +#pragma once +#include + +class MatEx { +public: + MatEx() : + mat(cv::Mat()) + , Bpp(-1) { + + }; + + MatEx(cv::Mat &mat, int bpp) : + mat(cv::Mat()) + , Bpp(bpp) + { + this->mat = mat; + this->Bpp = bpp; + } +public: + int Bpp; + cv::Mat mat; +}; \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/hg_ocr.cpp b/hgdriver/ImageProcess_test/hg_ocr.cpp new file mode 100644 index 0000000..5c60f2f --- /dev/null +++ b/hgdriver/ImageProcess_test/hg_ocr.cpp @@ -0,0 +1,513 @@ +#ifdef WIN32 +#include "hg_ocr.h" +#include "allheaders.h" +#include "baseapi.h" +#include "basedir.h" +#include "osdetect.h" +#include "renderer.h" +#include "strngs.h" +#include "tprintf.h" +#include "resultiterator.h" +#include + +static unsigned char string_CIDTOGIDMAP[] = { + 120,156,236,194,1,9,0,0,0,2,160,250,127,186,33,137, + 166,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,128,123,3,0,0,255,255,236,194,1,13,0,0, + 0,194,32,223,191,180,69,24,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,235,0,0,0,255, + 255,236,194,1,13,0,0,0,194,32,223,191,180,69,24,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,235,0,0,0,255,255,237,194,1,13,0,0,0,194,32, + 223,191,180,69,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,235,0,255,0,16}; + +static unsigned char string_TTF[] = { + 0,1,0,0,0,10,0,128,0,3,0,32,79,83,47,50,86,221,200,148, + 0,0,1,40,0,0,0,96,99,109,97,112,0,18,0,78,0,0,1,144,0,0, + 0,44,103,108,121,102,0,0,0,0,0,0,1,196,0,0,0,1,104,101, + 97,100,2,80,182,226,0,0,0,172,0,0,0,54,104,104,101,97,0, + 3,0,2,0,0,0,228,0,0,0,36,104,109,116,120,0,0,0,0,0,0,1, + 136,0,0,0,8,108,111,99,97,0,0,0,0,0,0,1,188,0,0,0,6,109, + 97,120,112,0,3,0,1,0,0,1,8,0,0,0,32,110,97,109,101,165, + 232,245,73,0,0,1,200,0,0,0,80,112,111,115,116,0,1,0,1,0, + 0,2,24,0,0,0,32,0,1,0,0,0,1,0,0,167,55,179,76,95,15,60,245, + 4,7,1,0,0,0,0,0,207,154,252,110,0,0,0,0,207,154,252,110,0, + 0,128,0,0,0,0,1,0,0,0,16,0,2,0,0,0,0,0,0,0,1,0,0,0,1,255, + 255,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,3,0,0,1,144,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,5,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,71,79,79,71,0,64,255,255,0,0,0,1,255,255,0,0,0,1, + 0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, + 0,0,0,2,0,1,0,0,0,0,0,20,0,3,0,0,0,0,0,32,0,6,0,12,0,0,0,0, + 0,1,0,0,0,6,0,12,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3,0,42,0,0,0,3,0,0,0,5,0,22,0,11,0,1,0,0,0,0,0,5,0,11,0, + 0,0,3,0,1,4,9,0,5,0,22,0,11,86,101,114,115,105,111,110,32, + 49,46,48,0,86,0,101,0,114,0,115,0,105,0,111,0,110,0,32,0,49, + 0,46,0,48,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0}; + +static const char* endstream = "endstream\nendobj\n"; + +Pix* createPix(const unsigned char * imgData, int width, int height, int bytes_per_pixel, int bytes_per_line); + +void PreloadRenderers(tesseract::TessBaseAPI* api, + tesseract::PointerVector* renderers, const char* outputbase); + +char* GetPDFTextObjectss(tesseract::TessBaseAPI* api, double width, double height, int& len); + +HG_OCR::HG_OCR() + : api(new tesseract::TessBaseAPI()) +{ + +} + +HG_OCR::HG_OCR(PSM_TYPE type) + : api(new tesseract::TessBaseAPI()) +{ + init_orientation("./tessdata/osd.traineddata"); +} + +HG_OCR::~HG_OCR() +{ + if (api != nullptr) + delete reinterpret_cast(api); +} + +void HG_OCR::init(HG_OCR::PSM_TYPE type) +{ + init_orientation("./tessdata/osd.traineddata"); +} + +void HG_OCR::init(const char * filename, PSM_TYPE type) +{ + switch (type) + { + case Orientation: + init_orientation(filename); + break; + } +} + +int HG_OCR::getOrientation(unsigned char *imgData, int width, int height, int channels, int step) +{ + int orientation, direction, lineOrder; + float deskewAngle; + getOrientation(imgData, width, height, channels, step, + orientation, direction, lineOrder, deskewAngle); + + return orientation; +} + +bool HG_OCR::getOrientation(unsigned char* imgData, int width, int height, int channels, int step, + int& orientation, int& direction, int& lineOrder, float& deskewAngle) +{ + if (api == nullptr) return false; + + tesseract::TessBaseAPI* ptr = reinterpret_cast(api); + ptr->SetImage(imgData, width, height, channels, step); + +#if 0 + tesseract::PageIterator* it = ptr->AnalyseLayout(); + + if (it != nullptr) + { + it->Orientation(reinterpret_cast(&orientation), + reinterpret_cast(&direction), + reinterpret_cast(&lineOrder), + &deskewAngle); + delete it; + return true; + } + else + return false; +#endif + orientation = ptr->AnalyseLayout1(); +} + +void HG_OCR::init_orientation(const char *filename) +{ + auto ret= reinterpret_cast(api)->Init(filename, "osd"); + reinterpret_cast(api)->SetPageSegMode(tesseract::PSM_AUTO_OSD); +} + +void PreloadRenderers(tesseract::TessBaseAPI* api, + tesseract::PointerVector* renderers, + const char* outputbase) +{ + bool b; + api->GetBoolVariable("tessedit_create_pdf", &b); + + if (b) + { + bool textonly; + api->GetBoolVariable("textonly_pdf", &textonly); + printf("GetDatapath%s\n", api->GetDatapath()); + renderers->push_back(new tesseract::TessPDFRenderer(outputbase, api->GetDatapath(), textonly)); + } +} + +Pix* createPix(const unsigned char * imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line) +{ + int bpp = bytes_per_pixel * 8; + if (bpp == 0) bpp = 1; + Pix* pix = pixCreate(width, height, bpp == 24 ? 32 : bpp); + l_uint32* data = pixGetData(pix); + int wpl = pixGetWpl(pix); + switch (bpp) { + case 1: + for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) + { + for (int x = 0; x < width; ++x) { + if (imagedata[x / 8] & (0x80 >> (x % 8))) + CLEAR_DATA_BIT(data, x); + else + SET_DATA_BIT(data, x); + } + } + break; + + case 8: + // Greyscale just copies the bytes in the right order. + for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) + for (int x = 0; x < width; ++x) + SET_DATA_BYTE(data, x, imagedata[x]); + break; + + case 24: + // Put the colors in the correct places in the line buffer. + for (int y = 0; y < height; ++y, imagedata += bytes_per_line) + { + for (int x = 0; x < width; ++x, ++data) { + SET_DATA_BYTE(data, COLOR_RED, imagedata[3 * x]); + SET_DATA_BYTE(data, COLOR_GREEN, imagedata[3 * x + 1]); + SET_DATA_BYTE(data, COLOR_BLUE, imagedata[3 * x + 2]); + } + } + break; + + case 32: + // Maintain byte order consistency across different endianness. + for (int y = 0; y < height; ++y, imagedata += bytes_per_line, data += wpl) + for (int x = 0; x < width; ++x) + data[x] = (imagedata[x * 4] << 24) | (imagedata[x * 4 + 1] << 16) | + (imagedata[x * 4 + 2] << 8) | imagedata[x * 4 + 3]; + break; + + default: + break; + } + + pix->informat = bytes_per_pixel == 1 ? 1 : 2; + if (bytes_per_pixel == 1) + { + PIXCMAP* colormap = pixcmapCreate(8); + LEPT_FREE(colormap->array); + colormap->array = (l_uint8 *)LEPT_CALLOC(256, sizeof(RGBA_QUAD)); + colormap->n = 256; + colormap->nalloc = 256; + colormap->depth = 8; + l_uint8* ptr = reinterpret_cast(colormap->array); + for (int i = 0; i < 256; i++) + ptr[i * 4 + 0] = ptr[i * 4 + 1] = ptr[i * 4 + 2] = ptr[i * 4 + 3] = i; + pixSetColormap(pix, colormap); + } + pixSetXRes(pix, 200); + pixSetYRes(pix, 200); + + //FILE* file = fopenWriteStream("aaa.bmp", "w"); + //pixWriteStreamBmp(file, pix); + //fclose(file); + return pix; +} + +double prec(double x) { + double kPrecision = 1000.0; + double a = round(x * kPrecision) / kPrecision; + if (a == -0) + return 0; + return a; +} + +void ClipBaseline(int ppi, int x1, int y1, int x2, int y2, + int *line_x1, int *line_y1, + int *line_x2, int *line_y2) +{ + *line_x1 = x1; + *line_y1 = y1; + *line_x2 = x2; + *line_y2 = y2; + double rise = abs(y2 - y1) * 72 / ppi; + double run = abs(x2 - x1) * 72 / ppi; + if (rise < 2.0 && 2.0 < run) + *line_y1 = *line_y2 = (y1 + y2) / 2; +} + +long dist2(int x1, int y1, int x2, int y2) +{ + return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); +} + +void GetWordBaseline(int writing_direction, int ppi, int height, + int word_x1, int word_y1, int word_x2, int word_y2, + int line_x1, int line_y1, int line_x2, int line_y2, + double *x0, double *y0, double *length) +{ + if (writing_direction == tesseract::WRITING_DIRECTION_RIGHT_TO_LEFT) + { + Swap(&word_x1, &word_x2); + Swap(&word_y1, &word_y2); + } + double word_length; + double x, y; + { + int px = word_x1; + int py = word_y1; + double l2 = dist2(line_x1, line_y1, line_x2, line_y2); + if (l2 == 0) { + x = line_x1; + y = line_y1; + } + else { + double t = ((px - line_x2) * (line_x2 - line_x1) + + (py - line_y2) * (line_y2 - line_y1)) / l2; + x = line_x2 + t * (line_x2 - line_x1); + y = line_y2 + t * (line_y2 - line_y1); + } + word_length = sqrt(static_cast(dist2(word_x1, word_y1, + word_x2, word_y2))); + word_length = word_length * 72.0 / ppi; + x = x * 72 / ppi; + y = height - (y * 72.0 / ppi); + } + *x0 = x; + *y0 = y; + *length = word_length; +} + +void AffineMatrix(int writing_direction, + int line_x1, int line_y1, int line_x2, int line_y2, + double *a, double *b, double *c, double *d) +{ + double theta = atan2(static_cast(line_y1 - line_y2), + static_cast(line_x2 - line_x1)); + *a = cos(theta); + *b = sin(theta); + *c = -sin(theta); + *d = cos(theta); + switch (writing_direction) { + case tesseract::WRITING_DIRECTION_RIGHT_TO_LEFT: + *a = -*a; + *b = -*b; + break; + case tesseract::WRITING_DIRECTION_TOP_TO_BOTTOM: + // TODO(jbreiden) Consider using the vertical PDF writing mode. + break; + default: + break; + } +} + +bool CodepointToUtf16be(int code, char utf16[20]) +{ + if ((code > 0xD7FF && code < 0xE000) || code > 0x10FFFF) { + tprintf("Dropping invalid codepoint %d\n", code); + return false; + } + if (code < 0x10000) { + snprintf(utf16, 20, "%04X", code); + } + else { + int a = code - 0x010000; + int high_surrogate = (0x03FF & (a >> 10)) + 0xD800; + int low_surrogate = (0x03FF & a) + 0xDC00; + snprintf(utf16, 20, "%04X%04X", high_surrogate, low_surrogate); + } + return true; +} + +char* GetPDFTextObjectss(tesseract::TessBaseAPI* api, double width, double height, int& len) +{ + STRING pdf_str(""); + double ppi = api->GetSourceYResolution(); + + // These initial conditions are all arbitrary and will be overwritten + double old_x = 0.0, old_y = 0.0; + int old_fontsize = 0; + tesseract::WritingDirection old_writing_direction = tesseract::WRITING_DIRECTION_LEFT_TO_RIGHT; + bool new_block = true; + int fontsize = 0; + double a = 1; + double b = 0; + double c = 0; + double d = 1; + + // TODO(jbreiden) This marries the text and image together. + // Slightly cleaner from an abstraction standpoint if this were to + // live inside a separate text object. + pdf_str += "q "; + pdf_str.add_str_double("", prec(width)); + pdf_str += " 0 0 "; + pdf_str.add_str_double("", prec(height)); + pdf_str += " 0 0 cm"; + if (true) { + pdf_str += " /Im1 Do"; + } + pdf_str += " Q\n"; + + int line_x1 = 0; + int line_y1 = 0; + int line_x2 = 0; + int line_y2 = 0; + + tesseract::ResultIterator *res_it = api->GetIterator(); + while (!res_it->Empty(tesseract::RIL_BLOCK)) + { + if (res_it->IsAtBeginningOf(tesseract::RIL_BLOCK)) + { + pdf_str += "BT\n3 Tr"; // Begin text object, use invisible ink + old_fontsize = 0; // Every block will declare its fontsize + new_block = true; // Every block will declare its affine matrix + } + + if (res_it->IsAtBeginningOf(tesseract::RIL_TEXTLINE)) + { + int x1, y1, x2, y2; + res_it->Baseline(tesseract::RIL_TEXTLINE, &x1, &y1, &x2, &y2); + ClipBaseline(ppi, x1, y1, x2, y2, &line_x1, &line_y1, &line_x2, &line_y2); + } + + if (res_it->Empty(tesseract::RIL_WORD)) + { + res_it->Next(tesseract::RIL_WORD); + continue; + } + + // Writing direction changes at a per-word granularity + tesseract::WritingDirection writing_direction; + { + tesseract::Orientation orientation; + tesseract::TextlineOrder textline_order; + float deskew_angle; + res_it->Orientation(&orientation, &writing_direction, + &textline_order, &deskew_angle); + if (writing_direction != tesseract::WRITING_DIRECTION_TOP_TO_BOTTOM) + { + switch (res_it->WordDirection()) { + case DIR_LEFT_TO_RIGHT: + writing_direction = tesseract::WRITING_DIRECTION_LEFT_TO_RIGHT; + break; + case DIR_RIGHT_TO_LEFT: + writing_direction = tesseract::WRITING_DIRECTION_RIGHT_TO_LEFT; + break; + default: + writing_direction = old_writing_direction; + } + } + } + + // Where is word origin and how long is it? + double x, y, word_length; + { + int word_x1, word_y1, word_x2, word_y2; + res_it->Baseline(tesseract::RIL_WORD, &word_x1, &word_y1, &word_x2, &word_y2); + GetWordBaseline(writing_direction, ppi, height, + word_x1, word_y1, word_x2, word_y2, + line_x1, line_y1, line_x2, line_y2, + &x, &y, &word_length); + } + + if (writing_direction != old_writing_direction || new_block) + { + AffineMatrix(writing_direction, + line_x1, line_y1, line_x2, line_y2, &a, &b, &c, &d); + pdf_str.add_str_double(" ", prec(a)); // . This affine matrix + pdf_str.add_str_double(" ", prec(b)); // . sets the coordinate + pdf_str.add_str_double(" ", prec(c)); // . system for all + pdf_str.add_str_double(" ", prec(d)); // . text that follows. + pdf_str.add_str_double(" ", prec(x)); // . + pdf_str.add_str_double(" ", prec(y)); // . + pdf_str += (" Tm "); // Place cursor absolutely + new_block = false; + } + else + { + double dx = x - old_x; + double dy = y - old_y; + pdf_str.add_str_double(" ", prec(dx * a + dy * b)); + pdf_str.add_str_double(" ", prec(dx * c + dy * d)); + pdf_str += (" Td "); // Relative moveto + } + old_x = x; + old_y = y; + old_writing_direction = writing_direction; + + // Adjust font size on a per word granularity. Pay attention to + // fontsize, old_fontsize, and pdf_str. We've found that for + // in Arabic, Tesseract will happily return a fontsize of zero, + // so we make up a default number to protect ourselves. + { + bool bold, italic, underlined, monospace, serif, smallcaps; + int font_id; + res_it->WordFontAttributes(&bold, &italic, &underlined, &monospace, + &serif, &smallcaps, &fontsize, &font_id); + const int kDefaultFontsize = 8; + if (fontsize <= 0) + fontsize = kDefaultFontsize; + if (fontsize != old_fontsize) + { + char textfont[20]; + snprintf(textfont, sizeof(textfont), "/f-0-0 %d Tf ", fontsize); + pdf_str += textfont; + old_fontsize = fontsize; + } + } + + bool last_word_in_line = res_it->IsAtFinalElement(tesseract::RIL_TEXTLINE, tesseract::RIL_WORD); + bool last_word_in_block = res_it->IsAtFinalElement(tesseract::RIL_BLOCK, tesseract::RIL_WORD); + STRING pdf_word(""); + int pdf_word_len = 0; + do { + const char *grapheme = res_it->GetUTF8Text(tesseract::RIL_SYMBOL); + if (grapheme && grapheme[0] != '\0') { + GenericVector unicodes; + UNICHAR::UTF8ToUnicode(grapheme, &unicodes); + char utf16[20]; + for (int i = 0; i < unicodes.length(); i++) + { + int code = unicodes[i]; + if (CodepointToUtf16be(code, utf16)) + { + pdf_word += utf16; + pdf_word_len++; + } + } + } + delete[]grapheme; + res_it->Next(tesseract::RIL_SYMBOL); + } + while (!res_it->Empty(tesseract::RIL_BLOCK) && !res_it->IsAtBeginningOf(tesseract::RIL_WORD)); + if (word_length > 0 && pdf_word_len > 0 && fontsize > 0) + { + double h_stretch = 2 * prec(100.0 * word_length / (fontsize * pdf_word_len)); + pdf_str.add_str_double("", h_stretch); + pdf_str += " Tz"; // horizontal stretch + pdf_str += " [ <"; + pdf_str += pdf_word; // UTF-16BE representation + pdf_str += "> ] TJ"; // show the text + } + if (last_word_in_line) { + pdf_str += " \n"; + } + if (last_word_in_block) { + pdf_str += "ET\n"; // end the text object + } + } + char *ret = new char[pdf_str.length() + 1]; + strcpy(ret, pdf_str.string()); + delete res_it; + len = pdf_str.length(); + return ret; +} +#endif \ No newline at end of file diff --git a/hgdriver/ImageProcess_test/hg_ocr.h b/hgdriver/ImageProcess_test/hg_ocr.h new file mode 100644 index 0000000..b9660b2 --- /dev/null +++ b/hgdriver/ImageProcess_test/hg_ocr.h @@ -0,0 +1,43 @@ +#ifndef HG_OCR_H +#define HG_OCR_H + +class HG_OCR +{ +public: + + enum PSM_TYPE + { + Orientation, + OCR + }; + + enum SAVE_MODE + { + PDF = 0x1, + TXT = 0x2 + }; + +public: + HG_OCR(); + + HG_OCR(PSM_TYPE type); + + ~HG_OCR(); + + void init(PSM_TYPE type); + + void init(const char* filename, PSM_TYPE type); + + int getOrientation(unsigned char* imgData, int width, int height, int channels, int step); + + bool getOrientation(unsigned char* imgData, int width, int height, int channels, int step, + int& orientation, int& direction, int& lineOrder, float& deskewAngle); +private: + + void init_orientation(const char *filename); + +private: + void* api; +}; + +#endif // HG_OCR_H diff --git a/hgdriver/ImageProcess_test/imgprocdefs.h b/hgdriver/ImageProcess_test/imgprocdefs.h new file mode 100644 index 0000000..ba5fea9 --- /dev/null +++ b/hgdriver/ImageProcess_test/imgprocdefs.h @@ -0,0 +1,22 @@ +#ifndef IMAGE_PROCESS_DEFINES_H +#define IMAGE_PROCESS_DEFINES_H + +//#if defined(_MSC_VER) +//# define HT_DECL_EXPORT __declspec(dllexport) +//# define HT_DECL_IMPORT __declspec(dllimport) +//#elif defined(__linux__) || defined(__linux) +//# define HT_DECL_EXPORT __attribute__((visibility("default"))) +//# define HT_DECL_IMPORT __attribute__((visibility("default"))) +//# define HT_DECL_HIDDEN __attribute__((visibility("hidden"))) +//#endif +// +//#if defined(GIMGPROC_LIBRARY_BUILD) +//#define HT_DECL_EXPORT +//#elif defined(_DIRECT_BUILD) +//#define +//#else +////#define HT_DECL_IMPORT +//#endif +#define IMAGE_PROCESS_DEFINES_H + +#endif // !IMAGE_PROCESS_DEFINES_H diff --git a/hgdriver/hgdev/CMakeLists.txt b/hgdriver/hgdev/CMakeLists.txt index 76c0213..f181f24 100644 --- a/hgdriver/hgdev/CMakeLists.txt +++ b/hgdriver/hgdev/CMakeLists.txt @@ -1,7 +1,7 @@ project(gdev) add_compile_options(-std=c++11) add_definitions(-DOEM_HUAGAO) -add_definitions(-DKYLIN) +add_definitions(-DUOS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS) diff --git a/hgdriver/hgdev/hg_scanner_439.cpp b/hgdriver/hgdev/hg_scanner_439.cpp new file mode 100644 index 0000000..cff3ef0 --- /dev/null +++ b/hgdriver/hgdev/hg_scanner_439.cpp @@ -0,0 +1,1898 @@ +#include "hg_scanner_439.h" +#include "../wrapper/hg_log.h" +#include "filetools.h" + +#ifdef WIN32 +#include "scanner_manager.h" +#endif + +#include + +//#define SAVE_TO_FILE + +#define USB_REQ_GET_FPGA_REGS 0x40 +#define USB_REQ_SET_FPGA_REGS 0x41 +#define USB_REQ_GET_MOTOR_REGS 0x42 +#define USB_REQ_SET_MOTOR_REGS 0x43 + +#define USB_REQ_GET_DEV_STATUS 0x60 +#define USB_REQ_GET_DEV_CONFIGURATION 0x61 +#define USB_REQ_SET_DEV_CONFIGURATION 0x62 +#define USB_REQ_GET_DEV_REGS 0x63 +#define USB_REQ_SET_DEV_REGS 0x64 +#ifdef OEM_LISICHENG +static std::string jsontext("{{\"device_type\":\"G239-lsc\",\"option_count\":61,\"1\":{\"category\":\"base\",\"name\":\"cfg-1\",\"title\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"desc\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"type\":\"button\",\"cur\":\"button\",\"default\":\"button\",\"size\":0},\"2\":{\"category\":\"advanced\",\"name\":\"cfg-2\",\"title\":\"\\u5e2e\\u52a9\",\"desc\":\"\\u663e\\u793a\\u8f6f\\u4ef6\\u5e2e\\u52a9\\u6587\\u6863\",\"type\":\"button\",\"cur\":\"true\",\"default\":\"true\",\"size\":4},\"3\":{\"category\":\"base\",\"name\":\"grp-1\",\"title\":\"\\u57fa\\u672c\\u8bbe\\u7f6e\",\"type\":\"group\"},\"4\":{\"category\":\"base\",\"name\":\"cfg-4\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"5\":{\"category\":\"base\",\"name\":\"cfg-5\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\\u7c7b\\u578b\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":32,\"range\":[\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"\\u5f69\\u8272+\\u7070\\u5ea6\",\"\\u5f69\\u8272+\\u9ed1\\u767d\",\"\\u7070\\u5ea6+\\u9ed1\\u767d\"],\"depend_or\":[\"4==true\"]},\"6\":{\"category\":\"base\",\"name\":\"mode\",\"title\":\"\\u989c\\u8272\\u6a21\\u5f0f\",\"desc\":\"\\u8bbe\\u7f6e\\u989c\\u8272\\u4f4d\\u6df1\",\"type\":\"string\",\"cur\":\"24\\u4f4d\\u5f69\\u8272\",\"default\":\"24\\u4f4d\\u5f69\\u8272\",\"size\":32,\"range\":[\"24\\u4f4d\\u5f69\\u8272\",\"256\\u7ea7\\u7070\\u5ea6\",\"\\u9ed1\\u767d\",\"\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"],\"depend_or\":[\"4!=true\"]},\"7\":{\"category\":\"base\",\"name\":\"cfg-7\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u9608\\u503c\",\"desc\":\"\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":0,\"max\":255},\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"8\":{\"category\":\"base\",\"name\":\"cfg-8\",\"title\":\"\\u7070\\u5ea6\\u6216\\u9ed1\\u767d\\u56fe\\u50cf - \\u9664\\u8272\",\"desc\":\"\\u9664\\u53bb\\u56fe\\u50cf\\u5f69\\u8272\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u9664\\u8272\",\"default\":\"\\u4e0d\\u9664\\u8272\",\"size\":24,\"range\":[\"\\u4e0d\\u9664\\u8272\",\"\\u9664\\u7ea2\\u8272\",\"\\u9664\\u7eff\\u8272\",\"\\u9664\\u84dd\\u8272\",\"\\u7ea2\\u8272\\u589e\\u5f3a\",\"\\u7eff\\u8272\\u589e\\u5f3a\",\"\\u84dd\\u8272\\u589e\\u5f3a\"],\"depend_and\":[\"4!=true\",\"6!=24\\u4f4d\\u5f69\\u8272\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"9\":{\"category\":\"base\",\"name\":\"cfg-9\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u591a\\u6d41\\u8f93\\u51fa\\u9664\\u7ea2\",\"desc\":\"\\u591a\\u901a\\u9053\\u8f93\\u51fa\\u4e2d\\uff0c\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"10\":{\"category\":\"base\",\"name\":\"cfg-10\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u7b54\\u9898\\u5361\\u9664\\u7ea2\",\"desc\":\"\\u7b54\\u9898\\u5361\\u626b\\u63cf\\u4e2d\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"11\":{\"category\":\"base\",\"name\":\"cfg-11\",\"title\":\"\\u80cc\\u666f\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u5f69\\u8272\\u56fe\\u50cf\\u80cc\\u666f\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"12\":{\"category\":\"base\",\"name\":\"cfg-12\",\"title\":\" \\u80cc\\u666f\\u8272\\u5f69\\u6d6e\\u52a8\\u8303\\u56f4\",\"desc\":\"\\u8bbe\\u5b9a\\u80cc\\u666f\\u8272\\u5f69\\u7684\\u6d6e\\u52a8\\u8303\\u56f4\\uff0c\\u5728\\u8be5\\u8303\\u56f4\\u5185\\u7684\\u90fd\\u5f53\\u4f5c\\u80cc\\u666f\\u79fb\\u9664\",\"type\":\"int\",\"cur\":20,\"default\":20,\"size\":4,\"range\":{\"min\":1,\"max\":128},\"depend_or\":[\"11==true\"]},\"13\":{\"category\":\"base\",\"name\":\"cfg-13\",\"title\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"desc\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":24,\"range\":[\"\\u65e0\",\"\\u9510\\u5316\",\"\\u8fdb\\u4e00\\u6b65\\u9510\\u5316\",\"\\u6a21\\u7cca\",\"\\u8fdb\\u4e00\\u6b65\\u6a21\\u7cca\"],\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"14\":{\"category\":\"base\",\"name\":\"cfg-14\",\"title\":\"\\u53bb\\u9664\\u6469\\u5c14\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"15\":{\"category\":\"base\",\"name\":\"cfg-15\",\"title\":\"\\u9664\\u7f51\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"16\":{\"category\":\"base\",\"name\":\"cfg-16\",\"title\":\"\\u9519\\u8bef\\u6269\\u6563\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"17\":{\"category\":\"base\",\"name\":\"cfg-17\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u566a\\u70b9\\u4f18\\u5316\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"18\":{\"category\":\"base\",\"name\":\"cfg-18\",\"title\":\" \\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"type\":\"int\",\"cur\":30,\"default\":30,\"size\":4,\"range\":{\"min\":10,\"max\":50},\"depend_or\":[\"17==true\"]},\"19\":{\"category\":\"base\",\"name\":\"pagesize\",\"title\":\"\\u7eb8\\u5f20\\u5c3a\\u5bf8\",\"desc\":\"\\u8bbe\\u7f6e\\u7eb8\\u5f20\\u5927\\u5c0f\",\"type\":\"string\",\"cur\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"default\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"size\":48,\"range\":[\"A3\",\"8\\u5f00\",\"A4\",\"A4\\u6a2a\\u5411\",\"16\\u5f00\",\"16\\u5f00\\u6a2a\\u5411\",\"A5\",\"A5\\u6a2a\\u5411\",\"A6\",\"A6\\u6a2a\\u5411\",\"B4\",\"B5\",\"B5\\u6a2a\\u5411\",\"B6\",\"B6\\u6a2a\\u5411\",\"Letter\",\"Letter\\u6a2a\\u5411\",\"Double Letter\",\"LEGAL\",\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"\\u4e09\\u8054\\u8bd5\\u5377\"]},\"20\":{\"category\":\"base\",\"name\":\"cfg-20\",\"title\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"19!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19!=\\u4e09\\u8054\\u8bd5\\u5377\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\"]},\"21\":{\"category\":\"base\",\"name\":\"tl-x\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4e0a\\u89d2x\\u5750\\u6807\",\"type\":\"float\",\"cur\":0.000000,\"default\":0.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":210.000000},\"depend_and\":[\"20==true\"]},\"22\":{\"category\":\"base\",\"name\":\"br-x\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4e0b\\u89d2x\\u5750\\u6807\",\"type\":\"float\",\"cur\":210.000000,\"default\":210.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":210.000000},\"depend_and\":[\"20==true\"]},\"23\":{\"category\":\"base\",\"name\":\"tl-y\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u4e0a\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4e0a\\u89d2y\\u5750\\u6807\",\"type\":\"float\",\"cur\":0.000000,\"default\":0.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":297.000000},\"depend_and\":[\"20==true\"]},\"24\":{\"category\":\"base\",\"name\":\"br-y\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u4e0b\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4e0b\\u89d2y\\u5750\\u6807\",\"type\":\"float\",\"cur\":297.000000,\"default\":297.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":297.000000},\"depend_and\":[\"20==true\"]},\"25\":{\"category\":\"base\",\"name\":\"cfg-25\",\"title\":\"\\u5c3a\\u5bf8\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u5b9e\\u9645\\u5c3a\\u5bf8\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"19==A3\",\"19==A4\",\"19==A4\\u6a2a\\u5411\",\"19==A5\",\"19==A5\\u6a2a\\u5411\",\"19==A6\",\"19==A6\\u6a2a\\u5411\",\"19==B4\",\"19==B5\",\"19==B5\\u6a2a\\u5411\",\"19==B6\",\"19==B6\\u6a2a\\u5411\",\"19==Double Letter\",\"19==LEGAL\",\"19==Letter\",\"19==Letter\\u6a2a\\u5411\"]},\"26\":{\"category\":\"base\",\"name\":\"source\",\"title\":\"\\u626b\\u63cf\\u9875\\u9762\",\"desc\":\"\\u8bbe\\u7f6e\\u9875\\u9762\\u626b\\u63cf\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u53cc\\u9762\",\"default\":\"\\u53cc\\u9762\",\"size\":40,\"range\":[\"\\u5355\\u9762\",\"\\u53cc\\u9762\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\",\"\\u5bf9\\u6298\"]},\"27\":{\"category\":\"base\",\"name\":\"cfg-27\",\"title\":\" \\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\u7075\\u654f\\u5ea6\",\"desc\":\"\\u7075\\u654f\\u5ea6\\u8d8a\\u9ad8\\uff0c\\u5219\\u8d8a\\u5bb9\\u6613\\u8df3\\u8fc7\",\"type\":\"int\",\"cur\":50,\"default\":50,\"size\":4,\"range\":{\"min\":1,\"max\":100},\"depend_or\":[\"26==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"26==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\"]},\"28\":{\"category\":\"base\",\"name\":\"resolution\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u626b\\u63cf\\u4eea\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,150,200,240,300,600]},\"29\":{\"category\":\"base\",\"name\":\"cfg-29\",\"title\":\"\\u753b\\u8d28\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"default\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"size\":24,\"range\":[\"\\u901f\\u5ea6\\u4f18\\u5148\",\"\\u753b\\u8d28\\u4f18\\u5148\"],\"depend_or\":[\"28==300\",\"28==600\"]},\"30\":{\"category\":\"base\",\"name\":\"cfg-30\",\"title\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"desc\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5355\\u9762\"]},\"31\":{\"category\":\"base\",\"name\":\"cfg-31\",\"title\":\"\\u56fe\\u50cf\\u62c6\\u5206\",\"desc\":\"\\u81ea\\u52a8\\u62c6\\u5206\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5bf9\\u6298\",\"26!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\",\"26!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\"]},\"32\":{\"category\":\"base\",\"name\":\"cfg-32\",\"title\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"desc\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4,\"depend_or\":[\"26!=\\u5bf9\\u6298\"]},\"33\":{\"category\":\"base\",\"name\":\"grp-2\",\"title\":\"\\u4eae\\u5ea6\",\"type\":\"group\"},\"34\":{\"category\":\"base\",\"name\":\"cfg-34\",\"title\":\"\\u542f\\u7528\\u8272\\u8c03\\u66f2\\u7ebf\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"35\":{\"category\":\"base\",\"name\":\"brightness\",\"title\":\"\\u4eae\\u5ea6\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4eae\\u5ea6\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":1,\"max\":255},\"depend_and\":[\"34==false\"]},\"36\":{\"category\":\"base\",\"name\":\"contrast\",\"title\":\"\\u5bf9\\u6bd4\\u5ea6\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u5bf9\\u6bd4\\u5ea6\",\"type\":\"int\",\"cur\":4,\"default\":4,\"size\":4,\"range\":{\"min\":1,\"max\":7},\"depend_and\":[\"34==false\"]},\"37\":{\"category\":\"base\",\"name\":\"cfg-37\",\"title\":\"\\u4f3d\\u9a6c\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4f3d\\u739b\\u503c\",\"type\":\"float\",\"cur\":1.000000,\"default\":1.000000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":5.000000},\"depend_and\":[\"34==false\"]},\"38\":{\"category\":\"base\",\"name\":\"grp-3\",\"title\":\"\\u56fe\\u50cf\\u5904\\u7406\",\"type\":\"group\"},\"39\":{\"category\":\"base\",\"name\":\"cfg-39\",\"title\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"desc\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"40\":{\"category\":\"base\",\"name\":\"cfg-40\",\"title\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"desc\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5bf9\\u6298\",\"39!=true\",\"19!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32!=true\"]},\"41\":{\"category\":\"advanced\",\"name\":\"cfg-41\",\"title\":\"\\u9608\\u503c\",\"desc\":\"\\u9608\\u503c\",\"type\":\"int\",\"cur\":40,\"default\":40,\"size\":4,\"range\":{\"min\":30,\"max\":50},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\"]},\"42\":{\"category\":\"advanced\",\"name\":\"cfg-42\",\"title\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"desc\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"type\":\"int\",\"cur\":8,\"default\":8,\"size\":4,\"range\":{\"min\":1,\"max\":20},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\"]},\"43\":{\"category\":\"advanced\",\"name\":\"cfg-43\",\"title\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"desc\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"type\":\"int\",\"cur\":5,\"default\":5,\"size\":4,\"range\":{\"min\":5,\"max\":30},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\"]},\"44\":{\"category\":\"advanced\",\"name\":\"cfg-44\",\"title\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"desc\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"default\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"size\":40,\"range\":[\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"\\u51f9\\u591a\\u8fb9\\u5f62\"],\"depend_or\":[\"39==true\"]},\"45\":{\"category\":\"base\",\"name\":\"cfg-45\",\"title\":\"\\u9632\\u6b62\\u6e17\\u900f\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"46\":{\"category\":\"base\",\"name\":\"cfg-46\",\"title\":\" \\u9632\\u6b62\\u6e17\\u900f\\u7b49\\u7ea7\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u8f83\\u5f31\",\"default\":\"\\u8f83\\u5f31\",\"size\":16,\"range\":[\"\\u5f31\",\"\\u8f83\\u5f31\",\"\\u4e00\\u822c\",\"\\u8f83\\u5f3a\",\"\\u5f3a\"],\"depend_or\":[\"45==true\"]},\"47\":{\"category\":\"base\",\"name\":\"cfg-47\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u7eb8\\u5f20\\u4e2d\\u7684\\u7a7f\\u5b54\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"48\":{\"category\":\"base\",\"name\":\"cfg-48\",\"title\":\" \\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":0.500000},\"depend_or\":[\"47==true\"]},\"49\":{\"category\":\"base\",\"name\":\"cfg-49\",\"title\":\"\\u8272\\u5f69\\u586b\\u5145\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"39==true\"]},\"50\":{\"category\":\"base\",\"name\":\"grp-4\",\"title\":\"\\u9001\\u7eb8\\u65b9\\u5f0f\\u8bbe\\u7f6e\",\"type\":\"group\"},\"51\":{\"category\":\"base\",\"name\":\"ultrasonic Disable|Enable\",\"title\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\",\"desc\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\\u9001\\u7eb8\\u72b6\\u6001\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"52\":{\"category\":\"base\",\"name\":\"cfg-52\",\"title\":\"\\u88c5\\u8ba2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u4e0a\\u662f\\u5426\\u6709\\u9489\\u4e66\\u9489\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"53\":{\"category\":\"base\",\"name\":\"cfg-53\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u626b\\u63cf\\u7eb8\\u5f20\\u6570\\u91cf\",\"type\":\"string\",\"cur\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"default\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"size\":32,\"range\":[\"\\u8fde\\u7eed\\u626b\\u63cf\",\"\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"54\":{\"category\":\"base\",\"name\":\"cfg-54\",\"title\":\" \\u626b\\u63cf\\u6570\\u91cf\",\"desc\":\"\\u626b\\u63cf\\u6307\\u5b9a\\u6570\\u91cf\",\"type\":\"int\",\"cur\":1,\"default\":1,\"size\":4,\"depend_or\":[\"53==\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"55\":{\"category\":\"base\",\"name\":\"cfg-55\",\"title\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"desc\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"type\":\"string\",\"cur\":\"0\\u00b0\",\"default\":\"0\\u00b0\",\"size\":40,\"range\":[\"0\\u00b0\",\"90\\u00b0\",\"180\\u00b0\",\"-90\\u00b0\"]},\"56\":{\"category\":\"base\",\"name\":\"cfg-56\",\"title\":\"\\u80cc\\u9762\\u65cb\\u8f6c180\\u00b0\",\"desc\":\"\\u80cc\\u9762\\u626b\\u63cf\\u7684\\u56fe\\u50cf\\u65cb\\u8f6c180\\u00b0\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5355\\u9762\",\"26!=\\u5bf9\\u6298\",\"55!=\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b\\u00b0\"]},\"57\":{\"category\":\"base\",\"name\":\"cfg-57\",\"title\":\"\\u6298\\u89d2\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6298\\u89d2\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"58\":{\"category\":\"base\",\"name\":\"cfg-58\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100},\"depend_or\":[\"57==true\"]},\"59\":{\"category\":\"base\",\"name\":\"cfg-59\",\"title\":\"\\u6b6a\\u659c\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6b6a\\u659c\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"60\":{\"category\":\"base\",\"name\":\"cfg-60\",\"title\":\"\\u6b6a\\u659c\\u5bb9\\u5fcd\\u5ea6\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7eb8\\u5f20\\u7684\\u6b6a\\u659c\\u89d2\\u5ea6\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":3,\"default\":3,\"size\":4,\"range\":{\"min\":1,\"max\":5},\"depend_or\":[\"59==true\"]}}"); +#else +static std::string jsontext("{\"device_type\":\"G239\",\"option_count\":61,\"1\":{\"category\":\"base\",\"name\":\"cfg-1\",\"title\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"desc\":\"\\u6062\\u590d\\u9ed8\\u8ba4\\u8bbe\\u7f6e\",\"type\":\"button\",\"cur\":\"button\",\"default\":\"button\",\"size\":0},\"2\":{\"category\":\"advanced\",\"name\":\"cfg-2\",\"title\":\"\\u5e2e\\u52a9\",\"desc\":\"\\u663e\\u793a\\u8f6f\\u4ef6\\u5e2e\\u52a9\\u6587\\u6863\",\"type\":\"button\",\"cur\":\"true\",\"default\":\"true\",\"size\":4},\"3\":{\"category\":\"base\",\"name\":\"grp-1\",\"title\":\"\\u57fa\\u672c\\u8bbe\\u7f6e\",\"type\":\"group\"},\"4\":{\"category\":\"base\",\"name\":\"cfg-4\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"5\":{\"category\":\"base\",\"name\":\"cfg-5\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\\u7c7b\\u578b\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":32,\"range\":[\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"\\u5f69\\u8272+\\u7070\\u5ea6\",\"\\u5f69\\u8272+\\u9ed1\\u767d\",\"\\u7070\\u5ea6+\\u9ed1\\u767d\"],\"depend_or\":[\"4==true\"]},\"6\":{\"category\":\"base\",\"name\":\"mode\",\"title\":\"\\u989c\\u8272\\u6a21\\u5f0f\",\"desc\":\"\\u8bbe\\u7f6e\\u989c\\u8272\\u4f4d\\u6df1\",\"type\":\"string\",\"cur\":\"24\\u4f4d\\u5f69\\u8272\",\"default\":\"24\\u4f4d\\u5f69\\u8272\",\"size\":32,\"range\":[\"24\\u4f4d\\u5f69\\u8272\",\"256\\u7ea7\\u7070\\u5ea6\",\"\\u9ed1\\u767d\",\"\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"],\"depend_or\":[\"4!=true\"]},\"7\":{\"category\":\"base\",\"name\":\"cfg-7\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u9608\\u503c\",\"desc\":\"\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":0,\"max\":255},\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"8\":{\"category\":\"base\",\"name\":\"cfg-8\",\"title\":\"\\u7070\\u5ea6\\u6216\\u9ed1\\u767d\\u56fe\\u50cf - \\u9664\\u8272\",\"desc\":\"\\u9664\\u53bb\\u56fe\\u50cf\\u5f69\\u8272\",\"type\":\"string\",\"cur\":\"\\u4e0d\\u9664\\u8272\",\"default\":\"\\u4e0d\\u9664\\u8272\",\"size\":24,\"range\":[\"\\u4e0d\\u9664\\u8272\",\"\\u9664\\u7ea2\\u8272\",\"\\u9664\\u7eff\\u8272\",\"\\u9664\\u84dd\\u8272\",\"\\u7ea2\\u8272\\u589e\\u5f3a\",\"\\u7eff\\u8272\\u589e\\u5f3a\",\"\\u84dd\\u8272\\u589e\\u5f3a\"],\"depend_and\":[\"4!=true\",\"6!=24\\u4f4d\\u5f69\\u8272\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"9\":{\"category\":\"base\",\"name\":\"cfg-9\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u591a\\u6d41\\u8f93\\u51fa\\u9664\\u7ea2\",\"desc\":\"\\u591a\\u901a\\u9053\\u8f93\\u51fa\\u4e2d\\uff0c\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"10\":{\"category\":\"base\",\"name\":\"cfg-10\",\"title\":\"24\\u4f4d\\u5f69\\u8272\\u56fe\\u50cf - \\u7b54\\u9898\\u5361\\u9664\\u7ea2\",\"desc\":\"\\u7b54\\u9898\\u5361\\u626b\\u63cf\\u4e2d\\u53bb\\u9664\\u7ea2\\u8272\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"11\":{\"category\":\"base\",\"name\":\"cfg-11\",\"title\":\"\\u80cc\\u666f\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u5f69\\u8272\\u56fe\\u50cf\\u80cc\\u666f\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=256\\u7ea7\\u7070\\u5ea6\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"12\":{\"category\":\"base\",\"name\":\"cfg-12\",\"title\":\" \\u80cc\\u666f\\u8272\\u5f69\\u6d6e\\u52a8\\u8303\\u56f4\",\"desc\":\"\\u8bbe\\u5b9a\\u80cc\\u666f\\u8272\\u5f69\\u7684\\u6d6e\\u52a8\\u8303\\u56f4\\uff0c\\u5728\\u8be5\\u8303\\u56f4\\u5185\\u7684\\u90fd\\u5f53\\u4f5c\\u80cc\\u666f\\u79fb\\u9664\",\"type\":\"int\",\"cur\":20,\"default\":20,\"size\":4,\"range\":{\"min\":1,\"max\":128},\"depend_or\":[\"11==true\"]},\"13\":{\"category\":\"base\",\"name\":\"cfg-13\",\"title\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"desc\":\"\\u9510\\u5316\\u4e0e\\u6a21\\u7cca\",\"type\":\"string\",\"cur\":\"\\u65e0\",\"default\":\"\\u65e0\",\"size\":24,\"range\":[\"\\u65e0\",\"\\u9510\\u5316\",\"\\u8fdb\\u4e00\\u6b65\\u9510\\u5316\",\"\\u6a21\\u7cca\",\"\\u8fdb\\u4e00\\u6b65\\u6a21\\u7cca\"],\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"14\":{\"category\":\"base\",\"name\":\"cfg-14\",\"title\":\"\\u53bb\\u9664\\u6469\\u5c14\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"15\":{\"category\":\"base\",\"name\":\"cfg-15\",\"title\":\"\\u9664\\u7f51\\u7eb9\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"4!=true\",\"6!=\\u9ed1\\u767d\",\"6!=\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"]},\"16\":{\"category\":\"base\",\"name\":\"cfg-16\",\"title\":\"\\u9519\\u8bef\\u6269\\u6563\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"17\":{\"category\":\"base\",\"name\":\"cfg-17\",\"title\":\"\\u9ed1\\u767d\\u56fe\\u50cf\\u566a\\u70b9\\u4f18\\u5316\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"6==\\u9ed1\\u767d\"]},\"18\":{\"category\":\"base\",\"name\":\"cfg-18\",\"title\":\" \\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"desc\":\"\\u566a\\u70b9\\u4f18\\u5316\\u5c3a\\u5bf8\",\"type\":\"int\",\"cur\":30,\"default\":30,\"size\":4,\"range\":{\"min\":10,\"max\":50},\"depend_or\":[\"17==true\"]},\"19\":{\"category\":\"base\",\"name\":\"pagesize\",\"title\":\"\\u7eb8\\u5f20\\u5c3a\\u5bf8\",\"desc\":\"\\u8bbe\\u7f6e\\u7eb8\\u5f20\\u5927\\u5c0f\",\"type\":\"string\",\"cur\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"default\":\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"size\":48,\"range\":[\"A3\",\"8\\u5f00\",\"A4\",\"A4\\u6a2a\\u5411\",\"16\\u5f00\",\"16\\u5f00\\u6a2a\\u5411\",\"A5\",\"A5\\u6a2a\\u5411\",\"A6\",\"A6\\u6a2a\\u5411\",\"B4\",\"B5\",\"B5\\u6a2a\\u5411\",\"B6\",\"B6\\u6a2a\\u5411\",\"Letter\",\"Letter\\u6a2a\\u5411\",\"Double Letter\",\"LEGAL\",\"\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"\\u4e09\\u8054\\u8bd5\\u5377\"]},\"20\":{\"category\":\"base\",\"name\":\"cfg-20\",\"title\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"19!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19!=\\u4e09\\u8054\\u8bd5\\u5377\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\"]},\"21\":{\"category\":\"base\",\"name\":\"tl-x\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4e0a\\u89d2x\\u5750\\u6807\",\"type\":\"float\",\"cur\":0.000000,\"default\":0.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":210.000000},\"depend_and\":[\"20==true\"]},\"22\":{\"category\":\"base\",\"name\":\"br-x\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4e0b\\u89d2x\\u5750\\u6807\",\"type\":\"float\",\"cur\":210.000000,\"default\":210.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":210.000000},\"depend_and\":[\"20==true\"]},\"23\":{\"category\":\"base\",\"name\":\"tl-y\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u4e0a\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u5de6\\u4e0a\\u89d2y\\u5750\\u6807\",\"type\":\"float\",\"cur\":0.000000,\"default\":0.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":297.000000},\"depend_and\":[\"20==true\"]},\"24\":{\"category\":\"base\",\"name\":\"br-y\",\"title\":\"\\u626b\\u63cf\\u533a\\u57df\\u4e0b\\u4fa7\\uff08mm\\uff09\",\"desc\":\"\\u81ea\\u5b9a\\u4e49\\u626b\\u63cf\\u533a\\u57df\\u53f3\\u4e0b\\u89d2y\\u5750\\u6807\",\"type\":\"float\",\"cur\":297.000000,\"default\":297.000000,\"size\":4,\"range\":{\"min\":0.000000,\"max\":297.000000},\"depend_and\":[\"20==true\"]},\"25\":{\"category\":\"base\",\"name\":\"cfg-25\",\"title\":\"\\u5c3a\\u5bf8\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u5b9e\\u9645\\u5c3a\\u5bf8\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_or\":[\"19==A3\",\"19==A4\",\"19==A4\\u6a2a\\u5411\",\"19==A5\",\"19==A5\\u6a2a\\u5411\",\"19==A6\",\"19==A6\\u6a2a\\u5411\",\"19==B4\",\"19==B5\",\"19==B5\\u6a2a\\u5411\",\"19==B6\",\"19==B6\\u6a2a\\u5411\",\"19==Double Letter\",\"19==LEGAL\",\"19==Letter\",\"19==Letter\\u6a2a\\u5411\"]},\"26\":{\"category\":\"base\",\"name\":\"source\",\"title\":\"\\u626b\\u63cf\\u9875\\u9762\",\"desc\":\"\\u8bbe\\u7f6e\\u9875\\u9762\\u626b\\u63cf\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u53cc\\u9762\",\"default\":\"\\u53cc\\u9762\",\"size\":40,\"range\":[\"\\u5355\\u9762\",\"\\u53cc\\u9762\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\",\"\\u5bf9\\u6298\"]},\"27\":{\"category\":\"base\",\"name\":\"cfg-27\",\"title\":\" \\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\u7075\\u654f\\u5ea6\",\"desc\":\"\\u7075\\u654f\\u5ea6\\u8d8a\\u9ad8\\uff0c\\u5219\\u8d8a\\u5bb9\\u6613\\u8df3\\u8fc7\",\"type\":\"int\",\"cur\":50,\"default\":50,\"size\":4,\"range\":{\"min\":1,\"max\":100},\"depend_or\":[\"26==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\",\"26==\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\"]},\"28\":{\"category\":\"base\",\"name\":\"resolution\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u626b\\u63cf\\u4eea\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"cur\":200,\"default\":200,\"size\":4,\"range\":[100,150,200,240,300,600]},\"29\":{\"category\":\"base\",\"name\":\"cfg-29\",\"title\":\"\\u753b\\u8d28\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"default\":\"\\u901f\\u5ea6\\u4f18\\u5148\",\"size\":24,\"range\":[\"\\u901f\\u5ea6\\u4f18\\u5148\",\"\\u753b\\u8d28\\u4f18\\u5148\"],\"depend_or\":[\"28==300\",\"28==600\"]},\"30\":{\"category\":\"base\",\"name\":\"cfg-30\",\"title\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"desc\":\"\\u4ea4\\u6362\\u6b63\\u53cd\\u9762\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5355\\u9762\"]},\"31\":{\"category\":\"base\",\"name\":\"cfg-31\",\"title\":\"\\u56fe\\u50cf\\u62c6\\u5206\",\"desc\":\"\\u81ea\\u52a8\\u62c6\\u5206\\u56fe\\u50cf\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5bf9\\u6298\",\"26!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u53d1\\u7968\\u7eb8\\uff09\",\"26!=\\u8df3\\u8fc7\\u7a7a\\u767d\\u9875\\uff08\\u901a\\u7528\\uff09\"]},\"32\":{\"category\":\"base\",\"name\":\"cfg-32\",\"title\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"desc\":\"\\u81ea\\u52a8\\u7ea0\\u504f\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4,\"depend_or\":[\"26!=\\u5bf9\\u6298\"]},\"33\":{\"category\":\"base\",\"name\":\"grp-2\",\"title\":\"\\u4eae\\u5ea6\",\"type\":\"group\"},\"34\":{\"category\":\"base\",\"name\":\"cfg-34\",\"title\":\"\\u542f\\u7528\\u8272\\u8c03\\u66f2\\u7ebf\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"35\":{\"category\":\"base\",\"name\":\"brightness\",\"title\":\"\\u4eae\\u5ea6\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4eae\\u5ea6\",\"type\":\"int\",\"cur\":128,\"default\":128,\"size\":4,\"range\":{\"min\":1,\"max\":255},\"depend_and\":[\"34==false\"]},\"36\":{\"category\":\"base\",\"name\":\"contrast\",\"title\":\"\\u5bf9\\u6bd4\\u5ea6\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u5bf9\\u6bd4\\u5ea6\",\"type\":\"int\",\"cur\":4,\"default\":4,\"size\":4,\"range\":{\"min\":1,\"max\":7},\"depend_and\":[\"34==false\"]},\"37\":{\"category\":\"base\",\"name\":\"cfg-37\",\"title\":\"\\u4f3d\\u9a6c\\u503c\",\"desc\":\"\\u8c03\\u6574\\u56fe\\u7247\\u4f3d\\u739b\\u503c\",\"type\":\"float\",\"cur\":1.000000,\"default\":1.000000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":5.000000},\"depend_and\":[\"34==false\"]},\"38\":{\"category\":\"base\",\"name\":\"grp-3\",\"title\":\"\\u56fe\\u50cf\\u5904\\u7406\",\"type\":\"group\"},\"39\":{\"category\":\"base\",\"name\":\"cfg-39\",\"title\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"desc\":\"\\u6d88\\u9664\\u9ed1\\u6846\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"40\":{\"category\":\"base\",\"name\":\"cfg-40\",\"title\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"desc\":\"\\u6df1\\u8272\\u6837\\u5f20\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5bf9\\u6298\",\"39!=true\",\"19!=\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19!=\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32!=true\"]},\"41\":{\"category\":\"advanced\",\"name\":\"cfg-41\",\"title\":\"\\u9608\\u503c\",\"desc\":\"\\u9608\\u503c\",\"type\":\"int\",\"cur\":40,\"default\":40,\"size\":4,\"range\":{\"min\":30,\"max\":50},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\"]},\"42\":{\"category\":\"advanced\",\"name\":\"cfg-42\",\"title\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"desc\":\"\\u80cc\\u666f\\u6297\\u566a\\u7b49\\u7ea7\",\"type\":\"int\",\"cur\":8,\"default\":8,\"size\":4,\"range\":{\"min\":1,\"max\":20},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\"]},\"43\":{\"category\":\"advanced\",\"name\":\"cfg-43\",\"title\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"desc\":\"\\u8fb9\\u7f18\\u7f29\\u8fdb\",\"type\":\"int\",\"cur\":5,\"default\":5,\"size\":4,\"range\":{\"min\":5,\"max\":30},\"depend_or\":[\"39==true\",\"19==\\u5339\\u914d\\u539f\\u59cb\\u5c3a\\u5bf8\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207\",\"32==true\",\"19==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\"]},\"44\":{\"category\":\"advanced\",\"name\":\"cfg-44\",\"title\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"desc\":\"\\u80cc\\u666f\\u586b\\u5145\\u65b9\\u5f0f\",\"type\":\"string\",\"cur\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"default\":\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"size\":40,\"range\":[\"\\u51f8\\u591a\\u8fb9\\u5f62\",\"\\u51f9\\u591a\\u8fb9\\u5f62\"],\"depend_or\":[\"39==true\"]},\"45\":{\"category\":\"base\",\"name\":\"cfg-45\",\"title\":\"\\u9632\\u6b62\\u6e17\\u900f\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"46\":{\"category\":\"base\",\"name\":\"cfg-46\",\"title\":\" \\u9632\\u6b62\\u6e17\\u900f\\u7b49\\u7ea7\",\"desc\":\"\",\"type\":\"string\",\"cur\":\"\\u8f83\\u5f31\",\"default\":\"\\u8f83\\u5f31\",\"size\":16,\"range\":[\"\\u5f31\",\"\\u8f83\\u5f31\",\"\\u4e00\\u822c\",\"\\u8f83\\u5f3a\",\"\\u5f3a\"],\"depend_or\":[\"45==true\"]},\"47\":{\"category\":\"base\",\"name\":\"cfg-47\",\"title\":\"\\u7a7f\\u5b54\\u79fb\\u9664\",\"desc\":\"\\u79fb\\u9664\\u7eb8\\u5f20\\u4e2d\\u7684\\u7a7f\\u5b54\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"48\":{\"category\":\"base\",\"name\":\"cfg-48\",\"title\":\" \\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"desc\":\"\\u7a7f\\u5b54\\u641c\\u7d22\\u8303\\u56f4\\u5360\\u5e45\\u9762\\u6bd4\\u4f8b\",\"type\":\"float\",\"cur\":0.100000,\"default\":0.100000,\"size\":4,\"range\":{\"min\":0.010000,\"max\":0.500000},\"depend_or\":[\"47==true\"]},\"49\":{\"category\":\"base\",\"name\":\"cfg-49\",\"title\":\"\\u8272\\u5f69\\u586b\\u5145\",\"desc\":\"\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"39==true\"]},\"50\":{\"category\":\"base\",\"name\":\"grp-4\",\"title\":\"\\u9001\\u7eb8\\u65b9\\u5f0f\\u8bbe\\u7f6e\",\"type\":\"group\"},\"51\":{\"category\":\"base\",\"name\":\"ultrasonic Disable|Enable\",\"title\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\",\"desc\":\"\\u8d85\\u58f0\\u6ce2\\u68c0\\u6d4b\\u9001\\u7eb8\\u72b6\\u6001\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"52\":{\"category\":\"base\",\"name\":\"cfg-52\",\"title\":\"\\u88c5\\u8ba2\\u68c0\\u6d4b\",\"desc\":\"\\u68c0\\u6d4b\\u7eb8\\u5f20\\u4e0a\\u662f\\u5426\\u6709\\u9489\\u4e66\\u9489\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"53\":{\"category\":\"base\",\"name\":\"cfg-53\",\"title\":\"\\u626b\\u63cf\\u5f20\\u6570\",\"desc\":\"\\u626b\\u63cf\\u7eb8\\u5f20\\u6570\\u91cf\",\"type\":\"string\",\"cur\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"default\":\"\\u8fde\\u7eed\\u626b\\u63cf\",\"size\":32,\"range\":[\"\\u8fde\\u7eed\\u626b\\u63cf\",\"\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"54\":{\"category\":\"base\",\"name\":\"cfg-54\",\"title\":\" \\u626b\\u63cf\\u6570\\u91cf\",\"desc\":\"\\u626b\\u63cf\\u6307\\u5b9a\\u6570\\u91cf\",\"type\":\"int\",\"cur\":1,\"default\":1,\"size\":4,\"depend_or\":[\"53==\\u626b\\u63cf\\u6307\\u5b9a\\u5f20\\u6570\"]},\"55\":{\"category\":\"base\",\"name\":\"cfg-55\",\"title\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"desc\":\"\\u6587\\u7a3f\\u65b9\\u5411\",\"type\":\"string\",\"cur\":\"0\\u00b0\",\"default\":\"0\\u00b0\",\"size\":40,\"range\":[\"0\\u00b0\",\"90\\u00b0\",\"180\\u00b0\",\"-90\\u00b0\",\"\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b\\u00b0\"]},\"56\":{\"category\":\"base\",\"name\":\"cfg-56\",\"title\":\"\\u80cc\\u9762\\u65cb\\u8f6c180\\u00b0\",\"desc\":\"\\u80cc\\u9762\\u626b\\u63cf\\u7684\\u56fe\\u50cf\\u65cb\\u8f6c180\\u00b0\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4,\"depend_and\":[\"26!=\\u5355\\u9762\",\"26!=\\u5bf9\\u6298\",\"55!=\\u81ea\\u52a8\\u6587\\u672c\\u65b9\\u5411\\u8bc6\\u522b\\u00b0\"]},\"57\":{\"category\":\"base\",\"name\":\"cfg-57\",\"title\":\"\\u6298\\u89d2\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6298\\u89d2\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":false,\"default\":false,\"size\":4},\"58\":{\"category\":\"base\",\"name\":\"cfg-58\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100},\"depend_or\":[\"57==true\"]},\"59\":{\"category\":\"base\",\"name\":\"cfg-59\",\"title\":\"\\u6b6a\\u659c\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6b6a\\u659c\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"60\":{\"category\":\"base\",\"name\":\"cfg-60\",\"title\":\"\\u6b6a\\u659c\\u5bb9\\u5fcd\\u5ea6\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7eb8\\u5f20\\u7684\\u6b6a\\u659c\\u89d2\\u5ea6\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":3,\"default\":3,\"size\":4,\"range\":{\"min\":1,\"max\":5},\"depend_or\":[\"59==true\"]}}"); +static std::string jsontext2("\"59\":{\"category\":\"base\",\"name\":\"cfg-59\",\"title\":\" \\u6298\\u89d2\\u5927\\u5c0f\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7684\\u6298\\u89d2\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":70,\"default\":70,\"size\":4,\"range\":{\"min\":0,\"max\":100},\"depend_or\":[\"58==true\"]},\"60\":{\"category\":\"base\",\"name\":\"cfg-60\",\"title\":\"\\u6b6a\\u659c\\u68c0\\u6d4b\",\"desc\":\"\\u7eb8\\u5f20\\u6b6a\\u659c\\u68c0\\u6d4b\",\"type\":\"bool\",\"cur\":true,\"default\":true,\"size\":4},\"61\":{\"category\":\"base\",\"name\":\"cfg-61\",\"title\":\"\\u6b6a\\u659c\\u5bb9\\u5fcd\\u5ea6\",\"desc\":\"\\u503c\\u8d8a\\u5c0f\\uff0c\\u4ee3\\u8868\\u80fd\\u68c0\\u6d4b\\u5230\\u7eb8\\u5f20\\u7684\\u6b6a\\u659c\\u89d2\\u5ea6\\u8d8a\\u5c0f\",\"type\":\"int\",\"cur\":3,\"default\":3,\"size\":4,\"range\":{\"min\":1,\"max\":5},\"depend_or\":[\"60==true\"]}}"); +#endif +enum hg_239_setting_item +{ + HG_239_SETTING_RESTORE = 1, // 恢复默认设置 + HG_239_SETTING_HELP, // 帮助 + + HG__239_SETTING_GROUP_1, + + HG_239_SETTING_COLOR_MODE, // 颜色模式 + + HG_239_SETTING_ERASE_COLOR, // 除色 + HG_239_SETTING_ERASE_MULTI_RED, // 多流输出除红 + HG_239_SETTING_ERASE_ANSWER_RED, // 答题卡除红 + HG_239_SETTING_ERASE_BACKGROUND, // 移除背景 + HG_239_SETTING_ERASE_BKG_RANGE, // 移除背景范围 + HG_239_SETTING_NOISE, // 黑白图像噪点优化 + HG_239_SETTING_NOISE_SIZE, // 噪点优化尺寸 + HG_239_SETTING_PAPER_SIZE, // 纸张尺寸 + + HG_239_SETTING_CUSTOM_AREA, // 自定义扫描区域 + HG_239_SETTING_CUSTOM_AREA_LEFT, // 扫描区域左侧(mm) + HG_239_SETTING_CUSTOM_AREA_RIGHT, // 扫描区域右侧(mm) + HG_239_SETTING_CUSTOM_AREA_TOP, // 扫描区域上侧(mm) + HG_239_SETTING_CUSTOM_AREA_BOTTOM, // 扫描区域下侧(mm) + + HG_239_SETTING_PAPER_SIZE_CHECK, // 尺寸检测 + HG_239_SETTING_PAGE, // 扫描页面 + HG_239_SETTING_SKIP_NILL, // 跳过空白页灵敏度 + HG_239_SETTING_RESOLUTION, // 分辨率 + HG_239_SETTING_IMG_QUALITY, // 画质 + HG_239_SETTING_REVERSE, // 交换正反面 + HG_239_SETTING_SPLIT, // 图像拆分 + HG_239_SETTING_CORRECT, // 自动纠偏 + HG_239_SETTING_ERASE_HOLE, // 穿孔移除 + HG_239_SETTING_HOLE_SEARCH, // 穿孔搜索范围 + + HG__239_SETTING_GROUP_2, + + HG_239_SETTING_CUSTOM_GAMMA, // 启用色调曲线 + HG_239_SETTING_LIGHT, // 亮度 + HG_239_SETTING_CONTRAST, // 对比度 + HG_239_SETTING_GAMMA, // 伽玛 + + HG__239_SETTING_GROUP_3, + + HG_239_SETTING_SHARP, // 锐化与模糊 + HG_239_SETTING_ERASE_BLACK_BORDER, // 消除黑框 + HG_239_SETTING_SAMPLE, // 深色样张 + HG_239_SETTING_THRESHOLD, // 阈值 + HG_239_SETTING_ANTI_NOISE, // 背景抗噪等级 + HG_239_SETTING_MARGIN, // 边缘缩进 + HG_239_SETTING_FILLING, // 背景填充方式 + HG_239_SETTING_PERMEATE, // 防止渗透 + HG_239_SETTING_PERMEATE_lv, // 防止渗透等级 + HG_239_SETTING_REMOVE_MORR, // 去除摩尔纹 + HG_239_SETTING_ERROR_EXTENTION, // 错误扩散 + HG_239_SETTING_REMOVE_TXTTURE, // 除网纹 + + HG__239_SETTING_GROUP_4, + + HG_239_SETTING_ULTRASONIC, // 超声波检测 + HG_239_SETTING_STAPLE, // 装订检测 + HG_239_SETTING_SCAN_METHOD, // 连续扫描或扫描指定张数 + HG_239_SETTING_SCAN_COUNT, // 扫描指定数量 + HG_239_SETTING_DIRECTION, // 文稿方向 删除文稿自动识别 + HG_239_SETTING_ROTATE, // 背面旋转180° + HG_239_SETTING_FRACTATE, // 折角检测 + HG_239_SETTING_FRACTATE_COMPLEX, // 折角检测复杂度 + HG_239_SETTING_SCREW, // 歪斜检测 + HG_239_SETTING_SCREW_COMPLEX, // 歪斜检测复杂度 + + + HG_239_SETTING_END, + + //暂时屏蔽 + HG_239_SETTING_MULTI_OUT = 500, // 多流输出 +}; +enum Scanner_Reg_Defs +{ + SR_CMD, + SR_STATUS, + SR_SCAN_COUNT, + SR_OS, + SR_SENSORS, + SR_MOTOR, + SR_IM_TYPE, + SR_IM_COUNT, + SR_IM_TX, + SR_IM_FRONT_SIZE, + SR_IM_CLEAR, + SR_IM_TXING, + SR_IM_POP, + SR_IM_ABORT, + SR_COUNT, + SR_CONFIG_SCAN_PARAM, + SR_GET_FWVERSION, + SR_SET_FWERSION, + SR_GET_SERIALNUM, + SR_SET_SERIALNUM, + SR_CONFIF_IMGPROCPARAM, + SC_AUTOCORRECT, + SC_GET_CORRECT_PARAM, + SC_SET_CORRECT_PARAM, + SR_GET_H_RATIO, + SR_SET_H_RATIO, + SR_GET_V_RATIO, + SR_SET_V_RATIO, + SR_GET_SERIAL_LEN, + SR_GET_GRAY_SP, + SR_GET_COLOR_SP, + SR_SET_GRAY_SP, + SR_SET_COLOR_SP, + SR_SET_SLEEPTIME, + SR_GET_SLEEPTIME, + SR_GET_SLEEP_STAUTUS, + SR_GET_IMAGEPROCESSDONE, + SR_GET_KEEP_LAST_PAPER, + SR_GET_PAPERON, + SR_SET_SPEEDMODE, + SR_GET_SPEEDMODE, + SR_GET_JSON_SIZE, + SR_GET_JSON, + SR_SET_JSON_PATH, + SR_SET_JSON, + SR_GET_FILE_POS, + SR_SET_FILE_POS, + SR_NOTIFY_SLEEP, + SR_GET_FEEDMODE, + SR_SET_FEEDMODE, + SR_GET_CUO_ERROR = 0x50, + SR_GET_DOU_ERROR, + SR_GET_JAM_ERROR, + SR_GET_SCANN_NUM, + SR_CLR_ROLLER_NUM, + SR_GET_ROLLER_NUM, + SR_UPDATA_START = 0x100, + SR_UPDATA_STAUTUS = 0x101, + SR_UPDATA_MD5_RELUST = 0x102, + SR_UPDATA_RECOVERY = 0x103, + SR_UPDATA_REBOOT = 0x104, + SR_POWEROFF = 0x105, + SR_REBOOT = 0x106, + SR_FLAT_CLR_MAX_BRIGHT, + SR_FLAT_GRAY_MAX_BRIGHT, + SR_KERNEL_VERSION_INFO_LENGTH, + SR_GET_KERNEL_VERSION, + SR_GET_MBSTATUS, + SR_GET_IPADDR_LENGHT = 0x200, + SR_GET_MACADDR, + SR_GET_IPADDR, + SR_GET_MBVERSION_LENGHT, + SR_GET_MBVERSION, + SR_GET_USBVIDPID, + SR_SET_USBVIDPID +}; +enum Scanner_Cmd_Defs +{ + SC_START, + SC_STOP, + SC_CLEAR, + SC_COUNT +}; +enum HGType +{ + MtBoard = 1, + FPGA, + V4L2, + IMG, + AutoCorrect, + STOPSCAN, +}; +struct HGEIntInfo +{ + HGType From; + unsigned int Code; + unsigned int Img_Index; +}; +namespace settings +{ + // device status to scanner_err + scanner_err device_status_to_hg_err(HGEIntInfo* ds) + { + scanner_err code = SCANNER_ERR_OK; + + if (ds->From == HGType::FPGA) + code = SCANNER_ERR_OK; + else if (ds->From == HGType::MtBoard) + { + switch (ds->Code) + { + case 0x00002: + code = SCANNER_ERR_DEVICE_NO_PAPER; + break; + case 0x00004: + code = SCANNER_ERR_DEVICE_COVER_OPENNED; + break; + case 0x00008: + code = SCANNER_ERR_DEVICE_FEEDING_PAPER; + break; + case 0x00010: + code = SCANNER_ERR_DEVICE_PAPER_JAMMED; + break; + case 0x00020: + code = SCANNER_ERR_DEVICE_DOUBLE_FEEDING; + break; + case 0x00040: + code = SCANNER_ERR_DEVICE_STAPLE_ON; + break; + case 0x00080: + code = SCANNER_ERR_DEVICE_PAPER_SKEW; + break; + case 0x10000: + case 0x80000: + code = SCANNER_ERR_TIMEOUT; + break; + case 0x20000: + code = SCANNER_ERR_DEVICE_SIZE_CHECK; + break; + default: + break; + } + } + else if (ds->From == HGType::IMG) + { + if (ds->Code == 1) + code = SCANNER_ERR_DEVICE_DOGEAR; + else if (ds->Code == 2) + code = SCANNER_ERR_DEVICE_SIZE_CHECK; + } + else if (ds->From == HGType::V4L2) + { + if (ds->Code == 0) + code = SCANNER_ERR_DEVICE_SCANN_ERROR; + else if (ds->Code == 1) + code = SCANNER_ERR_DEVICE_NO_IMAGE; + } + else if (ds->From == HGType::STOPSCAN) + code = SCANNER_ERR_DEVICE_STOPPED; + + return code; + } + + // resolution + static struct + { + float resolution; + int dev_value; + }resolution_map[] = + { + {100.0f, 1}, + {150.0f, 1}, + {200.0f, 1}, + {240.0f, 1}, + {300.0f, 0}, + {600.0f, 1} //临时版本发1 原来发2 + }; + bool is_equal(float l, float r) + { + return fabs(l - r) < .000001f; + } + int match_best_resolution(int resolution, bool* exact) + { + int rsl = resolution, + ind = 0; + bool good = true, *r = exact ? exact : &good; + + if (rsl <= resolution_map[0].resolution) + { + ind = 0; + } + else if (rsl >= resolution_map[ARRAY_SIZE(resolution_map) - 1].resolution) + { + ind = ARRAY_SIZE(resolution_map) - 1; + } + else + { + for (int i = 1; i < ARRAY_SIZE(resolution_map); ++i) + { + if (is_equal(rsl, resolution_map[i].resolution)) + { + ind = i; + break; + } + if (rsl < resolution_map[i].resolution) + { + float dif_l = rsl - resolution_map[i - 1].resolution, + dif_r = resolution_map[i].resolution - rsl; + + if (dif_l > dif_r) + ind = i; + else + ind = i - 1; + break; + } + } + } + + *r = is_equal(rsl, resolution_map[ind].resolution); + + return ind; + } +enum PaperSize_ +{ + G400_A3 = 0, + G400_A4, + G400_A4R, + G400_A5, + G400_A5R, + G400_A6, + G400_A6R, + G400_B4, + G400_B5, + G400_B5R, + G400_B6, + G400_B6R, + G400_DOUBLELETTER, + G400_LEGAL, + G400_LETTER, + G400_LETTERR, + G400_LONGLETTER = 16, + G400_MAXSIZE = 16, + G400_AUTO = 16, + G400_MAXAUTO = 16 +}; + // paper + static struct + { + int paper; + TwSS type; + int dev_value; + }paper_map[] = + { + {PAPER_A3, TwSS::A3, PaperSize_::G400_A3}, + {PAPER_8K, TwSS::K8, 0}, + {PAPER_A4, TwSS::A4, PaperSize_::G400_A4}, + {PAPER_A4_LATERAL, TwSS::A4, PaperSize_::G400_A4R}, + {PAPER_16K, TwSS::K16, 0}, + {PAPER_16K_LATERAL, TwSS::K16, 0}, + {PAPER_A5, TwSS::A5, PaperSize_::G400_A5}, + {PAPER_A5_LATERAL, TwSS::A5, PaperSize_::G400_A5R}, + {PAPER_A6, TwSS::A6, PaperSize_::G400_A6}, + {PAPER_A6_LATERAL, TwSS::A6, PaperSize_::G400_A6R}, + {PAPER_B4, TwSS::B4, PaperSize_::G400_B4}, + {PAPER_B5, TwSS::B5, PaperSize_::G400_B5}, + {PAPER_B5_LATERAL, TwSS::B5, PaperSize_::G400_B5R}, + {PAPER_B6, TwSS::B6, PaperSize_::G400_B6}, + {PAPER_B6_LATERAL, TwSS::B6, PaperSize_::G400_B6R}, + {PAPER_LETTER, TwSS::USLetter, PaperSize_::G400_LETTER}, + {PAPER_LETTER_LATERAL, TwSS::USLetter, PaperSize_::G400_LETTERR}, + {PAPER_DOUBLE_LETTER, TwSS::USLedger, PaperSize_::G400_DOUBLELETTER}, + {PAPER_LEGAL, TwSS::USLegal, PaperSize_::G400_LEGAL}, + {PAPER_AUTO_MATCH, TwSS::None, 0}, + {PAPER_MAX_SIZE_CLIP, TwSS::USStatement, PaperSize_::G400_MAXAUTO}, + {PAPER_MAX_SIZE, TwSS::MaxSize, PaperSize_::G400_MAXSIZE}, + {PAPER_TRIGEMINY, TwSS::Trigeminy, 16} + }; + int match_best_paper(int& paper, bool* exact, TwSS* type) + { + int ind = 0; + bool good = true, * r = exact ? exact : &good; + + for (int i = 0; i < ARRAY_SIZE(paper_map); ++i) + { + if (paper == paper_map[i].paper) + { + ind = i; + break; + } + } + + if (paper == paper_map[ind].paper) + *r = true; + else + *r = false; + VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Paper '%s' index = %d, device value = %d\n", paper_string(paper).c_str(), ind, paper_map[ind].dev_value); + paper = paper_map[ind].paper; + if (type) + *type = paper_map[ind].type; + + return ind; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class ... +hg_scanner_439::hg_scanner_439(const char* dev_name, int pid,usb_io* io) : hg_scanner(G20039Serial, dev_name, io) + , rewrite_conf_(false), reset_(false),pid_(pid) +{ + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "hg_scanner_439(%s) constructing ...\n", hg_log::format_ptr(this).c_str()); + dev_conf_.value = 0; +#ifndef MAPPING_FUNCTION_IN_BASE + init_setting_map(setting_map_, ARRAY_SIZE(setting_map_)); +#endif + init_settings(jsontext.c_str()); + writedown_device_configuration(); // initialize the hardware settings + init_version(); +} +hg_scanner_439::~hg_scanner_439() +{ + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "hg_scanner_439(%s) destroyed.\n", hg_log::format_ptr(this).c_str()); +} + +int hg_scanner_439::read_register(int addr, int* val) +{ + std::lock_guard lock(io_lock_); + + int l = sizeof(*val), + ret = io_->control_io(0x0c0, USB_REQ_GET_DEV_REGS, addr, 0, val, &l); + + if (ret) + status_ = ret; + + return ret; +} +int hg_scanner_439::write_register(int addr, int val) +{ + std::lock_guard lock(io_lock_); + + int l = sizeof(val), + ret = io_->control_io(0x040, USB_REQ_SET_DEV_REGS, addr, 0, &val, &l); + + if (ret) + status_ = ret; + + return ret; +} +int hg_scanner_439::write_command(int cmd) +{ + return write_register(0, cmd); +} +std::string hg_scanner_439::control_fetch(int addr, int val, int size) +{ + int l = sizeof(val), + ret = 0; + std::string data(""); + + ret = write_register(addr, val); + if (ret == SCANNER_ERR_OK) + { + std::lock_guard lock(io_lock_); + + l = size + 1; + data.resize(size + 2); + bzero(&data[0], size + 2); + ret = io_->read_bulk(&data[0], &l); + if (ret) + { + VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "control_fetch(%d, %d) - read_bulk = %s\n", addr, val, hg_scanner_err_name(ret)); + data.clear(); + } + } + else + VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "control_fetch(%d, %d) = %s\n", addr, val, hg_scanner_err_name(ret)); + + return data; +} + +std::string hg_scanner_439::get_fpga(void) +{ + int val = 0, + ret = read_register(SR_GET_MBVERSION_LENGHT, &val); + std::string fpga(""); + + if (ret == SCANNER_ERR_OK) + { + fpga.resize(val + 2); + bzero(&fpga[0], val + 2); + + return control_fetch(SR_GET_MBVERSION, 0, val); + } + + return fpga; +} +int hg_scanner_439::clr_roller_num(void) +{ + int val = 0, + ret = read_register(SR_CLR_ROLLER_NUM, &val); + + if (ret == SCANNER_ERR_OK) + return val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "clr_roller_num = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} +int hg_scanner_439::get_sleep_time(void) +{ + int val = 0, + ret = read_register(SR_GET_SLEEPTIME, &val); + + if (ret == SCANNER_ERR_OK) + return val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_sleep_time = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} +int hg_scanner_439::get_scan_mode(void) +{ + int val = 0, + ret = read_register(SR_OS, &val); + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get scan mode error: %s\n", hg_scanner_err_name(ret)); + status_ = ret; + + return -1; + } + else + return val; +} +int hg_scanner_439::get_status(void) +{ + int val = 0, + ret = read_register(SR_STATUS, &val); + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get status error: %s\n", hg_scanner_err_name(ret)); + status_ = ret; + + return -1; + } + else + return val; +} +bool hg_scanner_439::is_dev_tx(void) +{ + int val = 0, + ret = read_register(SR_STATUS, &val); + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "is_dev_tx() error: %s\n", hg_scanner_err_name(ret)); + status_ = ret; + + return false; + } + else + return val; +} +bool hg_scanner_439::is_dev_image_process_done(void) +{ + int val = 0, + ret = read_register(SR_GET_IMAGEPROCESSDONE, &val); + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "is_dev_image_process_done() error: %s\n", hg_scanner_err_name(ret)); + status_ = ret; + + return true; + } + else + return val; +} +bool hg_scanner_439::is_dev_image_keep_last_paper(void) +{ + + int val = 0, + ret = read_register(SR_GET_KEEP_LAST_PAPER, &val); + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "is_dev_image_keep_last_paper() error: %s\n", hg_scanner_err_name(ret)); + status_ = ret; + + return true; + } + else + return val; +} +int hg_scanner_439::get_scanned_count(void) +{ + int val = 0, + ret = read_register(SR_GET_SCANN_NUM, &val); + + if (ret == SCANNER_ERR_OK) + return val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_scanned_count = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} +int hg_scanner_439::get_image_count(void) +{ + int val = 0, + ret = read_register(SR_IM_COUNT, &val); + + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "get_image_count() = %d, error: %s\n", val, hg_scanner_err_name(ret)); + + if (ret == SCANNER_ERR_OK) + return val; + else + return -1; +} +int hg_scanner_439::get_front_data_size(void) +{ + int val = 0, + ret = read_register(SR_IM_FRONT_SIZE, &val); + + if (ret == SCANNER_ERR_OK) + return val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_front_data_size = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} +void hg_scanner_439::init_version(void) +{ + std::string fv(get_firmware_version()), + sn(get_serial_num()); + + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " HG3399 firmware version: %s\n", fv.c_str()); + //VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " HG3399 serial number: %s\n", sn.c_str()); + //VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " HG3399 IP: %s\n", get_ip().c_str()); + + if (fv.length() >= 10 && (fv[5] > 'A' || atoi(fv.substr(6, 4).c_str()) >= 1209)) + { + is_kernelsnap_211209_ = atoi(get_fpga().c_str()) >= 35211210; + } + else + is_kernelsnap_211209_ = false; +} +void hg_scanner_439::image_process(std::shared_ptr& buff) +{ + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Process image with %u bytes content ...\n", buff->size()); + + hg_imgproc::HIMGPRC handle = get_image_process_object(pid_); + hg_imgproc::IMGHEAD ih; + int err = SCANNER_ERR_OK, + index = 0; + void* buf = NULL; + + err = hg_imgproc::load_buffer(handle, buff); + err = hg_imgproc::decode(handle,pid_); + + if(image_prc_param_.bits.erase_bakground && !user_cancel_) + { + err = hg_imgproc::fadeback(handle,img_conf_.fadebackrange,img_conf_.is_duplex); + } + + if (image_prc_param_.bits.rid_red && img_conf_.pixtype == COLOR_MODE_24_BITS) + err = hg_imgproc::multi_out_red(handle); + + if (image_prc_param_.bits.split && !user_cancel_) + { + split3399_++; + int colormode=1; + if(img_conf_.filter == RID_COLOR_NONE) + colormode=img_conf_.pixtype; + + err = hg_imgproc::split(handle,img_conf_.multiOutput,img_conf_.splitImage,img_conf_.multi_output_red,colormode,img_conf_.is_duplex,split3399_); + VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "img split-> multiOutput is:%d splitImage is:%d multi_output_red is:%d pixtype is:%d is_duplex:%d\r\n" + ,img_conf_.multiOutput + ,img_conf_.splitImage + ,img_conf_.multi_output_red + ,img_conf_.pixtype + ,img_conf_.is_duplex); + } + + if (!image_prc_param_.bits.split || !image_prc_param_.bits.rid_red || !is_multiout) + { + if(img_conf_.automaticcolor) + { + hg_imgproc::auto_matic_color(handle,img_conf_.automaticcolortype); + } + } + if (img_conf_.is_autotext) + { + printf("文本方向自动识别\r\n"); + hg_imgproc::ocr_auto_txtdirect(handle); + } + if (is_quality_ == IMG_SPEED && resolution_ >= 300) + { + err = hg_imgproc::quality(handle,resolution_); + } + //多流输出最后处理 + if (is_multiout) + { + int multi_out = image_prc_param_.bits.multi_out; + err = hg_imgproc::multi_out(handle,multi_out); + } + hg_imgproc::final(handle); + + while (hg_imgproc::get_final_data(handle, &ih, &buf, index++) == SCANNER_ERR_OK && !user_cancel_) + { + VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "Final picture %d (%d * %d * %d) with %u bytes!\n", index + , ih.width, ih.height, ih.bits * ih.channels, ih.total_bytes); + + if(!img_type_.empty()) + { + std::vectorbmpdata; + + hg_imgproc::imgtypechange(handle,img_type_,buf,bmpdata); + //cv::imencode(img_type_,*((cv::Mat*)buf),bmpdata); + if(bmpdata.empty()) + { + status_ = SCANNER_ERR_NO_DATA; + return ; + } + buf = bmpdata.data(); + ih.total_bytes = bmpdata.size(); + + VLOG_MINI_6(LOG_LEVEL_DEBUG_INFO, "Set img type is:%s Final picture %d (%d * %d * %d) with %u bytes!\n",img_type_.c_str() ,index + , ih.width, ih.height, ih.bits * ih.channels, ih.total_bytes); + } + save_final_image(&ih, buf); + } + + hg_imgproc::release(handle); +} + +int hg_scanner_439::get_device_sleep_stautus(void) +{ + int ret =read_register(SR_GET_SLEEP_STAUTUS,0); + return ret; +} + +int hg_scanner_439::get_device_paperon_stautus(void) +{ + int ret =read_register(SR_GET_PAPERON,0); + return ret; +} +// int hg_scanner_439::writedown_device_configuration() +// { +// int ret = SCANNER_ERR_OK; + + +// ret = write_register(SR_CONFIG_SCAN_PARAM, dev_conf_.value); +// VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Writedown scanner configuration(0x%x) = %s\n", dev_conf_.value, hg_scanner_err_name(ret)); + +// return ret; +// } + +int hg_scanner_439::writedown_device_configuration(HGSCANCONF *dev_conf) +{ + int ret = SCANNER_ERR_OK; + + if(!dev_conf) + dev_conf = &dev_conf_; + + ret = write_register(SR_CONFIG_SCAN_PARAM, dev_conf->value); + + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Writedown scanner configuration(0x%x) = %s\n", dev_conf->value, hg_scanner_err_name(ret)); + return ret; +} + +int hg_scanner_439::writedown_image_configuration(void) +{ + int ret = write_register(SR_CONFIF_IMGPROCPARAM, sizeof(SCANCONF)); + if (ret != SCANNER_ERR_OK) + return ret; + + SCANCONF ic; + int len = sizeof(ic); + + bzero(&ic, len); + + ic.papertype = paper_size_; + + if (is_lateral(image_prc_param_.bits.paper)) + ic.paperAlign = Rot270; + // else if (image_prc_param_.bits.text_direction == TEXT_DIRECTION_AUTO) + // ic.paperAlign = AutoTextOrientation; + else + ic.paperAlign = Rot0; + + ic.en_sizecheck = dev_conf_.g200params.enable_sizecheck; + + if (image_prc_param_.bits.text_direction != TEXT_DIRECTION_AUTO) + ic.imageRotateDegree = (float)image_prc_param_.bits.text_direction; + else + ic.imageRotateDegree = 0; + + ic.imageRotateDegree *= 90.0f; + + ic.is_duplex = (image_prc_param_.bits.page == PAGE_DOUBLE + || image_prc_param_.bits.page == PAGE_OMIT_EMPTY + || image_prc_param_.bits.page == PAGE_OMIT_EMPTY_RECEIPT + || image_prc_param_.bits.page ==PAGE_FOLIO); + + ic.en_fold = (image_prc_param_.bits.page == PAGE_FOLIO); + ic.pixtype = image_prc_param_.bits.color_mode == COLOR_MODE_AUTO_MATCH ? 2 : image_prc_param_.bits.color_mode; + ic.automaticcolor = is_auto_matic_color; + + ic.automaticcolortype = 1;// ic.pixtype; //存疑 + if (resolution_ >= 300) + { + if(is_quality_ == IMG_SPEED) + { + ic.resolution_dst = 200; + } + else if(is_quality_ ==IMG_QUALITY) + { + ic.resolution_dst = resolution_; + } + } + else + { + ic.resolution_dst = resolution_; + } + + ic.resolution_native = 200.0f; + ic.gamma = (float)gamma_; + ic.contrast = (contrast_ - 4) * 333.0; + ic.brightness = (bright_ - 128) * (2000.0 / 254.0); + ic.threshold = threshold_; + ic.is_autocontrast = 0; //无参数 + ic.is_autocrop = (ic.papertype == TwSS::None || ic.papertype ==TwSS::USStatement); + ic.is_autodiscradblank_normal = image_prc_param_.bits.page == PAGE_OMIT_EMPTY; + ic.discardblank_percent = omit_empty_level_ >= 70 ? 70 : omit_empty_level_; + 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.hsvcorrect = image_prc_param_.bits.rid_answer_red; + ic.sharpen = image_prc_param_.bits.sharpen; + ic.enhance_color = image_prc_param_.bits.rid_color; + ic.fillbackground = image_prc_param_.bits.erase_black_frame; + ic.is_convex = (image_prc_param_.bits.fill_background == FILL_BKG_CONVEX_POLYGON); + ic.noise = image_prc_param_.bits.noise_optimize; + ic.indent = margin_; + ic.AutoCrop_threshold = threshold_; + if (test_1_paper_) + { + LOG_INFO(LOG_LEVEL_DEBUG_INFO, "scanning mode: testing ONE paper ...\n"); + ic.scannum = ic.is_duplex ? 2 : 1; + } + else + { + ic.scannum = (ic.is_duplex ? scan_count_ * 2 : scan_count_); + } + ic.is_backrotate180 = image_prc_param_.bits.rotate_back_180; + ic.is_dogeardetection = image_prc_param_.bits.fractate_check; + ic.hardwarecaps.en_skrewdetect = dev_conf_.g200params.screw_detect_enable; + ic.hardwarecaps.en_doublefeed = dev_conf_.g200params.ultrasonic_enable; + ic.hardwarecaps.en_stapledetect = dev_conf_.g200params.staple_enbale; + ic.hardwarecaps.skrewdetectlevel = dev_conf_.g200params.screw_detect_level; + // ic.hardwarecaps.is_autopaper = dev_conf_.g200params.is_autopaper; + ic.hardwarecaps.capturepixtype = 0; //暂无参数 获取图像类型 + ic.hardwarecaps.lowpowermode = LowPowerMode::Min_None; //暂无参数 设置休眠时间 两个参数3399未使用 + ic.fillhole.is_fillhole = image_prc_param_.bits.rid_hole; + ic.fillhole.fillholeratio = rid_hole_range_; + ic.detachnoise.is_detachnoise = image_prc_param_.bits.noise_optimize; + ic.detachnoise.detachnoise = noise_range_; + ic.is_autotext = image_prc_param_.bits.text_direction == TEXT_DIRECTION_AUTO ? 1 :0; + ic.isfillcolor = is_color_fill; + ic.refuseInflow = image_prc_param_.bits.is_permeate; + ic.colorCorrection = 0; + ic.removeMorr = image_prc_param_.bits.remove_morr; + ic.errorExtention = image_prc_param_.bits.error_extention ;// + ic.textureRemove = image_prc_param_.bits.remove_txtture;// + ic.splitImage = image_prc_param_.bits.split; +{ + ic.cropRect.enable = custom_area_; + int height = (custom_area_br_y_ *ic.resolution_dst) /25.4 - (custom_area_lt_y_ *ic.resolution_dst /25.4); + int width = (custom_area_br_x_ *ic.resolution_dst) /25.4 - (custom_area_lt_x_ *ic.resolution_dst /25.4); + ic.cropRect.height = height; + ic.cropRect.width = width; + ic.cropRect.x = custom_area_lt_x_ *ic.resolution_dst /25.4; + ic.cropRect.y = custom_area_lt_y_ *ic.resolution_dst /25.4; +} + ic.multiOutput = (MultiOutput)image_prc_param_.bits.multi_out; + ic.normalCrop = image_prc_param_.bits.dark_sample; + ic.dogeardistabce = fractate_level_; + ic.fadeback = image_prc_param_.bits.erase_bakground; + ic.fadebackrange = erase_bkg_range_; + + int filter_clr[] = { 3, 0, 1, 2, 5, 6, 7 }; + if(image_prc_param_.bits.color_mode == COLOR_MODE_24_BITS || image_prc_param_.bits.color_mode == COLOR_MODE_AUTO_MATCH) + ic.filter = 3; + else + { + ic.filter = filter_clr[image_prc_param_.bits.rid_color]; + // if(ic.filter != 3) + // ic.pixtype = 2; + + ic.hsvcorrect = 0; + ic.multi_output_red = 0; + ic.multiOutput = MultiOutput::Unused; + + } + //多留输出的处理 + if (image_prc_param_.bits.multi_out == MULTI_GRAY_AND_BW && is_multiout) + { + ic.pixtype = 1; + } + else if ((image_prc_param_.bits.multi_out == MULTI_OUT_ALL ||image_prc_param_.bits.multi_out == MULTI_COLOR_AND_GRAY||image_prc_param_.bits.multi_out == MULTI_COLOR_AND_BW) && is_multiout) + { + ic.pixtype = 2; + + } + if (is_multiout) + { + ic.hsvcorrect = 0; + ic.multi_output_red = 0; + ic.fadeback = false; + ic.sharpen = 0; + ic.removeMorr = 0; + ic.textureRemove = 0; + + ic.errorExtention = 0; + ic.detachnoise.is_detachnoise = 0; + } + if (ic.pixtype == 0) + { + ic.hsvcorrect = 0; + ic.multi_output_red = 0; + ic.fadeback = false; + ic.sharpen = 0; + ic.removeMorr = 0; + ic.textureRemove = 0; + } + + //自定义裁切 + if (image_prc_param_.bits.paper == PAPER_AUTO_MATCH + ||image_prc_param_.bits.paper == PAPER_MAX_SIZE + ||image_prc_param_.bits.paper == PAPER_MAX_SIZE_CLIP + ||image_prc_param_.bits.paper == PAPER_TRIGEMINY + ) + { + ic.cropRect.enable = false; + } + + { + std::lock_guard lock(io_lock_); + + ret = io_->write_bulk(&ic, &len); + + this_thread::sleep_for(chrono::milliseconds(500)); + io_->set_timeout(2000);//必要延时 + } + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Write-down 0x%x bytes image process parameters\n", len); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.pixtype=%d", ic.pixtype); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.papertype=%d", ic.papertype); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.AutoCrop_threshold=%d", ic.AutoCrop_threshold); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.autodescrew=%d", ic.autodescrew); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.automaticcolor=%d", ic.automaticcolor); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.brightness=%f", ic.brightness); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.contrast=%f", ic.contrast); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.en_fold=%d", ic.en_fold); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.en_sizecheck=%d", ic.en_sizecheck); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.enhance_color=%d", ic.enhance_color); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.fillbackground=%d", ic.fillbackground); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.filter=%d", ic.filter); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.gamma=%f", ic.gamma); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.hardwarecaps.capturepixtype=%d", ic.hardwarecaps.capturepixtype); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.hardwarecaps.en_doublefeed=%d", ic.hardwarecaps.en_doublefeed); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.hsvcorrect=%d", ic.hsvcorrect); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.imageRotateDegree=%f", ic.imageRotateDegree); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.indent=%d", 5); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_autocontrast=%d", ic.is_autocontrast); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_autocrop=%d", ic.is_autocrop); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_autodiscradblank_normal=%d", ic.is_autodiscradblank_normal); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_autodiscradblank_vince=%d", ic.is_autodiscradblank_vince); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_autotext=%d", ic.is_autotext); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_backrotate180=%d", ic.is_backrotate180); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_convex=%d", ic.is_convex); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_duplex=%d", ic.is_duplex); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_switchfrontback=%d", ic.is_switchfrontback); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.is_dogeardetection=%d", ic.is_dogeardetection); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.fillhole.multi_output_red=%d", ic.multi_output_red); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.noise=%d", 8); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.pixtype=%d", ic.pixtype); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.resolution_dst=%f", ic.resolution_dst); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.resolution_native=%f", ic.resolution_native); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.scannum=%d", ic.scannum); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.sharpen=%d", ic.sharpen); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.discardblank_percent=%d", ic.discardblank_percent); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.detachnoise.is_detachnoise=%d", ic.detachnoise.is_detachnoise); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.detachnoise.detachnoise=%d\r ", ic.detachnoise.detachnoise); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.detachnoise.refuseInflow=%d\r ", ic.refuseInflow); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.detachnoise.refuseInflow=%d\r ", ic.refuseInflow); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.removeMorr=%d\r ", ic.removeMorr); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.errorExtention=%d\r ", ic.errorExtention); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.textureRemove=%d\r\n ", ic.refuseInflow); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.fillhole.is_fillhole=%d\r\n ", ic.fillhole.is_fillhole); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.ic.fillhole.fillholeratio=%d\r\n ", ic.fillhole.fillholeratio); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.fadeback=%d\r\n ",ic.fadeback); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.cropRect.enable=%d\r ", ic.cropRect.enable); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.cropRect.width=%d\r\n ", ic.cropRect.width); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.cropRect.height=%d\r\n ", ic.cropRect.height); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.cropRect.x=%f\r\n ", ic.cropRect.x); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"\n ic.cropRect.y=%d\r\n ",ic.cropRect.y); + + img_conf_ = ic; + return ret; +} + +int hg_scanner_439::pop_first_image(void) +{ + int ret = write_register(SR_IM_POP, 1); + + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "popup first image = %s\n", hg_scanner_err_name(ret)); + + return ret; +} + +int hg_scanner_439::read_one_image_from_usb(void) +{ + //if (is_dev_tx()) + // return SCANNER_ERR_OK; + + //if (!is_kernelsnap_211209_) + //{ + // if (image_prc_param_.bits.page == PAGE_DOUBLE && !image_prc_param_.bits.fractate_check) + // if (get_image_count() < 3) + // return SCANNER_ERR_DEVICE_NO_IMAGE; + // if (get_image_count() < 2) + // return SCANNER_ERR_DEVICE_NO_IMAGE; + //} + int r = 0, + total = get_front_data_size(), + off = 0, + ret = SCANNER_ERR_OK; + + if (!waiting_for_memory_enough(total)) + { + status_ = SCANNER_ERR_INSUFFICIENT_MEMORY; + + return status_; + } + if (user_cancel_) + return SCANNER_ERR_USER_CANCELED; + + if (total == -1) + ret = status_; + else + { + std::shared_ptr buf(aquire_memory(total)); + if (!buf.get()) + return SCANNER_ERR_INSUFFICIENT_MEMORY; + + // write reading command + ret = write_register(SR_IM_TX, 1); + + if (ret == SCANNER_ERR_OK) + { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + r = total; + { + std::lock_guard lock(io_lock_); + + unsigned int size = r; + void* buff = buf->data(off, &size); + int block = 0; + if (!buff) + { + VLOG_MINI_3(LOG_LEVEL_FATAL, "memory(0x%08x + %u) fatal when read USB image %d !!!\n", off, r, usb_img_index_); + ret = SCANNER_ERR_INSUFFICIENT_MEMORY; + } + else + { + r = size; + while (r > 0) + { + block = 512 * 1024; + + if (r < block) + block = r; + + unsigned int size = block; + void* buff = buf->data(off, &size); + if (!buf) + { + //VLOG_MINI_3(LOG_LEVEL_FATAL, "memory(0x%08x + %u) fatal when read USB image %d !!!\n", index, block, usb_img_index_); + ret = SCANNER_ERR_INSUFFICIENT_MEMORY; + break; + } + block = size; + ret = io_->read_bulk(buff, &block); + if (ret != SCANNER_ERR_OK) + break; + + off += block; + r -= block; + } + } + } + if (ret == SCANNER_ERR_OK) + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Read image from USB = %s\n", hg_scanner_err_name(ret)); + ret = save_usb_data(buf); + if (ret == SCANNER_ERR_OK) + { + pop_first_image(); + //if(image_prc_param_.bits.page == PAGE_SINGLE) + // pop_first_image(); + } + } + else + { + char msg[128]; + sprintf(msg, "Read image data from USB err: %s\n", hg_scanner_err_name(ret)); + LOG_INFO(LOG_LEVEL_DEBUG_INFO, msg); + notify_ui_working_status(msg); + notify_ui_working_status(STATU_DESC_SCANNER_ERR_TIMEOUT, SANE_EVENT_ERROR); + } + } + } + + return ret; +} +void hg_scanner_439::discard_all_images(void) +{ + char buf[64]; + HGEIntInfo* info = (HGEIntInfo*)buf; + int size = sizeof(buf), + oto = 0, + pre_img = 0, + pre_int = 0, + ret = SCANNER_ERR_OK; + + { + std::lock_guard lock(io_lock_); + oto = io_->get_timeout(); + io_->set_timeout(100); + ret = io_->read_interrupt(buf, &size); + } + while (ret == SCANNER_ERR_OK) + { + pre_int++; + if (info->From == IMG) + { + while (get_image_count() > 0) + { + pop_first_image(); + pre_img++; + } + } + + size = sizeof(buf); + { + std::lock_guard lock(io_lock_); + ret = io_->read_interrupt(buf, &size); + } + } + { + std::lock_guard lock(io_lock_); + io_->set_timeout(oto); + } + if (pre_int) + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "prev-connection has left %d interrupt packet(s) && %d image(s).\n", pre_int, pre_img); +} + +//color_mode =-1 除色选项 +int hg_scanner_439::on_color_mode_changed(int& color_mode) +{ + int ret = SCANNER_ERR_OK; + + if ((((color_mode == COLOR_MODE_24_BITS || color_mode == COLOR_MODE_AUTO_MATCH) && !dev_conf_.g200params.color) || + ((color_mode != COLOR_MODE_24_BITS && color_mode != COLOR_MODE_AUTO_MATCH) && dev_conf_.g200params.color)) && color_mode != -1) + { + dev_conf_.g200params.color ^= 1; + ret = writedown_device_configuration(); + if(ret) + dev_conf_.g200params.color ^= 1; + } + if(color_mode == COLOR_MODE_AUTO_MATCH) + { + dev_conf_.g200params.color = 1; + } + + HGSCANCONF d = dev_conf_; + + if (image_prc_param_.bits.rid_color != RID_COLOR_NONE + &&(image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) + ) + { + d.g200params.color = 1; + ret = writedown_device_configuration(&d); + } + + if(image_prc_param_.bits.rid_color != RID_COLOR_NONE + && (image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) + && color_mode == -1) + { + d.g200params.color = 1; + } + else if (image_prc_param_.bits.rid_color == RID_COLOR_NONE + && (image_prc_param_.bits.color_mode == COLOR_MODE_256_GRAY || image_prc_param_.bits.color_mode == COLOR_MODE_BLACK_WHITE) + && color_mode == -1) + { + d.g200params.color = 0; + } + if(color_mode == -1) + ret = writedown_device_configuration(&d); + + return ret; +} +int hg_scanner_439::on_paper_changed(int& paper) +{ + bool exact = true; + int ind = settings::match_best_paper(paper, &exact, &paper_size_), + ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; + + if (dev_conf_.g200params.paper != settings::paper_map[ind].dev_value) + { + int old = dev_conf_.g200params.paper; + + dev_conf_.g200params.paper = settings::paper_map[ind].dev_value; + ret = writedown_device_configuration(); + if (ret) + { + dev_conf_.g200params.paper = old; + for (int i = 0; i < ARRAY_SIZE(settings::paper_map); ++i) + { + if (settings::paper_map[i].dev_value == old) + { + paper = settings::paper_map[i].paper; + break; + } + } + } + else if (!exact) + ret = SCANNER_ERR_NOT_EXACT; + } + + return ret; +} +int hg_scanner_439::on_paper_check_changed(bool& check) +{ + int ret = SCANNER_ERR_OK; + + if (dev_conf_.g200params.enable_sizecheck ^ check) + { + dev_conf_.g200params.enable_sizecheck = check; + ret = writedown_device_configuration(); + + if (ret) + { + dev_conf_.g200params.enable_sizecheck = !check; + check = dev_conf_.g200params.enable_sizecheck; + } + } + if (image_prc_param_.bits.paper == PAPER_AUTO_MATCH + ||image_prc_param_.bits.paper == PAPER_MAX_SIZE + ||image_prc_param_.bits.paper == PAPER_MAX_SIZE_CLIP + ||image_prc_param_.bits.paper == PAPER_TRIGEMINY + ||image_prc_param_.bits.paper == PAPER_16K + ||image_prc_param_.bits.paper == PAPER_8K + ||image_prc_param_.bits.paper == PAPER_16K_LATERAL + ) + { + HGSCANCONF *d = &dev_conf_; + d->g200params.enable_sizecheck = false; + ret = writedown_device_configuration(d); + } + + + return ret; +} +int hg_scanner_439::on_resolution_changed(int& dpi) +{ + bool exact = true; + int ind = settings::match_best_resolution(dpi, &exact), + ret = exact ? SCANNER_ERR_OK : SCANNER_ERR_NOT_EXACT; + + if (dev_conf_.g200params.dpi != settings::resolution_map[ind].dev_value) + { + int old = dev_conf_.g200params.dpi; + dev_conf_.g200params.dpi = settings::resolution_map[ind].dev_value; + dev_conf_.g200params.dpi = 1; + ret = writedown_device_configuration(); + if (ret) + { + dev_conf_.g200params.dpi = old; + } + else if (!exact) + ret = SCANNER_ERR_NOT_EXACT; + } + + if (ret == SCANNER_ERR_NOT_EXACT) + dpi = settings::resolution_map[ind].resolution; + + + + return ret; +} + +int hg_scanner_439::on_ultrasonic_check_changed(bool& check) +{ + int ret = SCANNER_ERR_OK; + + if (dev_conf_.g200params.ultrasonic_enable ^ check) + { + dev_conf_.g200params.ultrasonic_enable = check; + ret = writedown_device_configuration(); + if (ret) + { + dev_conf_.g200params.ultrasonic_enable = !check; + check = dev_conf_.g200params.ultrasonic_enable; + } + } + + return ret; +} +int hg_scanner_439::on_staple_check_changed(bool& check) +{ + int ret = SCANNER_ERR_OK; + + if (dev_conf_.g200params.staple_enbale ^ check) + { + dev_conf_.g200params.staple_enbale = check; + ret = writedown_device_configuration(); + if (ret) + { + dev_conf_.g200params.staple_enbale = !check; + check = dev_conf_.g200params.staple_enbale; + } + } + + return ret; +} +int hg_scanner_439::on_skew_check_changed(bool& check) +{ + int ret = SCANNER_ERR_OK; + + if (dev_conf_.g200params.screw_detect_enable ^ check) + { + dev_conf_.g200params.screw_detect_enable = check; + ret = writedown_device_configuration(); + if (ret) + { + dev_conf_.g200params.screw_detect_enable = !check; + check = dev_conf_.g200params.screw_detect_enable; + } + } + + return ret; +} +int hg_scanner_439::on_skew_check_level_changed(int& check) +{ + int ret = SCANNER_ERR_OK, + val = check, + old = dev_conf_.g200params.screw_detect_level; + HGSCANCONF cf; + + cf.g200params.screw_detect_level = -1; + + if (val < 0) + { + val = 0; + ret = SCANNER_ERR_NOT_EXACT; + } + else if (val > cf.g200params.screw_detect_level) + { + val = cf.g200params.screw_detect_level; + ret = SCANNER_ERR_NOT_EXACT; + } + if (val != dev_conf_.g200params.screw_detect_level) + { + dev_conf_.g200params.screw_detect_level = val; + ret = writedown_device_configuration(); + if (ret) + check = dev_conf_.g200params.screw_detect_level = old; + } + if (ret == SCANNER_ERR_OK && val != check) + { + check = val; + ret = SCANNER_ERR_NOT_EXACT; + } + + return ret; +} + +void hg_scanner_439::on_device_reconnected(void) +{ + int ret = writedown_device_configuration(); + init_version(); + + rewrite_conf_ = ret != SCANNER_ERR_OK; + if (reset_) + { + reset_ = false; + start(); + } +} +int hg_scanner_439::on_scanner_closing(bool force) +{ + return SCANNER_ERR_OK; +} + +void hg_scanner_439::thread_handle_usb_read(void) +{ + char buf[64]; + HGEIntInfo* info = (HGEIntInfo*)buf; + int size = sizeof(buf), + ret = SCANNER_ERR_OK, + to_cnt = 0, + count = 0; + + //status_ = SCANNER_ERR_DEVICE_BUSY; + while (run_ )//&& !user_cancel_ + { + if (user_cancel_) + { + break; + } + size = sizeof(buf); + { + std::lock_guard lock(io_lock_); + + ret = io_->read_interrupt(buf, &size); + io_->set_timeout(1000); + } + if (ret == SCANNER_ERR_TIMEOUT) + { + if (img_conf_.resolution_dst == 600.0 && ++to_cnt > 50) + { + status_ = ret; + notify_ui_working_status("通信超时", SANE_EVENT_ERROR, ret); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "600dpi '%s'\n", hg_scanner_err_name(status_)); + break; + } + else if (img_conf_.resolution_dst != 600.0 &&++to_cnt > 20) + { + status_ = ret; + notify_ui_working_status("通信超时", SANE_EVENT_ERROR, ret); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "其他dpi '%s'\n", hg_scanner_err_name(status_)); + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + if ((get_status() & 0x03) == 0) + { + status_ = SCANNER_ERR_OK; + break; + } + continue; + } + else if (ret != SCANNER_ERR_OK) + { + status_ = ret; + break; + } + + to_cnt = 0; + if (size == sizeof(buf)) + { + status_ = settings::device_status_to_hg_err(info); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "status from interrupt point is '%s'\n", hg_scanner_err_name(status_)); + + if (status_ != SCANNER_ERR_OK && status_ != SCANNER_ERR_TIMEOUT && status_ != SCANNER_ERR_DEVICE_STOPPED) + { + if (!is_dev_image_process_done()) + { + int st = status_; + while (!is_dev_image_process_done()) + std::this_thread::sleep_for(std::chrono::milliseconds(30)); + + while (get_image_count() > 0) + { + ret = read_one_image_from_usb(); + count++; + if (ret != SCANNER_ERR_OK + && ret != SCANNER_ERR_CREATE_FILE_FAILED + && ret != SCANNER_ERR_WRITE_FILE_FAILED) + break; + } + status_ = st; + } + VLOG_MINI_1(LOG_LEVEL_WARNING, "扫描失败, read interrupt返回状态为:%s\n", hg_scanner_err_description(status_)); + //notify_ui_working_status(("扫描失败 " + hg_scanner::error_description((scanner_err)status_)).c_str(), SANE_EVENT_ERROR, status_); + break; + } + + if (info->From == IMG) + { + int s = get_status(); + // if (s > 0 && s < 4) // running ... + { + while (get_image_count() > 0) + { + count++; + ret = read_one_image_from_usb(); + if (ret != SCANNER_ERR_OK + && ret != SCANNER_ERR_CREATE_FILE_FAILED + && ret != SCANNER_ERR_WRITE_FILE_FAILED) + break; + } + if (user_cancel_) + { + if (ret == SCANNER_ERR_INSUFFICIENT_MEMORY) + stop(); + status_ = ret = SCANNER_ERR_USER_CANCELED; + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "用户取消操作 '%s'\n", hg_scanner_err_name(status_)); + break; + } + } + //else + // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "status(0x%x) is not accept in usb thread\n", status); + } + else if (info->From == STOPSCAN) + { + LOG_INFO(LOG_LEVEL_DEBUG_INFO, "received 'STOPSCAN' message in usb thread, check remaining image and finish scanning ...\n"); + + // fetch all buffered images and exit ... + //while(!is_dev_image_process_done()) + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + while (get_image_count() > 0) + { + ret = read_one_image_from_usb(); + count++; + if (ret != SCANNER_ERR_OK + && ret != SCANNER_ERR_CREATE_FILE_FAILED + && ret != SCANNER_ERR_WRITE_FILE_FAILED) + break; + } + if (count == 0) + { + std::lock_guard lock(io_lock_); + + LOG_INFO(LOG_LEVEL_DEBUG_INFO, "First message received from USB is 'STOPSCAN'\n"); + // notify_ui_working_status(STATU_DESC_DEVICE_RESET); + // reset_ = true; + // ret = io_->reset(); + // status_ = SCANNER_ERR_IO; + } + else if (status_ == SCANNER_ERR_TIMEOUT || status_ == SCANNER_ERR_IO || status_ == SCANNER_ERR_DEVICE_STOPPED) + status_ = SCANNER_ERR_OK; + + int s = get_status(); + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "status after received 'STOPSCAN': 0x%x\n", s); + if (count || (s & 3) == 0) + { + LOG_INFO(LOG_LEVEL_DEBUG_INFO, "Really stopped ^_^\n"); + break; + } + } + else if (info->From == V4L2) + { + VLOG_MINI_2(LOG_LEVEL_WARNING, "V4L2 message received, code = %d, index = %d\n", info->Code, info->Img_Index); + // stop(); + break; + } + else + { + // error handling ... + VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "Read HGEIntInfo: From = %d, Code = %d, Img_Index = %d, status = %s\n", info->From, info->Code, info->Img_Index, hg_scanner_err_name(status_)); + } + } + else + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "read %d bytes, sizeof(buf) = %d\n", size, sizeof(buf)); + + this_thread::sleep_for(chrono::milliseconds(10)); + } + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "USB thread exit with code: %s, status = %s\n", hg_scanner_err_name(ret), hg_scanner_err_name(status_)); +} + +int hg_scanner_439::start(void) +{ + split3399_ = 0; + bool handled = false; + int ret = try_third_app_handle_start(handled), + val = 0; + + user_cancel_ = false; + + // for third-sane-app invoking, added on 2022-05-19 + if (handled) + return ret; + + user_cancel_ = false; + cb_mem_ = true; + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "scanner status: 0x%x\n", get_status()); + notify_ui_working_status(STATU_DESC_PREPARE_START); + + reset(); + get_roller_num(); + val = get_sleep_time(); + //if (val != 1) + //{ + // status_ = SCANNER_ERR_DEVICE_SLEEPING; + // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "scanner's status(0x%x) is considerring as sleepping.\n", val); + + // return status_; + //} + val = get_scan_mode(); + if (status_ == SCANNER_ERR_DEVICE_NOT_FOUND) + return status_; + + if (val == -1) + return status_; + if (val & 1) + { + status_ = SCANNER_ERR_DEVICE_COUNT_MODE; + + return status_; + } + + notify_ui_working_status(STATU_DESC_REWRITE_CONFIGURATION); + //if(rewrite_conf_) + { + //协议设置方式一定要注意 1:协议结构体做好,start一起发送 2:每次设置一次发送一次 注意事项:除色时颜色切换维彩色使用的是临时变量,下发一次被释放,如果start再次发就会导致协议层被覆盖 + //ret = writedown_device_configuration(); + } + + if(ret == SCANNER_ERR_OK) + { + ret = writedown_image_configuration(); + } + + if (ret) + { + VLOG_MINI_1(LOG_LEVEL_WARNING, "Write down image process parameters fail is(%s), the result will be unpredictable.\n", hg_scanner_err_name(ret)); + + std::string info(STATU_DESC_REWRITE_CONFIGURATION); + + info += std::string("\345\244\261\350\264\245\357\274\232") + hg_scanner_err_name(ret); + notify_ui_working_status(info.c_str(), SANE_EVENT_ERROR, ret); + } + + if (ret != SCANNER_ERR_OK) + { + VLOG_MINI_1(LOG_LEVEL_WARNING, "start status01 is(%s), the result will be unpredictable.\n", hg_scanner_err_name(ret)); + return ret; + } + ret = get_scanner_paperon(); + if (ret == SCANNER_ERR_DEVICE_NO_PAPER) + { + status_ = ret; + notify_ui_working_status(STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER, SANE_EVENT_ERROR, status_); + VLOG_MINI_1(LOG_LEVEL_WARNING, "device start status is(%s)\n", STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER); + return ret; + } + + ret = write_command(SC_START); + + io_->set_timeout(1000); + if (ret == SCANNER_ERR_OK) + { + //status_ = SCANNER_ERR_DEVICE_BUSY; + wait_usb_.notify(); + this_thread::sleep_for(chrono::milliseconds(100)); + ret = try_third_app_after_start(ret); + } + else + { + status_ = ret; + VLOG_MINI_3(LOG_LEVEL_WARNING, "(%s)[Thread %s]Send start command = %s\n", hg_log::current_time().c_str(), hg_log::format_current_thread_id().c_str(), hg_scanner_err_name(ret)); + } + VLOG_MINI_1(LOG_LEVEL_WARNING, "start result: %s\n", hg_scanner_err_name(ret)); + + return ret; +} +int hg_scanner_439::stop(void) +{ + int ret = SCANNER_ERR_OK; + + user_cancel_ = true; + ret = write_command(SC_STOP); + io_->set_timeout(500); + final_imgs_.clear(); + + return status_; +} +int hg_scanner_439::reset(void) +{ + final_imgs_.clear(); + discard_all_images(); + + return status_; +} +int hg_scanner_439::device_io_control(unsigned long code, void* data, unsigned* len) +{ + int ret = SCANNER_ERR_OUT_OF_RANGE; + + if (HG_CONTROL_CODE_OPTION_ENABLE == code) + { + OPTEN* opten = (OPTEN*)data; + + ret = SCANNER_ERR_OK; + if (opten->opt_num == HG_239_SETTING_CORRECT && !opten->enabled) // for BUG-20 modified by Gongbing on 2022-03-12 + { + bool enable = true; + setting_automatic_skew(opten->opt_num, &enable); + } + } + else if (IO_CTRL_CODE_TEST_SINGLE == code) + { + test_1_paper_ = true; + ret = start(); + } + else + ret = hg_scanner::device_io_control(code, data, len); + + return ret; +} +std::string hg_scanner_439::get_firmware_version(void) +{ + return control_fetch(SR_GET_FWVERSION, 0, 20); +} +std::string hg_scanner_439::get_serial_num(void) +{ + return control_fetch(SR_GET_SERIALNUM, 0, 20); +} +std::string hg_scanner_439::get_ip(void) +{ + return control_fetch(SR_GET_IPADDR, 0, 40); +} +int hg_scanner_439::get_roller_num(void) +{ + int val = 0, + ret = read_register(SR_GET_ROLLER_NUM, &val); + + if (ret == SCANNER_ERR_OK) + return val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_roller_num = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} +int hg_scanner_439::clear_roller_num(void) +{ + int val = 0, + ret = read_register(SR_CLR_ROLLER_NUM, &val); + + return ret; +} + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int hg_scanner_439::set_leaflet_scan(void) +{ + int ret = SCANNER_ERR_OK; + test_1_paper_ = true; + + ret = start(); + return ret; +} +int hg_scanner_439::get_abuot_info(void) +{ + + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::restore_default_setting(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::set_final_image_format(SANE_FinalImgFormat* fmt) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} + +int hg_scanner_439::get_compression_format(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::set_compression_format(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::set_auto_color_type(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} + +int hg_scanner_439::get_device_code(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_sleep_time(SANE_Power* getime) +{ + int val = 0, + ret = read_register(SR_GET_SLEEPTIME, &val); + + if (ret == SCANNER_ERR_OK) + *getime = (SANE_Power)val; + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_sleep_time = %s\n", hg_scanner_err_name(ret)); + return -1; + } +} + +int hg_scanner_439::set_sleep_time(int setsleepime) +{ + int ret = write_register(SR_SET_SLEEPTIME, setsleepime); + + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "set sleep time to %d = %s\n", setsleepime, hg_scanner_err_name(ret)); + + return ret; +} +int hg_scanner_439::get_dogear_distance(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::set_dogear_distance(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_scanner_paperon(SANE_Bool* paperon) +{ + int val = 0, + ret = read_register(SR_GET_PAPERON, &val); + + if (ret == SCANNER_ERR_OK) + { + if (!val) + { + ret = SCANNER_ERR_DEVICE_NO_PAPER; + if (paperon) + { + *paperon = true; + } + } + else + { + ret = SCANNER_ERR_OK; + if (paperon) + { + *paperon = false; + } + } + } + else + { + VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "get_scanner_paperon = %s\n", hg_scanner_err_name(ret)); + return -1; + } + return ret; +} +int hg_scanner_439::set_scan_when_paper_on(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_scan_when_paper_on(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_scan_with_hole(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::set_scan_with_hole(void) +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_scan_is_sleep() +{ + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int hg_scanner_439::get_device_log(string &log) +{ + int ret = SCANNER_ERR_OK; + + int len = log.size(); + ret = write_register(SR_SET_JSON_PATH, len); + if (ret == SCANNER_ERR_OK) + ret = io_->write_bulk(&log[0],&len); + + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "log path:%s ret:%s\n", log.c_str(),hg_scanner_err_name(ret)); + return ret; +} +int hg_scanner_439::notify_sleep() +{ + int val = 0, + ret = write_register(SR_NOTIFY_SLEEP, val); + + return ret; +} \ No newline at end of file diff --git a/hgdriver/hgdev/hg_scanner_439.h b/hgdriver/hgdev/hg_scanner_439.h new file mode 100644 index 0000000..8410a95 --- /dev/null +++ b/hgdriver/hgdev/hg_scanner_439.h @@ -0,0 +1,121 @@ +#pragma once + +// hg_scanner is the base class of kinds of scanners +// +// created on 2022-01-30 +// +#include +#include +#include +#include +#include + +#include "hg_scanner.h" + +#ifdef OEM_HANWANG +#define hg_scanner_439 hw_scanner_239 +#elif defined(OEM_LISICHENG) +#define hg_scanner_439 lsc_scanner_239 +#endif + +class hg_scanner_439 : public hg_scanner +{ + //BlockingQueue>> final_imgs_; // JPG ... +// image_data final_imgs_; // JPG .. + + int pid_; + HGSCANCONF dev_conf_; + bool rewrite_conf_; + bool reset_; + bool is_kernelsnap_211209_; + + int read_register(int addr, int* val); + int write_register(int addr, int val); + int write_command(int cmd); + std::string control_fetch(int addr, int val, int size); + + std::string get_fpga(void); + int clr_roller_num(void); + int get_sleep_time(void); + int get_scan_mode(void); + int get_status(void); + bool is_dev_tx(void); + bool is_dev_image_process_done(void); + bool is_dev_image_keep_last_paper(void); + int get_scanned_count(void); + int get_image_count(void); + int get_front_data_size(void); + void init_version(void); + int get_device_sleep_stautus(void); + int get_device_paperon_stautus(void); + + int writedown_device_configuration(HGSCANCONF *dev_conf = NULL); + int writedown_image_configuration(void); + int pop_first_image(void); + + int read_one_image_from_usb(void); + void discard_all_images(void); + +protected: + int on_color_mode_changed(int& color_mode) override; + virtual int on_paper_changed(int& paper) override; + virtual int on_paper_check_changed(bool& check) override; + virtual int on_resolution_changed(int& dpi) override; + + virtual int on_ultrasonic_check_changed(bool& check) override; + virtual int on_staple_check_changed(bool& check) override; + virtual int on_skew_check_changed(bool& check) override; + virtual int on_skew_check_level_changed(int& check) override; + + virtual void on_device_reconnected(void) override; + virtual int on_scanner_closing(bool force) override; + virtual void thread_handle_usb_read(void) override; + virtual void image_process(std::shared_ptr& buff) override; + +public: + hg_scanner_439(const char* dev_name, int pid,usb_io* io); + ~hg_scanner_439(); + +public: + virtual int start(void) override; + //virtual int get_image_info(IMG_PARAM* ii) override; + //virtual int read_image_data(unsigned char* buf, int* len) override; + virtual int stop(void) override; + virtual int reset(void) override; + virtual int device_io_control(unsigned long code, void* data, unsigned* len) override; + +public: + virtual int set_leaflet_scan(void);//单张扫描 + virtual int get_abuot_info(void);//获取软件关于信息 (基类实现) + virtual int restore_default_setting(void);//恢复默认设置 (基类实现) + virtual int set_final_image_format(SANE_FinalImgFormat* fmt); // 设置图像处理最终输出(final())的图像数据格式 (基类实现) *** + virtual int get_compression_format(void);//获取支持的压缩格式 ***功能不支持 + + virtual int get_roller_num(void); //获取滚轮张数 ***完成 + virtual int clear_roller_num(void); // 清除滚轴计数 ***完成 + + virtual int set_compression_format(void);//设置图像数据最终输出的压缩格式 ***功能不支持 + virtual int set_auto_color_type(void);// 设置自动匹配颜色模式 (基类实现) ***完成 + + virtual std::string get_firmware_version(void); + virtual std::string get_serial_num(void); + virtual std::string get_ip(void); + + virtual int get_device_code(void);//获取设备编码 + virtual int get_sleep_time(SANE_Power* getime);//获取功耗模式(休眠) + virtual int set_sleep_time(int setsleepime);//设置功耗模式(休眠) + + virtual int get_dogear_distance(void);//获取折角检测最小距离阈值 + virtual int set_dogear_distance(void);// 设置折角检测最小距离阈值 + virtual int get_scanner_paperon(SANE_Bool* paperon = NULL);//获取设备有无纸张 + virtual int set_scan_when_paper_on(void);//获取是否为检测到进纸盘上有纸即开始扫描 + virtual int get_scan_when_paper_on(void);//设置是否为检测到进纸盘上有纸即开始扫描 + virtual int get_scan_with_hole(void);// 获取是否为带孔扫描 + virtual int set_scan_with_hole(void);// 设置是否为带孔扫描 + + virtual int get_scan_is_sleep(void);//获取设备是否休眠当中 + virtual int get_device_log(string &log);//获取设备日志 + virtual int notify_sleep(void);//唤醒设备 +}; + +static int split3399_; //3399设备正面和反面图像是相对的,所以对折时反面需要进行特殊处理 \ No newline at end of file