算法更新
This commit is contained in:
parent
53174686f7
commit
186a2c3165
|
@ -1,10 +1,10 @@
|
||||||
#include "IMulti.h"
|
#include "IMulti.h"
|
||||||
|
|
||||||
IMulti::IMulti(void)
|
IMulti::IMulti(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IMulti::~IMulti(void)
|
IMulti::~IMulti(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "imgprocdefs.h"
|
#include "imgprocdefs.h"
|
||||||
|
|
||||||
class IMulti
|
class GIMGPROC_LIBRARY_API IMulti
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IMulti(void);
|
IMulti(void);
|
||||||
virtual ~IMulti(void);
|
virtual ~IMulti(void);
|
||||||
virtual std::vector<cv::Mat> apply(cv::Mat& pDib) = 0;
|
virtual std::vector<cv::Mat> apply(cv::Mat& pDib) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
CImageApply::CImageApply(void)
|
CImageApply::CImageApply(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApply::~CImageApply(void)
|
CImageApply::~CImageApply(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,34 @@
|
||||||
#ifndef IMAGE_APPLY_H
|
/*
|
||||||
#define IMAGE_APPLY_H
|
* ====================================================
|
||||||
|
|
||||||
#include <vector>
|
* 功能:所有图像处理功能类的基类
|
||||||
#include <memory>
|
* 作者:刘丁维
|
||||||
#include <opencv2/opencv.hpp>
|
* 生成时间:2020/4/21
|
||||||
|
* 最近修改时间:2020/4/21
|
||||||
class CImageApply
|
* 版本号:v1.0
|
||||||
{
|
|
||||||
public:
|
* ====================================================
|
||||||
CImageApply(void);
|
*/
|
||||||
virtual ~CImageApply(void);
|
|
||||||
|
#ifndef IMAGE_APPLY_H
|
||||||
virtual void apply(cv::Mat& pDib,int side) = 0;
|
#define IMAGE_APPLY_H
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide) = 0;
|
#include <memory>
|
||||||
};
|
#include <vector>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
typedef std::shared_ptr<CImageApply> ImageApplyPtr;
|
#include "imgprocdefs.h"
|
||||||
|
|
||||||
#endif //!IMAGE_APPLY_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<cv::Mat>& mats, bool isTwoSide) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<CImageApply> ImageApplyPtr;
|
||||||
|
|
||||||
|
#endif // !IMAGE_APPLY_H
|
||||||
|
|
|
@ -1,90 +1,90 @@
|
||||||
#include "ImageApplyAdjustColors.h"
|
#include "ImageApplyAdjustColors.h"
|
||||||
|
|
||||||
CImageApplyAdjustColors::CImageApplyAdjustColors(void)
|
CImageApplyAdjustColors::CImageApplyAdjustColors(void)
|
||||||
: m_brightness(0)
|
: m_brightness(0)
|
||||||
, m_contrast(0)
|
, m_contrast(0)
|
||||||
, m_gamma(1.0f)
|
, m_gamma(1.0f)
|
||||||
, lut(1, 256, CV_8UC1)
|
, lut(1, 256, CV_8UC1)
|
||||||
{
|
{
|
||||||
update_lutData();
|
update_lutData();
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma)
|
CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma)
|
||||||
: lut(1, 256, CV_8UC1)
|
: lut(1, 256, CV_8UC1)
|
||||||
{
|
{
|
||||||
setAdjustColors(brightness, contrast, gamma);
|
setAdjustColors(brightness, contrast, gamma);
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyAdjustColors::~CImageApplyAdjustColors(void)
|
CImageApplyAdjustColors::~CImageApplyAdjustColors(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side)
|
void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.empty()) return;
|
if (pDib.empty()) return;
|
||||||
|
|
||||||
if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f)
|
if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f)
|
||||||
cv::LUT(pDib, lut, pDib);
|
cv::LUT(pDib, lut, pDib);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyAdjustColors::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if(!var.empty())
|
if(!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma)
|
void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma)
|
||||||
{
|
{
|
||||||
m_brightness = cv::max(-255, cv::min(brightness, 255));
|
m_brightness = cv::max(-255, cv::min(brightness, 255));
|
||||||
m_contrast = cv::max(-127, cv::min(contrast, 127));
|
m_contrast = cv::max(-127, cv::min(contrast, 127));
|
||||||
m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f));
|
m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f));
|
||||||
update_lutData();
|
update_lutData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::setBrightness(int brightness)
|
void CImageApplyAdjustColors::setBrightness(int brightness)
|
||||||
{
|
{
|
||||||
m_brightness = cv::max(-255, cv::min(brightness, 255));
|
m_brightness = cv::max(-255, cv::min(brightness, 255));
|
||||||
update_lutData();
|
update_lutData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::setContrast(int contrast)
|
void CImageApplyAdjustColors::setContrast(int contrast)
|
||||||
{
|
{
|
||||||
m_contrast = cv::max(-127, cv::min(contrast, 127));
|
m_contrast = cv::max(-127, cv::min(contrast, 127));
|
||||||
update_lutData();
|
update_lutData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::setGamma(float gamma)
|
void CImageApplyAdjustColors::setGamma(float gamma)
|
||||||
{
|
{
|
||||||
m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f));
|
m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f));
|
||||||
update_lutData();
|
update_lutData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAdjustColors::update_lutData()
|
void CImageApplyAdjustColors::update_lutData()
|
||||||
{
|
{
|
||||||
unsigned char* ptr = lut.data;
|
unsigned char* ptr = lut.data;
|
||||||
|
//update gamma
|
||||||
uchar buffer[256];
|
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
//update brightness
|
//update brightness
|
||||||
ptr[i] = static_cast<unsigned char>(cv::max(0, cv::min(i + m_brightness, 255)));
|
ptr[i] = static_cast<unsigned char>(cv::max(0, cv::min(i + m_brightness, 255)));
|
||||||
|
|
||||||
//update contrast
|
//update contrast
|
||||||
if (ptr[i] < 128)
|
if (ptr[i] < 128)
|
||||||
ptr[i] = static_cast<unsigned char>(cv::max(0, cv::min(ptr[i] - m_contrast, 127)));
|
ptr[i] = static_cast<unsigned char>(cv::max(0, cv::min(ptr[i] - m_contrast, 127)));
|
||||||
else
|
else
|
||||||
ptr[i] = static_cast<unsigned char>(cv::max(127, cv::min(ptr[i] + m_contrast, 255)));
|
ptr[i] = static_cast<unsigned char>(cv::max(127, cv::min(ptr[i] + m_contrast, 255)));
|
||||||
}
|
}
|
||||||
float g = 1.0f / m_gamma;
|
float g = 1.0f / m_gamma;
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
ptr[i] = static_cast<unsigned char>(cv::min(255, static_cast<int>(cv::pow(static_cast<float>(ptr[i]) / 255.0f, g) * 255.0f + 0.5f)));
|
ptr[i] = static_cast<unsigned char>(cv::min(255, static_cast<int>(cv::pow(static_cast<float>(ptr[i]) / 255.0f, g) * 255.0f + 0.5f)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +1,65 @@
|
||||||
#ifndef IMAGE_APPLY_ADJUST_COLOR_H
|
/*
|
||||||
#define IMAGE_APPLY_ADJUST_COLOR_H
|
* ====================================================
|
||||||
|
|
||||||
#include "ImageApply.h"
|
* 功能:色彩调整,可以调整伽马、亮度、对比度效果。叠加优先级:亮度 > 对比度 > 伽马
|
||||||
|
* 作者:刘丁维
|
||||||
class CImageApplyAdjustColors : public CImageApply
|
* 生成时间:2020/4/21
|
||||||
{
|
* 最近修改时间:2020/4/21
|
||||||
public:
|
* 版本号:v1.0
|
||||||
|
|
||||||
CImageApplyAdjustColors(void);
|
* ====================================================
|
||||||
|
*/
|
||||||
/*
|
|
||||||
* brightness [in]: 亮度调节,取值范围[-255, 255]
|
#ifndef IMAGE_APPLY_ADJUST_COLOR_H
|
||||||
* constrast [in]: 对比度调节,取值范围[-128, 127]
|
#define IMAGE_APPLY_ADJUST_COLOR_H
|
||||||
* gamma [in]: 伽马调节,取值范围[0.1, 5.0]
|
|
||||||
*/
|
#include "ImageApply.h"
|
||||||
CImageApplyAdjustColors(int brightness, int contrast, float gamma);
|
|
||||||
|
class GIMGPROC_LIBRARY_API CImageApplyAdjustColors : public CImageApply
|
||||||
virtual ~CImageApplyAdjustColors(void);
|
{
|
||||||
|
public:
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
|
||||||
|
CImageApplyAdjustColors(void);
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
/*
|
||||||
void setAdjustColors(int brightness, int contrast, float gamma);
|
* brightness [in]: 亮度调节,取值范围[-255, 255]
|
||||||
|
* constrast [in]: 对比度调节,取值范围[-128, 127]
|
||||||
int getContrast() { return m_contrast; }
|
* gamma [in]: 伽马调节,取值范围[0.1, 5.0]
|
||||||
|
*/
|
||||||
int getBrightness() { return m_brightness; }
|
CImageApplyAdjustColors(int brightness, int contrast, float gamma);
|
||||||
|
|
||||||
double getGamma() { return m_gamma; }
|
virtual ~CImageApplyAdjustColors(void);
|
||||||
|
|
||||||
void setBrightness(int brightness);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
void setContrast(int contrast);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
void setGamma(float gamma);
|
void setAdjustColors(int brightness, int contrast, float gamma);
|
||||||
|
|
||||||
private:
|
int getContrast() { return m_contrast; }
|
||||||
|
|
||||||
void update_lutData();
|
int getBrightness() { return m_brightness; }
|
||||||
|
|
||||||
private:
|
double getGamma() { return m_gamma; }
|
||||||
|
|
||||||
int m_brightness;
|
void setBrightness(int brightness);
|
||||||
int m_contrast;
|
|
||||||
float m_gamma;
|
void setContrast(int contrast);
|
||||||
cv::Mat lut;
|
|
||||||
};
|
void setGamma(float gamma);
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_ADJUST_COLOR_H
|
private:
|
||||||
|
|
||||||
|
void update_lutData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_brightness;
|
||||||
|
int m_contrast;
|
||||||
|
float m_gamma;
|
||||||
|
cv::Mat lut;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !IMAGE_APPLY_ADJUST_COLOR_H
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
#include "ImageApplyAutoContrast.h"
|
#include "ImageApplyAutoContrast.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
CImageApplyAutoContrast::CImageApplyAutoContrast()
|
CImageApplyAutoContrast::CImageApplyAutoContrast()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyAutoContrast::~CImageApplyAutoContrast()
|
CImageApplyAutoContrast::~CImageApplyAutoContrast()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAutoContrast::apply(cv::Mat& pDib, int side)
|
void CImageApplyAutoContrast::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.empty()) return;
|
if (pDib.empty()) return;
|
||||||
|
|
||||||
if(pDib.channels() == 1)
|
if(pDib.channels() == 1)
|
||||||
cv::equalizeHist(pDib,pDib);
|
cv::equalizeHist(pDib,pDib);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::vector<cv::Mat> mats(3);
|
std::vector<cv::Mat> mats(3);
|
||||||
cv::split(pDib,mats);
|
cv::split(pDib,mats);
|
||||||
for(size_t i = 0; i < mats.size(); i++)
|
for(size_t i = 0; i < mats.size(); i++)
|
||||||
if(!mats[i].empty())
|
if(!mats[i].empty())
|
||||||
cv::equalizeHist(mats[i], mats[i]);
|
cv::equalizeHist(mats[i], mats[i]);
|
||||||
cv::merge(mats,pDib);
|
cv::merge(mats,pDib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyAutoContrast::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
void CImageApplyAutoContrast::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:自动色彩校正,实现原理为直方图均衡化
|
* 功能:自动色彩校正,实现原理为直方图均衡化
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_AUTO_CONTRAST_H
|
#ifndef IMAGE_APPLY_AUTO_CONTRAST_H
|
||||||
#define IMAGE_APPLY_AUTO_CONTRAST_H
|
#define IMAGE_APPLY_AUTO_CONTRAST_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyAutoContrast : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyAutoContrast : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CImageApplyAutoContrast();
|
CImageApplyAutoContrast();
|
||||||
|
|
||||||
virtual ~CImageApplyAutoContrast();
|
virtual ~CImageApplyAutoContrast();
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif // !IMAGE_APPLY_AUTO_CONTRAST_H
|
#endif // !IMAGE_APPLY_AUTO_CONTRAST_H
|
||||||
|
|
|
@ -1,393 +1,330 @@
|
||||||
#include "ImageApplyAutoCrop.h"
|
#include "ImageApplyAutoCrop.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
#include <iostream>
|
||||||
CImageApplyAutoCrop::CImageApplyAutoCrop()
|
#include <opencv2/imgproc/hal/hal.hpp>
|
||||||
: m_isCrop(false)
|
#include "ImageApplyDispersion.h"
|
||||||
, m_isDesaskew(false)
|
|
||||||
, m_isFillBlank(false)
|
CImageApplyAutoCrop::CImageApplyAutoCrop()
|
||||||
, m_isConvexHull(true)
|
: m_isCrop(false)
|
||||||
, m_isFillColor(false)
|
, m_isDesaskew(false)
|
||||||
, m_threshold(40)
|
, m_isFillBlank(false)
|
||||||
, m_noise(8)
|
, m_isConvexHull(true)
|
||||||
, m_indent(5)
|
, m_isFillColor(false)
|
||||||
, m_normalCrop(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,
|
, m_isDispersion(true)
|
||||||
double threshold, int noise, int indent, bool normalCrop)
|
{
|
||||||
: m_isCrop(isCrop)
|
}
|
||||||
, m_isDesaskew(isDesaskew)
|
|
||||||
, m_isFillBlank(isFillBlank)
|
CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor,
|
||||||
, m_isConvexHull(isConvex)
|
double threshold, int noise, int indent, bool normalCrop, bool dispersion)
|
||||||
, m_isFillColor(isFillColor)
|
: m_isCrop(isCrop)
|
||||||
, m_threshold(threshold)
|
, m_isDesaskew(isDesaskew)
|
||||||
, m_noise(noise)
|
, m_isFillBlank(isFillBlank)
|
||||||
, m_indent(indent)
|
, m_isConvexHull(isConvex)
|
||||||
, m_fixedSize(fixedSize)
|
, m_isFillColor(isFillColor)
|
||||||
, m_normalCrop(normalCrop)
|
, m_threshold(threshold)
|
||||||
{
|
, m_noise(noise)
|
||||||
}
|
, m_indent(indent)
|
||||||
|
, m_fixedSize(fixedSize)
|
||||||
CImageApplyAutoCrop::~CImageApplyAutoCrop()
|
, m_normalCrop(normalCrop)
|
||||||
{
|
, m_isDispersion(dispersion)
|
||||||
}
|
{
|
||||||
|
}
|
||||||
void matmul(double* mul1, double* mul2, double* dst)
|
|
||||||
{
|
CImageApplyAutoCrop::~CImageApplyAutoCrop()
|
||||||
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];
|
void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
|
||||||
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];
|
cv::Mat dst;
|
||||||
dst[6] = mul1[6] * mul2[0] + mul1[7] * mul2[3] + mul1[8] * mul2[6];
|
autoCrop_desaskew_fillBlank(pDib, dst, m_isCrop, m_isDesaskew, m_isFillBlank, m_fixedSize.width, m_fixedSize.height,
|
||||||
dst[7] = mul1[6] * mul2[1] + mul1[7] * mul2[4] + mul1[8] * mul2[7];
|
m_isConvexHull, m_isFillColor, m_threshold, m_noise, m_indent, m_normalCrop, m_isDispersion);
|
||||||
dst[8] = mul1[6] * mul2[2] + mul1[7] * mul2[5] + mul1[8] * mul2[8];
|
pDib = dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat concatenateMatrix(const cv::Mat& first, const cv::Mat& second)
|
void CImageApplyAutoCrop::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
double buffer1[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ;
|
(void)isTwoSide;
|
||||||
double buffer2[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1} ;
|
int i = 0;
|
||||||
cv::Mat mul1(3, 3, CV_64FC1, buffer1); //cv::Mat::eye(3, 3, CV_64F);
|
for (cv::Mat& var : mats) {
|
||||||
cv::Mat mul2(3, 3, CV_64FC1, buffer2); //cv::Mat::eye(3, 3, CV_64F);
|
if (i != 0 && isTwoSide == false)
|
||||||
cv::Mat mul_r;
|
break;
|
||||||
first.convertTo(mul_r, CV_64F);
|
if (!var.empty())
|
||||||
mul_r.row(0).copyTo(mul1.row(0));
|
apply(var, 0);
|
||||||
mul_r.row(1).copyTo(mul1.row(1));
|
i++;
|
||||||
|
}
|
||||||
second.convertTo(mul_r, CV_64F);
|
}
|
||||||
mul_r.row(0).copyTo(mul2.row(0));
|
|
||||||
mul_r.row(1).copyTo(mul2.row(1));
|
#define FRONT_TOP 70
|
||||||
|
#define FX_FY 0.5f
|
||||||
//mul1 = mul2 * mul1;
|
|
||||||
cv::Mat temp(3, 3, CV_64FC1);
|
void myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, cv::Size dsize, int flags, int borderType, const cv::Scalar& borderValue)
|
||||||
matmul(buffer2, buffer1, (double*)temp.data);
|
{
|
||||||
mul1 = temp;
|
int interpolation = flags;
|
||||||
mul_r = first.clone();
|
cv::Mat src = _src.getMat(), M0 = _M0.getMat();
|
||||||
mul1.row(0).copyTo(mul_r.row(0));
|
cv::Mat dst = _dst.getMat();
|
||||||
mul1.row(1).copyTo(mul_r.row(1));
|
|
||||||
return mul_r;
|
if (dst.data == src.data)
|
||||||
}
|
src = src.clone();
|
||||||
|
|
||||||
std::vector<cv::Mat> comMat()
|
double M[6] = { 0 };
|
||||||
{
|
cv::Mat matM(2, 3, CV_64F, M);
|
||||||
std::vector<cv::Mat> mats;
|
if (interpolation == cv::INTER_AREA)
|
||||||
cv::Point2f srcTri[3];
|
interpolation = cv::INTER_LINEAR;
|
||||||
srcTri[0] = cv::Point2f(1, 1);
|
|
||||||
srcTri[1] = cv::Point2f(1, 0);
|
M0.convertTo(matM, matM.type());
|
||||||
srcTri[2] = cv::Point2f(0, 1);
|
|
||||||
const float fact = 0.33f;
|
if (!(flags & cv::WARP_INVERSE_MAP))
|
||||||
|
{
|
||||||
float pos[] = { 0, 2 * fact, fact };
|
double D = M[0] * M[4] - M[1] * M[3];
|
||||||
cv::Point2f dstTri[3];
|
D = D != 0 ? 1. / D : 0;
|
||||||
dstTri[0] = cv::Point2f(1, 1);
|
double A11 = M[4] * D, A22 = M[0] * D;
|
||||||
dstTri[1] = cv::Point2f(1, 0.5);
|
M[0] = A11; M[1] *= -D;
|
||||||
dstTri[2] = cv::Point2f(0, 1);
|
M[3] *= -D; M[4] = A22;
|
||||||
|
double b1 = -M[0] * M[2] - M[1] * M[5];
|
||||||
for (int i = 0; i < 3; i++)
|
double b2 = -M[3] * M[2] - M[4] * M[5];
|
||||||
{
|
M[2] = b1; M[5] = b2;
|
||||||
dstTri[0] = cv::Point2f(1, 1 + pos[i]);
|
}
|
||||||
dstTri[1] = cv::Point2f(1, pos[i]);
|
|
||||||
dstTri[2] = cv::Point2f(0, 1 + pos[i]);
|
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);
|
||||||
mats.push_back(cv::getAffineTransform(srcTri, dstTri));
|
}
|
||||||
}
|
|
||||||
return mats;
|
uchar getBackGroudChannelMean(const cv::Mat& gray, int total, int threshold)
|
||||||
}
|
{
|
||||||
|
cv::Mat image_clone;
|
||||||
void brightSharp(cv::Mat& src)
|
cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25);
|
||||||
{
|
|
||||||
const float a = -0.49f;
|
int threnshold = total / 32;
|
||||||
const float b = 3.0f;
|
int channels[] = { 0 };
|
||||||
//float kernel_data[] = {
|
int nHistSize[] = { 256 };
|
||||||
// a, 0, 0, 0, a,
|
float range[] = { 0, 256 };
|
||||||
// 0, 0, a, 0, 0,
|
const float* fHistRanges[] = { range };
|
||||||
// 0, a, b, a, 0,
|
cv::Mat hist;
|
||||||
// 0, 0, a, 0, 0,
|
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false);
|
||||||
// a, 0, 0, 0, a };
|
|
||||||
|
int hist_array[256];
|
||||||
float kernel_data[] = {
|
for (int i = 0; i < 256; i++)
|
||||||
0, a, 0,
|
hist_array[i] = hist.at<float>(i, 0);
|
||||||
a, b, a,
|
|
||||||
0, a, 0
|
int length = 1;
|
||||||
};
|
const int length_max = 255 - threshold;
|
||||||
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
|
while (length < length_max)
|
||||||
cv::filter2D(src, src, src.depth(), kernel);
|
{
|
||||||
}
|
for (size_t i = threshold + 1; i < 256 - length; i++)
|
||||||
|
{
|
||||||
void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
|
int count = 0;
|
||||||
{
|
uint pixSum = 0;
|
||||||
(void)side;
|
for (size_t j = 0; j < length; j++)
|
||||||
if (pDib.empty()) return;
|
{
|
||||||
|
count += hist_array[j + i];
|
||||||
if (m_normalCrop)
|
pixSum += hist_array[j + i] * (i + j);
|
||||||
{
|
}
|
||||||
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();
|
if (count >= threnshold)
|
||||||
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 pixSum / count;
|
||||||
return;
|
}
|
||||||
}
|
length++;
|
||||||
|
}
|
||||||
if (!m_isCrop && !m_isDesaskew && !m_isFillBlank && m_fixedSize.empty()) return;
|
return 255;
|
||||||
|
}
|
||||||
cv::Mat src = pDib;
|
|
||||||
cv::Mat thre;
|
cv::Scalar getBackGroudColor(const cv::Mat& image, int total, int threshold)
|
||||||
cv::Mat dst;
|
{
|
||||||
hg::threshold_Mat(src, thre, m_threshold);
|
if (image.channels() == 3)
|
||||||
|
{
|
||||||
if (m_noise > 0)
|
cv::Mat image_bgr[3];
|
||||||
{
|
cv::split(image, image_bgr);
|
||||||
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(m_noise, 1));
|
|
||||||
cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element);
|
uchar bgr[3];
|
||||||
}
|
for (size_t i = 0; i < 3; i++)
|
||||||
|
bgr[i] = getBackGroudChannelMean(image_bgr[i], total, threshold);
|
||||||
if (m_indent > 0)
|
return cv::Scalar(bgr[0], bgr[1], bgr[2]);
|
||||||
{
|
}
|
||||||
cv::Mat element = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(m_indent, m_indent));
|
else
|
||||||
cv::morphologyEx(thre, thre, cv::MORPH_ERODE, element);
|
return cv::Scalar::all(getBackGroudChannelMean(image, total, threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cv::Vec4i> hierarchy;
|
CImageApplyDispersion dispersion_apply;
|
||||||
std::vector<std::vector<cv::Point>> contours;
|
#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,
|
||||||
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
bool isConvex, bool isColorBlank, double threshold, int noise, int indent, bool isNormalCrop, bool dispersion)
|
||||||
m_maxContour = hg::getMaxContour(contours, hierarchy);
|
{
|
||||||
|
if (src.empty()) return;
|
||||||
if (m_maxContour.size() == 0)
|
|
||||||
{
|
if (isNormalCrop)
|
||||||
thre.release();
|
{
|
||||||
//
|
cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows);
|
||||||
if (!m_isCrop)
|
dst = src(roi).clone();
|
||||||
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;
|
||||||
#ifdef LOG
|
}
|
||||||
FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply");
|
|
||||||
#endif // LOG
|
if (!isAutoCrop && !isDesaskew && !isFillBlank && (dWidth <= 0 || dHeight <= 0))
|
||||||
return;
|
{
|
||||||
}
|
dst = src.clone();
|
||||||
|
return;
|
||||||
thre.release();
|
}
|
||||||
dst.release();
|
|
||||||
|
cv::Mat resizeMat;
|
||||||
cv::RotatedRect rect = hg::getBoundingRect(m_maxContour);
|
cv::Mat thre;
|
||||||
m_rect = rect;
|
|
||||||
cv::Rect boudingRect = cv::boundingRect(m_maxContour);
|
cv::resize(src, resizeMat, cv::Size(), FX_FY, FX_FY, cv::INTER_NEAREST);
|
||||||
boudingRect.x -= 1;
|
hg::threshold_Mat(resizeMat, thre, threshold);
|
||||||
boudingRect.y -= 1;
|
|
||||||
boudingRect.width += 2;
|
if (noise > 0)
|
||||||
boudingRect.height += 2;
|
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));
|
||||||
if (m_isDesaskew && rect.angle != 0)
|
|
||||||
{
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
cv::Point2f srcTri[4], srcTri_temp[3], dstTri[3];
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
rect.points(srcTri);
|
|
||||||
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
||||||
dstTri[0] = cv::Point2f(0, rect.size.height - 1);
|
|
||||||
dstTri[1] = cv::Point2f(0, 0);
|
for (std::vector<cv::Point>& sub : contours)
|
||||||
dstTri[2] = cv::Point2f(rect.size.width - 1, 0);
|
for (cv::Point& p : sub)
|
||||||
|
p /= FX_FY;
|
||||||
srcTri_temp[0] = dstTri[0];
|
|
||||||
srcTri_temp[1] = dstTri[1];
|
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
||||||
srcTri_temp[2] = dstTri[2];
|
|
||||||
cv::Mat warp_mat;
|
if (maxContour.empty())
|
||||||
warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
{
|
||||||
if (src.channels() == 1)
|
if (isAutoCrop)
|
||||||
{
|
dst = src.clone();
|
||||||
cv::warpAffine(src, dst, warp_mat, rect.size, cv::INTER_LINEAR);
|
else
|
||||||
}
|
{
|
||||||
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();
|
||||||
cv::Mat bgr[3];
|
}
|
||||||
cv::split(src, bgr);
|
return;
|
||||||
auto mats = comMat();
|
}
|
||||||
warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
|
||||||
warp_mat = concatenateMatrix(mats[0], warp_mat);
|
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
||||||
|
|
||||||
cv::warpAffine(bgr[0], bgr[0], warp_mat, rect.size, cv::INTER_LINEAR);
|
if (dispersion)
|
||||||
|
{
|
||||||
warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
cv::Mat mat_dispersion = src(cv::boundingRect(maxContour));
|
||||||
warp_mat = concatenateMatrix(mats[1], warp_mat);
|
dispersion_apply.apply(mat_dispersion, 0);
|
||||||
cv::warpAffine(bgr[1], bgr[1], warp_mat, rect.size, cv::INTER_LINEAR);
|
}
|
||||||
|
|
||||||
warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
cv::Scalar blankColor;
|
||||||
warp_mat = concatenateMatrix(mats[2], warp_mat);
|
if (isFillBlank)
|
||||||
cv::warpAffine(bgr[2], bgr[2], warp_mat, rect.size, cv::INTER_LINEAR);
|
if (isColorBlank)
|
||||||
|
blankColor = getBackGroudColor(resizeMat, rect.size.area() * FX_FY * FX_FY, COLOR_SCALE_THRE);
|
||||||
cv::merge(bgr, 3, dst);
|
else
|
||||||
}
|
blankColor = cv::Scalar::all(255);
|
||||||
|
else
|
||||||
double* ptr_m = reinterpret_cast<double*>(warp_mat.data);
|
blankColor = cv::Scalar::all(0);
|
||||||
double a = ptr_m[0];
|
|
||||||
double b = ptr_m[1];
|
if (isAutoCrop)
|
||||||
double c = ptr_m[2];
|
if (isDesaskew)
|
||||||
double d = ptr_m[3];
|
dst = cv::Mat(cv::Size(rect.size), src.type(), blankColor);
|
||||||
double e = ptr_m[4];
|
else
|
||||||
double f = ptr_m[5];
|
dst = cv::Mat(rect.boundingRect().size(), src.type(), blankColor);
|
||||||
|
else
|
||||||
for (cv::Point& p : m_maxContour)
|
dst = cv::Mat(dHeight, dWidth, src.type(), blankColor);
|
||||||
{
|
|
||||||
p.x = static_cast<int>(a * p.x + b * p.y + c);
|
cv::Mat dstROI;
|
||||||
p.y = static_cast<int>(d * p.x + e * p.y + f);
|
if (isDesaskew && rect.angle != 0)
|
||||||
}
|
{
|
||||||
|
cv::Point2f srcTri[4], dstTri[3];
|
||||||
for (std::vector<cv::Point>& sub : contours)
|
rect.points(srcTri);
|
||||||
for (cv::Point& p : sub)
|
srcTri[0].x -= 1;
|
||||||
{
|
srcTri[1].x -= 1;
|
||||||
p.x = static_cast<int>(a * p.x + b * p.y + c);
|
srcTri[2].x -= 1;
|
||||||
p.y = static_cast<int>(d * p.x + e * p.y + f);
|
|
||||||
}
|
int w = rect.size.width;
|
||||||
}
|
int h = rect.size.height;
|
||||||
else
|
int x = (dst.cols - w) / 2;
|
||||||
{
|
int y = (dst.rows - h) / 2;
|
||||||
auto t_rect = boudingRect & cv::Rect(0, 0, src.cols, src.rows);
|
dstTri[0] = cv::Point2f(0, h);
|
||||||
dst = src(t_rect);
|
dstTri[1] = cv::Point2f(0, 0);
|
||||||
if (dst.channels() == 3)
|
dstTri[2] = cv::Point2f(w, 0);
|
||||||
{
|
|
||||||
cv::Mat bgr[3];
|
dstROI = dst(cv::Rect(x, y, w, h) & cv::Rect(0, 0, dst.cols, dst.rows));
|
||||||
cv::split(dst, bgr);
|
myWarpAffine(src, dstROI, cv::getAffineTransform(srcTri, dstTri), dstROI.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||||
auto mats = comMat();
|
}
|
||||||
for (int i = 0; i < 3; i++)
|
else
|
||||||
cv::warpAffine(bgr[i], bgr[i], mats[i], t_rect.size(), cv::INTER_LINEAR);
|
{
|
||||||
cv::merge(bgr, 3, dst);
|
cv::Rect bounding = cv::boundingRect(maxContour);
|
||||||
}
|
|
||||||
}
|
if (bounding.width > dst.cols)
|
||||||
|
{
|
||||||
cv::Scalar autoBGColor;
|
bounding.x += (bounding.width - dst.cols) / 2;
|
||||||
if (m_isFillBlank)
|
bounding.width = dst.cols;
|
||||||
{
|
}
|
||||||
if (m_isConvexHull)
|
|
||||||
{
|
if (bounding.height > dst.rows)
|
||||||
if (m_maxContour.size() == 0)
|
{
|
||||||
{
|
bounding.y += (bounding.height - dst.rows) / 2;
|
||||||
thre.release();
|
bounding.height = dst.rows;
|
||||||
//<2F><><EFBFBD><EFBFBD>ǹ̶<C7B9><CCB6><EFBFBD><EFBFBD>棬<EFBFBD>뷵<EFBFBD>ز<EFBFBD><D8B2>к<EFBFBD>ijߴ<C4B3>
|
}
|
||||||
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();
|
dstROI = dst(cv::Rect((dst.cols - bounding.width) / 2, (dst.rows - bounding.height) / 2, bounding.width, bounding.height));
|
||||||
return;
|
src(bounding).copyTo(dstROI);
|
||||||
}
|
}
|
||||||
hg::convexHull(m_maxContour, m_maxContour);
|
|
||||||
contours.clear();
|
if (isFillBlank)
|
||||||
contours.push_back(m_maxContour);
|
{
|
||||||
}
|
if (isConvex)
|
||||||
|
{
|
||||||
contours.push_back(std::vector<cv::Point>());
|
hg::convexHull(maxContour, maxContour);
|
||||||
contours[contours.size() - 1].push_back(cv::Point(-1, dst.rows - 1));
|
contours.clear();
|
||||||
contours[contours.size() - 1].push_back(cv::Point(-1, -1));
|
contours.push_back(maxContour);
|
||||||
contours[contours.size() - 1].push_back(cv::Point(dst.cols, -1));
|
}
|
||||||
contours[contours.size() - 1].push_back(cv::Point(dst.cols, dst.rows));
|
|
||||||
|
cv::Point2f srcTri[4], dstTri[3];
|
||||||
autoBGColor = m_isFillColor ? getBackGroudColor(pDib, rect.size.area()) : cv::Scalar(255, 255, 255);
|
int w, h;
|
||||||
hg::fillPolys(dst, contours, autoBGColor);
|
if (isDesaskew && rect.angle != 0)
|
||||||
}
|
{
|
||||||
else
|
rect.points(srcTri);
|
||||||
{
|
srcTri[0].x -= 1;
|
||||||
m_maxContour.clear();
|
srcTri[1].x -= 1;
|
||||||
m_maxContour.push_back(cv::Point(-1, dst.rows));
|
srcTri[2].x -= 1;
|
||||||
m_maxContour.push_back(cv::Point(-1, -1));
|
w = rect.size.width;
|
||||||
m_maxContour.push_back(cv::Point(dst.cols, -1));
|
h = rect.size.height;
|
||||||
m_maxContour.push_back(cv::Point(dst.cols, dst.rows));
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
pDib.release();
|
cv::Rect bounding = rect.boundingRect();
|
||||||
if (/*(m_isCrop && side == 0) || (side == 1 && m_fixedSize.width * m_fixedSize.height == 0)*/ m_isCrop)
|
srcTri[0] = cv::Point(bounding.x, bounding.br().y - 1);
|
||||||
pDib = dst.clone();
|
srcTri[1] = cv::Point(bounding.x, bounding.y);
|
||||||
else
|
srcTri[2] = cv::Point(bounding.br().x - 1, bounding.y);
|
||||||
{
|
w = bounding.width;
|
||||||
pDib = cv::Mat(m_fixedSize, dst.type(), m_isFillBlank ? autoBGColor : cv::Scalar(0, 0, 0));
|
h = bounding.height;
|
||||||
|
}
|
||||||
cv::Rect roi;
|
|
||||||
roi.x = dst.cols > pDib.cols ? (dst.cols - pDib.cols) / 2 : 0;
|
dstTri[0] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + h - indent);
|
||||||
roi.width = cv::min(pDib.cols, dst.cols);
|
dstTri[1] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + indent);
|
||||||
roi.y = dst.rows > pDib.rows ? (dst.rows - pDib.rows) / 2 : 0;
|
dstTri[2] = cv::Point2f((dstROI.cols - w) / 2 - indent + w, (dstROI.rows - h) / 2 + indent);
|
||||||
roi.height = cv::min(pDib.rows, dst.rows);
|
cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri);
|
||||||
cv::Rect rect((pDib.cols - roi.width) / 2, (pDib.rows - roi.height) / 2, roi.width, roi.height);
|
|
||||||
|
double* ptr_m = reinterpret_cast<double*>(warp_mat.data);
|
||||||
for (cv::Point& p : m_maxContour)
|
double a = ptr_m[0];
|
||||||
p += roi.tl();
|
double b = ptr_m[1];
|
||||||
dst(roi).copyTo(pDib(rect));
|
double c = ptr_m[2];
|
||||||
}
|
double d = ptr_m[3];
|
||||||
#ifdef LOG
|
double e = ptr_m[4];
|
||||||
FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply8");
|
double f = ptr_m[5];
|
||||||
#endif // LOG
|
|
||||||
}
|
int x, y;
|
||||||
|
for (std::vector<cv::Point>& sub : contours)
|
||||||
void CImageApplyAutoCrop::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
for (cv::Point& p : sub)
|
||||||
{
|
{
|
||||||
if (mats.empty()) return;
|
x = p.x;
|
||||||
if (!mats[0].empty()) {
|
y = p.y;
|
||||||
apply(mats[0], 0);
|
p.x = static_cast<int>(a * x + b * y + c);
|
||||||
m_rects.push_back(m_rect);
|
p.y = static_cast<int>(d * x + e * y + f);
|
||||||
//brightSharp(mats[0]);
|
}
|
||||||
}
|
|
||||||
|
contours.push_back(std::vector<cv::Point>());
|
||||||
if (isTwoSide && mats.size() > 1)
|
contours[contours.size() - 1].push_back(cv::Point(-1, dstROI.rows - 1));
|
||||||
{
|
contours[contours.size() - 1].push_back(cv::Point(-1, -1));
|
||||||
cv::Size dSize = m_fixedSize;
|
contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, -1));
|
||||||
if (!mats[0].empty())
|
contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, dst.rows));
|
||||||
m_fixedSize = mats[0].size();
|
hg::fillPolys(dstROI, contours, blankColor);
|
||||||
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<float>(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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,112 +1,125 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:自动裁剪、纠偏、除黑底
|
* 功能:自动裁剪、纠偏、除黑底
|
||||||
* 作者:刘丁维
|
* 作者:刘丁绿
|
||||||
* 生成时间:2020/4/21
|
* 生成时间_020/4/21
|
||||||
* 最近修改时间:2020/4/21 v1.0
|
* 最近修改时间:2020/4/21 v1.0
|
||||||
2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用)
|
2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用_
|
||||||
2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度。
|
2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度
|
||||||
2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG。
|
2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG
|
||||||
2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG。
|
2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG
|
||||||
2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏)
|
2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏_
|
||||||
2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底。
|
2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底
|
||||||
* 版本号: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时可选用,实现传统裁切
|
||||||
#ifndef IMAGE_APPLY_AUTO_CROP_H
|
2021/07/13 v1.3.6 调整normalCrop逻辑,当normalCrop为true时,m_isCrop m_isDesaskew m_isFillBlank失效
|
||||||
#define IMAGE_APPLY_AUTO_CROP_H
|
2021/07/19 v1.3.7 调整仿射变换模式为INTER_LINEAR
|
||||||
|
2021/07/22 v1.3.8 修复第二次寻边,找不到外界轮廓会导致崩溃的BUG
|
||||||
#include "ImageApply.h"
|
2021/08/02 v1.3.9 精细化除黑底算法,可以应对只有条纹内容的黑色图像
|
||||||
|
2021/10/08 v1.3.10 优化算法,用腐蚀代替绘制实现缩进,提高整体算法效率
|
||||||
class CImageApplyAutoCrop : public CImageApply
|
2021/10/19 v1.3.11 解决一些极端情况,例如纸张自然0角度,纸张定格在图像顶部的处理
|
||||||
{
|
2021/10/19 v1.3.12 微调裁切纠偏像素精度
|
||||||
public:
|
2022/04/24 v1.4 重构算法,增加除色散功能
|
||||||
CImageApplyAutoCrop();
|
2022/05/03 v1.4.1 完善逻辑
|
||||||
|
2022/06/09 v1.4.2 修复获取文稿底色时,threshold值,设为固定值0.5
|
||||||
|
* 版本号:v1.4.2
|
||||||
/*
|
|
||||||
* isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剪
|
* ====================================================
|
||||||
* isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏
|
*/
|
||||||
* isFillBlank [in]:黑底填充使能,true为填充,false为不填充
|
|
||||||
* fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像素
|
#ifndef IMAGE_APPLY_AUTO_CROP_H
|
||||||
* isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true
|
#define IMAGE_APPLY_AUTO_CROP_H
|
||||||
* isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false
|
|
||||||
* threshold [in]:二值化阈值,取值范围(0, 255),默认40
|
#include "ImageApply.h"
|
||||||
* noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默认2
|
|
||||||
* indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5
|
class GIMGPROC_LIBRARY_API CImageApplyAutoCrop : public CImageApply
|
||||||
* normalCrop [in]:为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式,默认false
|
{
|
||||||
*/
|
public:
|
||||||
CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex = true,
|
CImageApplyAutoCrop();
|
||||||
bool isFillColor = false, double threshold = 40, int noise = 8, int indent = 5, bool normalCrop = false);
|
|
||||||
|
/*
|
||||||
virtual ~CImageApplyAutoCrop();
|
* isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剿
|
||||||
|
* isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
* isFillBlank [in]:黑底填充使能,true为填充,false为不填充
|
||||||
|
* fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像紿
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
* isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true
|
||||||
|
* isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false
|
||||||
bool isAutoCrop() { return m_isCrop; }
|
* threshold [in]:二值化阈值,取值范囿0, 255),默访0
|
||||||
|
* noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默访
|
||||||
bool isFillBlank() { return m_isFillBlank; }
|
* indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默访
|
||||||
|
* normalCrop [in]:为true时,m_isCrop m_isDesaskew m_isFillBlank失效,固定裁切采用最传统的裁切方式,默认false
|
||||||
bool isDesaskew() { return m_isDesaskew; }
|
* dispersion [in]:为true时,除色散;false时不除色散。默认为true
|
||||||
|
*/
|
||||||
bool isConvexHull() { return m_isConvexHull; }
|
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);
|
||||||
double threshold() { return m_threshold; }
|
|
||||||
|
virtual ~CImageApplyAutoCrop();
|
||||||
const cv::RotatedRect& rotatedROI() { return m_rect; }
|
|
||||||
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
const std::vector<cv::RotatedRect>& rotatedROIs() { return m_rects; }
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
int noise() { return m_noise; }
|
|
||||||
|
bool isAutoCrop() { return m_isCrop; }
|
||||||
int indent() { return m_indent; }
|
|
||||||
|
bool isFillBlank() { return m_isFillBlank; }
|
||||||
cv::Size fixedSize() { return m_fixedSize; }
|
|
||||||
|
bool isDesaskew() { return m_isDesaskew; }
|
||||||
const std::vector<cv::Point>& maxContour() { return m_maxContour; }
|
|
||||||
|
bool isConvexHull() { return m_isConvexHull; }
|
||||||
void setAutoCrop(bool enabled) { m_isCrop = enabled; }
|
|
||||||
|
cv::RotatedRect getROI() { return m_rect; }
|
||||||
void setFillBlank(bool enabled) { m_isFillBlank = enabled; }
|
|
||||||
|
double threshold() { return m_threshold; }
|
||||||
void setDesaskew(bool enabled) { m_isDesaskew = enabled; }
|
|
||||||
|
int noise() { return m_noise; }
|
||||||
void setConvexHull(bool convex) { m_isConvexHull = convex; }
|
|
||||||
|
int indent() { return m_indent; }
|
||||||
void setThreshold(double value) { m_threshold = value; }
|
|
||||||
|
cv::Size fixedSize() { return m_fixedSize; }
|
||||||
void setNoise(int value) { m_noise = value; }
|
|
||||||
|
const std::vector<cv::Point>& maxContour() { return m_maxContour; }
|
||||||
void setIndent(int value) { m_indent = value; }
|
|
||||||
|
void setAutoCrop(bool enabled) { m_isCrop = enabled; }
|
||||||
void setFixedSize(cv::Size size) { m_fixedSize = size; }
|
|
||||||
|
void setFillBlank(bool enabled) { m_isFillBlank = enabled; }
|
||||||
private:
|
|
||||||
cv::Scalar getBackGroudColor(const cv::Mat& image, int total);
|
void setDesaskew(bool enabled) { m_isDesaskew = enabled; }
|
||||||
|
|
||||||
uchar getBackGroudChannelMean(const cv::Mat& gray, int total);
|
void setConvexHull(bool convex) { m_isConvexHull = convex; }
|
||||||
|
|
||||||
private:
|
void setThreshold(double value) { m_threshold = value; }
|
||||||
bool m_isCrop;
|
|
||||||
bool m_isDesaskew;
|
void setNoise(int value) { m_noise = value; }
|
||||||
bool m_isFillBlank;
|
|
||||||
bool m_isConvexHull;
|
void setIndent(int value) { m_indent = value; }
|
||||||
bool m_isFillColor;
|
|
||||||
|
void setFixedSize(cv::Size size) { m_fixedSize = size; }
|
||||||
double m_threshold;
|
|
||||||
int m_noise;
|
void setDispersion(bool enable) { m_isDispersion = enable; }
|
||||||
int m_indent;
|
|
||||||
bool m_normalCrop; //为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方式
|
private:
|
||||||
cv::Size m_fixedSize;
|
bool m_isCrop;
|
||||||
cv::RotatedRect m_rect;
|
bool m_isDesaskew;
|
||||||
std::vector<cv::Point> m_maxContour;
|
bool m_isFillBlank;
|
||||||
std::vector<cv::RotatedRect> m_rects;
|
bool m_isConvexHull;
|
||||||
};
|
bool m_isFillColor;
|
||||||
|
bool m_isDispersion;
|
||||||
#endif // !IMAGE_APPLY_AUTO_CROP_H
|
|
||||||
|
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<cv::RotatedRect> m_rects;
|
||||||
|
std::vector<cv::Point> 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
|
||||||
|
|
|
@ -1,164 +1,167 @@
|
||||||
#include "ImageApplyBWBinaray.h"
|
#include "ImageApplyBWBinaray.h"
|
||||||
|
|
||||||
CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant)
|
CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant)
|
||||||
: m_threshold(threshold)
|
: m_threshold(threshold)
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
, m_blockSize(blockSize)
|
, m_blockSize(blockSize)
|
||||||
, m_constant(constant)
|
, m_constant(constant)
|
||||||
, m_table(new uchar[256])
|
, m_table(new uchar[256])
|
||||||
{
|
{
|
||||||
memset(m_table, 255, 256);
|
memset(m_table, 255, 256);
|
||||||
memset(m_table, 0, static_cast<size_t>(m_threshold));
|
memset(m_table, 0, static_cast<size_t>(m_threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyBWBinaray::CImageApplyBWBinaray()
|
CImageApplyBWBinaray::CImageApplyBWBinaray()
|
||||||
: m_threshold(120)
|
: m_threshold(120)
|
||||||
, m_type(ThresholdType::THRESH_BINARY)
|
, m_type(ThresholdType::THRESH_BINARY)
|
||||||
, m_blockSize(25)
|
, m_blockSize(51)
|
||||||
, m_constant(5)
|
, m_constant(41)
|
||||||
, m_table(new uchar[256])
|
, m_table(new uchar[256])
|
||||||
{
|
{
|
||||||
memset(m_table, 255, 256);
|
memset(m_table, 255, 256);
|
||||||
memset(m_table, 0, static_cast<size_t>(m_threshold));
|
memset(m_table, 0, static_cast<size_t>(m_threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyBWBinaray::~CImageApplyBWBinaray(void)
|
CImageApplyBWBinaray::~CImageApplyBWBinaray(void)
|
||||||
{
|
{
|
||||||
delete[] m_table;
|
delete[] m_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side)
|
#define THRESHOLD_LOW 30
|
||||||
{
|
#define THRESHOLD_UP 245
|
||||||
(void)side;
|
void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side)
|
||||||
if (pDib.empty()) return;
|
{
|
||||||
|
(void)side;
|
||||||
if (pDib.channels() == 3)
|
if (pDib.empty()) return;
|
||||||
cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
|
|
||||||
|
if (pDib.channels() == 3)
|
||||||
//20.12.29 修改参数为51 10 30 235
|
cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
|
||||||
//20.12.30 修改参数为51 20 30 235
|
|
||||||
// 修改参数为17 20 110 235
|
cv::Mat integ;
|
||||||
cv::Mat integ;
|
int blockSize = m_blockSize;//邻域尺寸
|
||||||
int blockSize = 17;//邻域尺寸
|
int threshold = m_constant;
|
||||||
int threshold = 20;
|
int low = THRESHOLD_LOW;
|
||||||
int low = 110;
|
int up = THRESHOLD_UP;
|
||||||
int up = 235;
|
int halfSize = blockSize / 2;
|
||||||
int halfSize = blockSize / 2;
|
int square_blockSize = blockSize * blockSize;
|
||||||
int square_blockSize = blockSize * blockSize;
|
switch (m_type)
|
||||||
switch (m_type)
|
{
|
||||||
{
|
case ThresholdType::THRESH_BINARY:
|
||||||
case ThresholdType::THRESH_BINARY:
|
cv::integral(pDib, integ, CV_32S);
|
||||||
cv::integral(pDib, integ, CV_32S);
|
|
||||||
|
for (int j = halfSize; j < integ.rows - halfSize - 1; j++)
|
||||||
for (int j = halfSize; j < integ.rows - halfSize - 1; j++)
|
{
|
||||||
{
|
uchar* data = pDib.ptr<uchar>(j);
|
||||||
uchar* data = pDib.ptr<uchar>(j);
|
int* idata1 = integ.ptr<int>(j - halfSize);
|
||||||
int* idata1 = integ.ptr<int>(j - halfSize);
|
int* idata2 = integ.ptr<int>(j + halfSize + 1);
|
||||||
int* idata2 = integ.ptr<int>(j + halfSize + 1);
|
for (int i = halfSize; i < integ.cols - halfSize - 1; i++)
|
||||||
for (int i = halfSize; i < integ.cols - halfSize - 1; i++)
|
{
|
||||||
{
|
if (data[i] < low)
|
||||||
if (data[i] < low)
|
data[i] = 0;
|
||||||
data[i] = 0;
|
else if (data[i] > up)
|
||||||
else if (data[i] > up)
|
data[i] = 255;
|
||||||
data[i] = 255;
|
else
|
||||||
else
|
data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255;
|
||||||
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(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(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, 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);
|
||||||
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;
|
||||||
break;
|
case ThresholdType::THRESH_OTSU:
|
||||||
case ThresholdType::THRESH_OTSU:
|
cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU);
|
||||||
cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU);
|
break;
|
||||||
break;
|
case ThresholdType::ADAPTIVE_GAUSSIAN:
|
||||||
case ThresholdType::ADAPTIVE_GAUSSIAN:
|
cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
|
||||||
cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
|
break;
|
||||||
break;
|
case ThresholdType::ADAPTIVE_MEAN:
|
||||||
case ThresholdType::ADAPTIVE_MEAN:
|
cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
|
||||||
cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
|
break;
|
||||||
break;
|
case ThresholdType::ERROR_DIFFUSION:
|
||||||
case ThresholdType::ERROR_DIFFUSION:
|
errorDiffuse(pDib);
|
||||||
errorDiffuse(pDib);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
#ifdef LOG
|
||||||
|
FileTools::write_log("imgprc.txt", "exit CImageApplyBWBinaray apply");
|
||||||
void CImageApplyBWBinaray::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
#endif // LOG
|
||||||
{
|
}
|
||||||
(void)isTwoSide;
|
|
||||||
int i = 0;
|
void CImageApplyBWBinaray::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
for (cv::Mat& var : mats) {
|
{
|
||||||
if (i != 0 && isTwoSide == false)
|
(void)isTwoSide;
|
||||||
break;
|
int i = 0;
|
||||||
if (!var.empty())
|
for (cv::Mat& var : mats) {
|
||||||
apply(var, 0);
|
if (i != 0 && isTwoSide == false)
|
||||||
i++;
|
break;
|
||||||
}
|
if (!var.empty())
|
||||||
}
|
apply(var, 0);
|
||||||
|
i++;
|
||||||
void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image)
|
}
|
||||||
{
|
}
|
||||||
if (image.rows < 3 || image.cols < 3)
|
|
||||||
{
|
void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image)
|
||||||
cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY);
|
{
|
||||||
return;
|
if (image.rows < 3 || image.cols < 3)
|
||||||
}
|
{
|
||||||
|
cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY);
|
||||||
cv::Mat dst;
|
return;
|
||||||
image.convertTo(dst, CV_16S);
|
}
|
||||||
|
|
||||||
size_t rows = static_cast<size_t>(image.rows) - 1;
|
cv::Mat dst;
|
||||||
size_t cols = static_cast<size_t>(image.cols) - 1;
|
image.convertTo(dst, CV_16S);
|
||||||
|
|
||||||
short** pixels_dst = new short* [static_cast<size_t>(image.rows)];
|
size_t rows = static_cast<size_t>(image.rows) - 1;
|
||||||
for (int i = 0; i < image.rows; i++)
|
size_t cols = static_cast<size_t>(image.cols) - 1;
|
||||||
pixels_dst[i] = reinterpret_cast<short*>(dst.data + i * static_cast<int>(dst.step));
|
|
||||||
|
short** pixels_dst = new short* [static_cast<size_t>(image.rows)];
|
||||||
short error;
|
for (int i = 0; i < image.rows; i++)
|
||||||
for (size_t y = 0; y < rows; y++)
|
pixels_dst[i] = reinterpret_cast<short*>(dst.data + i * static_cast<int>(dst.step));
|
||||||
for (size_t x = 1; x < cols; x++)
|
|
||||||
{
|
short error;
|
||||||
short dstPix = pixels_dst[y][x];
|
for (size_t y = 0; y < rows; y++)
|
||||||
if (dstPix >= m_threshold)
|
for (size_t x = 1; x < cols; x++)
|
||||||
{
|
{
|
||||||
pixels_dst[y][x] = 255;
|
short dstPix = pixels_dst[y][x];
|
||||||
error = dstPix - 255;
|
if (dstPix >= m_threshold)
|
||||||
}
|
{
|
||||||
else
|
pixels_dst[y][x] = 255;
|
||||||
{
|
error = dstPix - 255;
|
||||||
pixels_dst[y][x] = 0;
|
}
|
||||||
error = dstPix;
|
else
|
||||||
}
|
{
|
||||||
|
pixels_dst[y][x] = 0;
|
||||||
pixels_dst[y][x + 1] += error * 1 / 16;
|
error = dstPix;
|
||||||
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;
|
pixels_dst[y][x + 1] += error * 1 / 16;
|
||||||
}
|
pixels_dst[y + 1][x - 1] += error * 1 / 16;
|
||||||
image.release();
|
pixels_dst[y + 1][x] += error * 1 / 16;
|
||||||
dst.convertTo(image, CV_8U);
|
pixels_dst[y + 1][x + 1] += error * 1 / 16;
|
||||||
|
}
|
||||||
rows++;
|
image.release();
|
||||||
uchar* ptr = image.data;
|
dst.convertTo(image, CV_8U);
|
||||||
size_t step = image.step;
|
|
||||||
size_t offset;
|
rows++;
|
||||||
for (size_t y = 0; y < rows; y++)
|
uchar* ptr = image.data;
|
||||||
{
|
size_t step = image.step;
|
||||||
offset = y * step;
|
size_t offset;
|
||||||
ptr[offset] = m_table[ptr[offset]];
|
for (size_t y = 0; y < rows; y++)
|
||||||
offset += cols;
|
{
|
||||||
ptr[offset] = m_table[ptr[offset]];
|
offset = y * step;
|
||||||
}
|
ptr[offset] = m_table[ptr[offset]];
|
||||||
|
offset += cols;
|
||||||
cols++;
|
ptr[offset] = m_table[ptr[offset]];
|
||||||
ptr = image.data + step * (rows - 1);
|
}
|
||||||
for (size_t x = 0; x < cols; x++)
|
|
||||||
ptr[x] = m_table[ptr[x]];
|
cols++;
|
||||||
|
ptr = image.data + step * (rows - 1);
|
||||||
delete[] pixels_dst;
|
for (size_t x = 0; x < cols; x++)
|
||||||
}
|
ptr[x] = m_table[ptr[x]];
|
||||||
|
|
||||||
|
delete[] pixels_dst;
|
||||||
|
}
|
||||||
|
|
|
@ -1,86 +1,87 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:二值化处理
|
* 功能:二值化处理
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法
|
* 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法
|
||||||
2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果
|
2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果
|
||||||
2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果
|
2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果
|
||||||
2020/12/21 v1.3.1 调整自适应阈值上下限
|
2020/12/21 v1.3.1 调整自适应阈值上下限
|
||||||
2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25
|
2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25
|
||||||
* 版本号:v1.3.2
|
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
|
#ifndef IMAGE_APPLY_BW_BINARAY_H
|
||||||
|
#define IMAGE_APPLY_BW_BINARAY_H
|
||||||
#include "ImageApply.h"
|
|
||||||
|
#include "ImageApply.h"
|
||||||
class CImageApplyBWBinaray:public CImageApply
|
|
||||||
{
|
class GIMGPROC_LIBRARY_API CImageApplyBWBinaray:public CImageApply
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
enum class ThresholdType
|
|
||||||
{
|
enum class ThresholdType
|
||||||
THRESH_BINARY = 0, //传统二值化
|
{
|
||||||
THRESH_OTSU, //大津阈值
|
THRESH_BINARY = 0, //传统二值化
|
||||||
|
THRESH_OTSU, //大津阈值
|
||||||
ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值
|
|
||||||
ADAPTIVE_MEAN, //均值局部自适应阈值
|
ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值
|
||||||
|
ADAPTIVE_MEAN, //均值局部自适应阈值
|
||||||
ERROR_DIFFUSION //错误扩散
|
|
||||||
};
|
ERROR_DIFFUSION //错误扩散
|
||||||
|
};
|
||||||
/*
|
|
||||||
* type [in]:二值化模式
|
/*
|
||||||
* threshold [in]:阈值,当选择THRESH_OTSU时无效
|
* type [in]:二值化模式
|
||||||
* blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,表示局部观察块的宽度
|
* threshold [in]:阈值,当选择THRESH_OTSU时无效
|
||||||
* constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,与blockSize形成比例关系,作为局部筛选阈值
|
* 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(ThresholdType type, int threshold = 120, int blockSize = 51, int constant = 41);
|
||||||
CImageApplyBWBinaray();
|
|
||||||
|
CImageApplyBWBinaray();
|
||||||
virtual ~CImageApplyBWBinaray(void);
|
|
||||||
|
virtual ~CImageApplyBWBinaray(void);
|
||||||
virtual void apply(cv::Mat& pDib,int side);
|
|
||||||
|
virtual void apply(cv::Mat& pDib,int side);
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
double getThreshold() { return m_threshold; }
|
|
||||||
|
double getThreshold() { return m_threshold; }
|
||||||
ThresholdType getThresholdType() { return m_type; }
|
|
||||||
|
ThresholdType getThresholdType() { return m_type; }
|
||||||
int getBlockSize() { return m_blockSize; }
|
|
||||||
|
int getBlockSize() { return m_blockSize; }
|
||||||
double getConstant() { return m_constant; }
|
|
||||||
|
double getConstant() { return m_constant; }
|
||||||
void setThreshold(double value) { m_threshold = value; }
|
|
||||||
|
void setThreshold(double value) { m_threshold = value; }
|
||||||
void setThresholdType(ThresholdType type) { m_type = type; }
|
|
||||||
|
void setThresholdType(ThresholdType type) { m_type = type; }
|
||||||
void setBlockSize(int value) { m_blockSize = value; }
|
|
||||||
|
void setBlockSize(int value) { m_blockSize = value; }
|
||||||
void setConstant(double value) { m_constant = value; }
|
|
||||||
|
void setConstant(double value) { m_constant = value; }
|
||||||
private:
|
|
||||||
|
private:
|
||||||
void errorDiffuse(cv::Mat& image);
|
|
||||||
|
void errorDiffuse(cv::Mat& image);
|
||||||
private:
|
|
||||||
double m_threshold;
|
private:
|
||||||
|
double m_threshold;
|
||||||
ThresholdType m_type;
|
|
||||||
|
ThresholdType m_type;
|
||||||
int m_blockSize;
|
|
||||||
|
int m_blockSize;
|
||||||
double m_constant;
|
|
||||||
|
double m_constant;
|
||||||
uchar* m_table;
|
|
||||||
};
|
uchar* m_table;
|
||||||
|
};
|
||||||
#endif //!IMAGE_APPLY_BW_BINARAY_H
|
|
||||||
|
#endif //!IMAGE_APPLY_BW_BINARAY_H
|
||||||
|
|
||||||
|
|
|
@ -1,127 +1,127 @@
|
||||||
#include "ImageApplyChannel.h"
|
#include "ImageApplyChannel.h"
|
||||||
#include "ImageApplyAdjustColors.h"
|
#include "ImageApplyAdjustColors.h"
|
||||||
|
|
||||||
CImageApplyChannel::CImageApplyChannel()
|
CImageApplyChannel::CImageApplyChannel()
|
||||||
: m_channel(Invalid)
|
: m_channel(Invalid)
|
||||||
, colors(new CImageApplyAdjustColors(0, 30, 1.0))
|
, colors(new CImageApplyAdjustColors(0, 30, 1.0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyChannel::CImageApplyChannel(Channel channel)
|
CImageApplyChannel::CImageApplyChannel(Channel channel)
|
||||||
: m_channel(channel)
|
: m_channel(channel)
|
||||||
, colors(new CImageApplyAdjustColors(0, 30, 1.0))
|
, colors(new CImageApplyAdjustColors(0, 30, 1.0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyChannel::~CImageApplyChannel()
|
CImageApplyChannel::~CImageApplyChannel()
|
||||||
{
|
{
|
||||||
if (colors != nullptr) delete colors;
|
if (colors != nullptr) delete colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyChannel::apply(cv::Mat& pDib, int side)
|
void CImageApplyChannel::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.empty()) return;
|
if (pDib.empty()) return;
|
||||||
|
|
||||||
cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1);
|
cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1);
|
||||||
switch (m_channel)
|
switch (m_channel)
|
||||||
{
|
{
|
||||||
case Red:
|
case Red:
|
||||||
cv::extractChannel(pDib, dst, 2);
|
cv::extractChannel(pDib, dst, 2);
|
||||||
colors->apply(pDib, side);
|
colors->apply(pDib, side);
|
||||||
break;
|
break;
|
||||||
case Green:
|
case Green:
|
||||||
cv::extractChannel(pDib, dst, 1);
|
cv::extractChannel(pDib, dst, 1);
|
||||||
break;
|
break;
|
||||||
case Blue:
|
case Blue:
|
||||||
cv::extractChannel(pDib, dst, 0);
|
cv::extractChannel(pDib, dst, 0);
|
||||||
break;
|
break;
|
||||||
case All:
|
case All:
|
||||||
colourless(pDib, dst, 80);
|
colourless(pDib, dst, 80);
|
||||||
break;
|
break;
|
||||||
case Except_Red:
|
case Except_Red:
|
||||||
except_channel(pDib, dst, 2);
|
except_channel(pDib, dst, 2);
|
||||||
break;
|
break;
|
||||||
case Except_Green:
|
case Except_Green:
|
||||||
except_channel(pDib, dst, 1);
|
except_channel(pDib, dst, 1);
|
||||||
break;
|
break;
|
||||||
case Except_Blue:
|
case Except_Blue:
|
||||||
except_channel(pDib, dst, 0);
|
except_channel(pDib, dst, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pDib.release();
|
pDib.release();
|
||||||
pDib = dst;
|
pDib = dst;
|
||||||
|
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply");
|
FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyChannel::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyChannel::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel)
|
void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel)
|
||||||
{
|
{
|
||||||
cv::Mat mv[3];
|
cv::Mat mv[3];
|
||||||
cv::split(src, mv);
|
cv::split(src, mv);
|
||||||
cv::Mat mask, mask1, mask2;
|
cv::Mat mask, mask1, mask2;
|
||||||
switch (channel)
|
switch (channel)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
mask1 = mv[0] - mv[1];
|
mask1 = mv[0] - mv[1];
|
||||||
mask2 = mv[0] - mv[2];
|
mask2 = mv[0] - mv[2];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mask1 = mv[1] - mv[0];
|
mask1 = mv[1] - mv[0];
|
||||||
mask2 = mv[1] - mv[2];
|
mask2 = mv[1] - mv[2];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mask1 = mv[2] - mv[1];
|
mask1 = mv[2] - mv[1];
|
||||||
mask2 = mv[2] - mv[0];
|
mask2 = mv[2] - mv[0];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cv::min(mask1, mask2, mask);
|
cv::min(mask1, mask2, mask);
|
||||||
|
|
||||||
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
|
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
|
||||||
dst -= mask;
|
dst -= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold)
|
void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold)
|
||||||
{
|
{
|
||||||
if (src.channels() != 3)
|
if (src.channels() != 3)
|
||||||
{
|
{
|
||||||
dst = src;
|
dst = src;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat hsv;
|
cv::Mat hsv;
|
||||||
cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL);
|
cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL);
|
||||||
cv::Mat mv_hsv[3];
|
cv::Mat mv_hsv[3];
|
||||||
cv::split(hsv, mv_hsv);
|
cv::split(hsv, mv_hsv);
|
||||||
size_t total = mv_hsv[1].total();
|
size_t total = mv_hsv[1].total();
|
||||||
uchar* ptr_s = mv_hsv[1].data;
|
uchar* ptr_s = mv_hsv[1].data;
|
||||||
uchar* ptr_v = mv_hsv[2].data;
|
uchar* ptr_v = mv_hsv[2].data;
|
||||||
for (size_t i = 0; i < total; i++)
|
for (size_t i = 0; i < total; i++)
|
||||||
if (ptr_s[i] > threshold)
|
if (ptr_s[i] > threshold)
|
||||||
{
|
{
|
||||||
ptr_s[i] = 0;
|
ptr_s[i] = 0;
|
||||||
ptr_v[i] = 255;
|
ptr_v[i] = 255;
|
||||||
}
|
}
|
||||||
cv::merge(mv_hsv, 3, hsv);
|
cv::merge(mv_hsv, 3, hsv);
|
||||||
cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL);
|
cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL);
|
||||||
cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY);
|
cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +1,65 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图
|
* 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:v1.0 2020/4/21
|
* 最近修改时间:v1.0 2020/4/21
|
||||||
v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。
|
v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。
|
||||||
v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。
|
v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。
|
||||||
v1.3 2021/5/24 替换红色增强算法方案。
|
v1.3 2021/5/24 替换红色增强算法方案。
|
||||||
* 版本号:v1.3
|
* 版本号:v1.3
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_CHANNEL_H
|
#ifndef IMAGE_APPLY_CHANNEL_H
|
||||||
#define IMAGE_APPLY_CHANNEL_H
|
#define IMAGE_APPLY_CHANNEL_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyAdjustColors;
|
class CImageApplyAdjustColors;
|
||||||
class CImageApplyChannel : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyChannel : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef enum channel
|
typedef enum channel
|
||||||
{
|
{
|
||||||
Red, //红色通道
|
Red, //红色通道
|
||||||
Green, //绿色通道
|
Green, //绿色通道
|
||||||
Blue, //蓝色通道
|
Blue, //蓝色通道
|
||||||
All, //去除所有HSV色彩结构中,S大于80的色彩
|
All, //去除所有HSV色彩结构中,S大于80的色彩
|
||||||
Invalid, //无效
|
Invalid, //无效
|
||||||
Except_Red, //绿蓝色通道混合
|
Except_Red, //绿蓝色通道混合
|
||||||
Except_Green, //红蓝色通道混合
|
Except_Green, //红蓝色通道混合
|
||||||
Except_Blue //红绿色通道混合
|
Except_Blue //红绿色通道混合
|
||||||
}Channel;
|
}Channel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CImageApplyChannel();
|
CImageApplyChannel();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* channel [in]:通道模式
|
* channel [in]:通道模式
|
||||||
* */
|
* */
|
||||||
CImageApplyChannel(Channel channel);
|
CImageApplyChannel(Channel channel);
|
||||||
|
|
||||||
virtual ~CImageApplyChannel(void);
|
virtual ~CImageApplyChannel(void);
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib,int side);
|
virtual void apply(cv::Mat& pDib,int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void except_channel(const cv::Mat& src, cv::Mat& dst, int channel);
|
void except_channel(const cv::Mat& src, cv::Mat& dst, int channel);
|
||||||
|
|
||||||
void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80);
|
void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Channel m_channel;
|
Channel m_channel;
|
||||||
CImageApplyAdjustColors* colors;
|
CImageApplyAdjustColors* colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_CHANNEL_H
|
#endif // !IMAGE_APPLY_CHANNEL_H
|
||||||
|
|
|
@ -1,126 +1,155 @@
|
||||||
#include "ImageApplyColorRecognition.h"
|
#include "ImageApplyColorRecognition.h"
|
||||||
#include "ImageApplyHeaders.h"
|
#include "ImageApplyHeaders.h"
|
||||||
|
|
||||||
static CImageApplyBWBinaray m_bw;
|
static CImageApplyBWBinaray m_bw;
|
||||||
static CImageApplyAdjustColors m_ac(0, 50, 1.0f);
|
static CImageApplyAdjustColors m_ac(0, 50, 1.0f);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检测图像是否是彩色。当前逻辑仅针对红色像素进行判断,即存在红色像素则为彩色,否则为非彩色
|
/// 检测图像是否是彩色。当前逻辑仅针对红色像素进行判断,即存在红色像素则为彩色,否则为非彩色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="image">待测图像</param>
|
/// <param name="image">待测图像</param>
|
||||||
/// <returns>true为彩色,false为非彩色</returns>
|
/// <returns>true为彩色,false为非彩色</returns>
|
||||||
bool isColor(const cv::Mat& image)
|
bool isColor(const cv::Mat& image)
|
||||||
{
|
{
|
||||||
if (image.channels() != 3) return false;
|
if (image.channels() != 3) return false;
|
||||||
|
|
||||||
cv::Mat pDib_resize;
|
cv::Mat pDib_resize;
|
||||||
cv::resize(image, pDib_resize, cv::Size(image.cols / 9, image.rows / 9), 0, 0, cv::INTER_AREA);
|
cv::resize(image, pDib_resize, cv::Size(image.cols / 4, image.rows / 4), 0, 0, cv::INTER_NEAREST);
|
||||||
|
|
||||||
cv::Mat hsv;
|
cv::Mat hsv;
|
||||||
cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL);
|
cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL);
|
||||||
std::vector<cv::Mat> hsv_channels;
|
std::vector<cv::Mat> hsv_channels;
|
||||||
cv::split(hsv, hsv_channels);
|
cv::split(hsv, hsv_channels);
|
||||||
|
|
||||||
cv::Mat range_h1, range_h2, range_s, range_v;
|
cv::Mat range_s1, range_s2;
|
||||||
cv::inRange(hsv_channels[0], 0, 85, range_h1);
|
cv::inRange(hsv_channels[1], 220, 255, range_s1); //饱和度在[220, 255]的像素
|
||||||
cv::inRange(hsv_channels[0], 170, 255, range_h2);
|
cv::inRange(hsv_channels[1], 50, 220, range_s2); //饱和度在[50, 220]的像素
|
||||||
cv::inRange(hsv_channels[1], 60, 255, range_s);
|
#if 0
|
||||||
cv::inRange(hsv_channels[2], 100, 255, range_v);
|
cv::imwrite("range_s1.bmp", range_s1);
|
||||||
|
cv::imwrite("range_s2.bmp", range_s2);
|
||||||
cv::Mat thre = (range_h1 | range_h2) & range_s & range_v;
|
#endif
|
||||||
return (cv::sum(thre)[0] / 255)> 4;
|
double sum = cv::sum(range_s1)[0] / 255;
|
||||||
}
|
double total = range_s1.total();
|
||||||
|
|
||||||
bool isGray(const cv::Mat& image)
|
// if (sum / total > 0.0001)
|
||||||
{
|
if (sum / total > 0.001)
|
||||||
if (image.channels() == 3) return true;
|
return true;
|
||||||
|
sum += cv::sum(range_s2)[0] / 255;
|
||||||
cv::Mat image_clone;
|
// if (sum / total > 0.001)
|
||||||
cv::resize(image, image_clone, cv::Size(), 0.25, 0.25);
|
if (sum / total > 0.03)
|
||||||
int channels[] = { 0 };
|
return true;
|
||||||
int histsize[] = { 256 };
|
return false;
|
||||||
float range[] = { 0, 256 };
|
}
|
||||||
const float* histRanges[] = { range };
|
|
||||||
cv::Mat hist;
|
bool isGray(const cv::Mat& image)
|
||||||
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, histsize, histRanges, true, false);
|
{
|
||||||
|
//if (image.channels() == 3) return true;
|
||||||
float pixel_count0 = hist.at<float>(0, 0);
|
|
||||||
float pixel_count255 = hist.at<float>(255, 0);
|
//cv::Mat image_clone;
|
||||||
float total = image_clone.total();
|
//cv::resize(image, image_clone, cv::Size(), 0.25, 0.25);
|
||||||
|
//int channels[] = { 0 };
|
||||||
return ((pixel_count0 + pixel_count255) / total) > 0.95;
|
//int histsize[] = { 256 };
|
||||||
}
|
//float range[] = { 0, 256 };
|
||||||
|
//const float* histRanges[] = { range };
|
||||||
CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode)
|
//cv::Mat hist;
|
||||||
: m_mode(mode)
|
//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<float>(i, 0);
|
||||||
CImageApplyColorRecognition::~CImageApplyColorRecognition(void)
|
|
||||||
{
|
|
||||||
}
|
//float sum = 0;
|
||||||
|
//for (size_t i = 0; i < 40; i++)
|
||||||
void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side)
|
//{
|
||||||
{
|
|
||||||
//先判断是否需要判断是彩色
|
//}
|
||||||
if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono)
|
//float pixel_count0 = hist.at<float>(0, 0);
|
||||||
{
|
//float pixel_count255 = hist.at<float>(255, 0);
|
||||||
//如果是彩色,直接退出
|
//float total = image_clone.total();
|
||||||
if (isColor(pDib))
|
|
||||||
{
|
//return ((pixel_count0 + pixel_count255) / total) > 0.95;
|
||||||
m_result = Color;
|
return false;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
}
|
CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode)
|
||||||
|
: m_mode(mode)
|
||||||
if (pDib.channels() == 3)
|
{
|
||||||
cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
|
}
|
||||||
|
|
||||||
if (m_mode == Color_Gray)
|
CImageApplyColorRecognition::~CImageApplyColorRecognition(void)
|
||||||
{
|
{
|
||||||
m_result = Gray;
|
}
|
||||||
return;
|
|
||||||
}
|
void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side)
|
||||||
|
{
|
||||||
if (m_mode == Color_Mono)
|
if (pDib.channels() != 3)
|
||||||
{
|
{
|
||||||
m_bw.apply(pDib, side);
|
m_result = Gray;
|
||||||
m_result = Mono;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
m_result = isColor(pDib) ? Color : Gray;
|
||||||
|
if (m_result == Gray && pDib.channels() == 3)
|
||||||
if (isGray(pDib))
|
cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
|
||||||
m_result = Gray;
|
|
||||||
else
|
//先判断是否需要判断是彩色
|
||||||
{
|
//if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono)
|
||||||
m_bw.apply(pDib, side);
|
//{
|
||||||
m_result = Mono;
|
// //如果是彩色,直接退出
|
||||||
}
|
// if (isColor(pDib))
|
||||||
}
|
// {
|
||||||
|
// m_result = Color;
|
||||||
void CImageApplyColorRecognition::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
// return;
|
||||||
{
|
// }
|
||||||
m_results.clear();
|
//}
|
||||||
if (mats.empty()) return;
|
|
||||||
|
//if (pDib.channels() == 3)
|
||||||
if (!mats[0].empty())
|
// cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
|
||||||
apply(mats[0], 0);
|
|
||||||
|
//if (m_mode == Color_Gray)
|
||||||
m_results.push_back(m_result);
|
//{
|
||||||
|
// m_result = Gray;
|
||||||
if (isTwoSide && mats.size() > 1)
|
// return;
|
||||||
if (!mats[1].empty())
|
//}
|
||||||
apply(mats[1], 1);
|
|
||||||
|
//if (m_mode == Color_Mono)
|
||||||
m_results.push_back(m_result);
|
//{
|
||||||
}
|
// m_bw.apply(pDib, side);
|
||||||
|
// m_result = Mono;
|
||||||
CImageApplyColorRecognition::ColorType CImageApplyColorRecognition::getResult()
|
// return;
|
||||||
{
|
//}
|
||||||
return m_result;
|
|
||||||
}
|
//if (isGray(pDib))
|
||||||
|
// m_result = Gray;
|
||||||
std::vector<CImageApplyColorRecognition::ColorType> CImageApplyColorRecognition::getResults()
|
//else
|
||||||
{
|
//{
|
||||||
return m_results;
|
// m_bw.apply(pDib, side);
|
||||||
}
|
// m_result = Mono;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CImageApplyColorRecognition::apply(std::vector<cv::Mat>& 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::ColorType> CImageApplyColorRecognition::getResults()
|
||||||
|
{
|
||||||
|
return m_results;
|
||||||
|
}
|
||||||
|
|
|
@ -1,68 +1,68 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:色彩识别,将识别会“灰度”的24位图转化为256色8位图, 把识别为“黑白”图转化为二值化的8位图
|
* 功能:色彩识别,将识别会“灰度”的24位图转化为256色8位图, 把识别为“黑白”图转化为二值化的8位图
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/7/17
|
* 生成时间:2020/7/17
|
||||||
* 最近修改时间:2021/04/19
|
* 最近修改时间:2021/04/19
|
||||||
* 版本号:v1.0 2020/7/17
|
* 版本号:v1.0 2020/7/17
|
||||||
* v1.1 2020/12/15 调整策略,仅判断红色像素,存在红色像素为彩色,否则为灰度;删除输出结果,直接转换图像。
|
* v1.1 2020/12/15 调整策略,仅判断红色像素,存在红色像素为彩色,否则为灰度;删除输出结果,直接转换图像。
|
||||||
* v1.2 2020/12/16 增加颜色限制模式(输出结果只可能两种),增加结果访问接口
|
* v1.2 2020/12/16 增加颜色限制模式(输出结果只可能两种),增加结果访问接口
|
||||||
* v1.3 2021/04/19 修改识别策略,能够识别占比1‰的彩色图像。只区分彩色和灰度图。
|
* v1.3 2021/04/19 修改识别策略,能够识别占比1‰的彩色图像。只区分彩色和灰度图。
|
||||||
* v1.4 2021/06/18 调整二级色彩区间,从原来的[90, 200]调整为[50, 200]。
|
* v1.4 2021/06/18 调整二级色彩区间,从原来的[90, 200]调整为[50, 200]。
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H
|
#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H
|
||||||
#define IMAGE_APPLY_COLOR_RECOGNITION_H
|
#define IMAGE_APPLY_COLOR_RECOGNITION_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyColorRecognition : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyColorRecognition : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//色彩识别模式
|
//色彩识别模式
|
||||||
enum ColorRecognitionMode
|
enum ColorRecognitionMode
|
||||||
{
|
{
|
||||||
AllColor, //全色模式 识别结果可能会是彩色、灰度、黑白
|
AllColor, //全色模式 识别结果可能会是彩色、灰度、黑白
|
||||||
Color_Gray, //彩色灰度模式 识别结果只会是彩色或者灰度
|
Color_Gray, //彩色灰度模式 识别结果只会是彩色或者灰度
|
||||||
Color_Mono, //彩色黑白模式 识别结果只会是彩色或者黑白
|
Color_Mono, //彩色黑白模式 识别结果只会是彩色或者黑白
|
||||||
Gray_Mono //灰度黑白模式 识别结果只会是灰度或者黑白
|
Gray_Mono //灰度黑白模式 识别结果只会是灰度或者黑白
|
||||||
};
|
};
|
||||||
|
|
||||||
//色彩类型
|
//色彩类型
|
||||||
enum ColorType
|
enum ColorType
|
||||||
{
|
{
|
||||||
Color, //彩色
|
Color, //彩色
|
||||||
Gray, //灰度
|
Gray, //灰度
|
||||||
Mono //黑白
|
Mono //黑白
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor);
|
CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor);
|
||||||
|
|
||||||
virtual ~CImageApplyColorRecognition(void);
|
virtual ~CImageApplyColorRecognition(void);
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取图片色彩类型。配合void apply(cv::Mat&, int)接口使用
|
/// 获取图片色彩类型。配合void apply(cv::Mat&, int)接口使用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>色彩类型</returns>
|
/// <returns>色彩类型</returns>
|
||||||
ColorType getResult();
|
ColorType getResult();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取图片色彩类型。配合void apply(std::vector<cv::Mat>&, int)接口使用
|
/// 获取图片色彩类型。配合void apply(std::vector<cv::Mat>&, int)接口使用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>色彩类型数组</returns>
|
/// <returns>色彩类型数组</returns>
|
||||||
std::vector<ColorType> getResults();
|
std::vector<ColorType> getResults();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ColorType m_result;
|
ColorType m_result;
|
||||||
std::vector<ColorType> m_results;
|
std::vector<ColorType> m_results;
|
||||||
ColorRecognitionMode m_mode;
|
ColorRecognitionMode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_CONCATENATION_H
|
#endif // !IMAGE_APPLY_CONCATENATION_H
|
||||||
|
|
|
@ -1,108 +1,108 @@
|
||||||
#include "ImageApplyConcatenation.h"
|
#include "ImageApplyConcatenation.h"
|
||||||
|
|
||||||
CImageApplyConcatenation::CImageApplyConcatenation()
|
CImageApplyConcatenation::CImageApplyConcatenation()
|
||||||
: m_direction(autoDirection)
|
: m_direction(autoDirection)
|
||||||
, m_BG_color(0, 0, 0)
|
, m_BG_color(0, 0, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyConcatenation::CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& background)
|
CImageApplyConcatenation::CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& background)
|
||||||
: m_direction(dir)
|
: m_direction(dir)
|
||||||
, m_BG_color(background)
|
, m_BG_color(background)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyConcatenation::~CImageApplyConcatenation(void)
|
CImageApplyConcatenation::~CImageApplyConcatenation(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyConcatenation::apply(cv::Mat& pDib, int side)
|
void CImageApplyConcatenation::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)pDib;
|
(void)pDib;
|
||||||
(void)side;
|
(void)side;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyConcatenation::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyConcatenation::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
if (mats.size() < 2)
|
if (mats.size() < 2)
|
||||||
{
|
{
|
||||||
mats.clear();
|
mats.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcatMode direction;
|
ConcatMode direction;
|
||||||
if (m_direction == ConcatMode::autoDirection)
|
if (m_direction == ConcatMode::autoDirection)
|
||||||
direction = (mats[0].cols > mats[0].rows) ? ConcatMode::vertical : ConcatMode::horizontal;
|
direction = (mats[0].cols > mats[0].rows) ? ConcatMode::vertical : ConcatMode::horizontal;
|
||||||
else
|
else
|
||||||
direction = m_direction;
|
direction = m_direction;
|
||||||
cv::Mat dst = concat(mats[0], mats[1], direction);
|
cv::Mat dst = concat(mats[0], mats[1], direction);
|
||||||
mats.clear();
|
mats.clear();
|
||||||
mats.push_back(dst);
|
mats.push_back(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat CImageApplyConcatenation::concat(cv::Mat &front, cv::Mat &back, ConcatMode direction)
|
cv::Mat CImageApplyConcatenation::concat(cv::Mat &front, cv::Mat &back, ConcatMode direction)
|
||||||
{
|
{
|
||||||
cv::Mat dst;
|
cv::Mat dst;
|
||||||
if (direction == horizontal)
|
if (direction == horizontal)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
int top, bottom;
|
int top, bottom;
|
||||||
if (front.rows > back.rows)
|
if (front.rows > back.rows)
|
||||||
{
|
{
|
||||||
top = (front.rows - back.rows) / 2;
|
top = (front.rows - back.rows) / 2;
|
||||||
bottom = front.rows - back.rows - top;
|
bottom = front.rows - back.rows - top;
|
||||||
cv::copyMakeBorder(back, back, top, bottom, 0, 0, cv::BORDER_CONSTANT);
|
cv::copyMakeBorder(back, back, top, bottom, 0, 0, cv::BORDER_CONSTANT);
|
||||||
}
|
}
|
||||||
else if (front.rows < back.rows)
|
else if (front.rows < back.rows)
|
||||||
{
|
{
|
||||||
top = (back.rows - front.rows) / 2;
|
top = (back.rows - front.rows) / 2;
|
||||||
bottom = back.rows - front.rows - top;
|
bottom = back.rows - front.rows - top;
|
||||||
cv::copyMakeBorder(front, front, top, bottom, 0, 0, cv::BORDER_CONSTANT);
|
cv::copyMakeBorder(front, front, top, bottom, 0, 0, cv::BORDER_CONSTANT);
|
||||||
}
|
}
|
||||||
cv::hconcat(front, back, dst);
|
cv::hconcat(front, back, dst);
|
||||||
#else
|
#else
|
||||||
int width = cv::max(front.cols, back.cols) * 2;
|
int width = cv::max(front.cols, back.cols) * 2;
|
||||||
int height = cv::max(front.rows, back.rows);
|
int height = cv::max(front.rows, back.rows);
|
||||||
|
|
||||||
dst = cv::Mat(height, width, front.type(), m_BG_color);
|
dst = cv::Mat(height, width, front.type(), m_BG_color);
|
||||||
front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows)));
|
front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows)));
|
||||||
int offset = front.cols;
|
int offset = front.cols;
|
||||||
front.release();
|
front.release();
|
||||||
back.copyTo(dst(cv::Rect(offset, 0, back.cols, back.rows)));
|
back.copyTo(dst(cv::Rect(offset, 0, back.cols, back.rows)));
|
||||||
back.release();
|
back.release();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (direction == vertical)
|
else if (direction == vertical)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
int left, right;
|
int left, right;
|
||||||
if (front.cols > back.cols)
|
if (front.cols > back.cols)
|
||||||
{
|
{
|
||||||
left = (front.cols - back.cols) / 2;
|
left = (front.cols - back.cols) / 2;
|
||||||
right = front.cols - back.cols - left;
|
right = front.cols - back.cols - left;
|
||||||
cv::copyMakeBorder(back, back, 0, 0, left, right, cv::BORDER_CONSTANT);
|
cv::copyMakeBorder(back, back, 0, 0, left, right, cv::BORDER_CONSTANT);
|
||||||
}
|
}
|
||||||
else if (front.cols < back.cols)
|
else if (front.cols < back.cols)
|
||||||
{
|
{
|
||||||
left = (back.cols - front.cols) / 2;
|
left = (back.cols - front.cols) / 2;
|
||||||
right = back.cols - front.cols - left;
|
right = back.cols - front.cols - left;
|
||||||
cv::copyMakeBorder(front, front, 0, 0, left, right, cv::BORDER_CONSTANT);
|
cv::copyMakeBorder(front, front, 0, 0, left, right, cv::BORDER_CONSTANT);
|
||||||
}
|
}
|
||||||
cv::vconcat(front, back, dst);
|
cv::vconcat(front, back, dst);
|
||||||
#else
|
#else
|
||||||
int width = cv::max(front.cols, back.cols);
|
int width = cv::max(front.cols, back.cols);
|
||||||
int height = cv::max(front.rows, back.rows) * 2;
|
int height = cv::max(front.rows, back.rows) * 2;
|
||||||
|
|
||||||
dst = cv::Mat(height, width, front.type(), m_BG_color);
|
dst = cv::Mat(height, width, front.type(), m_BG_color);
|
||||||
front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows)));
|
front.copyTo(dst(cv::Rect(0, 0, front.cols, front.rows)));
|
||||||
int offset = front.rows;
|
int offset = front.rows;
|
||||||
front.release();
|
front.release();
|
||||||
back.copyTo(dst(cv::Rect(0, offset, back.cols, back.rows)));
|
back.copyTo(dst(cv::Rect(0, offset, back.cols, back.rows)));
|
||||||
back.release();
|
back.release();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//front.release();
|
//front.release();
|
||||||
//back.release();
|
//back.release();
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,60 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:拼接,又名对折
|
* 功能:拼接,又名对折
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/29
|
* 最近修改时间:2020/4/29
|
||||||
* 版本号:v1.0 2020/4/21
|
* 版本号:v1.0 2020/4/21
|
||||||
* 版本号:v1.1 2020/4/29 : 1、添加m_BG_color接口,可设置图片背景;2、优化内存消耗
|
* 版本号:v1.1 2020/4/29 : 1、添加m_BG_color接口,可设置图片背景;2、优化内存消耗
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_CONCATENATION_H
|
#ifndef IMAGE_APPLY_CONCATENATION_H
|
||||||
#define IMAGE_APPLY_CONCATENATION_H
|
#define IMAGE_APPLY_CONCATENATION_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyConcatenation : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyConcatenation : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//对折方向
|
//对折方向
|
||||||
enum ConcatMode
|
enum ConcatMode
|
||||||
{
|
{
|
||||||
horizontal = 0, //左右拼接 吅
|
horizontal = 0, //左右拼接 吅
|
||||||
vertical, //上下拼接 吕
|
vertical, //上下拼接 吕
|
||||||
autoDirection
|
autoDirection
|
||||||
|
};
|
||||||
};
|
public:
|
||||||
public:
|
CImageApplyConcatenation(); //默认m_direction = autoDirection;
|
||||||
CImageApplyConcatenation(); //默认m_direction = autoDirection;
|
|
||||||
|
/*
|
||||||
/*
|
* dir [in]:拼接方向
|
||||||
* dir [in]:拼接方向
|
* backgroud [in]:背景颜色,默认为黑色
|
||||||
* backgroud [in]:背景颜色,默认为黑色
|
* */
|
||||||
* */
|
CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& backgroud = cv::Scalar(0, 0, 0));
|
||||||
CImageApplyConcatenation(ConcatMode dir, const cv::Scalar& backgroud = cv::Scalar(0, 0, 0));
|
|
||||||
|
virtual ~CImageApplyConcatenation(void);
|
||||||
virtual ~CImageApplyConcatenation(void);
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
inline ConcatMode getConcatDirection() { return m_direction; }
|
||||||
inline ConcatMode getConcatDirection() { return m_direction; }
|
|
||||||
|
inline void setFildDirection(ConcatMode dir) { m_direction = dir; }
|
||||||
inline void setFildDirection(ConcatMode dir) { m_direction = dir; }
|
|
||||||
|
inline cv::Scalar getBackGroundColor() const { return m_BG_color; }
|
||||||
inline cv::Scalar getBackGroundColor() const { return m_BG_color; }
|
|
||||||
|
inline void setBackGroundColor(const cv::Scalar& color) { m_BG_color = color; }
|
||||||
inline void setBackGroundColor(const cv::Scalar& color) { m_BG_color = color; }
|
|
||||||
|
private:
|
||||||
private:
|
|
||||||
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
|
||||||
|
cv::Mat concat(cv::Mat& front, cv::Mat& back, ConcatMode direction = autoDirection);
|
||||||
cv::Mat concat(cv::Mat& front, cv::Mat& back, ConcatMode direction = autoDirection);
|
|
||||||
|
private:
|
||||||
private:
|
ConcatMode m_direction;
|
||||||
ConcatMode m_direction;
|
cv::Scalar m_BG_color;
|
||||||
cv::Scalar m_BG_color;
|
};
|
||||||
};
|
|
||||||
|
#endif // !IMAGE_APPLY_CONCATENATION_H
|
||||||
#endif // !IMAGE_APPLY_CONCATENATION_H
|
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
#include "ImageApplyCustomCrop.h"
|
#include "ImageApplyCustomCrop.h"
|
||||||
|
|
||||||
CImageApplyCustomCrop::CImageApplyCustomCrop(const cv::Rect &rect)
|
CImageApplyCustomCrop::CImageApplyCustomCrop(const cv::Rect &rect)
|
||||||
: m_rect(rect)
|
: m_rect(rect)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyCustomCrop::~CImageApplyCustomCrop()
|
CImageApplyCustomCrop::~CImageApplyCustomCrop()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomCrop::apply(cv::Mat &pDib, int side)
|
void CImageApplyCustomCrop::apply(cv::Mat &pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if(pDib.empty()) return;
|
if(pDib.empty()) return;
|
||||||
pDib = pDib(cv::Rect(0, 0, pDib.cols, pDib.rows) & m_rect).clone();
|
pDib = pDib(cv::Rect(0, 0, pDib.cols, pDib.rows) & m_rect).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomCrop::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
void CImageApplyCustomCrop::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:自定义裁剪
|
* 功能:自定义裁剪
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_CUSTOM_CROP_H
|
#ifndef IMAGE_APPLY_CUSTOM_CROP_H
|
||||||
#define IMAGE_APPLY_CUSTOM_CROP_H
|
#define IMAGE_APPLY_CUSTOM_CROP_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyCustomCrop : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyCustomCrop : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rect [in]:裁剪区域
|
* rect [in]:裁剪区域
|
||||||
* */
|
* */
|
||||||
CImageApplyCustomCrop(const cv::Rect& rect);
|
CImageApplyCustomCrop(const cv::Rect& rect);
|
||||||
|
|
||||||
virtual~ CImageApplyCustomCrop(void);
|
virtual~ CImageApplyCustomCrop(void);
|
||||||
|
|
||||||
inline cv::Rect getROI() const { return m_rect; }
|
inline cv::Rect getROI() const { return m_rect; }
|
||||||
|
|
||||||
inline void setROI(const cv::Rect& roi) { m_rect = roi; }
|
inline void setROI(const cv::Rect& roi) { m_rect = roi; }
|
||||||
|
|
||||||
virtual void apply(cv::Mat &pDib, int side);
|
virtual void apply(cv::Mat &pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
private:
|
private:
|
||||||
cv::Rect m_rect;
|
cv::Rect m_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMAGE_APPLY_CUSTOM_CROP_H
|
#endif // IMAGE_APPLY_CUSTOM_CROP_H
|
||||||
|
|
|
@ -1,63 +1,63 @@
|
||||||
#include "ImageApplyCustomGamma.h"
|
#include "ImageApplyCustomGamma.h"
|
||||||
|
|
||||||
CImageApplyCustomGamma::CImageApplyCustomGamma(unsigned char* table,int length)
|
CImageApplyCustomGamma::CImageApplyCustomGamma(unsigned char* table,int length)
|
||||||
: emptyPtr(false)
|
: emptyPtr(false)
|
||||||
{
|
{
|
||||||
if(table==nullptr)
|
if(table==nullptr)
|
||||||
emptyPtr = true;
|
emptyPtr = true;
|
||||||
|
|
||||||
init_gamma_table();
|
init_gamma_table();
|
||||||
setLUT(table,length == 256 ? 1 : 3);
|
setLUT(table,length == 256 ? 1 : 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyCustomGamma::~CImageApplyCustomGamma()
|
CImageApplyCustomGamma::~CImageApplyCustomGamma()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomGamma::setLUT(const unsigned char* table, int byteCount)
|
void CImageApplyCustomGamma::setLUT(const unsigned char* table, int byteCount)
|
||||||
{
|
{
|
||||||
if (emptyPtr)
|
if (emptyPtr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (byteCount == 1)
|
if (byteCount == 1)
|
||||||
memcpy(m_table_bit8, table, 256);
|
memcpy(m_table_bit8, table, 256);
|
||||||
else if (byteCount == 3)
|
else if (byteCount == 3)
|
||||||
memcpy(m_table_bit24, table, 768);
|
memcpy(m_table_bit24, table, 768);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomGamma::apply(cv::Mat& pDib, int side)
|
void CImageApplyCustomGamma::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (emptyPtr)
|
if (emptyPtr)
|
||||||
return;
|
return;
|
||||||
int numOfChannels = pDib.channels();
|
int numOfChannels = pDib.channels();
|
||||||
cv::Mat mat_table(1, 256, CV_8UC(numOfChannels), (numOfChannels == 3) ? m_table_bit24 : m_table_bit8);
|
cv::Mat mat_table(1, 256, CV_8UC(numOfChannels), (numOfChannels == 3) ? m_table_bit24 : m_table_bit8);
|
||||||
cv::LUT(pDib, mat_table, pDib);
|
cv::LUT(pDib, mat_table, pDib);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomGamma::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyCustomGamma::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomGamma::setTableData(const unsigned char* data, int length)
|
void CImageApplyCustomGamma::setTableData(const unsigned char* data, int length)
|
||||||
{
|
{
|
||||||
setLUT(data, length == 256 ? 1 : 3);
|
setLUT(data, length == 256 ? 1 : 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCustomGamma::init_gamma_table()
|
void CImageApplyCustomGamma::init_gamma_table()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < 256; ++i)
|
for (size_t i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
m_table_bit8[i] = static_cast<unsigned char>(i);
|
m_table_bit8[i] = static_cast<unsigned char>(i);
|
||||||
m_table_bit24[i * 3] = m_table_bit24[i * 3 + 1] = m_table_bit24[i * 3 + 2] = static_cast<unsigned char>(i);
|
m_table_bit24[i * 3] = m_table_bit24[i * 3 + 1] = m_table_bit24[i * 3 + 2] = static_cast<unsigned char>(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:自定义伽马校正。原理为哈希表查值
|
* 功能:自定义伽马校正。原理为哈希表查值
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_CUSTOM_CAMMA_H
|
#ifndef IMAGE_APPLY_CUSTOM_CAMMA_H
|
||||||
#define IMAGE_APPLY_CUSTOM_CAMMA_H
|
#define IMAGE_APPLY_CUSTOM_CAMMA_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyCustomGamma : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyCustomGamma : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* table [in]:自定义查值表
|
* table [in]:自定义查值表
|
||||||
* length [in]:表的长度,灰度表256,彩色表768
|
* length [in]:表的长度,灰度表256,彩色表768
|
||||||
* */
|
* */
|
||||||
CImageApplyCustomGamma(unsigned char* table,int length);
|
CImageApplyCustomGamma(unsigned char* table,int length);
|
||||||
|
|
||||||
virtual ~CImageApplyCustomGamma();
|
virtual ~CImageApplyCustomGamma();
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
void setTableData(const unsigned char* data, int length);
|
void setTableData(const unsigned char* data, int length);
|
||||||
private:
|
private:
|
||||||
void init_gamma_table();
|
void init_gamma_table();
|
||||||
void setLUT(const unsigned char* table, int byteCount);
|
void setLUT(const unsigned char* table, int byteCount);
|
||||||
bool emptyPtr;
|
bool emptyPtr;
|
||||||
private:
|
private:
|
||||||
unsigned char m_table_bit8[256];
|
unsigned char m_table_bit8[256];
|
||||||
|
|
||||||
unsigned char m_table_bit24[768];
|
unsigned char m_table_bit24[768];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H
|
#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
#include "ImageApplyCvtColor.h"
|
#include "ImageApplyCvtColor.h"
|
||||||
|
|
||||||
CImageApplyCvtColor::CImageApplyCvtColor(ConversionCodes type)
|
CImageApplyCvtColor::CImageApplyCvtColor(ConversionCodes type)
|
||||||
: m_code(type)
|
: m_code(type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyCvtColor::~CImageApplyCvtColor()
|
CImageApplyCvtColor::~CImageApplyCvtColor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCvtColor::apply(cv::Mat& pDib, int side)
|
void CImageApplyCvtColor::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.channels() == 1) return;
|
if (pDib.channels() == 1) return;
|
||||||
if (m_code > 3)
|
if (m_code > 3)
|
||||||
cv::cvtColor(pDib, pDib, static_cast<cv::ColorConversionCodes>(m_code));
|
cv::cvtColor(pDib, pDib, static_cast<cv::ColorConversionCodes>(m_code));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cv::Mat gray(pDib.size(), CV_8UC1);
|
cv::Mat gray(pDib.size(), CV_8UC1);
|
||||||
if (m_code == BGR_MAX)
|
if (m_code == BGR_MAX)
|
||||||
{
|
{
|
||||||
for (size_t y = 0, rows = pDib.rows; y < rows; y++)
|
for (size_t y = 0, rows = pDib.rows; y < rows; y++)
|
||||||
{
|
{
|
||||||
uchar* ptr_y = pDib.ptr(y);
|
uchar* ptr_y = pDib.ptr(y);
|
||||||
uchar* gray_y = gray.ptr(y);
|
uchar* gray_y = gray.ptr(y);
|
||||||
for (size_t x = 0, cols = pDib.cols; x < cols; x++)
|
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]));
|
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)
|
else if (m_code == BGR_MIN)
|
||||||
{
|
{
|
||||||
for (size_t y = 0, rows = pDib.rows; y < rows; y++)
|
for (size_t y = 0, rows = pDib.rows; y < rows; y++)
|
||||||
{
|
{
|
||||||
uchar* ptr_y = pDib.ptr(y);
|
uchar* ptr_y = pDib.ptr(y);
|
||||||
uchar* gray_y = gray.ptr(y);
|
uchar* gray_y = gray.ptr(y);
|
||||||
for (size_t x = 0, cols = pDib.cols; x < cols; x++)
|
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]));
|
gray_y[x] = cv::min(ptr_y[x * 3], cv::min(ptr_y[x * 3 + 1], ptr_y[x * 3 + 2]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pDib.release();
|
pDib.release();
|
||||||
pDib = gray;
|
pDib = gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyCvtColor::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyCvtColor::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,52 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:色彩变换
|
* 功能:色彩变换
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/6/19
|
* 生成时间:2020/6/19
|
||||||
* 最近修改时间:v1.0 2020/6/19
|
* 最近修改时间:v1.0 2020/6/19
|
||||||
v1.1 2020/6/20 添加BGR转HSV,添加BGR_MAX,添加BGR_MIN
|
v1.1 2020/6/20 添加BGR转HSV,添加BGR_MAX,添加BGR_MIN
|
||||||
* 版本号:v1.1
|
* 版本号:v1.1
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_CONVERT_COLOR_H
|
#ifndef IMAGE_APPLY_CONVERT_COLOR_H
|
||||||
#define IMAGE_APPLY_CONVERT_COLOR_H
|
#define IMAGE_APPLY_CONVERT_COLOR_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyCvtColor : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyCvtColor : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//转换模式
|
//转换模式
|
||||||
enum ConversionCodes
|
enum ConversionCodes
|
||||||
{
|
{
|
||||||
BGR_MAX = 1, //BGR取大值,转GRAY
|
BGR_MAX = 1, //BGR取大值,转GRAY
|
||||||
BGR_MIN = 2, //BGR取小值,转GRAY
|
BGR_MIN = 2, //BGR取小值,转GRAY
|
||||||
BGR2GRAY = 6, //BGR转GRAY
|
BGR2GRAY = 6, //BGR转GRAY
|
||||||
BGR2HSV = 40 //BGR转HSV
|
BGR2HSV = 40 //BGR转HSV
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* type [in]:色彩转换模式,默认BGR转Gray
|
* type [in]:色彩转换模式,默认BGR转Gray
|
||||||
* */
|
* */
|
||||||
CImageApplyCvtColor(ConversionCodes type = BGR2GRAY);
|
CImageApplyCvtColor(ConversionCodes type = BGR2GRAY);
|
||||||
|
|
||||||
virtual ~CImageApplyCvtColor();
|
virtual ~CImageApplyCvtColor();
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
inline ConversionCodes getConversionCode() { return m_code; }
|
inline ConversionCodes getConversionCode() { return m_code; }
|
||||||
|
|
||||||
inline void setConversionCode(ConversionCodes code) { m_code = code; }
|
inline void setConversionCode(ConversionCodes code) { m_code = code; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConversionCodes m_code;
|
ConversionCodes m_code;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H
|
#endif // !IMAGE_APPLY_CUSTOM_CAMMA_H
|
||||||
|
|
|
@ -1,42 +1,46 @@
|
||||||
#include "ImageApplyDetachNoise.h"
|
#include "ImageApplyDetachNoise.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
CImageApplyDetachNoise::CImageApplyDetachNoise(int noise)
|
CImageApplyDetachNoise::CImageApplyDetachNoise(int noise)
|
||||||
: m_noise(noise)
|
: m_noise(noise)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyDetachNoise::~CImageApplyDetachNoise(void)
|
CImageApplyDetachNoise::~CImageApplyDetachNoise(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side)
|
void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.empty()||pDib.channels() != 1)
|
if (pDib.empty()||pDib.channels() != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cv::Mat mask;
|
cv::Mat mask;
|
||||||
cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV);
|
cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV);
|
||||||
|
|
||||||
std::vector<std::vector<cv::Point>> contours;
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
std::vector<cv::Vec4i> h;
|
std::vector<cv::Vec4i> h;
|
||||||
hg::findContours(mask, contours, h);
|
hg::findContours(mask, contours, h);
|
||||||
|
|
||||||
for (const std::vector<cv::Point>& contour : contours)
|
for (const std::vector<cv::Point>& contour : contours)
|
||||||
if (contourArea(contour) < m_noise)
|
{
|
||||||
fillConvexPoly(pDib, contour, cv::Scalar(255));
|
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<cv::Mat> &mats, bool isTwoSide)
|
|
||||||
{
|
}
|
||||||
(void)isTwoSide;
|
}
|
||||||
int i = 0;
|
|
||||||
for (cv::Mat& var : mats) {
|
void CImageApplyDetachNoise::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
||||||
if (i != 0 && isTwoSide == false)
|
{
|
||||||
break;
|
(void)isTwoSide;
|
||||||
if (!var.empty())
|
int i = 0;
|
||||||
apply(var, 0);
|
for (cv::Mat& var : mats) {
|
||||||
i++;
|
if (i != 0 && isTwoSide == false)
|
||||||
}
|
break;
|
||||||
}
|
if (!var.empty())
|
||||||
|
apply(var, 0);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,46 +1,39 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:除噪,消除3*3以内的像素点,主要针对黑白图
|
* 功能:除噪,消除3*3以内的像素点,主要针对黑白图
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21 v1.0
|
* 最近修改时间:2020/4/21 v1.0
|
||||||
2020/5/29 v1.1 增加接口,使噪点大小阈值可调
|
2020/05/29 v1.1 增加接口,使噪点大小阈值可调
|
||||||
* 版本号:v1.1
|
2021/08/03 v1.2 设置默认noise尺寸为3,表示3*3的block尺寸;将判定逻辑由原来的尺寸变为矩形长宽。
|
||||||
|
* 版本号:v1.2
|
||||||
* ====================================================
|
|
||||||
*/
|
* ====================================================
|
||||||
|
*/
|
||||||
#ifndef IMAGE_APPLY_DETACH_NOISE_H
|
|
||||||
#define IMAGE_APPLY_DETACH_NOISE_H
|
#ifndef IMAGE_APPLY_DETACH_NOISE_H
|
||||||
|
#define IMAGE_APPLY_DETACH_NOISE_H
|
||||||
#include "ImageApply.h"
|
|
||||||
|
#include "ImageApply.h"
|
||||||
class CImageApplyDetachNoise : public CImageApply
|
|
||||||
{
|
class GIMGPROC_LIBRARY_API CImageApplyDetachNoise : public CImageApply
|
||||||
public:
|
{
|
||||||
CImageApplyDetachNoise(int
|
public:
|
||||||
|
CImageApplyDetachNoise(int noise = 3);
|
||||||
|
|
||||||
|
inline int getNoise() { return m_noise; }
|
||||||
|
|
||||||
|
inline void setNoise(int noise) { m_noise = noise; }
|
||||||
|
|
||||||
|
virtual ~CImageApplyDetachNoise(void);
|
||||||
= 1);
|
|
||||||
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
inline int getNoise() { return m_noise; }
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
inline void setNoise(int noise) { m_noise = noise; }
|
|
||||||
|
private:
|
||||||
virtual ~CImageApplyDetachNoise(void);
|
int m_noise;
|
||||||
|
};
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
#endif // !IMAGE_APPLY_DETACH_NOISE_H
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_noise;
|
|
||||||
};
|
|
||||||
#endif // !IMAGE_APPLY_DETACH_NOISE_H
|
|
||||||
|
|
||||||
|
|
|
@ -1,114 +1,114 @@
|
||||||
#include "ImageApplyDiscardBlank.h"
|
#include "ImageApplyDiscardBlank.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh)
|
CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh)
|
||||||
: m_threshold(threshold)
|
: m_threshold(threshold)
|
||||||
, m_edge(edge)
|
, m_edge(edge)
|
||||||
, m_devTh(devTh)
|
, m_devTh(devTh)
|
||||||
, m_meanTh(meanTh)
|
, m_meanTh(meanTh)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void)
|
CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side)
|
void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
if (apply(pDib, m_threshold, m_edge, m_devTh))
|
if (apply(pDib, m_threshold, m_edge, m_devTh))
|
||||||
pDib.release();
|
pDib.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyDiscardBlank::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyDiscardBlank::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2)
|
bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
if (val1[i] > val2[i])
|
if (val1[i] > val2[i])
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh)
|
bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh)
|
||||||
{
|
{
|
||||||
double min, max;
|
double min, max;
|
||||||
cv::minMaxLoc(img, &min, &max, 0, 0, mask);
|
cv::minMaxLoc(img, &min, &max, 0, 0, mask);
|
||||||
if (cv::mean(img, mask)[0] < meanTh)
|
if (cv::mean(img, mask)[0] < meanTh)
|
||||||
return false;
|
return false;
|
||||||
return (max - min) < devTh;
|
return (max - min) < devTh;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh)
|
bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh)
|
||||||
{
|
{
|
||||||
if (pDib.empty())
|
if (pDib.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
cv::Mat img_resize;
|
cv::Mat img_resize;
|
||||||
cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2);
|
cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2);
|
||||||
|
|
||||||
cv::Mat threshold_img;
|
cv::Mat threshold_img;
|
||||||
if (img_resize.channels() == 3)
|
if (img_resize.channels() == 3)
|
||||||
cv::cvtColor(img_resize, threshold_img, cv::COLOR_BGR2GRAY);
|
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);
|
cv::threshold(img_resize.channels() == 3 ? threshold_img : img_resize, threshold_img, threshold, 255, CV_THRESH_BINARY);
|
||||||
|
|
||||||
std::vector<std::vector<cv::Point>> contours;
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
std::vector<cv::Vec4i> h1;
|
std::vector<cv::Vec4i> h1;
|
||||||
hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
|
hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
|
||||||
|
|
||||||
std::vector<cv::Point> contour;
|
std::vector<cv::Point> contour;
|
||||||
for (const std::vector<cv::Point>& sub : contours)
|
for (const std::vector<cv::Point>& sub : contours)
|
||||||
for (const cv::Point& p : sub)
|
for (const cv::Point& p : sub)
|
||||||
contour.push_back(p);
|
contour.push_back(p);
|
||||||
|
|
||||||
cv::RotatedRect rect = hg::getBoundingRect(contour);
|
cv::RotatedRect rect = hg::getBoundingRect(contour);
|
||||||
rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5);
|
rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5);
|
||||||
cv::Point2f box[4];
|
cv::Point2f box[4];
|
||||||
rect.points(box);
|
rect.points(box);
|
||||||
contour.clear();
|
contour.clear();
|
||||||
contours.clear();
|
contours.clear();
|
||||||
|
|
||||||
for (size_t i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
contour.push_back(box[i]);
|
contour.push_back(box[i]);
|
||||||
contours.push_back(contour);
|
contours.push_back(contour);
|
||||||
cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1);
|
cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1);
|
||||||
hg::fillPolys(mask, contours, cv::Scalar::all(255));
|
hg::fillPolys(mask, contours, cv::Scalar::all(255));
|
||||||
cv::blur(img_resize, img_resize, cv::Size(3, 3));
|
cv::blur(img_resize, img_resize, cv::Size(3, 3));
|
||||||
|
|
||||||
bool b = true;
|
bool b = true;
|
||||||
if (img_resize.channels() == 3)
|
if (img_resize.channels() == 3)
|
||||||
{
|
{
|
||||||
cv::Mat bgr[3];
|
cv::Mat bgr[3];
|
||||||
cv::split(img_resize, bgr);
|
cv::split(img_resize, bgr);
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
b &= maxMinCompare(bgr[i], mask, devTh, meanTh);
|
b &= maxMinCompare(bgr[i], mask, devTh, meanTh);
|
||||||
if (!b) break;
|
if (!b) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
b &= maxMinCompare(img_resize, mask, devTh, meanTh);
|
b &= maxMinCompare(img_resize, mask, devTh, meanTh);
|
||||||
/*
|
/*
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
cv::imwrite("<EFBFBD>հ<EFBFBD>ҳ/img1/" + std::to_string(index) + ".bmp", img_resize);
|
cv::imwrite("¿Õ°×Ò³/img1/" + std::to_string(index) + ".bmp", img_resize);
|
||||||
cv::imwrite("<EFBFBD>հ<EFBFBD>ҳ/mask1/" + std::to_string(index) + ".bmp", mask);
|
cv::imwrite("¿Õ°×Ò³/mask1/" + std::to_string(index) + ".bmp", mask);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cv::imwrite("<EFBFBD>հ<EFBFBD>ҳ/img2/" + std::to_string(index) + ".bmp", img_resize);
|
cv::imwrite("¿Õ°×Ò³/img2/" + std::to_string(index) + ".bmp", img_resize);
|
||||||
cv::imwrite("<EFBFBD>հ<EFBFBD>ҳ/mask2/" + std::to_string(index) + ".bmp", mask);
|
cv::imwrite("¿Õ°×Ò³/mask2/" + std::to_string(index) + ".bmp", mask);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,48 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:空白页识别。
|
* 功能:空白页识别。
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21 v1.0
|
* 最近修改时间:2020/4/21 v1.0
|
||||||
2020/8/12 v1.1 开放setIntensity和setMinArea;取消isNormal标识位;扩大setIntensity的设置范围,从[2, 20]扩大到[1, 100]
|
2020/8/12 v1.1 开放setIntensity和setMinArea;取消isNormal标识位;扩大setIntensity的设置范围,从[2, 20]扩大到[1, 100]
|
||||||
2020/8/25 v1.1.1 纸张检测缩进,从100像素调整到20像素
|
2020/8/25 v1.1.1 纸张检测缩进,从100像素调整到20像素
|
||||||
2020/10/16 v1.2 添加新接口,能够高效便捷判断图片是否为空白页
|
2020/10/16 v1.2 添加新接口,能够高效便捷判断图片是否为空白页
|
||||||
2020/10/19 v1.2.1 修复静态空白页判断识别误判的BUG
|
2020/10/19 v1.2.1 修复静态空白页判断识别误判的BUG
|
||||||
2021/04/13 v1.3.0 增加标准/票据标识位
|
2021/04/13 v1.3.0 增加标准/票据标识位
|
||||||
2021/08/12 v1.3.1 添加防止不同opencv版本导致计算结果存在差异的代码。
|
2021/08/12 v1.3.1 添加防止不同opencv版本导致计算结果存在差异的代码。
|
||||||
2021/12/14 v1.3.2 重构算法。
|
2021/12/14 v1.3.2 重构算法。
|
||||||
2021/12/15 v1.3.3 微调参数。
|
2021/12/15 v1.3.3 微调参数。
|
||||||
2021/12/17 v1.3.4 增加背景色接口,实现对纯色纸张的空白页判定
|
2021/12/17 v1.3.4 增加背景色接口,实现对纯色纸张的空白页判定
|
||||||
* 版本号:v1.3.4
|
* 版本号:v1.3.4
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_DISCARD_BLANK_H
|
#ifndef IMAGE_APPLY_DISCARD_BLANK_H
|
||||||
#define IMAGE_APPLY_DISCARD_BLANK_H
|
#define IMAGE_APPLY_DISCARD_BLANK_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyDiscardBlank : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyDiscardBlank : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200);
|
CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200);
|
||||||
|
|
||||||
virtual ~CImageApplyDiscardBlank(void);
|
virtual ~CImageApplyDiscardBlank(void);
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& 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);
|
static bool apply(const cv::Mat& pDib, double threshold = 40, int edge = 150, int blockSize = 10, double devTh = 50, double meanTh = 200);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_threshold;
|
double m_threshold;
|
||||||
int m_edge;
|
int m_edge;
|
||||||
double m_devTh;
|
double m_devTh;
|
||||||
double m_meanTh;
|
double m_meanTh;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_DISCARD_BLANK_H
|
#endif // !IMAGE_APPLY_DISCARD_BLANK_H
|
|
@ -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<float>(0, 0) = a;
|
||||||
|
m_kernal_b.at<float>(1, 0) = 1.0f + sharpen - a;
|
||||||
|
m_kernal_b.at<float>(2, 0) = -sharpen;
|
||||||
|
|
||||||
|
m_kernal_g.at<float>(0, 0) = b;
|
||||||
|
m_kernal_g.at<float>(1, 0) = 1.0f + sharpen - b;
|
||||||
|
m_kernal_g.at<float>(2, 0) = -sharpen;
|
||||||
|
|
||||||
|
m_kernal_r.at<float>(0, 0) = c;
|
||||||
|
m_kernal_r.at<float>(1, 0) = 1.0f + sharpen - c;
|
||||||
|
m_kernal_r.at<float>(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<cv::Mat>& mats, bool isTwoSide)
|
||||||
|
{
|
||||||
|
}
|
|
@ -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<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
|
private:
|
||||||
|
cv::Mat m_kernal_b;
|
||||||
|
cv::Mat m_kernal_g;
|
||||||
|
cv::Mat m_kernal_r;
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -1,67 +1,106 @@
|
||||||
#include "ImageApplyDogEarDetection.h"
|
#include "ImageApplyDogEarDetection.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
CImageApplyDogEarDetection::CImageApplyDogEarDetection()
|
CImageApplyDogEarDetection::CImageApplyDogEarDetection()
|
||||||
: m_threshold(40)
|
: m_threshold(40)
|
||||||
, m_zoom(1.0)
|
, m_zoom_x(1.0)
|
||||||
, m_distance(50)
|
, m_zoom_y(1.0)
|
||||||
, m_result(false)
|
, m_distance1(50)
|
||||||
{
|
, m_distance2(50)
|
||||||
|
, m_result(0)
|
||||||
}
|
{
|
||||||
|
|
||||||
CImageApplyDogEarDetection::CImageApplyDogEarDetection(double threshlod, double zoom, double distance)
|
}
|
||||||
: m_threshold(threshlod)
|
|
||||||
, m_zoom(zoom)
|
CImageApplyDogEarDetection::CImageApplyDogEarDetection(double threshlod, double zoom_x, double zoom_y, double distance1, double distance2)
|
||||||
, m_distance(distance)
|
: m_threshold(threshlod)
|
||||||
, m_result(false)
|
, m_zoom_x(zoom_x)
|
||||||
{
|
, m_zoom_y(zoom_y)
|
||||||
|
, m_distance1(distance1)
|
||||||
}
|
, m_distance2(distance2)
|
||||||
|
, m_result(0)
|
||||||
CImageApplyDogEarDetection::~CImageApplyDogEarDetection()
|
{
|
||||||
{
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
CImageApplyDogEarDetection::~CImageApplyDogEarDetection()
|
||||||
void CImageApplyDogEarDetection::apply(cv::Mat &pDib, int side)
|
{
|
||||||
{
|
|
||||||
m_result = false;
|
}
|
||||||
(void)side;
|
|
||||||
if (pDib.empty()) return;
|
#define EDGE_ABS 4
|
||||||
cv::Mat src;
|
void CImageApplyDogEarDetection::apply(cv::Mat& pDib, int side)
|
||||||
if (m_zoom != 1.0)
|
{
|
||||||
cv::resize(pDib, src, cv::Size(), m_zoom, m_zoom, cv::INTER_NEAREST);
|
m_result = 0;
|
||||||
else
|
(void)side;
|
||||||
src = pDib;
|
if (pDib.empty()) return;
|
||||||
|
cv::Mat src;
|
||||||
cv::Mat thre;
|
if (m_zoom_x != 1.0 && m_zoom_y != 1.0)
|
||||||
hg::threshold_Mat(src, thre, m_threshold);
|
cv::resize(pDib, src, cv::Size(), m_zoom_x, m_zoom_y, cv::INTER_NEAREST);
|
||||||
std::vector<cv::Vec4i> hierarchy;
|
else
|
||||||
std::vector<std::vector<cv::Point>> contours;
|
src = pDib;
|
||||||
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
|
||||||
|
cv::Mat thre;
|
||||||
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
hg::threshold_Mat(src, thre, m_threshold);
|
||||||
if (maxContour.size() == 0)
|
|
||||||
{
|
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5, 1));
|
||||||
m_result = true;
|
cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||||
return;
|
|
||||||
}
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
hg::convexHull(maxContour, maxContour);
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
||||||
cv::Point2f vertexes[4];
|
|
||||||
rect.points(vertexes);
|
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
||||||
|
if (maxContour.size() == 0)
|
||||||
for (int i = 0; i < 4; i++)
|
{
|
||||||
if ((-cv::pointPolygonTest(maxContour, vertexes[i], true)) > (m_distance * m_zoom))
|
m_result = true;
|
||||||
{
|
return;
|
||||||
m_result = true;
|
}
|
||||||
return;
|
hg::convexHull(maxContour, maxContour);
|
||||||
}
|
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
||||||
}
|
cv::Point2f vertexes[4];
|
||||||
|
rect.points(vertexes);
|
||||||
void CImageApplyDogEarDetection::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
|
||||||
{
|
double distance;
|
||||||
(void)mats;
|
for (int i = 0; i < 4; i++)
|
||||||
(void)isTwoSide;
|
{
|
||||||
}
|
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<cv::Mat>& mats, bool isTwoSide)
|
||||||
|
{
|
||||||
|
(void)mats;
|
||||||
|
(void)isTwoSide;
|
||||||
|
}
|
||||||
|
|
|
@ -1,56 +1,64 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:折角检测。检测原理:计算纸张的理论四角顶点,到实际轮廓最小距离。当任意顶点到轮廓最小距离超过阈值,则判定为折角
|
* 功能:折角检测。检测原理:计算纸张的理论四角顶点,到实际轮廓最小距离。当任意顶点到轮廓最小距离超过阈值,则判定为折角
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/10/30
|
* 生成时间:2020/10/30
|
||||||
* 最近修改时间:2020/10/30
|
* 最近修改时间:2020/10/30 v1.0
|
||||||
* 版本号: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不一致的问题。
|
||||||
#ifndef IMAGE_APPLY_DOGEAR_DETECTION_H
|
* 版本号:v1.4
|
||||||
#define IMAGE_APPLY_DOGEAR_DETECTION_H
|
|
||||||
|
* ====================================================
|
||||||
#include "ImageApply.h"
|
*/
|
||||||
|
|
||||||
class CImageApplyDogEarDetection :public CImageApply
|
#ifndef IMAGE_APPLY_DOGEAR_DETECTION_H
|
||||||
{
|
#define IMAGE_APPLY_DOGEAR_DETECTION_H
|
||||||
public:
|
|
||||||
|
#include "ImageApply.h"
|
||||||
/// <summary>
|
|
||||||
/// 折角检测默认构造函数,threshold = 40, zoom = 1.0, distance = 50
|
class GIMGPROC_LIBRARY_API CImageApplyDogEarDetection : public CImageApply
|
||||||
/// </summary>
|
{
|
||||||
CImageApplyDogEarDetection();
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 折角检测构造函数
|
/// 折角检测默认构造函数,threshold = 40, zoom = 1.0, distance = 50
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="threshlod">二值化阈值</param>
|
CImageApplyDogEarDetection();
|
||||||
/// <param name="zoom">原图缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放)</param>
|
|
||||||
/// <param name="distance">理论顶点到实际轮廓最小距离的阈值,大于该阈值则判定为折角,默认值50(像素)</param>
|
/// <summary>
|
||||||
CImageApplyDogEarDetection(double threshlod, double zoom = 1.0, double distance = 50);
|
/// 折角检测构造函数
|
||||||
|
/// </summary>
|
||||||
virtual ~CImageApplyDogEarDetection(void);
|
/// <param name="threshlod">二值化阈值</param>
|
||||||
|
/// <param name="zoom_x">原图X轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放)</param>
|
||||||
/// <summary>
|
/// <param name="zoom_y">原图Y轴缩放比例,对于大尺寸图像而言通过zoom缩小图像可减少计算量。默认值1.0(不缩放)</param>
|
||||||
/// 获取检测结果。该函数须在调用apply之后使用。
|
/// <param name="distance">理论顶点到实际轮廓最小距离的阈值,大于该阈值则判定为折角,默认值50(像素)</param>
|
||||||
/// </summary>
|
CImageApplyDogEarDetection(double threshlod, double zoom_x = 1.0, double zoom_y = 1.0, double distance1 = 50, double distance2 = 50);
|
||||||
/// <returns>true为折角,false为不折角</returns>
|
|
||||||
inline bool getResult() { return m_result; }
|
virtual ~CImageApplyDogEarDetection(void);
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
/// <summary>
|
||||||
|
/// 获取检测结果。该函数须在调用apply之后使用。
|
||||||
private:
|
/// </summary>
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
/// <returns>0为非折角;1为普通折角;2为可能是扫描不完整造成的折角</returns>
|
||||||
|
inline int getResult() { return m_result; }
|
||||||
private:
|
|
||||||
double m_threshold;
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
double m_zoom;
|
|
||||||
double m_distance;
|
private:
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
bool m_result;
|
|
||||||
};
|
private:
|
||||||
|
double m_threshold;
|
||||||
#endif // IMAGE_APPLY_DOGEAR_DETECTION_H
|
double m_zoom_x;
|
||||||
|
double m_zoom_y;
|
||||||
|
double m_distance1;
|
||||||
|
double m_distance2;
|
||||||
|
|
||||||
|
int m_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGE_APPLY_DOGEAR_DETECTION_H
|
||||||
|
|
|
@ -1,150 +1,150 @@
|
||||||
#include "ImageApplyFadeBackGroundColor.h"
|
#include "ImageApplyFadeBackGroundColor.h"
|
||||||
|
|
||||||
|
|
||||||
CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range)
|
CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range)
|
||||||
: m_threshold(threshold)
|
: m_threshold(threshold)
|
||||||
, m_offset(offset)
|
, m_offset(offset)
|
||||||
, m_range(range)
|
, m_range(range)
|
||||||
{
|
{
|
||||||
memset(m_table1, 255, 768);
|
memset(m_table1, 255, 768);
|
||||||
memset(m_table1, 0, m_threshold * 3);
|
memset(m_table1, 0, m_threshold * 3);
|
||||||
|
|
||||||
memset(m_table2, 255, 256 * 3);
|
memset(m_table2, 255, 256 * 3);
|
||||||
for (size_t i = 0; i < 256; i++)
|
for (size_t i = 0; i < 256; i++)
|
||||||
m_table2[i] = i;
|
m_table2[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor()
|
CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side)
|
void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
if (pDib.channels() != 3)
|
if (pDib.channels() != 3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
cv::Mat mask;
|
cv::Mat mask;
|
||||||
cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY);
|
cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY);
|
||||||
cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY);
|
cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY);
|
||||||
//cv::imwrite("mask.jpg", mask);
|
//cv::imwrite("mask.jpg", mask);
|
||||||
cv::Mat bgr[3];
|
cv::Mat bgr[3];
|
||||||
cv::split(pDib, bgr);
|
cv::split(pDib, bgr);
|
||||||
|
|
||||||
int histSize = 255;
|
int histSize = 255;
|
||||||
float range[] = { 0, 255 };
|
float range[] = { 0, 255 };
|
||||||
const float* histRange = { range };
|
const float* histRange = { range };
|
||||||
|
|
||||||
cv::Mat hist_bgr[3];
|
cv::Mat hist_bgr[3];
|
||||||
cv::Scalar mean_bgr;
|
cv::Scalar mean_bgr;
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange);
|
cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange);
|
||||||
double maxVal = 0;
|
double maxVal = 0;
|
||||||
cv::Point maxLoc;
|
cv::Point maxLoc;
|
||||||
cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc);
|
cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc);
|
||||||
mean_bgr[i] = maxLoc.y;
|
mean_bgr[i] = maxLoc.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask);
|
cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask);
|
||||||
#else
|
#else
|
||||||
fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range);
|
fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range)
|
void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range)
|
||||||
{
|
{
|
||||||
int hist_bgr[3][256] = { 0 };
|
int hist_bgr[3][256] = { 0 };
|
||||||
|
|
||||||
int width = bytesPerLine / 3;
|
int width = bytesPerLine / 3;
|
||||||
unsigned char* mask = new unsigned char[width * height];
|
unsigned char* mask = new unsigned char[width * height];
|
||||||
unsigned char* ptr_data = data;
|
unsigned char* ptr_data = data;
|
||||||
unsigned char* ptr_mask = mask;
|
unsigned char* ptr_mask = mask;
|
||||||
|
|
||||||
//创建掩模mask,并且统计三通道的直方图
|
//创建掩模mask,并且统计三通道的直方图
|
||||||
for (size_t i = 0; i < height; i++)
|
for (size_t i = 0; i < height; i++)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
unsigned char b = 0;
|
unsigned char b = 0;
|
||||||
for (size_t j = 0; j < width; j++)
|
for (size_t j = 0; j < width; j++)
|
||||||
{
|
{
|
||||||
b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]];
|
b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]];
|
||||||
ptr_mask[j] = b;
|
ptr_mask[j] = b;
|
||||||
for (size_t k = 0; k < 3; k++)
|
for (size_t k = 0; k < 3; k++)
|
||||||
hist_bgr[k][ptr_data[x + k] & b]++;
|
hist_bgr[k][ptr_data[x + k] & b]++;
|
||||||
x += 3;
|
x += 3;
|
||||||
}
|
}
|
||||||
ptr_data += bytesPerLine;
|
ptr_data += bytesPerLine;
|
||||||
ptr_mask += width;
|
ptr_mask += width;
|
||||||
}
|
}
|
||||||
|
|
||||||
//统计背景色
|
//统计背景色
|
||||||
int max_vals[3] = { 0 };
|
int max_vals[3] = { 0 };
|
||||||
int max_indexes[3];
|
int max_indexes[3] = { 0 };
|
||||||
|
|
||||||
for (size_t i = 1; i < 256; i++)
|
for (size_t i = 1; i < 256; i++)
|
||||||
for (size_t j = 0; j < 3; j++)
|
for (size_t j = 0; j < 3; j++)
|
||||||
if (hist_bgr[j][i] > max_vals[j])
|
if (hist_bgr[j][i] > max_vals[j])
|
||||||
{
|
{
|
||||||
max_vals[j] = hist_bgr[j][i];
|
max_vals[j] = hist_bgr[j][i];
|
||||||
max_indexes[j] = i;
|
max_indexes[j] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建背景色误查值表,在误差±range范围内的颜色被同样视为背景色
|
//创建背景色误查值表,在误差±range范围内的颜色被同样视为背景色
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
memset(m_table_rgb[i], 0, 256);
|
memset(m_table_rgb[i], 0, 256);
|
||||||
int start = cv::max(max_indexes[i] - range, 0);
|
int start = cv::max(max_indexes[i] - range, 0);
|
||||||
int end = cv::min(max_indexes[i] + range, 255);
|
int end = cv::min(max_indexes[i] + range, 255);
|
||||||
memset(m_table_rgb[i] + start, 255, end - start + 1);
|
memset(m_table_rgb[i] + start, 255, end - start + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据背景色误差查值表,更新掩模,排除背景色以外的内容
|
//根据背景色误差查值表,更新掩模,排除背景色以外的内容
|
||||||
ptr_data = data;
|
ptr_data = data;
|
||||||
ptr_mask = mask;
|
ptr_mask = mask;
|
||||||
for (size_t i = 0; i < height; i++)
|
for (size_t i = 0; i < height; i++)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for (size_t j = 0; j < width; j++)
|
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]];
|
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;
|
x += 3;
|
||||||
}
|
}
|
||||||
ptr_data += bytesPerLine;
|
ptr_data += bytesPerLine;
|
||||||
ptr_mask += width;
|
ptr_mask += width;
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据掩模,除背景色
|
//根据掩模,除背景色
|
||||||
unsigned char offset_rgb[3];
|
unsigned char offset_rgb[3];
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
offset_rgb[i] = 255 + offset - max_indexes[i];
|
offset_rgb[i] = 255 + offset - max_indexes[i];
|
||||||
|
|
||||||
ptr_data = data;
|
ptr_data = data;
|
||||||
ptr_mask = mask;
|
ptr_mask = mask;
|
||||||
for (size_t i = 0; i < height; i++)
|
for (size_t i = 0; i < height; i++)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for (size_t j = 0; j < width; j++)
|
for (size_t j = 0; j < width; j++)
|
||||||
{
|
{
|
||||||
for (size_t k = 0; k < 3; k++)
|
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])];
|
ptr_data[x + k] = m_table2[(int)ptr_data[x + k] + (offset_rgb[k] & ptr_mask[j])];
|
||||||
x += 3;
|
x += 3;
|
||||||
}
|
}
|
||||||
ptr_data += bytesPerLine;
|
ptr_data += bytesPerLine;
|
||||||
ptr_mask += width;
|
ptr_mask += width;
|
||||||
}
|
}
|
||||||
delete[] mask;
|
delete[] mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFadeBackGroudColor::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyFadeBackGroudColor::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats)
|
for (cv::Mat& var : mats)
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
{
|
{
|
||||||
apply(var, i);
|
apply(var, i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,64 +1,65 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:消除文稿纸张底色
|
* 功能:消除文稿纸张底色
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/11/30
|
* 生成时间:2020/11/30
|
||||||
* 最近修改时间:2021/04/14 v2.0 改为档位设置
|
* 最近修改时间:2021/04/14 v2.0 改为档位设置
|
||||||
* 2021/04/14 v2.1 调整方案,与LINUX方案保持一致。
|
* 2021/04/14 v2.1 调整方案,与LINUX方案保持一致。
|
||||||
* 2021/08/03 v2.2 自定义获取饱和度算法,避免不同opencv版本结果存在偏差。
|
* 2021/08/03 v2.2 自定义获取饱和度算法,避免不同opencv版本结果存在偏差。
|
||||||
* 2021/10/12 v2.3 重构算法,去除原来分档设定改为自动识别颜色,并去除底色。
|
* 2021/10/12 v2.3 重构算法,去除原来分档设定改为自动识别颜色,并去除底色。
|
||||||
* 2021/10/23 v3.0 重构算法。避开黑色背景(制作掩模),计算文稿平均底色,并进行增白。
|
* 2021/10/23 v3.0 重构算法。避开黑色背景(制作掩模),计算文稿平均底色,并进行增白。
|
||||||
* 2021/10/26 v3.1 构造函数增加参数,可设置生成掩模时的阈值。
|
* 2021/10/26 v3.1 构造函数增加参数,可设置生成掩模时的阈值。
|
||||||
* 2021/10/28 v3.2 重构算法,改用纯C++代码实现功能,提高处理速度。
|
* 2021/10/28 v3.2 重构算法,改用纯C++代码实现功能,提高处理速度。
|
||||||
* 2021/10/29 v3.3 优化算法,增加range参数。针对复杂内容的图像,能够有效甄别背景和非背景内容。
|
* 2021/10/29 v3.3 优化算法,增加range参数。针对复杂内容的图像,能够有效甄别背景和非背景内容。
|
||||||
* 版本号:v3.2
|
* 2022/03/08 v3.4 修复变量未初始化的BUG。
|
||||||
|
* 版本号:v3.4
|
||||||
* ====================================================
|
|
||||||
*/
|
* ====================================================
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
|
||||||
#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
||||||
|
#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
||||||
#include "ImageApply.h"
|
|
||||||
|
#include "ImageApply.h"
|
||||||
class CImageApplyAdjustColors;
|
|
||||||
class CImageApplyFadeBackGroudColor : public CImageApply
|
class CImageApplyAdjustColors;
|
||||||
{
|
class GIMGPROC_LIBRARY_API CImageApplyFadeBackGroudColor : public CImageApply
|
||||||
public:
|
{
|
||||||
/// <summary>
|
public:
|
||||||
/// 构造函数
|
/// <summary>
|
||||||
/// </summary>
|
/// 构造函数
|
||||||
/// <param name="offset">在自动识别增白参数的基础上,增加的偏移量。取值范围[-255, 255]</param>
|
/// </summary>
|
||||||
CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40);
|
/// <param name="offset">在自动识别增白参数的基础上,增加的偏移量。取值范围[-255, 255]</param>
|
||||||
|
CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40);
|
||||||
virtual ~CImageApplyFadeBackGroudColor();
|
|
||||||
|
virtual ~CImageApplyFadeBackGroudColor();
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
|
||||||
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
/// <summary>
|
|
||||||
/// 除文稿底色算法,仅支持24位图像
|
/// <summary>
|
||||||
/// </summary>
|
/// 除文稿底色算法,仅支持24位图像
|
||||||
/// <param name="data">图像数据头指针</param>
|
/// </summary>
|
||||||
/// <param name="bytesPerLine">每行数据大小</param>
|
/// <param name="data">图像数据头指针</param>
|
||||||
/// <param name="height">图像高度</param>
|
/// <param name="bytesPerLine">每行数据大小</param>
|
||||||
/// <param name="threshold">阈值,参考值为100</param>
|
/// <param name="height">图像高度</param>
|
||||||
/// <param name="offset">文稿底色增亮偏移量,默认为0。值越大,背景越白,反之越暗</param>
|
/// <param name="threshold">阈值,参考值为100</param>
|
||||||
/// <param name="range">底色误差范围,色彩与识别到的底色误差在[-range, range]范围内,视为底色,否则不会被消除</param>
|
/// <param name="offset">文稿底色增亮偏移量,默认为0。值越大,背景越白,反之越暗</param>
|
||||||
void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range);
|
/// <param name="range">底色误差范围,色彩与识别到的底色误差在[-range, range]范围内,视为底色,否则不会被消除</param>
|
||||||
|
void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range);
|
||||||
private:
|
|
||||||
int m_threshold;
|
private:
|
||||||
int m_offset;
|
int m_threshold;
|
||||||
int m_range;
|
int m_offset;
|
||||||
uchar m_table1[768];
|
int m_range;
|
||||||
uchar m_table2[512];
|
uchar m_table1[768];
|
||||||
uchar m_table_rgb[3][256];
|
uchar m_table2[512];
|
||||||
};
|
uchar m_table_rgb[3][256];
|
||||||
|
};
|
||||||
#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
|
||||||
|
#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H
|
||||||
|
|
|
@ -1,97 +1,97 @@
|
||||||
#include "ImageApplyFilter.h"
|
#include "ImageApplyFilter.h"
|
||||||
|
|
||||||
CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize)
|
CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
, m_kernel(kSize)
|
, m_kernel(kSize)
|
||||||
{
|
{
|
||||||
m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9;
|
m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyFilter::~CImageApplyFilter()
|
CImageApplyFilter::~CImageApplyFilter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::apply(cv::Mat& pDib, int side)
|
void CImageApplyFilter::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply");
|
FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
|
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case FilterMode::Sharpen:
|
case FilterMode::Sharpen:
|
||||||
case FilterMode::Sharpen_More:
|
case FilterMode::Sharpen_More:
|
||||||
sharpen(pDib, m_kSize);
|
sharpen(pDib, m_kSize);
|
||||||
break;
|
break;
|
||||||
case FilterMode::AverBlur:
|
case FilterMode::AverBlur:
|
||||||
case FilterMode::AverBlur_More:
|
case FilterMode::AverBlur_More:
|
||||||
averblur(pDib, static_cast<int>(m_kSize));
|
averblur(pDib, static_cast<int>(m_kSize));
|
||||||
break;
|
break;
|
||||||
case FilterMode::BilateralFilter:
|
case FilterMode::BilateralFilter:
|
||||||
bilateralFilter(pDib, m_kernel);
|
bilateralFilter(pDib, m_kernel);
|
||||||
break;
|
break;
|
||||||
case FilterMode::GaussianBlur:
|
case FilterMode::GaussianBlur:
|
||||||
gaussianBlur(pDib, m_kernel);
|
gaussianBlur(pDib, m_kernel);
|
||||||
break;
|
break;
|
||||||
case FilterMode::BrightSharp:
|
case FilterMode::BrightSharp:
|
||||||
brightSharp(pDib);
|
brightSharp(pDib);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply");
|
FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyFilter::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
if (mats.empty()) return;
|
if (mats.empty()) return;
|
||||||
|
|
||||||
if (!mats[0].empty())
|
if (!mats[0].empty())
|
||||||
apply(mats[0], 0);
|
apply(mats[0], 0);
|
||||||
|
|
||||||
if (isTwoSide && mats.size() > 1)
|
if (isTwoSide && mats.size() > 1)
|
||||||
if (!mats[1].empty())
|
if (!mats[1].empty())
|
||||||
apply(mats[1], 1);
|
apply(mats[1], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::averblur(cv::Mat& src, int kSize)
|
void CImageApplyFilter::averblur(cv::Mat& src, int kSize)
|
||||||
{
|
{
|
||||||
cv::blur(src, src, cv::Size(kSize, kSize));
|
cv::blur(src, src, cv::Size(kSize, kSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::sharpen(cv::Mat& src, float kSize)
|
void CImageApplyFilter::sharpen(cv::Mat& src, float kSize)
|
||||||
{
|
{
|
||||||
float other = (1.0f - kSize) / 4;
|
float other = (1.0f - kSize) / 4;
|
||||||
float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 };
|
float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 };
|
||||||
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
|
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
|
||||||
|
|
||||||
cv::filter2D(src, src, src.depth(), kernel);
|
cv::filter2D(src, src, src.depth(), kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::brightSharp(cv::Mat& src)
|
void CImageApplyFilter::brightSharp(cv::Mat& src)
|
||||||
{
|
{
|
||||||
const float a = -0.49f;
|
const float a = -0.49f;
|
||||||
const float b = 3.0f;
|
const float b = 3.0f;
|
||||||
float kernel_data[] =
|
float kernel_data[] =
|
||||||
{
|
{
|
||||||
0, a, 0,
|
0, a, 0,
|
||||||
a, b, a,
|
a, b, a,
|
||||||
0, a, 0
|
0, a, 0
|
||||||
};
|
};
|
||||||
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
|
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
|
||||||
cv::filter2D(src, src, src.depth(), kernel);
|
cv::filter2D(src, src, src.depth(), kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel)
|
void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel)
|
||||||
{
|
{
|
||||||
cv::Mat dst;
|
cv::Mat dst;
|
||||||
cv::bilateralFilter(src, dst, static_cast<int>(kernel), kernel * 2, kernel / 2);
|
cv::bilateralFilter(src, dst, static_cast<int>(kernel), kernel * 2, kernel / 2);
|
||||||
src.release();
|
src.release();
|
||||||
src = dst;
|
src = dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyFilter::gaussianBlur(cv::Mat src, int kSize)
|
void CImageApplyFilter::gaussianBlur(cv::Mat src, int kSize)
|
||||||
{
|
{
|
||||||
cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0);
|
cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:滤镜。目前包括锐化、加强锐化、模糊和加强模糊
|
* 功能:滤镜。目前包括锐化、加强锐化、模糊和加强模糊
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21 v1.0
|
* 最近修改时间:2020/4/21 v1.0
|
||||||
2020/7/17 v1.1 增加双边滤波(BilateralFilter)效果,用于实现“背景平滑”功能;
|
2020/7/17 v1.1 增加双边滤波(BilateralFilter)效果,用于实现“背景平滑”功能;
|
||||||
2020/11/30 v1.2 增加高斯模糊(GaussianBlur)
|
2020/11/30 v1.2 增加高斯模糊(GaussianBlur)
|
||||||
2021/07/21 v1.2.1 增加增亮锐化(BrightSharp)
|
2021/07/21 v1.2.1 增加增亮锐化(BrightSharp)
|
||||||
2021/10/19 v1.2.2 调整增亮锐化参数
|
2021/10/19 v1.2.2 调整增亮锐化参数
|
||||||
* 版本号:v1.2.2
|
* 版本号:v1.2.2
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_FILTER_H
|
#ifndef IMAGE_APPLY_FILTER_H
|
||||||
#define IMAGE_APPLY_FILTER_H
|
#define IMAGE_APPLY_FILTER_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyFilter : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyFilter : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum FilterMode
|
enum FilterMode
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Sharpen, //锐化
|
Sharpen, //锐化
|
||||||
Sharpen_More, //进一步锐化
|
Sharpen_More, //进一步锐化
|
||||||
AverBlur, //模糊
|
AverBlur, //模糊
|
||||||
AverBlur_More, //进一步模糊
|
AverBlur_More, //进一步模糊
|
||||||
BilateralFilter, //双边滤波--背景平滑,减少复杂背景的色彩数量,利于jpg等压缩比例
|
BilateralFilter, //双边滤波--背景平滑,减少复杂背景的色彩数量,利于jpg等压缩比例
|
||||||
GaussianBlur,
|
GaussianBlur,
|
||||||
BrightSharp //5 * 5提亮锐化
|
BrightSharp //5 * 5提亮锐化
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sharpentype [in]:滤镜模式
|
* sharpentype [in]:滤镜模式
|
||||||
*/
|
*/
|
||||||
CImageApplyFilter(FilterMode type, int kSize = 30);
|
CImageApplyFilter(FilterMode type, int kSize = 30);
|
||||||
|
|
||||||
virtual ~CImageApplyFilter();
|
virtual ~CImageApplyFilter();
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
private:
|
private:
|
||||||
void averblur(cv::Mat& src, int kSize);
|
void averblur(cv::Mat& src, int kSize);
|
||||||
|
|
||||||
void sharpen(cv::Mat& src, float kSize);
|
void sharpen(cv::Mat& src, float kSize);
|
||||||
|
|
||||||
void brightSharp(cv::Mat& src);
|
void brightSharp(cv::Mat& src);
|
||||||
|
|
||||||
void bilateralFilter(cv::Mat& src, double kernel);
|
void bilateralFilter(cv::Mat& src, double kernel);
|
||||||
|
|
||||||
void gaussianBlur(cv::Mat src, int kSize);
|
void gaussianBlur(cv::Mat src, int kSize);
|
||||||
private:
|
private:
|
||||||
int m_type;
|
int m_type;
|
||||||
float m_kSize;
|
float m_kSize;
|
||||||
double m_kernel;
|
double m_kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_SHARPEN_H
|
#endif // !IMAGE_APPLY_SHARPEN_H
|
||||||
|
|
|
@ -1,144 +1,163 @@
|
||||||
#include "ImageApplyHSVCorrect.h"
|
#include "ImageApplyHSVCorrect.h"
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
|
|
||||||
CImageApplyHSVCorrect::CImageApplyHSVCorrect()
|
CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode, bool cvtColor, uint bgr)
|
||||||
: m_table(new uint[256 * 256 * 256])
|
: m_table(new uint[256 * 256 * 256])
|
||||||
{
|
{
|
||||||
initLUT();
|
initLUT();
|
||||||
}
|
switch (mode)
|
||||||
|
{
|
||||||
CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode)
|
case CImageApplyHSVCorrect::Red_Removal:
|
||||||
: m_table(new uint[256 * 256 * 256])
|
set_HSV_value(std::pair<uchar, uchar>(0, 63), std::pair<uchar, uchar>(30, 255), std::pair<uchar, uchar>(120, 255), bgr, cvtColor);
|
||||||
{
|
set_HSV_value(std::pair<uchar, uchar>(200, 255), std::pair<uchar, uchar>(30, 255), std::pair<uchar, uchar>(120, 255), bgr, cvtColor);
|
||||||
initLUT();
|
break;
|
||||||
switch (mode)
|
case CImageApplyHSVCorrect::LowSaturation_Removal:
|
||||||
{
|
set_HSV_value(std::pair<uchar, uchar>(0, 255), std::pair<uchar, uchar>(0, 30), std::pair<uchar, uchar>(0, 255), bgr, cvtColor);
|
||||||
case CImageApplyHSVCorrect::Red_Removal:
|
break;
|
||||||
set_HSV_value(std::pair<uchar, uchar>(0, 63), std::pair<uchar, uchar>(20, 255), std::pair<uchar, uchar>(160, 255), 0x00FFFFFF);
|
default:
|
||||||
set_HSV_value(std::pair<uchar, uchar>(191, 255), std::pair<uchar, uchar>(20, 255), std::pair<uchar, uchar>(160, 255), 0x00FFFFFF);
|
break;
|
||||||
break;
|
}
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
CImageApplyHSVCorrect::~CImageApplyHSVCorrect()
|
||||||
}
|
{
|
||||||
|
delete [] m_table;
|
||||||
CImageApplyHSVCorrect::~CImageApplyHSVCorrect()
|
}
|
||||||
{
|
|
||||||
delete [] m_table;
|
void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side)
|
||||||
}
|
{
|
||||||
|
(void)side;
|
||||||
void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side)
|
if (pDib.empty() || pDib.channels() != 3) return;
|
||||||
{
|
#if 0
|
||||||
(void)side;
|
uchar* src = pDib.data;
|
||||||
if (pDib.empty() || pDib.channels() != 3) return;
|
cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3);
|
||||||
|
uchar* dst = z.data;
|
||||||
uchar* src = pDib.data;
|
|
||||||
cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3);
|
int bytesPerLine = pDib.cols * pDib.channels();
|
||||||
uchar* dst = z.data;
|
for (size_t i = 0, rows = pDib.rows; i < rows; i++)
|
||||||
|
{
|
||||||
int total = pDib.total();
|
uchar* ptr = pDib.ptr(i);
|
||||||
#pragma omp parallel for
|
for (size_t j = 0, cols = pDib.cols; j < cols; j++)
|
||||||
for (int i = 0; i < total; i++)
|
{
|
||||||
{
|
int offset = i * 3;
|
||||||
int offset = i * 3;
|
int index = *reinterpret_cast<uint*>(ptr + offset) & 0x00ffffff;
|
||||||
int index = *reinterpret_cast<uint*>(src + offset) & 0x00ffffff;
|
uint color = m_table[index];
|
||||||
uint color = m_table[index];
|
*reinterpret_cast<uint*>(dst + offset) |= color;
|
||||||
*reinterpret_cast<uint*>(dst + offset) |= color;
|
}
|
||||||
}
|
}
|
||||||
pDib = z;
|
pDib = z;
|
||||||
}
|
#else
|
||||||
|
cv::Mat bgra;
|
||||||
void CImageApplyHSVCorrect::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
cv::cvtColor(pDib, bgra, cv::COLOR_BGR2BGRA);
|
||||||
{
|
|
||||||
(void)isTwoSide;
|
long total = bgra.total();
|
||||||
int i = 0;
|
uint* ptr = bgra.ptr<uint>();
|
||||||
for (cv::Mat& var : mats) {
|
for (long i = 0; i < total; i++)
|
||||||
if (i != 0 && isTwoSide == false)
|
ptr[i] = m_table[ptr[i] & 0x00FFFFFF];
|
||||||
break;
|
|
||||||
if (!var.empty())
|
cv::cvtColor(bgra, pDib, cv::COLOR_BGRA2BGR);
|
||||||
apply(var, 0);
|
#endif
|
||||||
i++;
|
}
|
||||||
}
|
|
||||||
}
|
void CImageApplyHSVCorrect::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
||||||
|
{
|
||||||
void CImageApplyHSVCorrect::initLUT()
|
(void)isTwoSide;
|
||||||
{
|
int i = 0;
|
||||||
#if 0
|
for (cv::Mat& var : mats) {
|
||||||
uchar h, s, v;
|
if (i != 0 && isTwoSide == false)
|
||||||
#endif
|
break;
|
||||||
for (uint b = 0; b < 256; b++)
|
if (!var.empty())
|
||||||
for (uint g = 0; g < 256; g++)
|
apply(var, 0);
|
||||||
for (uint r = 0; r < 256; r++)
|
i++;
|
||||||
{
|
}
|
||||||
#if 0
|
}
|
||||||
RGB_2_HSV_full(r, g, b, h, s, v);
|
|
||||||
|
void CImageApplyHSVCorrect::initLUT()
|
||||||
uint index = b | (g << 8) | (r << 16);
|
{
|
||||||
if (h < 12 || h > 245)
|
#if 0
|
||||||
m_table[index] = index & 0x00ffffff;
|
uchar h, s, v;
|
||||||
else
|
#endif
|
||||||
m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff;
|
for (uint b = 0; b < 256; b++)
|
||||||
#else
|
for (uint g = 0; g < 256; g++)
|
||||||
m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16);
|
for (uint r = 0; r < 256; r++)
|
||||||
#endif
|
{
|
||||||
}
|
#if 0
|
||||||
}
|
RGB_2_HSV_full(r, g, b, h, s, v);
|
||||||
|
|
||||||
void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r,
|
uint index = b | (g << 8) | (r << 16);
|
||||||
const uint dst_b, const uint dst_g, const uint dst_r)
|
if (h < 12 || h > 245)
|
||||||
{
|
m_table[index] = index & 0x00ffffff;
|
||||||
m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16);
|
else
|
||||||
}
|
m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff;
|
||||||
|
#else
|
||||||
void CImageApplyHSVCorrect::set_HSV_value(const std::pair<uchar, uchar>& range_h,
|
m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16);
|
||||||
const std::pair<uchar, uchar>& range_s,
|
#endif
|
||||||
const std::pair<uchar, uchar>& range_v,
|
}
|
||||||
uint bgr)
|
}
|
||||||
{
|
|
||||||
uchar h, s, v;
|
void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r,
|
||||||
for (int b = 0; b < 256; b++)
|
const uint dst_b, const uint dst_g, const uint dst_r)
|
||||||
for (int g = 0; g < 256; g++)
|
{
|
||||||
for (int r = 0; r < 256; r++)
|
m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16);
|
||||||
{
|
}
|
||||||
RGB_2_HSV_full(r, g, b, h, s, v);
|
|
||||||
if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v))
|
void CImageApplyHSVCorrect::set_HSV_value(const std::pair<uchar, uchar>& range_h,
|
||||||
m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff;
|
const std::pair<uchar, uchar>& range_s,
|
||||||
}
|
const std::pair<uchar, uchar>& range_v,
|
||||||
}
|
uint bgr, bool cvtGray)
|
||||||
|
{
|
||||||
void CImageApplyHSVCorrect::set_table(const uint* table)
|
uchar h, s, v;
|
||||||
{
|
for (int b = 0; b < 256; b++)
|
||||||
memcpy(m_table, table, 256 * 256 * 256);
|
for (int g = 0; g < 256; g++)
|
||||||
}
|
for (int r = 0; r < 256; r++)
|
||||||
|
{
|
||||||
bool CImageApplyHSVCorrect::contained(uchar value, const std::pair<uchar, uchar> &range)
|
RGB_2_HSV_full(r, g, b, h, s, v);
|
||||||
{
|
if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v))
|
||||||
return value >= range.first && value <= range.second;
|
{
|
||||||
}
|
if (cvtGray)
|
||||||
|
{
|
||||||
void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v)
|
int a = (b + g + r) / 3 * 0x00010101;
|
||||||
{
|
m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = (b + g + r) / 3 * 0x00010101;
|
||||||
int minn = cv::min(r, cv::min(g, b));
|
}
|
||||||
int maxx = cv::max(r, cv::max(g, b));
|
else
|
||||||
v = static_cast<uchar>(maxx); //V
|
m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff;
|
||||||
|
}
|
||||||
int delta = maxx - minn;
|
}
|
||||||
float _h;
|
}
|
||||||
if (maxx == 0)
|
|
||||||
{
|
void CImageApplyHSVCorrect::set_table(const uint* table)
|
||||||
h = s = v = 0;
|
{
|
||||||
return;
|
memcpy(m_table, table, 256 * 256 * 256 * sizeof(uint));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
s = static_cast<uchar>(delta * 255 / maxx);
|
bool CImageApplyHSVCorrect::contained(uchar value, const std::pair<uchar, uchar> &range)
|
||||||
|
{
|
||||||
if (r == maxx)
|
return value >= range.first && value <= range.second;
|
||||||
_h = static_cast<float>(g - b) / static_cast<float>(delta);
|
}
|
||||||
else if (g == maxx)
|
|
||||||
_h = 2 + static_cast<float>(b - r) / static_cast<float>(delta);
|
void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v)
|
||||||
else
|
{
|
||||||
_h = 4 + static_cast<float>(r - g) / static_cast<float>(delta);
|
int minn = cv::min(r, cv::min(g, b));
|
||||||
|
int maxx = cv::max(r, cv::max(g, b));
|
||||||
float __h = _h * 42.6666666667f;
|
v = static_cast<uchar>(maxx); //V
|
||||||
h = (__h >= 0) ? static_cast<uchar>(__h) : static_cast<uchar>(__h + 256);
|
|
||||||
}
|
int delta = maxx - minn;
|
||||||
|
float _h;
|
||||||
|
if (maxx == 0)
|
||||||
|
{
|
||||||
|
h = s = v = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s = static_cast<uchar>(delta * 255 / maxx);
|
||||||
|
|
||||||
|
if (r == maxx)
|
||||||
|
_h = static_cast<float>(g - b) / static_cast<float>(delta);
|
||||||
|
else if (g == maxx)
|
||||||
|
_h = 2 + static_cast<float>(b - r) / static_cast<float>(delta);
|
||||||
|
else
|
||||||
|
_h = 4 + static_cast<float>(r - g) / static_cast<float>(delta);
|
||||||
|
|
||||||
|
float __h = _h * 42.6666666667f;
|
||||||
|
h = (__h >= 0) ? static_cast<uchar>(__h) : static_cast<uchar>(__h + 256);
|
||||||
|
}
|
||||||
|
|
|
@ -1,87 +1,95 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
*
|
||||||
* 功能:彩色图像,色彩校正。基于LUT实现,预设BGR查值表(表达所有HVS),对BGR原图进行查值校正。
|
* 功能:彩色图像,色彩校正。基于LUT实现,预设BGR查值表(表达所有HVS),对BGR原图进行查值校正。
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/3/21
|
* 生成时间:2020/3/21
|
||||||
* 最近修改时间:v1.0 2020/3/21
|
* 最近修改时间:v1.0 2020/03/21
|
||||||
v1.1 2020/6/15 调整除红效果的HSV取值范围
|
v1.1 2020/06/15 调整除红效果的HSV取值范围
|
||||||
* 版本号:v1.1
|
v1.2 2021/08/02 调整内存指针,适应ROI图像的内存偏移。
|
||||||
|
v1.3 2021/08/26 替换答题卡除红Red_Removal实现方案。
|
||||||
* ====================================================
|
v1.4 2022/04/22 增加功能,支持用像素灰度值填充原来彩色像素;删除默认构造函数;增加校正选项Deafault和LowSaturation_Removal
|
||||||
*/
|
v1.4.1 2022/04/25 调整数据类型,避免数据访问越界。
|
||||||
|
v1.4.2 2022/06/09 修复一个内存大小的错误。
|
||||||
#ifndef IMAGE_APPLY_COLOR_CORRECT_H
|
* 版本号:v1.4.2
|
||||||
#define IMAGE_APPLY_COLOR_CORRECT_H
|
*
|
||||||
|
* ====================================================
|
||||||
#include "ImageApply.h"
|
*/
|
||||||
|
|
||||||
class CImageApplyHSVCorrect : public CImageApply
|
#ifndef IMAGE_APPLY_COLOR_CORRECT_H
|
||||||
{
|
#define IMAGE_APPLY_COLOR_CORRECT_H
|
||||||
public:
|
|
||||||
enum CorrectOption
|
#include "ImageApply.h"
|
||||||
{
|
|
||||||
Red_Removal //除掉红色。红色定义H:[0, 85]∪[170, 255],S:[10, 255],V:[120,255]
|
class GIMGPROC_LIBRARY_API CImageApplyHSVCorrect : public CImageApply
|
||||||
};
|
{
|
||||||
public:
|
public:
|
||||||
|
enum CorrectOption
|
||||||
CImageApplyHSVCorrect();
|
{
|
||||||
|
Deafault, //默认,无任何除色效果
|
||||||
/*
|
LowSaturation_Removal, //除掉低饱和度像素
|
||||||
* mode [in]:预设初色模式
|
Red_Removal //除掉红色。红色定义H:[0, 85]∪[170, 255],S:[10, 255],V:[120,255]
|
||||||
*/
|
};
|
||||||
CImageApplyHSVCorrect(CorrectOption mode);
|
public:
|
||||||
|
/*
|
||||||
virtual ~CImageApplyHSVCorrect();
|
* mode [in]:预设初色模式
|
||||||
|
* cvtColor [in]:替代像素使用默认值,还是使用灰度值。true为灰度值,false为默认值
|
||||||
virtual void apply(cv::Mat& pDib,int side);
|
* bgr:[in] 用uint表示BGR值,B在低位,R在高位。(当cvtGray 为false时生效)
|
||||||
|
*/
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
CImageApplyHSVCorrect(CorrectOption mode = CorrectOption::Deafault, bool cvtColor = false, uint bgr = 0x00FFFFFF);
|
||||||
|
|
||||||
/*
|
virtual ~CImageApplyHSVCorrect();
|
||||||
* 函数功能:初始化查值表,按照RGB(R在高位,B在低位)的32位数据进行索引,值与索引一致。
|
|
||||||
表中索引范围[0,0x00FFFFFF]。在构造函数中会默认调用该函数。
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
*/
|
|
||||||
void initLUT();
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:将查值表指定RGB索引值设置为目标值。
|
* 函数功能:初始化查值表,按照RGB(R在高位,B在低位)的32位数据进行索引,值与索引一致。
|
||||||
索引 = src_b | (src_g << 8) | (src_r << 16)
|
表中索引范围[0,0x00FFFFFF]。在构造函数中会默认调用该函数。
|
||||||
值 = dst_b | (dst_g << 8) | (dst_r << 16)
|
*/
|
||||||
* src_b:[in] 原查值表B通道索引
|
void initLUT();
|
||||||
* src_g:[in] 原查值表G通道索引
|
|
||||||
* src_r:[in] 原查值表R通道索引
|
/*
|
||||||
* dst_b:[in] 目标查值表B通道值
|
* 函数功能:将查值表指定RGB索引值设置为目标值。
|
||||||
* dst_g:[in] 目标查值表G通道值
|
索引 = src_b | (src_g << 8) | (src_r << 16)
|
||||||
* dst_r:[in] 目标查值表R通道值
|
值 = dst_b | (dst_g << 8) | (dst_r << 16)
|
||||||
*/
|
* src_b:[in] 原查值表B通道索引
|
||||||
void set_single(const uint src_b, const uint src_g, const uint src_r,
|
* src_g:[in] 原查值表G通道索引
|
||||||
const uint dst_b, const uint dst_g, const uint dst_r);
|
* src_r:[in] 原查值表R通道索引
|
||||||
/*
|
* dst_b:[in] 目标查值表B通道值
|
||||||
* 函数功能:按照HSV色彩空间描述色彩范围,将该范围对应的BGR索引设置为0x00FFFFFF(默认白色)
|
* dst_g:[in] 目标查值表G通道值
|
||||||
* range_h:[in] H分量范围,取值范围[0, 255]
|
* dst_r:[in] 目标查值表R通道值
|
||||||
* range_s:[in] S分量范围,取值范围[0, 255]
|
*/
|
||||||
* range_v:[in] V分量范围,取值范围[0, 255]
|
void set_single(const uint src_b, const uint src_g, const uint src_r,
|
||||||
* bgr:[in] 用uint表示BGR值,B在低位,R在高位
|
const uint dst_b, const uint dst_g, const uint dst_r);
|
||||||
*/
|
|
||||||
void set_HSV_value(const std::pair<uchar, uchar>& range_h,
|
/*
|
||||||
const std::pair<uchar, uchar>& range_s,
|
* 函数功能:按照HSV色彩空间描述色彩范围,将该范围对应的BGR索引设置为0x00FFFFFF(默认白色)
|
||||||
const std::pair<uchar, uchar>& range_v,
|
* range_h:[in] H分量范围,取值范围[0, 255]
|
||||||
uint bgr = 0x00FFFFFF);
|
* range_s:[in] S分量范围,取值范围[0, 255]
|
||||||
|
* range_v:[in] V分量范围,取值范围[0, 255]
|
||||||
/*
|
* bgr:[in] 用uint表示BGR值,B在低位,R在高位。(当cvtGray 为false时生效)
|
||||||
* 函数功能:设置外部查值表,表默认长度为 256 * 256 * 256 * sizeof(uint)
|
* cvtGray:[in] 为true时,根据RGB值转换为灰度值
|
||||||
* table:[in] 数组指针
|
*/
|
||||||
*/
|
void set_HSV_value(const std::pair<uchar, uchar>& range_h,
|
||||||
void set_table(const uint* table);
|
const std::pair<uchar, uchar>& range_s,
|
||||||
|
const std::pair<uchar, uchar>& range_v,
|
||||||
private:
|
uint bgr = 0x00FFFFFF, bool cvtGray = false);
|
||||||
static bool contained(uchar value, const std::pair<uchar, uchar>& range);
|
|
||||||
|
/*
|
||||||
static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v);
|
* 函数功能:设置外部查值表,表默认长度为 256 * 256 * 256 * sizeof(uint)
|
||||||
|
* table:[in] 数组指针
|
||||||
private:
|
*/
|
||||||
uint* m_table;
|
void set_table(const uint* table);
|
||||||
};
|
|
||||||
|
private:
|
||||||
#endif
|
static bool contained(uchar value, const std::pair<uchar, uchar>& range);
|
||||||
|
|
||||||
|
static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint* m_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,34 +1,33 @@
|
||||||
#ifndef IMAGE_APPLY_HEADER_H
|
#ifndef IMAGE_APPLY_HEADER_H
|
||||||
#define IMAGE_APPLY_HEADER_H
|
#define IMAGE_APPLY_HEADER_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
#include "ImageApplyAdjustColors.h"
|
#include "ImageApplyAdjustColors.h"
|
||||||
#include "ImageApplyAutoCrop.h"
|
#include "ImageApplyAutoContrast.h"
|
||||||
#include "ImageApplyBWBinaray.h"
|
#include "ImageApplyAutoCrop.h"
|
||||||
#include "ImageApplyChannel.h"
|
//#include "ImageApplyBarCodeRecognition.h"
|
||||||
#include "ImageApplyCrop.h"
|
#include "ImageApplyBWBinaray.h"
|
||||||
#include "ImageApplyDiscardBlank.h"
|
#include "ImageApplyChannel.h"
|
||||||
#include "ImageApplyOutHole.h"
|
#include "ImageApplyColorRecognition.h"
|
||||||
#include "ImageApplyDogEarDetection.h"
|
#include "ImageApplyConcatenation.h"
|
||||||
#include "ImageApplyResize.h"
|
#include "ImageApplyCustomCrop.h"
|
||||||
#include "ImageApplyRotation.h"
|
#include "ImageApplyCustomGamma.h"
|
||||||
#include "ImageApplySharpen.h"
|
#include "ImageApplyCvtColor.h"
|
||||||
#include "ImageApplyConcatenation.h"
|
#include "ImageApplyDetachNoise.h"
|
||||||
#include "ImageApplyHSVCorrect.h"
|
#include "ImageApplyDiscardBlank.h"
|
||||||
#include "ImageApplyDetachNoise.h"
|
#include "ImageApplyDispersion.h"
|
||||||
#include "ImageApplyColorRecognition.h"
|
#include "ImageApplyDogEarDetection.h"
|
||||||
#include "ImageApplyUV.h"
|
#include "ImageApplyFadeBackGroundColor.h"
|
||||||
#include "ImageApplyAutoContrast.h"
|
#include "ImageApplyFilter.h"
|
||||||
#include "ImageApplyCustomCrop.h"
|
#include "ImageApplyHSVCorrect.h"
|
||||||
#include "ImageApplyCustomGamma.h"
|
#include "ImageApplyOutHole.h"
|
||||||
#include "ImageApplyCvtColor.h"
|
#include "ImageApplyRefuseInflow.h"
|
||||||
#include "ImageApplyFadeBackGroundColor.h"
|
#include "ImageApplyResize.h"
|
||||||
#include "ImageApplyFilter.h"
|
#include "ImageApplyRotation.h"
|
||||||
#include "ImageApplyRefuseInflow.h"
|
#include "ImageApplySplit.h"
|
||||||
#include "ImageApplySplit.h"
|
#include "ImageApplySizeDetection.h"
|
||||||
#include "ImageApplyTextureRemoval.h"
|
#include "ImageApplyTextureRemoval.h"
|
||||||
#include "ImageMulti.h"
|
#include "ImageMulti.h"
|
||||||
#include "ImageMultiOutputRed.h"
|
#include "ImageMultiOutputRed.h"
|
||||||
#include "ImageApplySplit.h"
|
#include "ImageApplySplit.h"
|
||||||
#include "ImageApplySizeDetection.h"
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
@ -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<cv::Vec4i> hierarchy;
|
||||||
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
|
|
||||||
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
||||||
|
std::vector<cv::Point> 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<std::vector<cv::Point>> marks;
|
||||||
|
std::vector<cv::RotatedRect> 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<cv::Point>& 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<std::vector<cv::Point>>& contours, const cv::RotatedRect& region,
|
||||||
|
const cv::Range& range, std::vector<std::vector<cv::Point>>& marks, std::vector<cv::RotatedRect>& 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<cv::Point> 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<cv::Point> 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<cv::Vec4i> hierarchy;
|
||||||
|
std::vector<std::vector<cv::Point>> 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;
|
||||||
|
}
|
|
@ -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<std::vector<cv::Point>>& contours, const cv::RotatedRect& region, const cv::Range& range,
|
||||||
|
std::vector<std::vector<cv::Point>>& marks, std::vector<cv::RotatedRect>& 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
|
|
@ -1,323 +1,342 @@
|
||||||
#include "ImageApplyOutHole.h"
|
#include "ImageApplyOutHole.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
#include "Device/filetools.h"
|
#include "Device/filetools.h"
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
|
|
||||||
CImageApplyOutHole::CImageApplyOutHole(void)
|
CImageApplyOutHole::CImageApplyOutHole(void)
|
||||||
: CImageApply()
|
: CImageApply()
|
||||||
, m_borderSize(600)
|
, m_borderSize(600)
|
||||||
, m_edgeScale(0.1f)
|
, m_edgeScale(0.1f)
|
||||||
, m_threshold(100)
|
, m_threshold(100)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold)
|
CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold)
|
||||||
: CImageApply()
|
: CImageApply()
|
||||||
, m_borderSize(borderSize)
|
, m_borderSize(borderSize)
|
||||||
, m_edgeScale(edgeScale)
|
, m_edgeScale(edgeScale)
|
||||||
, m_threshold(threshold)
|
, m_threshold(threshold)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyOutHole::~CImageApplyOutHole(void)
|
CImageApplyOutHole::~CImageApplyOutHole(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyOutHole::apply(cv::Mat& pDib, int side)
|
void CImageApplyOutHole::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)pDib;
|
(void)pDib;
|
||||||
(void)side;
|
(void)side;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "enter ImageOutHole apply");
|
FileTools::write_log("imgprc.txt", "enter ImageOutHole apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
|
|
||||||
if (mats.size() < 2)
|
if (mats.size() < 2)
|
||||||
{
|
{
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mats[0].empty() || mats[1].empty())
|
if (mats[0].empty() || mats[1].empty())
|
||||||
{
|
{
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
||||||
#endif // LOG
|
#endif // LOG
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//二值化正反面图像
|
//二值化正反面图像
|
||||||
cv::Mat front = mats[0];
|
cv::Mat front = mats[0];
|
||||||
cv::Mat back = mats[1];
|
cv::Mat back = mats[1];
|
||||||
cv::Mat front_thre, back_thre;
|
cv::Mat front_thre, back_thre;
|
||||||
hg::threshold_Mat(front, front_thre, m_threshold);
|
hg::threshold_Mat(front, front_thre, m_threshold);
|
||||||
hg::threshold_Mat(back, back_thre, m_threshold);
|
hg::threshold_Mat(back, back_thre, m_threshold);
|
||||||
|
|
||||||
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 1));
|
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(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::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
|
cv::flip(back_thre, back_thre, 1); //1:Horizontal
|
||||||
|
|
||||||
//正反面图像寻边
|
//正反面图像寻边
|
||||||
std::vector<std::vector<cv::Point>> contours_front, contours_back;
|
std::vector<std::vector<cv::Point>> contours_front, contours_back;
|
||||||
std::vector<cv::Vec4i> b1_front, b1_back;
|
std::vector<cv::Vec4i> b1_front, b1_back;
|
||||||
hg::findContours(front_thre.clone(), contours_front, b1_front, cv::RETR_EXTERNAL);
|
hg::findContours(front_thre.clone(), contours_front, b1_front, cv::RETR_EXTERNAL);
|
||||||
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_EXTERNAL);
|
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_EXTERNAL);
|
||||||
|
|
||||||
//提取正反面图像最大轮廓
|
//提取正反面图像最大轮廓
|
||||||
std::vector<cv::Point> maxContour_front = hg::getMaxContour(contours_front, b1_front);
|
std::vector<cv::Point> maxContour_front = hg::getMaxContour(contours_front, b1_front);
|
||||||
std::vector<cv::Point> maxContour_back = hg::getMaxContour(contours_back, b1_back);
|
std::vector<cv::Point> maxContour_back = hg::getMaxContour(contours_back, b1_back);
|
||||||
|
|
||||||
cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //提取正面最大轮廓的最小外接矩形
|
if (maxContour_front.empty() || maxContour_back.empty())
|
||||||
cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //提取反面最大轮廓的最小外接矩形
|
return;
|
||||||
|
|
||||||
//如果正反面图像尺寸差异超过20个像素,直接放弃处理
|
cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //提取正面最大轮廓的最小外接矩形
|
||||||
if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 ||
|
cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //提取反面最大轮廓的最小外接矩形
|
||||||
cv::abs(rrect_front.size.height - rrect_back.size.height) > 20)
|
|
||||||
return;
|
//如果正反面图像尺寸差异超过20个像素,直接放弃处理
|
||||||
|
if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 ||
|
||||||
//提取正反面图像重叠部分区域
|
cv::abs(rrect_front.size.height - rrect_back.size.height) > 20)
|
||||||
cv::Rect roi_front, roi_back;
|
return;
|
||||||
cv::RotatedRect mask_rotatedRect;
|
|
||||||
getRoi(rrect_front, rrect_back, cv::Size(front.cols, front.rows), roi_front, roi_back, mask_rotatedRect);
|
//提取正反面图像重叠部分区域
|
||||||
|
cv::Rect roi_front, roi_back;
|
||||||
cv::Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分
|
cv::RotatedRect mask_rotatedRect;
|
||||||
cv::Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分
|
getRoi(rrect_front, rrect_back, front.size(), back.size(), roi_front, roi_back, mask_rotatedRect);
|
||||||
|
|
||||||
//正反面二值图像做或运算,真正镂空区域保留0,其他地方填充为255
|
cv::Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分
|
||||||
cv::Mat mask;
|
cv::Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分
|
||||||
cv::bitwise_or(roiMat_front, roiMat_back, mask); //或运算,正反面二值图像重叠
|
//cv::imwrite("roiMat_front.jpg", roiMat_front);
|
||||||
|
//cv::imwrite("roiMat_back.jpg", roiMat_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::bitwise_not(mask, mask); //反色
|
//cv::imwrite("mask1.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::bitwise_not(mask, mask);
|
||||||
|
//cv::imwrite("mask2.jpg", mask); //反色
|
||||||
//为了避免孔洞彻底贯穿纸边,人为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连
|
|
||||||
cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(0), 15); //绘制纸张矩形边缘
|
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)); //膨胀算法,增大孔洞连通区域面积
|
||||||
std::vector<std::vector<cv::Point>> contours_mask;
|
//cv::imwrite("mask3.jpg", mask);
|
||||||
std::vector<cv::Vec4i> b1_mask;
|
|
||||||
hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //提取重叠图像轮廓
|
//为了避免孔洞彻底贯穿纸边,人为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连
|
||||||
|
cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(255), 15); //绘制纸张矩形边缘
|
||||||
//过滤非孔洞的联通区域
|
//cv::imwrite("mask4.jpg", mask);
|
||||||
std::vector<std::vector<cv::Point>> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize);
|
|
||||||
//for (size_t i = 0; i < hole_contours.size(); i++)
|
std::vector<std::vector<cv::Point>> contours_mask;
|
||||||
// cv::drawContours(mask, hole_contours, static_cast<int>(i), cv::Scalar(127), 2);
|
std::vector<cv::Vec4i> b1_mask;
|
||||||
//cv::imwrite("mask.jpg", mask);
|
hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //提取重叠图像轮廓
|
||||||
cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area());
|
|
||||||
for (size_t i = 0; i < hole_contours.size(); i++)
|
//过滤非孔洞的联通区域
|
||||||
{
|
std::vector<std::vector<cv::Point>> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize);
|
||||||
std::vector<std::vector<cv::Point>> contourss_temp;
|
|
||||||
contourss_temp.push_back(hole_contours[i]);
|
cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area());
|
||||||
cv::Mat front_temp = front(roi_front);
|
for (size_t i = 0; i < hole_contours.size(); i++)
|
||||||
hg::fillPolys(front_temp, contourss_temp, color);
|
{
|
||||||
}
|
std::vector<std::vector<cv::Point>> contourss_temp;
|
||||||
|
contourss_temp.push_back(hole_contours[i]);
|
||||||
if (isTwoSide)
|
cv::Mat front_temp = front(roi_front);
|
||||||
{
|
hg::fillPolys(front_temp, contourss_temp, color);
|
||||||
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());
|
if (isTwoSide)
|
||||||
for (size_t i = 0; i < hole_contours.size(); i++)
|
{
|
||||||
{
|
int width_ = roi_back.width;
|
||||||
std::vector<cv::Point> hole_contour;
|
roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转
|
||||||
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
color = getBackGroudColor(back(roi_back), rrect_front.size.area());
|
||||||
hole_contour.push_back(cv::Point(width_ - hole_contours[i][j].x - 1, hole_contours[i][j].y));
|
for (size_t i = 0; i < hole_contours.size(); i++)
|
||||||
|
{
|
||||||
std::vector<std::vector<cv::Point>> contours_temp;
|
std::vector<cv::Point> hole_contour;
|
||||||
contours_temp.push_back(hole_contour);
|
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
||||||
cv::Mat back_temp = back(roi_back);
|
hole_contour.push_back(cv::Point(width_ - hole_contours[i][j].x - 1, hole_contours[i][j].y));
|
||||||
hg::fillPolys(back_temp, contours_temp, color);
|
|
||||||
}
|
std::vector<std::vector<cv::Point>> contours_temp;
|
||||||
}
|
contours_temp.push_back(hole_contour);
|
||||||
#ifdef LOG
|
cv::Mat back_temp = back(roi_back);
|
||||||
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
hg::fillPolys(back_temp, contours_temp, color);
|
||||||
#endif // LOG
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef LOG
|
||||||
void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize,
|
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
|
||||||
cv::Rect& roi_front, cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect)
|
#endif // LOG
|
||||||
{
|
}
|
||||||
cv::Size size(static_cast<int>(rrect_front.size.width + rrect_back.size.width) / 2, static_cast<int>(rrect_front.size.height + rrect_back.size.height) / 2);
|
|
||||||
float angle = (rrect_front.angle + rrect_back.angle) / 2;
|
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)
|
||||||
rrect_front.size = rrect_back.size = size;
|
{
|
||||||
rrect_front.angle = rrect_back.angle = angle;
|
cv::Rect roi_front_ = rrect_front.boundingRect();
|
||||||
|
cv::Rect roi_back_ = rrect_back.boundingRect();
|
||||||
roi_front = rrect_front.boundingRect();
|
|
||||||
roi_back = rrect_back.boundingRect();
|
cv::Size meanSize = (roi_front_.size() + roi_back_.size()) / 2;
|
||||||
|
roi_front_.x += (roi_front_.width - meanSize.width) / 2;
|
||||||
if (roi_front.width != roi_back.width || roi_front.height != roi_back.height)
|
roi_front_.width = meanSize.width;
|
||||||
{
|
roi_front_.y += (roi_front_.height - meanSize.height) / 2;
|
||||||
roi_front.height = roi_back.height;
|
roi_front_.height = meanSize.height;
|
||||||
roi_front.width = roi_back.width;
|
roi_back_.x += (roi_back_.width - meanSize.width) / 2;
|
||||||
}
|
roi_back_.width = meanSize.width;
|
||||||
|
roi_back_.y += (roi_back_.height - meanSize.height) / 2;
|
||||||
cv::Point offset(0, 0);
|
roi_back_.height = meanSize.height;
|
||||||
int top = std::min(roi_front.y, roi_back.y);
|
|
||||||
if (top < 0)
|
mask_rotatedRect.angle = (rrect_front.angle + rrect_back.angle) / 2;
|
||||||
{
|
mask_rotatedRect.size = (rrect_front.size + rrect_back.size) / 2.0f;
|
||||||
roi_front.y -= top;
|
mask_rotatedRect.center = cv::Point2f(roi_front_.size().width + roi_back_.size().width, roi_front_.size().height + roi_back_.size().height) / 4.0f;
|
||||||
roi_back.y -= top;
|
|
||||||
roi_front.height += top;
|
roi_front = roi_front_ & cv::Rect(cv::Point(0, 0), srcSize_front);
|
||||||
roi_back.height += top;
|
roi_back = roi_back_ & cv::Rect(cv::Point(0, 0), srcSize_back);
|
||||||
offset.y += top;
|
|
||||||
}
|
int offset_left_f = roi_front.x - roi_front_.x;
|
||||||
|
int offset_left_b = roi_back.x - roi_back_.x;
|
||||||
int left = std::min(roi_front.x, roi_back.x);
|
int offset_top_f = roi_front.y - roi_front_.y;
|
||||||
if (left < 0)
|
int offset_top_b = roi_back.y - roi_back_.y;
|
||||||
{
|
int offset_right_f = roi_front_.br().x - roi_front.br().x;
|
||||||
roi_front.x -= left;
|
int offset_right_b = roi_back_.br().x - roi_back.br().x;
|
||||||
roi_back.x -= left;
|
int offset_bottom_f = roi_front_.br().y - roi_front.br().y;
|
||||||
roi_front.width += left;
|
int offset_bottom_b = roi_back_.br().y - roi_back.br().y;
|
||||||
roi_back.width += left;
|
|
||||||
offset.x += left;
|
if (offset_left_f > offset_left_b)
|
||||||
}
|
{
|
||||||
|
roi_back.x += offset_left_f - offset_left_b;
|
||||||
int right = std::max(roi_front.x + roi_front.width, roi_back.x + roi_back.width);
|
roi_back.width -= offset_left_f - offset_left_b;
|
||||||
if (right >= srcSize.width)
|
mask_rotatedRect.center.x -= offset_left_f - offset_left_b;
|
||||||
{
|
}
|
||||||
roi_front.width -= (right - srcSize.width + 1);
|
else
|
||||||
roi_back.width -= (right - srcSize.width + 1);
|
{
|
||||||
}
|
roi_front.x += offset_left_b - offset_left_f;
|
||||||
|
roi_front.width -= offset_left_b - offset_left_f;
|
||||||
int bottom = std::max(roi_front.y + roi_front.height, roi_back.y + roi_back.height);
|
mask_rotatedRect.center.x -= offset_left_b - offset_left_f;
|
||||||
if (bottom >= srcSize.height)
|
}
|
||||||
{
|
|
||||||
roi_front.height -= (bottom - srcSize.height + 1);
|
if (offset_top_f > offset_top_b)
|
||||||
roi_back.height -= (bottom - srcSize.height + 1);
|
{
|
||||||
}
|
roi_back.y += offset_top_f - offset_top_b;
|
||||||
|
roi_back.height -= offset_top_f - offset_top_b;
|
||||||
mask_rotatedRect.center = cv::Point((roi_front.width + offset.x) / 2, (roi_front.height + offset.y) / 2);
|
mask_rotatedRect.center.y -= offset_top_f - offset_top_b;
|
||||||
mask_rotatedRect.size = size;
|
}
|
||||||
mask_rotatedRect.angle = angle;
|
else
|
||||||
}
|
{
|
||||||
|
roi_front.y += offset_top_b - offset_top_f;
|
||||||
std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& m,
|
roi_front.height -= offset_top_b - offset_top_f;
|
||||||
cv::RotatedRect roi, float edgeScale, float areaThreshold)
|
mask_rotatedRect.center.y -= offset_top_b - offset_top_f;
|
||||||
{
|
}
|
||||||
edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f));
|
|
||||||
cv::RotatedRect roi2(roi.center, cv::Size(static_cast<int>(roi.size.width * (1 - edgeScale * 2)),
|
if (offset_right_f > offset_right_b)
|
||||||
static_cast<int>(roi.size.height * (1 - edgeScale * 2))), roi.angle);
|
roi_back.width -= offset_right_f - offset_right_b;
|
||||||
|
else
|
||||||
std::vector<cv::Point> vertices_roi1 = hg::getVertices(roi);
|
roi_front.width -= offset_right_b - offset_right_f;
|
||||||
std::vector<cv::Point> vertices_roi2 = hg::getVertices(roi2);
|
|
||||||
|
if (offset_bottom_f > offset_bottom_b)
|
||||||
std::vector<std::vector<cv::Point>> hole_contours;
|
roi_back.height -= offset_bottom_f - offset_bottom_b;
|
||||||
for (size_t i = 0, length = contours.size(); i < length; i++)
|
else
|
||||||
{
|
roi_front.height -= offset_bottom_b - offset_bottom_f;
|
||||||
if (m[i][2] != -1) continue;
|
}
|
||||||
|
|
||||||
cv::RotatedRect rrect = hg::getBoundingRect(contours[i]);
|
std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& m,
|
||||||
if (rrect.size.area() < areaThreshold) continue;
|
cv::RotatedRect roi, float edgeScale, float areaThreshold)
|
||||||
|
{
|
||||||
bool enabled = true;
|
edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f));
|
||||||
for (size_t j = 0, count = contours[i].size(); j < count; j++)
|
cv::RotatedRect roi2(roi.center, cv::Size(static_cast<int>(roi.size.width * (1 - edgeScale * 2)),
|
||||||
{
|
static_cast<int>(roi.size.height * (1 - edgeScale * 2))), roi.angle);
|
||||||
cv::Point p(contours[i][j]);
|
|
||||||
double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外
|
std::vector<cv::Point> vertices_roi1 = hg::getVertices(roi);
|
||||||
double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外
|
std::vector<cv::Point> vertices_roi2 = hg::getVertices(roi2);
|
||||||
//如果在纸张外,或者边缘内,视为非孔洞
|
|
||||||
if (temp1 < 0 || temp2 > 0)
|
std::vector<std::vector<cv::Point>> hole_contours;
|
||||||
{
|
for (size_t i = 0, length = contours.size(); i < length; i++)
|
||||||
enabled = false;
|
{
|
||||||
break;
|
if (m[i][2] != -1) continue;
|
||||||
}
|
|
||||||
}
|
cv::RotatedRect rrect = hg::getBoundingRect(contours[i]);
|
||||||
|
if (rrect.size.width < areaThreshold ||
|
||||||
if (enabled)
|
rrect.size.height < areaThreshold ||
|
||||||
hole_contours.push_back(contours[i]);
|
rrect.size.width > areaThreshold * 6 ||
|
||||||
}
|
rrect.size.height > areaThreshold * 6)
|
||||||
return hole_contours;
|
continue;
|
||||||
}
|
|
||||||
|
bool enabled = true;
|
||||||
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints)
|
for (size_t j = 0, count = contours[i].size(); j < count; j++)
|
||||||
{
|
{
|
||||||
if (pixelPoints.empty()) return cv::Scalar(255, 255, 255);
|
cv::Point p(contours[i][j]);
|
||||||
|
double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外
|
||||||
int channels = image.channels();
|
double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外
|
||||||
|
//如果在纸张外,或者边缘内,视为非孔洞
|
||||||
int temp[3] = { 0 };
|
if (temp1 < 0 || temp2 > 0)
|
||||||
for (size_t i = 0, length = pixelPoints.size(); i < length; ++i)
|
{
|
||||||
{
|
enabled = false;
|
||||||
int x = cv::min(cv::max(0, pixelPoints[i].x), image.cols - 1);
|
break;
|
||||||
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)
|
if (enabled)
|
||||||
temp[j] += ptr[j];
|
hole_contours.push_back(contours[i]);
|
||||||
}
|
}
|
||||||
|
return hole_contours;
|
||||||
return cv::Scalar(temp[0] / static_cast<int>(pixelPoints.size()),
|
}
|
||||||
temp[1] / static_cast<int>(pixelPoints.size()),
|
|
||||||
temp[2] / static_cast<int>(pixelPoints.size()));
|
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints)
|
||||||
}
|
{
|
||||||
|
if (pixelPoints.empty()) return cv::Scalar(255, 255, 255);
|
||||||
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, int total)
|
|
||||||
{
|
int channels = image.channels();
|
||||||
if (image.channels() == 3)
|
|
||||||
{
|
int temp[3] = { 0 };
|
||||||
cv::Mat image_bgr[3];
|
for (size_t i = 0, length = pixelPoints.size(); i < length; ++i)
|
||||||
cv::split(image, image_bgr);
|
{
|
||||||
|
int x = cv::min(cv::max(0, pixelPoints[i].x), image.cols - 1);
|
||||||
uchar bgr[3];
|
int y = cv::min(cv::max(0, pixelPoints[i].y), image.rows - 1);
|
||||||
for (size_t i = 0; i < 3; i++)
|
|
||||||
bgr[i] = getBackGroudChannelMean(image_bgr[i], total);
|
const unsigned char* ptr = image.ptr(y, x);
|
||||||
return cv::Scalar(bgr[0], bgr[1], bgr[2]);
|
for (int j = 0; j < channels; ++j)
|
||||||
}
|
temp[j] += ptr[j];
|
||||||
else
|
}
|
||||||
return cv::Scalar::all(getBackGroudChannelMean(image, total));
|
|
||||||
}
|
return cv::Scalar(temp[0] / static_cast<int>(pixelPoints.size()),
|
||||||
|
temp[1] / static_cast<int>(pixelPoints.size()),
|
||||||
uchar CImageApplyOutHole::getBackGroudChannelMean(const cv::Mat& gray, int total)
|
temp[2] / static_cast<int>(pixelPoints.size()));
|
||||||
{
|
}
|
||||||
cv::Mat image_clone;
|
|
||||||
cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25);
|
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, int total)
|
||||||
|
{
|
||||||
int threnshold = total / 32;
|
if (image.channels() == 3)
|
||||||
int channels[] = { 0 };
|
{
|
||||||
int nHistSize[] = { 256 };
|
cv::Mat image_bgr[3];
|
||||||
float range[] = { 0, 256 };
|
cv::split(image, image_bgr);
|
||||||
const float* fHistRanges[] = { range };
|
|
||||||
cv::Mat hist;
|
uchar bgr[3];
|
||||||
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false);
|
for (size_t i = 0; i < 3; i++)
|
||||||
|
bgr[i] = getBackGroudChannelMean(image_bgr[i], total);
|
||||||
int hist_array[256];
|
return cv::Scalar(bgr[0], bgr[1], bgr[2]);
|
||||||
for (int i = 0; i < 256; i++)
|
}
|
||||||
hist_array[i] = hist.at<float>(i, 0);
|
else
|
||||||
|
return cv::Scalar::all(getBackGroudChannelMean(image, total));
|
||||||
int length = 1;
|
}
|
||||||
const int length_max = 255 - m_threshold;
|
|
||||||
while (length < length_max)
|
uchar CImageApplyOutHole::getBackGroudChannelMean(const cv::Mat& gray, int total)
|
||||||
{
|
{
|
||||||
for (size_t i = m_threshold + 1; i < 256 - length; i++)
|
cv::Mat image_clone;
|
||||||
{
|
cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25);
|
||||||
int count = 0;
|
|
||||||
uint pixSum = 0;
|
int threnshold = total / 32;
|
||||||
for (size_t j = 0; j < length; j++)
|
int channels[] = { 0 };
|
||||||
{
|
int nHistSize[] = { 256 };
|
||||||
count += hist_array[j + i];
|
float range[] = { 0, 256 };
|
||||||
pixSum += hist_array[j + i] * (i + j);
|
const float* fHistRanges[] = { range };
|
||||||
}
|
cv::Mat hist;
|
||||||
|
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false);
|
||||||
if (count >= threnshold)
|
|
||||||
return pixSum / count;
|
int hist_array[256];
|
||||||
}
|
for (int i = 0; i < 256; i++)
|
||||||
length++;
|
hist_array[i] = hist.at<float>(i, 0);
|
||||||
}
|
|
||||||
return 255;
|
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;
|
||||||
}
|
}
|
|
@ -1,74 +1,80 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:装订孔填充
|
* 功能:装订孔填充
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/11/21
|
* 生成时间:2020/11/21
|
||||||
* 最近修改时间:2020/05/12 v1.0
|
* 最近修改时间:2020/05/12 v1.0
|
||||||
* 2020/11/17 v1.1
|
* 2020/11/17 v1.1
|
||||||
* 2021/09/06 v1.2 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。
|
* 2021/09/06 v1.2 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。
|
||||||
* 2021/11/03 v1.3 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。
|
* 2021/11/03 v1.3 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。
|
||||||
* 2021/11/04 v1.4 增加背景抗噪机制,能够抗5像素的背景噪声。
|
* 2021/11/04 v1.4 增加背景抗噪机制,能够抗5像素的背景噪声。
|
||||||
* 2021/11/17 v1.5 调整代码格式,避免一些由于opencv版本导致的BUG。
|
* 2021/11/17 v1.5 调整代码格式,避免一些由于opencv版本导致的BUG。
|
||||||
* 版本号:v1.5
|
* 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]
|
||||||
#ifndef IMAGE_APPLY_OUT_HOLE_H
|
* 2022/07/22 v1.7.1 修复自动识别填充颜色的BUG
|
||||||
#define IMAGE_APPLY_OUT_HOLE_H
|
* 版本号:v1.7.1
|
||||||
|
|
||||||
#include "ImageApply.h"
|
* ====================================================
|
||||||
|
*/
|
||||||
class CImageApplyOutHole : public CImageApply
|
|
||||||
{
|
#ifndef IMAGE_APPLY_OUT_HOLE_H
|
||||||
public:
|
#define IMAGE_APPLY_OUT_HOLE_H
|
||||||
|
|
||||||
CImageApplyOutHole();
|
#include "ImageApply.h"
|
||||||
|
|
||||||
/*
|
class GIMGPROC_LIBRARY_API CImageApplyOutHole : public CImageApply
|
||||||
* borderSize [in]:孔洞面积阈值
|
{
|
||||||
* edgeScale [in]:纸张边缘区域比例,取值范围(0,0.5),默认值0.1
|
public:
|
||||||
* threshold [in]:二值化阈值
|
|
||||||
*/
|
CImageApplyOutHole();
|
||||||
CImageApplyOutHole(float borderSize, float edgeScale, double threshold);
|
|
||||||
|
/*
|
||||||
~CImageApplyOutHole(void);
|
* borderSize [in]:孔洞面积阈值
|
||||||
|
* edgeScale [in]:纸张边缘区域比例,取值范围(0,0.5),默认值0.1
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
* threshold [in]:二值化阈值
|
||||||
|
*/
|
||||||
float getBorderSize() { return m_borderSize; }
|
CImageApplyOutHole(float borderSize, float edgeScale, double threshold);
|
||||||
|
|
||||||
float getEdgeScale() { return m_edgeScale; }
|
~CImageApplyOutHole(void);
|
||||||
|
|
||||||
double getThreshold() { return m_threshold; }
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
void setBorderSize(float size) { m_borderSize = size; }
|
float getBorderSize() { return m_borderSize; }
|
||||||
|
|
||||||
void setEdgeScale(float scale) { m_edgeScale = scale; }
|
float getEdgeScale() { return m_edgeScale; }
|
||||||
|
|
||||||
void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); }
|
double getThreshold() { return m_threshold; }
|
||||||
|
|
||||||
private:
|
void setBorderSize(float size) { m_borderSize = size; }
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
void setEdgeScale(float scale) { m_edgeScale = scale; }
|
||||||
|
|
||||||
void getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, cv::Size srcSize, cv::Rect& roi_front,
|
void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); }
|
||||||
cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect);
|
|
||||||
|
private:
|
||||||
std::vector<std::vector<cv::Point> > filterPoly(std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& m, cv::RotatedRect roi,
|
|
||||||
float edgeScale, float areaThreshold);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
cv::Scalar getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints);
|
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);
|
||||||
cv::Scalar getBackGroudColor(const cv::Mat& image, int total);
|
|
||||||
|
std::vector<std::vector<cv::Point> > filterPoly(std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& m, cv::RotatedRect roi,
|
||||||
uchar getBackGroudChannelMean(const cv::Mat& gray, int total);
|
float edgeScale, float areaThreshold);
|
||||||
|
|
||||||
private:
|
cv::Scalar getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints);
|
||||||
float m_borderSize;
|
|
||||||
float m_edgeScale;
|
cv::Scalar getBackGroudColor(const cv::Mat& image, int total);
|
||||||
double m_threshold;
|
|
||||||
};
|
uchar getBackGroudChannelMean(const cv::Mat& gray, int total);
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_OUT_HOLE_H
|
private:
|
||||||
|
float m_borderSize;
|
||||||
|
float m_edgeScale;
|
||||||
|
double m_threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !IMAGE_APPLY_OUT_HOLE_H
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
#include "ImageApplyRefuseInflow.h"
|
#include "ImageApplyRefuseInflow.h"
|
||||||
#include "ImageApplyAdjustColors.h"
|
#include "ImageApplyAdjustColors.h"
|
||||||
|
|
||||||
CImageApplyRefuseInflow::CImageApplyRefuseInflow(int constrast)
|
CImageApplyRefuseInflow::CImageApplyRefuseInflow(int constrast)
|
||||||
: m_adjustColor(new CImageApplyAdjustColors(0, constrast, 1.0f))
|
: m_adjustColor(new CImageApplyAdjustColors(0, constrast, 1.0f))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyRefuseInflow::~CImageApplyRefuseInflow()
|
CImageApplyRefuseInflow::~CImageApplyRefuseInflow()
|
||||||
{
|
{
|
||||||
delete m_adjustColor;
|
delete m_adjustColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side)
|
void CImageApplyRefuseInflow::apply(cv::Mat& pDib, int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
#if 0
|
#if 0
|
||||||
static unsigned char table_contrast[] = {
|
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, 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,
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
|
||||||
50, 51, 52, 53, 54, 55, 56, 57, 198, 199,
|
50, 51, 52, 53, 54, 55, 56, 57, 198, 199,
|
||||||
200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
|
200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
|
||||||
210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
|
210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
|
||||||
220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
|
220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
|
||||||
230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
|
240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
|
||||||
250, 251, 252, 253, 254, 255, 255, 255, 255, 255,
|
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, 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);
|
static cv::Mat mat_table(1, 256, CV_8UC1, table_contrast);
|
||||||
cv::LUT(pDib, mat_table, pDib);
|
cv::LUT(pDib, mat_table, pDib);
|
||||||
#else
|
#else
|
||||||
m_adjustColor->apply(pDib, side);
|
m_adjustColor->apply(pDib, side);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CImageApplyRefuseInflow::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyRefuseInflow::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
(void)isTwoSide;
|
(void)isTwoSide;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (cv::Mat& var : mats) {
|
for (cv::Mat& var : mats) {
|
||||||
if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
break;
|
break;
|
||||||
if (!var.empty())
|
if (!var.empty())
|
||||||
apply(var, 0);
|
apply(var, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:防渗透。
|
* 功能:防渗透。
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:v1.0 2020/04/21
|
* 最近修改时间:v1.0 2020/04/21
|
||||||
* v1.1 2022/05/04 重构算法,采用提高对比度实现防渗透。
|
* v1.1 2022/05/04 重构算法,采用提高对比度实现防渗透。
|
||||||
* 版本号:v1.1
|
* 版本号:v1.1
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_REFUSE_INFLOW_H
|
#ifndef IMAGE_APPLY_REFUSE_INFLOW_H
|
||||||
#define IMAGE_APPLY_REFUSE_INFLOW_H
|
#define IMAGE_APPLY_REFUSE_INFLOW_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyAdjustColors;
|
class CImageApplyAdjustColors;
|
||||||
class CImageApplyRefuseInflow : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyRefuseInflow : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CImageApplyRefuseInflow(int constrast = 15);
|
CImageApplyRefuseInflow(int constrast = 15);
|
||||||
|
|
||||||
virtual ~CImageApplyRefuseInflow();
|
virtual ~CImageApplyRefuseInflow();
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib, int side);
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CImageApplyAdjustColors* m_adjustColor;
|
CImageApplyAdjustColors* m_adjustColor;
|
||||||
};
|
};
|
||||||
#endif // !IMAGE_APPLY_REFUSE_INFLOW_H
|
#endif // !IMAGE_APPLY_REFUSE_INFLOW_H
|
||||||
|
|
|
@ -1,45 +1,47 @@
|
||||||
#include "ImageApplyResize.h"
|
#include "ImageApplyResize.h"
|
||||||
|
|
||||||
CImageApplyResize::CImageApplyResize()
|
CImageApplyResize::CImageApplyResize()
|
||||||
: m_fx(1.0)
|
: m_fx(1.0)
|
||||||
, m_fy(1.0)
|
, m_fy(1.0)
|
||||||
, m_type(ResizeType::RATIO)
|
, m_type(ResizeType::RATIO)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplyResize::CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy)
|
CImageApplyResize::CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
, m_dSize(size)
|
, m_dSize(size)
|
||||||
, m_fx(fx)
|
, m_fx(fx)
|
||||||
, m_fy(fy)
|
, m_fy(fy)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CImageApplyResize::~CImageApplyResize(void)
|
CImageApplyResize::~CImageApplyResize(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CImageApplyResize::apply(cv::Mat& pDib,int side)
|
void CImageApplyResize::apply(cv::Mat& pDib,int side)
|
||||||
{
|
{
|
||||||
(void)side;
|
(void)side;
|
||||||
if (pDib.empty()) return;
|
if (pDib.empty()) return;
|
||||||
if (m_type == ResizeType::RATIO)
|
|
||||||
cv::resize(pDib, pDib, cv::Size(0, 0), m_fx, m_fy);
|
if (m_type == ResizeType::RATIO)
|
||||||
else
|
cv::resize(pDib, pDib, cv::Size(0, 0), m_fx, m_fy);
|
||||||
cv::resize(pDib, pDib, m_dSize);
|
else
|
||||||
}
|
cv::resize(pDib, pDib, m_dSize);
|
||||||
|
}
|
||||||
void CImageApplyResize::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
|
||||||
{
|
void CImageApplyResize::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
(void)isTwoSide;
|
{
|
||||||
int i = 0;
|
(void)isTwoSide;
|
||||||
for (cv::Mat& var : mats) {
|
|
||||||
if (i != 0 && isTwoSide == false)
|
int i = 0;
|
||||||
break;
|
for (cv::Mat& var : mats) {
|
||||||
if (!var.empty())
|
if (i != 0 && isTwoSide == false)
|
||||||
apply(var, 0);
|
break;
|
||||||
i++;
|
if (!var.empty())
|
||||||
}
|
apply(var, 0);
|
||||||
}
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,69 +1,69 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:自定义伽马校正。原理为哈希表查值
|
* 功能:自定义伽马校正。原理为哈希表查值
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_RESIZE_H
|
#ifndef IMAGE_APPLY_RESIZE_H
|
||||||
#define IMAGE_APPLY_RESIZE_H
|
#define IMAGE_APPLY_RESIZE_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
|
|
||||||
class CImageApplyResize : public CImageApply
|
class GIMGPROC_LIBRARY_API CImageApplyResize : public CImageApply
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class ResizeType
|
enum class ResizeType
|
||||||
{
|
{
|
||||||
RATIO, //比例缩放
|
RATIO, //比例缩放
|
||||||
DSIZE //尺寸缩放
|
DSIZE //尺寸缩放
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CImageApplyResize();
|
CImageApplyResize();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* type [in]:缩放类型
|
* type [in]:缩放类型
|
||||||
* size [in]:目标尺寸,当type为DSIZE时生效
|
* size [in]:目标尺寸,当type为DSIZE时生效
|
||||||
* fx [in]:横向目标比例,当type为RATIO时生效
|
* fx [in]:横向目标比例,当type为RATIO时生效
|
||||||
* fy [in]:纵向目标比例,当type为RATIO时生效
|
* fy [in]:纵向目标比例,当type为RATIO时生效
|
||||||
*/
|
*/
|
||||||
CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy);
|
CImageApplyResize(ResizeType type, const cv::Size& size, double fx, double fy);
|
||||||
|
|
||||||
virtual ~CImageApplyResize(void);
|
virtual ~CImageApplyResize(void);
|
||||||
|
|
||||||
virtual void apply(cv::Mat& pDib,int side);
|
virtual void apply(cv::Mat& pDib,int side);
|
||||||
|
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
|
||||||
|
|
||||||
double getFX() { return m_fx; }
|
double getFX() { return m_fx; }
|
||||||
|
|
||||||
double getFY() { return m_fy; }
|
double getFY() { return m_fy; }
|
||||||
|
|
||||||
cv::Size getDSize() { return m_dSize; }
|
cv::Size getDSize() { return m_dSize; }
|
||||||
|
|
||||||
ResizeType getType() { return m_type; }
|
ResizeType getType() { return m_type; }
|
||||||
|
|
||||||
void setFX(double value) { m_fx = value; }
|
void setFX(double value) { m_fx = value; }
|
||||||
|
|
||||||
void setFY(double value) { m_fy = value; }
|
void setFY(double value) { m_fy = value; }
|
||||||
|
|
||||||
void setDSize(const cv::Size& size) { m_dSize = size; }
|
void setDSize(const cv::Size& size) { m_dSize = size; }
|
||||||
|
|
||||||
void setType(ResizeType type) { m_type = type; }
|
void setType(ResizeType type) { m_type = type; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_fx;
|
double m_fx;
|
||||||
double m_fy;
|
double m_fy;
|
||||||
cv::Size m_dSize;
|
cv::Size m_dSize;
|
||||||
ResizeType m_type;
|
ResizeType m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_RESIZE_H
|
#endif // !IMAGE_APPLY_RESIZE_H
|
||||||
|
|
|
@ -1,172 +1,139 @@
|
||||||
#include "ImageApplyRotation.h"
|
#include "ImageApplyRotation.h"
|
||||||
//#define USE_TESSERCAT
|
|
||||||
|
#ifdef _WIN32
|
||||||
//#define USE_HANWANG
|
#ifdef USE_HANWANG
|
||||||
|
#include<sstream>
|
||||||
//#define HG_GPDF_API_BUILD
|
#endif
|
||||||
#include "hg_ocr.h"
|
#endif
|
||||||
|
|
||||||
CImageApplyRotation::CImageApplyRotation(RotationType rotation, bool isBackTransposed, int dpi, const char* tessdataPath)
|
CImageApplyRotation::CImageApplyRotation(RotationType rotation, bool isBackTransposed, int dpi, const char* tessdataPath)
|
||||||
: m_rotation(rotation)
|
: m_rotation(rotation)
|
||||||
, m_backTranspose(isBackTransposed)
|
, m_backTranspose(isBackTransposed)
|
||||||
, m_dpi(dpi)
|
, m_dpi(dpi)
|
||||||
, osd(nullptr)
|
#ifdef _WIN32
|
||||||
{
|
#ifdef USE_HANWANG
|
||||||
if (rotation == RotationType::AutoTextOrientation)
|
, m_ocr(nullptr)
|
||||||
{
|
#endif
|
||||||
#ifdef USE_TESSERCAT
|
#endif
|
||||||
osd = new HG_OCR();
|
{
|
||||||
std::string strpath(tessdataPath);
|
#ifdef _WIN32
|
||||||
reinterpret_cast<HG_OCR*>(osd)->init(strpath.c_str(), HG_OCR::PSM_TYPE::Orientation);
|
#ifdef USE_HANWANG
|
||||||
#endif
|
if (tessdataPath != nullptr)
|
||||||
}
|
{
|
||||||
}
|
std::wstringstream wss;
|
||||||
|
wss << tessdataPath;
|
||||||
CImageApplyRotation::~CImageApplyRotation()
|
m_ocr = new HG_OCR(wss.str().c_str());
|
||||||
{
|
}
|
||||||
#ifdef USE_TESSERCAT
|
#endif
|
||||||
if (osd) delete reinterpret_cast<HG_OCR*>(osd);
|
#endif
|
||||||
#endif
|
}
|
||||||
}
|
|
||||||
|
CImageApplyRotation::~CImageApplyRotation()
|
||||||
void CImageApplyRotation::apply(cv::Mat& pDib, int side)
|
{
|
||||||
{
|
#ifdef _WIN32
|
||||||
m_angleResult = 0;
|
#ifdef USE_HANWANG
|
||||||
if (pDib.empty())
|
if (m_ocr)
|
||||||
{
|
delete m_ocr;
|
||||||
return;
|
#endif
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
if (m_rotation == RotationType::AutoTextOrientation) //<2F>Զ<EFBFBD><D4B6>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>ʶ<EFBFBD><CAB6>
|
|
||||||
{
|
void CImageApplyRotation::apply(cv::Mat& pDib, int side)
|
||||||
#ifdef USE_HANWANG
|
{
|
||||||
cv::Mat temp;
|
#ifdef LOG
|
||||||
if (m_dpi != 200)
|
FileTools::write_log("imgprc.txt", "enter CImageApplyRotation apply");
|
||||||
{
|
#endif // LOG
|
||||||
double scale = 200 / static_cast<double>(m_dpi);
|
if (pDib.empty())
|
||||||
int new_w = static_cast<int>(pDib.cols * scale) / 4 * 4;
|
{
|
||||||
int new_h = pDib.rows * scale;
|
#ifdef LOG
|
||||||
cv::resize(pDib, temp, cv::Size(new_w, new_h));
|
FileTools::write_log("imgprc.txt", "exit CImageApplyRotation apply");
|
||||||
}
|
#endif // LOG
|
||||||
else
|
return;
|
||||||
temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone();
|
}
|
||||||
|
|
||||||
if (temp.channels() == 3)
|
if (m_rotation == RotationType::AutoTextOrientation) //<2F>Զ<EFBFBD><D4B6>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>ʶ<EFBFBD><CAB6>
|
||||||
cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY);
|
{
|
||||||
cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU);
|
#ifdef USE_HANWANG
|
||||||
|
cv::Mat temp;
|
||||||
int orientation = HG_OCR::orientation(temp.data, temp.cols, temp.rows, temp.channels());
|
if (m_dpi != 200)
|
||||||
|
{
|
||||||
switch (orientation)
|
double scale = 200 / static_cast<double>(m_dpi);
|
||||||
{
|
int new_w = static_cast<int>(pDib.cols * scale) / 4 * 4;
|
||||||
case 90:
|
int new_h = pDib.rows * scale;
|
||||||
cv::transpose(pDib, pDib);
|
cv::resize(pDib, temp, cv::Size(new_w, new_h));
|
||||||
cv::flip(pDib, pDib, 0);
|
}
|
||||||
break;
|
else
|
||||||
case 180:
|
temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone();
|
||||||
cv::flip(pDib, pDib, 0);
|
|
||||||
cv::flip(pDib, pDib, 1);
|
if (temp.channels() == 3)
|
||||||
break;
|
cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY);
|
||||||
case 270:
|
cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU);
|
||||||
cv::transpose(pDib, pDib);
|
|
||||||
cv::flip(pDib, pDib, 1);
|
int orientation = 0;
|
||||||
break;
|
if (m_ocr)
|
||||||
default:
|
orientation = m_ocr->orientation(temp.data, temp.cols, temp.rows, temp.channels());
|
||||||
break;
|
|
||||||
}
|
switch (orientation)
|
||||||
#endif
|
{
|
||||||
#ifdef USE_TESSERCAT
|
case 90:
|
||||||
if (osd)
|
cv::transpose(pDib, pDib);
|
||||||
{
|
cv::flip(pDib, pDib, 0);
|
||||||
cv::Mat temp;
|
break;
|
||||||
if (m_dpi != 200)
|
case 180:
|
||||||
{
|
cv::flip(pDib, pDib, 0);
|
||||||
double scale = 200 / static_cast<double>(m_dpi);
|
cv::flip(pDib, pDib, 1);
|
||||||
int new_w = (static_cast<int>(pDib.cols * scale) + 3) / 4 * 4;
|
break;
|
||||||
int new_h = pDib.rows * scale;
|
case 270:
|
||||||
cv::resize(pDib, temp, cv::Size(new_w, new_h));
|
cv::transpose(pDib, pDib);
|
||||||
}
|
cv::flip(pDib, pDib, 1);
|
||||||
else
|
break;
|
||||||
temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone();
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
HG_OCR* ptr_osd = reinterpret_cast<HG_OCR*>(osd);
|
#endif
|
||||||
int ori = -1;
|
}
|
||||||
int direction = -1;
|
else if (m_backTranspose && side == 1) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת180
|
||||||
int order = -1;
|
{
|
||||||
float angle = -1;
|
if (m_rotation != RotationType::Rotate_180) //<2F><>ת180<38><30>
|
||||||
ptr_osd->getOrientation(temp.data, temp.cols, temp.rows, temp.channels(), temp.step1(),
|
{
|
||||||
ori, direction, order, angle);
|
if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90<39><30> -90<39><30>
|
||||||
|
{
|
||||||
switch (ori)
|
transpose(pDib, pDib);
|
||||||
{
|
flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1);
|
||||||
case 1:
|
}
|
||||||
cv::transpose(pDib, pDib);
|
else
|
||||||
cv::flip(pDib, pDib, 0);
|
{
|
||||||
m_angleResult = 90;
|
flip(pDib, pDib, 0);
|
||||||
break;
|
flip(pDib, pDib, 1);
|
||||||
case 2:
|
}
|
||||||
cv::flip(pDib, pDib, 0);
|
}
|
||||||
cv::flip(pDib, pDib, 1);
|
}
|
||||||
m_angleResult = 180;
|
else //zh
|
||||||
break;
|
{
|
||||||
case 3:
|
if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90<39><30> -90<39><30>
|
||||||
cv::transpose(pDib, pDib);
|
{
|
||||||
cv::flip(pDib, pDib, 1);
|
transpose(pDib, pDib);
|
||||||
m_angleResult = 270;
|
flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 1 : 0);
|
||||||
break;
|
}
|
||||||
default:
|
else if (m_rotation == RotationType::Rotate_180)
|
||||||
m_angleResult = 0;
|
{
|
||||||
break;
|
flip(pDib, pDib, 0);
|
||||||
}
|
flip(pDib, pDib, 1);
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
}
|
#ifdef LOG
|
||||||
else if (m_backTranspose && side == 1) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת180
|
FileTools::write_log("imgprc.txt", "exit CImageApplyRotation apply");
|
||||||
{
|
#endif // LOG
|
||||||
if (m_rotation != RotationType::Rotate_180) //<2F><>ת180<38><30>
|
}
|
||||||
{
|
|
||||||
if (m_rotation == RotationType::Rotate_90_clockwise || m_rotation == RotationType::Rotate_90_anti_clockwise) //90<39><30> -90<39><30>
|
void CImageApplyRotation::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
transpose(pDib, pDib);
|
(void)isTwoSide;
|
||||||
flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1);
|
int i = 0;
|
||||||
m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 270 : 90;
|
for (cv::Mat& var : mats) {
|
||||||
}
|
if (!var.empty()) {
|
||||||
else
|
apply(var, i);
|
||||||
{
|
i++;
|
||||||
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<39><30> -90<39><30>
|
|
||||||
{
|
|
||||||
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<cv::Mat>& 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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +1,82 @@
|
||||||
#ifndef IMAGE_APPLY_ROTATION_H
|
/*
|
||||||
#define IMAGE_APPLY_ROTATION_H
|
* ====================================================
|
||||||
|
|
||||||
#include "ImageApply.h"
|
* 功能:旋转图像
|
||||||
|
* 作者:刘丁维
|
||||||
class CImageApplyRotation : public CImageApply
|
* 生成时间:2020/4/21
|
||||||
{
|
* 最近修改时间:v1.0 2020/04/21
|
||||||
public:
|
v1.1 2020/08/12 修复文稿方向自动识别导致崩溃的BUG
|
||||||
enum class RotationType
|
v1.2 2021/10/15 开放文稿方向识别模块
|
||||||
{
|
v1.2.1 2022/04/25 补充切换版本的预处理代码
|
||||||
Invalid,
|
* 版本号:v1.2.1
|
||||||
Rotate_90_clockwise,
|
|
||||||
Rotate_180,
|
* ====================================================
|
||||||
Rotate_90_anti_clockwise,
|
*/
|
||||||
|
|
||||||
AutoTextOrientation
|
#ifndef IMAGE_APPLY_ROTATION_H
|
||||||
};
|
#define IMAGE_APPLY_ROTATION_H
|
||||||
|
|
||||||
public:
|
#include "ImageApply.h"
|
||||||
|
|
||||||
CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr);
|
#ifdef _WIN32
|
||||||
|
//#define USE_HANWANG
|
||||||
virtual ~CImageApplyRotation();
|
#ifdef USE_HANWANG
|
||||||
|
#define HG_GPDF_API_BUILD
|
||||||
virtual void apply(cv::Mat& pDib, int side) override;
|
#include <hg_gpdf.h>
|
||||||
|
#endif
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
#endif
|
||||||
|
|
||||||
bool isBackTransposed() { return m_backTranspose; }
|
class GIMGPROC_LIBRARY_API CImageApplyRotation : public CImageApply
|
||||||
|
{
|
||||||
int getDPI() { return m_dpi; }
|
public:
|
||||||
|
enum class RotationType
|
||||||
int angleResult() { return m_angleResult; }
|
{
|
||||||
|
Invalid, //无效
|
||||||
const std::vector<int>& angleResults() { return m_angleResults; }
|
Rotate_90_clockwise, //顺时针90°
|
||||||
|
Rotate_180, //180°
|
||||||
RotationType getRotationType() { return m_rotation; }
|
Rotate_90_anti_clockwise, //逆时针90°,即270°
|
||||||
|
|
||||||
void setBackTransposed(bool enabled) { m_backTranspose = enabled; }
|
AutoTextOrientation //自动文稿方向识别旋转
|
||||||
|
};
|
||||||
void setDPI(int dpi) { m_dpi = dpi; }
|
|
||||||
|
public:
|
||||||
void setRotationType(RotationType type) { m_rotation = type; }
|
|
||||||
|
/*
|
||||||
private:
|
* rotation [in]:旋转类型
|
||||||
RotationType m_rotation;
|
* isBackTransposed [in]:true为背面180°旋转,反之亦然
|
||||||
bool m_backTranspose;
|
* dpi [in]:当前图像的DPI,该参数在rotation为AutoTextOrientation时生效。在识别文稿方向时,会默认将图像变换为200DPI进行识别
|
||||||
int m_dpi;
|
* tessadataPath [in]:训练库文件路径,该参数在rotation为AutoTextOrientation时生效
|
||||||
|
*/
|
||||||
void* osd;
|
CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr);
|
||||||
|
|
||||||
int m_angleResult;
|
virtual ~CImageApplyRotation();
|
||||||
std::vector<int> m_angleResults;
|
|
||||||
};
|
virtual void apply(cv::Mat& pDib, int side) override;
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_ROTATION_H
|
virtual void apply(std::vector<cv::Mat>& 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
|
||||||
|
|
|
@ -1,47 +1,46 @@
|
||||||
#include "ImageApplySizeDetection.h"
|
#include "ImageApplySizeDetection.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
CImageApplySizeDetection::CImageApplySizeDetection(int paperType, int thre_x, int thre_y)
|
CImageApplySizeDetection::CImageApplySizeDetection(int paperType, int thre_x, int thre_y)
|
||||||
: m_paperType(paperType)
|
: m_paperType(paperType)
|
||||||
, m_thre_x(thre_x)
|
, m_thre_x(thre_x)
|
||||||
, m_thre_y(thre_y)
|
, m_thre_y(thre_y)
|
||||||
{
|
{
|
||||||
printf("\n paperType =%d \r\n", paperType);
|
}
|
||||||
}
|
|
||||||
|
CImageApplySizeDetection::~CImageApplySizeDetection()
|
||||||
CImageApplySizeDetection::~CImageApplySizeDetection()
|
{
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
#define THRESHOLD 40
|
||||||
#define THRESHOLD 40
|
#define ELEMNT_K 8
|
||||||
#define ELEMNT_K 8
|
int CImageApplySizeDetection::apply(const cv::Mat& pDib)
|
||||||
int CImageApplySizeDetection::apply(const cv::Mat& pDib)
|
{
|
||||||
{
|
if (pDib.empty()) return 0;
|
||||||
if (pDib.empty()) return 0;
|
|
||||||
|
float width, height;
|
||||||
float width, height;
|
cv::Mat thre;
|
||||||
cv::Mat thre;
|
hg::threshold_Mat(pDib, thre, THRESHOLD);
|
||||||
hg::threshold_Mat(pDib, thre, THRESHOLD);
|
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(ELEMNT_K, 1));
|
||||||
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));
|
||||||
cv::morphologyEx(thre, thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
std::vector<std::vector<cv::Point>> contours;
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
std::vector<cv::Vec4i> hierarchy;
|
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
||||||
hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL);
|
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
||||||
std::vector<cv::Point> maxContour = hg::getMaxContour(contours, hierarchy);
|
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
||||||
cv::RotatedRect rect = hg::getBoundingRect(maxContour);
|
width = rect.size.width;
|
||||||
width = rect.size.width;
|
height = rect.size.height;
|
||||||
height = rect.size.height;
|
printf("\n width =%f ,height = %f ", width, height);
|
||||||
printf("\n width =%f ,height = %f ", width, height);
|
|
||||||
|
HGSize dstSize;
|
||||||
HGSize dstSize;
|
if (m_supportPaper.count((PaperSize)m_paperType) > 0)//°üº¬ÉèÖõķùÃæ
|
||||||
if (m_supportPaper.count((PaperSize)m_paperType) > 0)//包含设置的幅面
|
{
|
||||||
{
|
dstSize = m_supportPaper[(PaperSize)m_paperType];
|
||||||
dstSize = m_supportPaper[(PaperSize)m_paperType];
|
if ((width > (dstSize.width + m_thre_x)) ||
|
||||||
if ((width > (dstSize.width + m_thre_x)) ||
|
(width < (dstSize.width - m_thre_x)) ||
|
||||||
(width < (dstSize.width - m_thre_x)) ||
|
(height > (dstSize.height + m_thre_y)) ||
|
||||||
(height > (dstSize.height + m_thre_y)) ||
|
(height < (dstSize.height - m_thre_y)))
|
||||||
(height < (dstSize.height - m_thre_y)))
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,84 +1,83 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:尺寸检测
|
* 功能:尺寸检测
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2022/05/11
|
* 生成时间:2022/05/11
|
||||||
* 最近修改时间:2022/05/11
|
* 最近修改时间:2022/05/11
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_SIZE_DETECTION_H
|
#ifndef IMAGE_APPLY_SIZE_DETECTION_H
|
||||||
#define IMAGE_APPLY_SIZE_DETECTION_H
|
#define IMAGE_APPLY_SIZE_DETECTION_H
|
||||||
|
|
||||||
#include "ImageApply.h"
|
#include "ImageApply.h"
|
||||||
#include <map>
|
#include<map>
|
||||||
|
class GIMGPROC_LIBRARY_API CImageApplySizeDetection
|
||||||
class CImageApplySizeDetection
|
{
|
||||||
{
|
public:
|
||||||
public:
|
enum PaperSize
|
||||||
enum PaperSize
|
{
|
||||||
{
|
G400_A3,
|
||||||
G400_A3,
|
G400_A4,
|
||||||
G400_A4,
|
G400_A4R,
|
||||||
G400_A4R,
|
G400_A5,
|
||||||
G400_A5,
|
G400_A5R,
|
||||||
G400_A5R,
|
G400_A6,
|
||||||
G400_A6,
|
G400_A6R,
|
||||||
G400_A6R,
|
G400_B4,
|
||||||
G400_B4,
|
G400_B5,
|
||||||
G400_B5,
|
G400_B5R,
|
||||||
G400_B5R,
|
G400_B6R,
|
||||||
G400_B6R,
|
G400_B6,
|
||||||
G400_B6,
|
G400_DOUBLELETTER,
|
||||||
G400_DOUBLELETTER,
|
G400_LEGAL,
|
||||||
G400_LEGAL,
|
G400_LETTER,
|
||||||
G400_LETTER,
|
G400_LONGLETTER,
|
||||||
G400_LONGLETTER,
|
G400_MAXSIZE
|
||||||
G400_MAXSIZE
|
};
|
||||||
};
|
|
||||||
|
struct HGSize
|
||||||
struct HGSize
|
{
|
||||||
{
|
int width;
|
||||||
int width;
|
int height;
|
||||||
int height;
|
};
|
||||||
};
|
|
||||||
|
public:
|
||||||
public:
|
|
||||||
|
CImageApplySizeDetection(int paperType, int thre_x = 70, int thre_y = 80);
|
||||||
CImageApplySizeDetection(int paperType, int thre_x = 70, int thre_y = 80);
|
|
||||||
|
~CImageApplySizeDetection();
|
||||||
~CImageApplySizeDetection();
|
|
||||||
|
virtual int apply(const cv::Mat& pDib);
|
||||||
virtual int apply(const cv::Mat& pDib);
|
|
||||||
|
inline void setPaperType(int paperType) { m_paperType = paperType; }
|
||||||
inline void setPaperType(int paperType) { m_paperType = paperType; }
|
|
||||||
|
private:
|
||||||
private:
|
int m_paperType;
|
||||||
int m_paperType;
|
int m_thre_x;
|
||||||
int m_thre_x;
|
int m_thre_y;
|
||||||
int m_thre_y;
|
std::map<PaperSize, HGSize> m_supportPaper = {
|
||||||
std::map<PaperSize, HGSize> m_supportPaper = {
|
{PaperSize::G400_A3,HGSize{2338,3307}},
|
||||||
{PaperSize::G400_A3,HGSize{2338,3307}},
|
{PaperSize::G400_A4,HGSize{1653,2338}},
|
||||||
{PaperSize::G400_A4,HGSize{1653,2338}},
|
{PaperSize::G400_A4R,HGSize{2338,1653}},
|
||||||
{PaperSize::G400_A4R,HGSize{2338,1653}},
|
{PaperSize::G400_A5,HGSize{1165,1653}},
|
||||||
{PaperSize::G400_A5,HGSize{1165,1653}},
|
{PaperSize::G400_A5R,HGSize{1653,1165}},
|
||||||
{PaperSize::G400_A5R,HGSize{1653,1165}},
|
{PaperSize::G400_A6,HGSize{826,1165}},
|
||||||
{PaperSize::G400_A6,HGSize{826,1165}},
|
{PaperSize::G400_A6R,HGSize{1165,826}},
|
||||||
{PaperSize::G400_A6R,HGSize{1165,826}},
|
{PaperSize::G400_B4,HGSize{1969,2780}},
|
||||||
{PaperSize::G400_B4,HGSize{1969,2780}},
|
{PaperSize::G400_B5,HGSize{1385,1968}},
|
||||||
{PaperSize::G400_B5,HGSize{1385,1968}},
|
{PaperSize::G400_B5R,HGSize{1968,1385}},
|
||||||
{PaperSize::G400_B5R,HGSize{1968,1385}},
|
{PaperSize::G400_B6R,HGSize{1433,1007}},
|
||||||
{PaperSize::G400_B6R,HGSize{1433,1007}},
|
{PaperSize::G400_B6,HGSize{1007,1433}},
|
||||||
{PaperSize::G400_B6,HGSize{1007,1433}},
|
{PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}},
|
||||||
{PaperSize::G400_DOUBLELETTER,HGSize{2200,3400}},
|
{PaperSize::G400_LEGAL,HGSize{1700,2800}},
|
||||||
{PaperSize::G400_LEGAL,HGSize{1700,2800}},
|
{PaperSize::G400_LETTER,HGSize{1700,2198}},
|
||||||
{PaperSize::G400_LETTER,HGSize{1700,2198}},
|
{PaperSize::G400_LONGLETTER,HGSize{2040,2640}},
|
||||||
{PaperSize::G400_LONGLETTER,HGSize{2040,2640}},
|
{PaperSize::G400_MAXSIZE,HGSize{2338,6614}}
|
||||||
{PaperSize::G400_MAXSIZE,HGSize{2338,6614}}
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
#endif // !IMAGE_APPLY_SIZE_DETECTION_H
|
||||||
#endif // !IMAGE_APPLY_SIZE_DETECTION_H
|
|
||||||
|
|
|
@ -1,115 +1,113 @@
|
||||||
#include "ImageApplySplit.h"
|
#include "ImageApplySplit.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define BPP(type,index)
|
#define BPP(type,index)
|
||||||
CImageApplySplit::CImageApplySplit(int multitype,bool split, bool ismulti_filter_red,int colormode) :
|
CImageApplySplit::CImageApplySplit(int multitype,bool split, bool ismulti_filter_red,int colormode) :
|
||||||
m_bmulti_filter_red(ismulti_filter_red)
|
m_bmulti_filter_red(ismulti_filter_red)
|
||||||
, m_split(split)
|
, m_split(split)
|
||||||
, m_multitype(multitype)
|
, m_multitype(multitype)
|
||||||
, m_colormode(colormode)
|
, m_colormode(colormode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CImageApplySplit::~CImageApplySplit(void)
|
CImageApplySplit::~CImageApplySplit(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MatEx> CImageApplySplit::SplitMats(std::vector<cv::Mat>& mats, bool isTwoSide)
|
std::vector<MatEx> CImageApplySplit::SplitMats(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
std::vector<MatEx> rets;
|
std::vector<MatEx> rets;
|
||||||
for (size_t i = 0; i < mats.size(); i++)
|
for (size_t i = 0; i < mats.size(); i++)
|
||||||
{
|
{
|
||||||
if (mats[i].empty())
|
if (mats[i].empty())
|
||||||
continue;
|
continue;
|
||||||
// if (i != 0 && isTwoSide == false)
|
if (i != 0 && isTwoSide == false)
|
||||||
// break;
|
break;
|
||||||
|
|
||||||
int bpp = getBpp(i);
|
int bpp = getBpp(i);
|
||||||
if (m_split)//²ð·Ö
|
if (m_split)//²ð·Ö
|
||||||
{
|
{
|
||||||
std::vector<cv::Mat> retmats = apply(mats[i]);
|
std::vector<cv::Mat> retmats = apply(mats[i]);
|
||||||
if (bpp != -1) {
|
if (bpp != -1) {
|
||||||
}
|
}
|
||||||
else {//½ö²ð·Ö
|
else {//½ö²ð·Ö
|
||||||
if (m_colormode == 0) bpp = 1;//bw
|
if (m_colormode == 0) bpp = 1;//bw
|
||||||
else if (m_colormode == 1) bpp = 8;
|
else if (m_colormode == 1) bpp = 8;
|
||||||
else bpp = 24;
|
else bpp = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t j = 0; j < retmats.size(); j++)
|
for (size_t j = 0; j < retmats.size(); j++)
|
||||||
{
|
{
|
||||||
if (!retmats[j].empty()) {
|
if (!retmats[j].empty()) {
|
||||||
cv::transpose(retmats[j],retmats[j]);
|
MatEx matex(retmats[j], bpp);
|
||||||
cv::flip(retmats[j],retmats[j],i==0?1:0);
|
rets.push_back(matex);
|
||||||
MatEx matex(retmats[j], bpp);
|
}
|
||||||
rets.push_back(matex);
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
}
|
MatEx matex(mats[i], bpp);
|
||||||
else {
|
rets.push_back(matex);
|
||||||
MatEx matex(mats[i], bpp);
|
}
|
||||||
rets.push_back(matex);
|
}
|
||||||
}
|
return rets;
|
||||||
}
|
}
|
||||||
return rets;
|
|
||||||
}
|
std::vector<cv::Mat> CImageApplySplit::apply(cv::Mat& pDib)
|
||||||
|
{
|
||||||
std::vector<cv::Mat> CImageApplySplit::apply(cv::Mat& pDib)
|
if (pDib.empty())
|
||||||
{
|
return std::vector<cv::Mat>();
|
||||||
if (pDib.empty())
|
std::vector<cv::Mat> retMats;
|
||||||
return std::vector<cv::Mat>();
|
int heigth = pDib.rows;
|
||||||
std::vector<cv::Mat> retMats;
|
int width = pDib.cols;
|
||||||
int heigth = pDib.rows;
|
if (heigth > width)
|
||||||
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)));
|
||||||
cv::Mat matF = pDib(cv::Rect(0, 0, width, (int)(0.5 * heigth)));
|
retMats.push_back(matF);
|
||||||
cv::Mat matB = pDib(cv::Rect(0, (int)(0.5 * heigth), width, (int)(0.5 * heigth)));
|
retMats.push_back(matB);
|
||||||
retMats.push_back(matF);
|
}
|
||||||
retMats.push_back(matB);
|
else
|
||||||
}
|
{
|
||||||
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));
|
||||||
cv::Mat matF = pDib(cv::Rect(0, 0, (int)(width*0.5), heigth));
|
retMats.push_back(matF);
|
||||||
cv::Mat matB = pDib(cv::Rect((int)(width*0.5), 0, (int)(width * 0.5), heigth));
|
retMats.push_back(matB);
|
||||||
retMats.push_back(matF);
|
}
|
||||||
retMats.push_back(matB);
|
return retMats;
|
||||||
}
|
}
|
||||||
return retMats;
|
|
||||||
}
|
int CImageApplySplit::getBpp(int matIndex)
|
||||||
|
{
|
||||||
int CImageApplySplit::getBpp(int matIndex)
|
int ret = -1;
|
||||||
{
|
if (m_bmulti_filter_red) {
|
||||||
int ret = -1;
|
ret = matIndex == 0 ? 24 : 8;
|
||||||
if (m_bmulti_filter_red) {
|
}
|
||||||
ret = matIndex == 0 ? 24 : 8;
|
else
|
||||||
}
|
{
|
||||||
else
|
if (m_multitype == -1)
|
||||||
{
|
return ret;
|
||||||
if (m_multitype == -1)
|
switch (m_multitype)
|
||||||
return ret;
|
{
|
||||||
switch (m_multitype)
|
case 0://all
|
||||||
{
|
if (matIndex == 0) ret = 24;
|
||||||
case 0://all
|
else if (matIndex == 1) ret = 8;
|
||||||
if (matIndex == 0) ret = 24;
|
else ret = 1;
|
||||||
else if (matIndex == 1) ret = 8;
|
break;
|
||||||
else ret = 1;
|
case 1://clolr +gray
|
||||||
break;
|
if (matIndex == 0) ret = 24;
|
||||||
case 1://clolr +gray
|
else ret = 8;
|
||||||
if (matIndex == 0) ret = 24;
|
break;
|
||||||
else ret = 8;
|
case 2://color+bw
|
||||||
break;
|
if (matIndex == 0) ret = 24;
|
||||||
case 2://color+bw
|
else ret = 1;
|
||||||
if (matIndex == 0) ret = 24;
|
break;
|
||||||
else ret = 1;
|
case 3://gray+bw
|
||||||
break;
|
if (matIndex == 0) ret = 8;
|
||||||
case 3://gray+bw
|
else ret = 1;
|
||||||
if (matIndex == 0) ret = 8;
|
break;
|
||||||
else ret = 1;
|
default:
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
break;
|
}
|
||||||
}
|
return ret;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,38 +1,36 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:图像拆分
|
* 功能:图像拆分
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 版本号:v1.0
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_APPLY_SPLIT_H
|
#ifndef IMAGE_APPLY_SPLIT_H
|
||||||
#define IMAGE_APPLY_SPLIT_H
|
#define IMAGE_APPLY_SPLIT_H
|
||||||
#include "MatEx.h"
|
#include "MatEx.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "imgprocdefs.h"
|
#include "imgprocdefs.h"
|
||||||
|
|
||||||
class CImageApplySplit
|
class GIMGPROC_LIBRARY_API CImageApplySplit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CImageApplySplit(int multitype=-1,bool split=false,bool ismulti_filter_red=false,int colormode=1);//默认不多流输出 不多流除红 灰度
|
CImageApplySplit(int multitype=-1,bool split=false,bool ismulti_filter_red=false,int colormode=1);//默认不多流输出 不多流除红 灰度
|
||||||
|
|
||||||
~CImageApplySplit(void);
|
~CImageApplySplit(void);
|
||||||
std::vector<MatEx> SplitMats(std::vector<cv::Mat>& mats, bool isTwoSide);
|
std::vector<MatEx> SplitMats(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
|
private:
|
||||||
//private:
|
std::vector<cv::Mat> apply(cv::Mat& pDib);
|
||||||
std::vector<cv::Mat> apply(cv::Mat& pDib);
|
int getBpp(int matIndex);
|
||||||
int getBpp(int matIndex);
|
private://field
|
||||||
|
bool m_bmulti_filter_red;
|
||||||
private://field
|
int m_multitype;
|
||||||
bool m_bmulti_filter_red;
|
int m_colormode;
|
||||||
int m_multitype;
|
bool m_split;
|
||||||
int m_colormode;
|
};
|
||||||
bool m_split;
|
|
||||||
};
|
#endif // !IMAGE_APPLY_SPLIT_H
|
||||||
|
|
||||||
#endif // !IMAGE_APPLY_SPLIT_H
|
|
||||||
|
|
|
@ -1,172 +1,187 @@
|
||||||
#include "ImageApplyTextureRemoval.h"
|
#include "ImageApplyTextureRemoval.h"
|
||||||
|
|
||||||
//交换对角线
|
//交换对角线
|
||||||
void zero_to_center(cv::Mat& image, int colToCut, int rowToCut)
|
void zero_to_center(cv::Mat& image, int colToCut, int rowToCut)
|
||||||
{
|
{
|
||||||
cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut));
|
cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut));
|
||||||
cv::Mat q2(image, cv::Rect(colToCut, 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 q3(image, cv::Rect(0, rowToCut, colToCut, rowToCut));
|
||||||
cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut));
|
cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut));
|
||||||
|
|
||||||
//第二象限和第四象限进行交换
|
//第二象限和第四象限进行交换
|
||||||
cv::Mat tmpImg;
|
cv::Mat tmpImg;
|
||||||
q1.copyTo(tmpImg);
|
q1.copyTo(tmpImg);
|
||||||
q4.copyTo(q1);
|
q4.copyTo(q1);
|
||||||
tmpImg.copyTo(q4);
|
tmpImg.copyTo(q4);
|
||||||
|
|
||||||
//第一象限和第三象限进行交换
|
//第一象限和第三象限进行交换
|
||||||
q2.copyTo(tmpImg);
|
q2.copyTo(tmpImg);
|
||||||
q3.copyTo(q2);
|
q3.copyTo(q2);
|
||||||
tmpImg.copyTo(q3);
|
tmpImg.copyTo(q3);
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建光谱
|
//创建光谱
|
||||||
cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5)
|
cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5)
|
||||||
{
|
{
|
||||||
cv::Mat dst;
|
cv::Mat dst;
|
||||||
cv::magnitude(matArray[0], matArray[1], dst);
|
cv::magnitude(matArray[0], matArray[1], dst);
|
||||||
#if 1
|
#if 1
|
||||||
cv::divide(dst, dst.cols * dst.rows, dst, scale);
|
cv::divide(dst, dst.cols * dst.rows, dst, scale);
|
||||||
//imshow("频谱", dst);
|
//imshow("频谱", dst);
|
||||||
#else
|
#else
|
||||||
dst += Scalar::all(1);
|
dst += Scalar::all(1);
|
||||||
log(dst, dst);
|
log(dst, dst);
|
||||||
normalize(dst, dst, 1, 0, CV_MINMAX);
|
normalize(dst, dst, 1, 0, CV_MINMAX);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
imshow("频谱", dst);
|
imshow("频谱", dst);
|
||||||
#endif
|
#endif
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
//反傅里叶变换
|
//反傅里叶变换
|
||||||
void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst)
|
void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst)
|
||||||
{
|
{
|
||||||
cv::Mat complexIDFT;
|
cv::Mat complexIDFT;
|
||||||
cv::Mat matArray[2];
|
cv::Mat matArray[2];
|
||||||
cv::idft(src, complexIDFT);
|
cv::idft(src, complexIDFT);
|
||||||
cv::split(complexIDFT, matArray);
|
cv::split(complexIDFT, matArray);
|
||||||
cv::magnitude(matArray[0], matArray[1], dst);
|
cv::magnitude(matArray[0], matArray[1], dst);
|
||||||
cv::normalize(dst, dst, 0, 1, CV_MINMAX);
|
cv::normalize(dst, dst, 0, 1, CV_MINMAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
//制作陷波滤波器
|
//制作陷波滤波器
|
||||||
cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize)
|
cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize)
|
||||||
{
|
{
|
||||||
cv::Mat temp;
|
cv::Mat temp;
|
||||||
spectrum.convertTo(temp, CV_8UC1, 255);
|
spectrum.convertTo(temp, CV_8UC1, 255);
|
||||||
cv::threshold(temp, temp, 0, 255, CV_THRESH_OTSU);
|
//cv::imwrite("filter/temp.bmp", temp);
|
||||||
//imshow("二值化", 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::Mat element1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(dilateSize, dilateSize));
|
||||||
cv::dilate(temp, temp, element1);
|
cv::Mat element2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(erodeSize, erodeSize));
|
||||||
cv::erode(temp, temp, element2);
|
cv::line(temp, cv::Point(0, temp.rows / 2), cv::Point(temp.cols - 1, temp.rows / 2), cv::Scalar(255));
|
||||||
cv::floodFill(temp, cv::Point(temp.cols / 2, temp.rows / 2), cv::Scalar(0)); //漫水填充中心区域
|
cv::line(temp, cv::Point(temp.cols / 2, 0), cv::Point(temp.cols / 2, temp.rows - 1), cv::Scalar(255));
|
||||||
cv::medianBlur(~temp, temp, 3); //中值滤波
|
cv::dilate(temp, temp, element1);
|
||||||
//temp = ~temp;
|
cv::erode(temp, temp, element2);
|
||||||
//cv::imshow("二值化", temp);
|
//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::Mat filter;
|
|
||||||
temp.convertTo(filter, CV_32FC1);
|
//cv::imwrite("filter/temp3.bmp", temp);
|
||||||
cv::normalize(filter, filter, 1, 0.01, CV_MINMAX);
|
//temp = ~temp;
|
||||||
std::vector<cv::Mat> mv;
|
|
||||||
mv.push_back(filter);
|
//陷波滤波器复制
|
||||||
mv.push_back(filter);
|
cv::Mat filter;
|
||||||
cv::merge(mv, filter);
|
temp.convertTo(filter, CV_32FC1);
|
||||||
|
cv::normalize(filter, filter, 1, 0.01, CV_MINMAX);
|
||||||
return filter;
|
std::vector<cv::Mat> mv;
|
||||||
}
|
mv.push_back(filter);
|
||||||
|
mv.push_back(filter);
|
||||||
void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img)
|
cv::merge(mv, filter);
|
||||||
{
|
|
||||||
//得到DFT的最佳尺寸(2的指数),以加速计算
|
return filter;
|
||||||
cv::Mat paddedImg;
|
}
|
||||||
int m = cv::getOptimalDFTSize(img.rows);
|
|
||||||
int n = cv::getOptimalDFTSize(img.cols);
|
void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img)
|
||||||
|
{
|
||||||
//填充图像的下端和右端
|
//得到DFT的最佳尺寸(2的指数),以加速计算
|
||||||
cv::copyMakeBorder(img, paddedImg, 0, m - img.rows, 0, n - img.cols,
|
cv::Mat resizeMat;
|
||||||
cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
|
||||||
|
cv::resize(img, resizeMat, cv::Size(), 0.5, 0.5);
|
||||||
//将填充的图像组成一个复数的二维数组(两个通道的Mat),用于DFT
|
|
||||||
cv::Mat matArray[] = { cv::Mat_<float>(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) };
|
cv::Mat paddedImg;
|
||||||
cv::Mat complexInput, complexOutput;
|
int m = cv::getOptimalDFTSize(resizeMat.rows);
|
||||||
cv::merge(matArray, 2, complexInput);
|
int n = cv::getOptimalDFTSize(resizeMat.cols);
|
||||||
cv::dft(complexInput, complexOutput);
|
|
||||||
cv::split(complexOutput, matArray); //计算幅度谱(傅里叶谱)
|
//填充图像的下端和右端
|
||||||
|
cv::copyMakeBorder(resizeMat, paddedImg, 0, m - resizeMat.rows, 0, n - resizeMat.cols,
|
||||||
//滤波
|
cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||||
//将实部和虚部按照频谱图的方式换位
|
|
||||||
//低频在图像中心,用于滤波
|
//将填充的图像组成一个复数的二维数组(两个通道的Mat),用于DFT
|
||||||
zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2);
|
cv::Mat matArray[] = { cv::Mat_<float>(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) };
|
||||||
zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2);
|
cv::Mat complexInput, complexOutput;
|
||||||
cv::Mat spectrum = create_spectrum(matArray);
|
cv::merge(matArray, 2, complexInput);
|
||||||
|
cv::dft(complexInput, complexOutput);
|
||||||
//创建滤波器
|
cv::split(complexOutput, matArray); //计算幅度谱(傅里叶谱)
|
||||||
cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize);
|
|
||||||
cv::merge(matArray, 2, complexOutput);
|
//滤波
|
||||||
cv::multiply(complexOutput, filter, filter);
|
//将实部和虚部按照频谱图的方式换位
|
||||||
|
//低频在图像中心,用于滤波
|
||||||
//IDFT得到滤波结果
|
zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2);
|
||||||
cv::Size imgSize = img.size();
|
zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2);
|
||||||
inverseFourierTransform(filter, img);
|
cv::Mat spectrum = create_spectrum(matArray);
|
||||||
img = img(cv::Rect(cv::Point(0, 0), imgSize));
|
|
||||||
img *= 255;
|
//创建滤波器
|
||||||
img.convertTo(img, CV_8UC1);
|
cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize);
|
||||||
}
|
cv::merge(matArray, 2, complexOutput);
|
||||||
|
cv::multiply(complexOutput, filter, filter);
|
||||||
CImageApplyTextureRemoval::CImageApplyTextureRemoval()
|
|
||||||
: CImageApply()
|
cv::Size imgSize = img.size();
|
||||||
, m_dilateSize(5)
|
m = cv::getOptimalDFTSize(img.rows);
|
||||||
, m_erodeSize(3)
|
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,
|
||||||
CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize)
|
cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||||||
: CImageApply()
|
|
||||||
, m_dilateSize(dilateSize)
|
//IDFT得到滤波结果
|
||||||
, m_erodeSize(erodeSize)
|
inverseFourierTransform(filter, img);
|
||||||
{
|
img = img(cv::Rect(cv::Point(0, 0), imgSize));
|
||||||
|
img *= 255;
|
||||||
}
|
img.convertTo(img, CV_8UC1);
|
||||||
|
}
|
||||||
CImageApplyTextureRemoval::~CImageApplyTextureRemoval()
|
|
||||||
{
|
CImageApplyTextureRemoval::CImageApplyTextureRemoval()
|
||||||
|
: CImageApply()
|
||||||
}
|
, m_dilateSize(9)
|
||||||
|
, m_erodeSize(5)
|
||||||
void CImageApplyTextureRemoval::apply(cv::Mat &pDib, int side)
|
{
|
||||||
{
|
|
||||||
(void)side;
|
}
|
||||||
|
|
||||||
if (pDib.channels() == 1)
|
CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize)
|
||||||
textureRemovalGray(pDib);
|
: CImageApply()
|
||||||
else
|
, m_dilateSize(dilateSize)
|
||||||
{
|
, m_erodeSize(erodeSize)
|
||||||
std::vector<cv::Mat> rgb(3);
|
{
|
||||||
cv::split(pDib, rgb);
|
|
||||||
for (cv::Mat& var : rgb)
|
}
|
||||||
textureRemovalGray(var);
|
|
||||||
cv::merge(rgb, pDib);
|
CImageApplyTextureRemoval::~CImageApplyTextureRemoval()
|
||||||
}
|
{
|
||||||
|
|
||||||
pDib *= 1.15;
|
}
|
||||||
}
|
|
||||||
|
void CImageApplyTextureRemoval::apply(cv::Mat& pDib, int side)
|
||||||
void CImageApplyTextureRemoval::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
{
|
||||||
{
|
(void)side;
|
||||||
(void)isTwoSide;
|
|
||||||
|
if (pDib.channels() == 1)
|
||||||
int i = 0;
|
textureRemovalGray(pDib);
|
||||||
for (cv::Mat& var : mats) {
|
else
|
||||||
if (i != 0 && isTwoSide == false)
|
{
|
||||||
break;
|
std::vector<cv::Mat> rgb(3);
|
||||||
if (!var.empty())
|
cv::split(pDib, rgb);
|
||||||
apply(var, 0);
|
for (cv::Mat& var : rgb)
|
||||||
i++;
|
textureRemovalGray(var);
|
||||||
}
|
cv::merge(rgb, pDib);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CImageApplyTextureRemoval::apply(std::vector<cv::Mat>& 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:去除网纹
|
* 功能:去除网纹
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21 v1.0
|
||||||
* 版本号:v1.0
|
* 2022/4/09 v1.1 提高算法效率
|
||||||
|
* 版本号:v1.1
|
||||||
* ====================================================
|
|
||||||
*/
|
* ====================================================
|
||||||
|
*/
|
||||||
#ifndef IMAGE_APPLY_TEXTURE_REMOVAL_H
|
|
||||||
#define IMAGE_APPLY_TEXTURE_REMOVAL_H
|
#ifndef IMAGE_APPLY_TEXTURE_REMOVAL_H
|
||||||
|
#define IMAGE_APPLY_TEXTURE_REMOVAL_H
|
||||||
#include "ImageApply.h"
|
|
||||||
|
#include "ImageApply.h"
|
||||||
class CImageApplyTextureRemoval : public CImageApply
|
|
||||||
{
|
class GIMGPROC_LIBRARY_API CImageApplyTextureRemoval : public CImageApply
|
||||||
public:
|
{
|
||||||
CImageApplyTextureRemoval(void);
|
public:
|
||||||
|
CImageApplyTextureRemoval(void);
|
||||||
/*
|
|
||||||
* dilateSize [in]:膨胀像素
|
/*
|
||||||
* erodeSize [in]:腐蚀像素
|
* dilateSize [in]:膨胀像素
|
||||||
*/
|
* erodeSize [in]:腐蚀像素
|
||||||
CImageApplyTextureRemoval(int dilateSize, int erodeSize);
|
*/
|
||||||
|
CImageApplyTextureRemoval(int dilateSize, int erodeSize);
|
||||||
virtual ~CImageApplyTextureRemoval(void);
|
|
||||||
|
virtual ~CImageApplyTextureRemoval(void);
|
||||||
virtual void apply(cv::Mat& pDib,int side);
|
|
||||||
|
virtual void apply(cv::Mat& pDib, int side);
|
||||||
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
|
||||||
|
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
|
||||||
int getDilateSize() {return m_dilateSize;}
|
|
||||||
|
int getDilateSize() { return m_dilateSize; }
|
||||||
int getErodeSize() {return m_erodeSize;}
|
|
||||||
|
int getErodeSize() { return m_erodeSize; }
|
||||||
void setDilateSize(int size) {m_dilateSize = size;}
|
|
||||||
|
void setDilateSize(int size) { m_dilateSize = size; }
|
||||||
void setErodeSize(int size) {m_erodeSize = size;}
|
|
||||||
private:
|
void setErodeSize(int size) { m_erodeSize = size; }
|
||||||
void textureRemovalGray(cv::Mat& img);
|
private:
|
||||||
|
void textureRemovalGray(cv::Mat& img);
|
||||||
private:
|
|
||||||
int m_dilateSize;
|
private:
|
||||||
int m_erodeSize;
|
int m_dilateSize;
|
||||||
};
|
int m_erodeSize;
|
||||||
|
};
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -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<unsigned char>(cv::max(0, cv::min(i - m_contrast, 127)));
|
||||||
|
else
|
||||||
|
ptr[i] = static_cast<unsigned char>(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<std::vector<cv::Point>> contours;
|
||||||
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
|
hg::findContours(uv_resize, contours, hierarchy, cv::RETR_EXTERNAL);
|
||||||
|
|
||||||
|
std::map<int, cv::Scalar> 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<int, cv::Scalar> 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<uchar>(j, i))
|
||||||
|
{
|
||||||
|
uchar* color = image_roi.ptr<uchar>(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<uchar>(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;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* ====================================================
|
||||||
|
|
||||||
|
* <EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD>UVͼ<EFBFBD><EFBFBD>ԭͼ<EFBFBD>ϲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭͼ<EFBFBD><EFBFBD>ƫ<EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>UV<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭͼ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭͼƴ<EFBFBD><EFBFBD>Ϊһ<EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD>ù<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>UVһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD>
|
||||||
|
* <EFBFBD><EFBFBD><EFBFBD>ߣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ά
|
||||||
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䣺2020/7/20
|
||||||
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䣺2020/7/20
|
||||||
|
* <EFBFBD>汾<EFBFBD>ţ<EFBFBD>v1.0 2020/7/20
|
||||||
|
* ====================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMAGE_APPLY_UV_MERGE_H
|
||||||
|
#define IMAGE_APPLY_UV_MERGE_H
|
||||||
|
|
||||||
|
#include "ImageApply.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
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<int, cv::Scalar> 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
|
|
@ -1,72 +1,72 @@
|
||||||
#include "ImageMulti.h"
|
#include "ImageMulti.h"
|
||||||
|
|
||||||
IMageMulti::IMageMulti(int multiType,int thre)
|
IMageMulti::IMageMulti(int multiType,int thre)
|
||||||
{
|
{
|
||||||
m_multiType = multiType;
|
m_multiType = multiType;
|
||||||
m_thre = thre;
|
m_thre = thre;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMageMulti::~IMageMulti(void)
|
IMageMulti::~IMageMulti(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cv::Mat> IMageMulti::apply(cv::Mat& pDib)
|
std::vector<cv::Mat> IMageMulti::apply(cv::Mat& pDib)
|
||||||
{
|
{
|
||||||
std::vector<cv::Mat> retMats;
|
std::vector<cv::Mat> retMats;
|
||||||
if (pDib.empty())
|
if (pDib.empty())
|
||||||
return retMats;
|
return retMats;
|
||||||
retMats.push_back(pDib);
|
retMats.push_back(pDib);
|
||||||
switch (m_multiType)
|
switch (m_multiType)
|
||||||
{
|
{
|
||||||
case ALL:
|
case ALL:
|
||||||
{
|
{
|
||||||
if (pDib.channels() == 3){
|
if (pDib.channels() == 3){
|
||||||
cv::Mat dst;
|
cv::Mat dst;
|
||||||
cv::cvtColor(pDib, dst,cv::COLOR_BGR2GRAY);
|
cv::cvtColor(pDib, dst,cv::COLOR_BGR2GRAY);
|
||||||
retMats.push_back(dst);
|
retMats.push_back(dst);
|
||||||
}
|
}
|
||||||
cv::Mat dstThre;
|
cv::Mat dstThre;
|
||||||
cv::cvtColor(pDib, dstThre,cv::COLOR_BGR2GRAY);
|
cv::cvtColor(pDib, dstThre,cv::COLOR_BGR2GRAY);
|
||||||
//cv::threshold(dstThre, dstThre, m_thre, 255, cv::THRESH_BINARY);
|
//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);
|
cv::adaptiveThreshold(dstThre,dstThre,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5);
|
||||||
if (!dstThre.empty())
|
if (!dstThre.empty())
|
||||||
{
|
{
|
||||||
retMats.push_back(dstThre);
|
retMats.push_back(dstThre);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COLORGRAY:
|
case COLORGRAY:
|
||||||
{
|
{
|
||||||
if (pDib.channels() == 3) {
|
if (pDib.channels() == 3) {
|
||||||
cv::Mat dstGray;
|
cv::Mat dstGray;
|
||||||
cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY);
|
cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY);
|
||||||
retMats.push_back(dstGray);
|
retMats.push_back(dstGray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COLORBW:
|
case COLORBW:
|
||||||
{
|
{
|
||||||
if (pDib.channels() == 3) {
|
if (pDib.channels() == 3) {
|
||||||
cv::Mat dstGray;
|
cv::Mat dstGray;
|
||||||
cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY);
|
cv::cvtColor(pDib, dstGray, cv::COLOR_BGR2GRAY);
|
||||||
cv::Mat dstBW;
|
cv::Mat dstBW;
|
||||||
cv::adaptiveThreshold(dstGray,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5);
|
cv::adaptiveThreshold(dstGray,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5);
|
||||||
retMats.push_back(dstBW);
|
retMats.push_back(dstBW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GRAYBW://pDib should be GreyImage(channels() == 1)
|
case GRAYBW://pDib should be GreyImage(channels() == 1)
|
||||||
{
|
{
|
||||||
cv::Mat dstBW;
|
cv::Mat dstBW;
|
||||||
cv::adaptiveThreshold(pDib,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5);
|
cv::adaptiveThreshold(pDib,dstBW,255,cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY,25,5);
|
||||||
if (!dstBW.empty())
|
if (!dstBW.empty())
|
||||||
{
|
{
|
||||||
retMats.push_back(dstBW);
|
retMats.push_back(dstBW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return retMats;
|
return retMats;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
#ifndef IMAGE_MULTI_H
|
#ifndef IMAGE_MULTI_H
|
||||||
#define IMAGE_MULTI_H
|
#define IMAGE_MULTI_H
|
||||||
#include "IMulti.h"
|
#include "IMulti.h"
|
||||||
|
|
||||||
class IMageMulti
|
class GIMGPROC_LIBRARY_API IMageMulti
|
||||||
:public IMulti
|
:public IMulti
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum MultiOutput
|
enum MultiOutput
|
||||||
{
|
{
|
||||||
NONE=-1,
|
NONE=-1,
|
||||||
ALL,
|
ALL,
|
||||||
COLORGRAY,
|
COLORGRAY,
|
||||||
COLORBW,
|
COLORBW,
|
||||||
GRAYBW
|
GRAYBW
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
IMageMulti(int multiType = 0,int thre = 128);
|
IMageMulti(int multiType = 0,int thre = 128);
|
||||||
virtual ~IMageMulti(void);
|
virtual ~IMageMulti(void);
|
||||||
virtual std::vector<cv::Mat> apply(cv::Mat& pDib);
|
virtual std::vector<cv::Mat> apply(cv::Mat& pDib);
|
||||||
private:
|
private:
|
||||||
int m_multiType;
|
int m_multiType;
|
||||||
int m_thre;
|
int m_thre;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !IMAGE_MULTI_H
|
#endif // !IMAGE_MULTI_H
|
|
@ -1,63 +1,63 @@
|
||||||
#include "ImageMultiOutputRed.h"
|
#include "ImageMultiOutputRed.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ImageMultiOutputRed::ImageMultiOutputRed(short channelIndex)
|
ImageMultiOutputRed::ImageMultiOutputRed(short channelIndex)
|
||||||
{
|
{
|
||||||
m_channelIndex = channelIndex;
|
m_channelIndex = channelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageMultiOutputRed::~ImageMultiOutputRed(void)
|
ImageMultiOutputRed::~ImageMultiOutputRed(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cv::Mat> ImageMultiOutputRed::apply(cv::Mat& pDib)
|
std::vector<cv::Mat> ImageMultiOutputRed::apply(cv::Mat& pDib)
|
||||||
{
|
{
|
||||||
std::vector<cv::Mat> retMats;
|
std::vector<cv::Mat> retMats;
|
||||||
if (pDib.empty())
|
if (pDib.empty())
|
||||||
return retMats;
|
return retMats;
|
||||||
retMats.push_back(pDib);
|
retMats.push_back(pDib);
|
||||||
cv::Mat mat = FilterColor(pDib, m_channelIndex);
|
cv::Mat mat = FilterColor(pDib, m_channelIndex);
|
||||||
if (!mat.empty())
|
if (!mat.empty())
|
||||||
retMats.push_back(mat);
|
retMats.push_back(mat);
|
||||||
return retMats;
|
return retMats;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat ImageMultiOutputRed::FilterColor(cv::Mat image, short channel)
|
cv::Mat ImageMultiOutputRed::FilterColor(cv::Mat image, short channel)
|
||||||
{
|
{
|
||||||
cv::Mat dstImage(image.rows, image.cols, CV_8UC1);
|
cv::Mat dstImage(image.rows, image.cols, CV_8UC1);
|
||||||
int channels = image.channels();
|
int channels = image.channels();
|
||||||
if (channel > channels - 1)
|
if (channel > channels - 1)
|
||||||
{
|
{
|
||||||
return cv::Mat();
|
return cv::Mat();
|
||||||
}
|
}
|
||||||
if ((channel == 3) && (channels != 4) && (channels != 8))
|
if ((channel == 3) && (channels != 4) && (channels != 8))
|
||||||
{
|
{
|
||||||
return cv::Mat();
|
return cv::Mat();
|
||||||
}
|
}
|
||||||
if (channels <= 4)
|
if (channels <= 4)
|
||||||
{
|
{
|
||||||
int srcOffset = image.step - image.cols * channels;
|
int srcOffset = image.step - image.cols * channels;
|
||||||
int dstOffset = dstImage.step - dstImage.cols;
|
int dstOffset = dstImage.step - dstImage.cols;
|
||||||
unsigned char *src = image.data;
|
unsigned char *src = image.data;
|
||||||
unsigned char *dst = dstImage.data;
|
unsigned char *dst = dstImage.data;
|
||||||
src += channel;
|
src += channel;
|
||||||
|
|
||||||
for (int y = 0; y < image.rows; y++)
|
for (int y = 0; y < image.rows; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < image.cols; x++, src += channels, dst++)
|
for (int x = 0; x < image.cols; x++, src += channels, dst++)
|
||||||
{
|
{
|
||||||
unsigned short pix = *src;
|
unsigned short pix = *src;
|
||||||
if (pix >= 130)
|
if (pix >= 130)
|
||||||
{
|
{
|
||||||
pix = 255;
|
pix = 255;
|
||||||
}
|
}
|
||||||
*dst = pix;
|
*dst = pix;
|
||||||
}
|
}
|
||||||
src += srcOffset;
|
src += srcOffset;
|
||||||
dst += dstOffset;
|
dst += dstOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dstImage;
|
return dstImage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#ifndef IMAGE_MULTI_OUTPUT_RED_H
|
#ifndef IMAGE_MULTI_OUTPUT_RED_H
|
||||||
#define IMAGE_MULTI_OUTPUT_RED_H
|
#define IMAGE_MULTI_OUTPUT_RED_H
|
||||||
#include "IMulti.h"
|
#include "IMulti.h"
|
||||||
|
|
||||||
class ImageMultiOutputRed
|
class GIMGPROC_LIBRARY_API ImageMultiOutputRed
|
||||||
:public IMulti
|
:public IMulti
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageMultiOutputRed(short channelIndex);
|
ImageMultiOutputRed(short channelIndex);
|
||||||
virtual ~ImageMultiOutputRed(void);
|
virtual ~ImageMultiOutputRed(void);
|
||||||
virtual std::vector<cv::Mat> apply(cv::Mat& pDib) override;
|
virtual std::vector<cv::Mat> apply(cv::Mat& pDib) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
short m_channelIndex;
|
short m_channelIndex;
|
||||||
cv::Mat FilterColor(cv::Mat image, short channel);
|
cv::Mat FilterColor(cv::Mat image, short channel);
|
||||||
};
|
};
|
||||||
#endif //!IMAGE_MULTI_OUTPUT_RED_H
|
#endif //!IMAGE_MULTI_OUTPUT_RED_H
|
||||||
|
|
|
@ -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 = "版权"
|
|
@ -1,336 +1,349 @@
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
|
|
||||||
namespace hg
|
namespace hg
|
||||||
{
|
{
|
||||||
void convexHull(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, bool clockwise)
|
void convexHull(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, bool clockwise)
|
||||||
{
|
{
|
||||||
CvMemStorage* storage = cvCreateMemStorage(); //
|
CvMemStorage* storage = cvCreateMemStorage(); //
|
||||||
CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage
|
CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage
|
||||||
|
|
||||||
//
|
//将src的点集填充至ptseq
|
||||||
for (const cv::Point& item : src)
|
for (const cv::Point& item : src)
|
||||||
{
|
{
|
||||||
CvPoint p;
|
CvPoint p;
|
||||||
p.x = item.x;
|
p.x = item.x;
|
||||||
p.y = item.y;
|
p.y = item.y;
|
||||||
cvSeqPush(ptseq, &p);
|
cvSeqPush(ptseq, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
//μhullstorage
|
//获取轮廓点
|
||||||
CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0);
|
CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0);
|
||||||
|
|
||||||
//dst
|
if (hull == nullptr)
|
||||||
dst.clear();
|
{
|
||||||
for (int i = 0, hullCount = hull->total; i < hullCount; i++)
|
//释放storage
|
||||||
dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i));
|
cvReleaseMemStorage(&storage);
|
||||||
|
return;
|
||||||
//storage
|
}
|
||||||
cvReleaseMemStorage(&storage);
|
|
||||||
}
|
//填充dst
|
||||||
|
dst.clear();
|
||||||
#define R_COLOR 255
|
for (int i = 0, hullCount = hull->total; i < hullCount; i++)
|
||||||
void fillConvexHull(cv::Mat& image, const std::vector<cv::Point>& points)
|
dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i));
|
||||||
{
|
|
||||||
uint index_top = 0;
|
//释放storage
|
||||||
uint index_bottom = 0;
|
cvReleaseMemStorage(&storage);
|
||||||
for (size_t i = 0, length = points.size(); i < length; i++)
|
}
|
||||||
{
|
|
||||||
if (points[i].y < points[index_top].y)
|
#define R_COLOR 255
|
||||||
index_top = i;
|
void fillConvexHull(cv::Mat& image, const std::vector<cv::Point>& points)
|
||||||
if (points[i].y > points[index_bottom].y)
|
{
|
||||||
index_bottom = i;
|
uint index_top = 0;
|
||||||
}
|
uint index_bottom = 0;
|
||||||
|
for (size_t i = 0, length = points.size(); i < length; i++)
|
||||||
std::vector<cv::Point> edge_left;
|
{
|
||||||
uint temp = index_top;
|
if (points[i].y < points[index_top].y)
|
||||||
while (temp != index_bottom)
|
index_top = i;
|
||||||
{
|
if (points[i].y > points[index_bottom].y)
|
||||||
edge_left.push_back(points[temp]);
|
index_bottom = i;
|
||||||
temp = (temp + points.size() - 1) % points.size();
|
}
|
||||||
}
|
|
||||||
edge_left.push_back(points[index_bottom]);
|
std::vector<cv::Point> edge_left;
|
||||||
|
uint temp = index_top;
|
||||||
std::vector<cv::Point> edge_right;
|
while (temp != index_bottom)
|
||||||
temp = index_top;
|
{
|
||||||
while (temp != index_bottom)
|
edge_left.push_back(points[temp]);
|
||||||
{
|
temp = (temp + points.size() - 1) % points.size();
|
||||||
edge_right.push_back(points[temp]);
|
}
|
||||||
temp = (temp + points.size() + 1) % points.size();
|
edge_left.push_back(points[index_bottom]);
|
||||||
}
|
|
||||||
edge_right.push_back(points[index_bottom]);
|
std::vector<cv::Point> edge_right;
|
||||||
|
temp = index_top;
|
||||||
std::vector<int> left_edge_x;
|
while (temp != index_bottom)
|
||||||
std::vector<int> left_edge_y;
|
{
|
||||||
for (size_t i = 0, length = edge_left.size() - 1; i < length; i++)
|
edge_right.push_back(points[temp]);
|
||||||
{
|
temp = (temp + points.size() + 1) % points.size();
|
||||||
int y_top = edge_left[i].y;
|
}
|
||||||
int x_top = edge_left[i].x;
|
edge_right.push_back(points[index_bottom]);
|
||||||
int y_bottom = edge_left[i + 1].y;
|
|
||||||
int x_bottom = edge_left[i + 1].x;
|
std::vector<int> left_edge_x;
|
||||||
for (int y = y_top; y < y_bottom; y++)
|
std::vector<int> left_edge_y;
|
||||||
if (y >= 0 && y_top != y_bottom && y < image.rows)
|
for (size_t i = 0, length = edge_left.size() - 1; i < length; i++)
|
||||||
{
|
{
|
||||||
left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top));
|
int y_top = edge_left[i].y;
|
||||||
left_edge_y.push_back(y);
|
int x_top = edge_left[i].x;
|
||||||
}
|
int y_bottom = edge_left[i + 1].y;
|
||||||
}
|
int x_bottom = edge_left[i + 1].x;
|
||||||
size_t step = image.step;
|
for (int y = y_top; y < y_bottom; y++)
|
||||||
unsigned char* ptr;
|
if (y >= 0 && y_top != y_bottom && y < image.rows)
|
||||||
ptr = image.data + static_cast<uint>(left_edge_y[0]) * step;
|
{
|
||||||
for (size_t i = 0, length = left_edge_x.size(); i < length; i++)
|
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);
|
||||||
int pix = left_edge_x[i];
|
}
|
||||||
if (pix < image.cols - 1 && pix > 0)
|
}
|
||||||
memset(ptr + i * step, R_COLOR, static_cast<size_t>((pix + 1) * image.channels()));
|
size_t step = image.step;
|
||||||
}
|
unsigned char* ptr;
|
||||||
|
ptr = image.data + static_cast<uint>(left_edge_y[0]) * step;
|
||||||
std::vector<int> right_edge_x;
|
for (size_t i = 0, length = left_edge_x.size(); i < length; i++)
|
||||||
std::vector<int> right_edge_y;
|
{
|
||||||
for (size_t i = 0, length = edge_right.size() - 1; i < length; i++)
|
int pix = left_edge_x[i];
|
||||||
{
|
if (pix < image.cols - 1 && pix > 0)
|
||||||
int y_top = edge_right[i].y;
|
memset(ptr + i * step, R_COLOR, static_cast<size_t>((pix + 1) * image.channels()));
|
||||||
int x_top = edge_right[i].x;
|
}
|
||||||
int y_bottom = edge_right[i + 1].y;
|
|
||||||
int x_bottom = edge_right[i + 1].x;
|
std::vector<int> right_edge_x;
|
||||||
for (int y = y_top; y < y_bottom; y++)
|
std::vector<int> right_edge_y;
|
||||||
if (y_top != y_bottom && y < image.rows && y >= 0)
|
for (size_t i = 0, length = edge_right.size() - 1; i < length; i++)
|
||||||
{
|
{
|
||||||
right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top));
|
int y_top = edge_right[i].y;
|
||||||
right_edge_y.push_back(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++)
|
||||||
ptr = image.data + static_cast<uint>(right_edge_y[0]) * step;
|
if (y_top != y_bottom && y < image.rows && y >= 0)
|
||||||
for (size_t i = 0, length = right_edge_x.size(); i < length; i++)
|
{
|
||||||
{
|
right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top));
|
||||||
int pix = right_edge_x[i];
|
right_edge_y.push_back(y);
|
||||||
if (pix < image.cols - 1 && pix > 0)
|
}
|
||||||
memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast<size_t>(pix * image.channels()));
|
}
|
||||||
}
|
|
||||||
|
ptr = image.data + static_cast<uint>(right_edge_y[0]) * step;
|
||||||
if (edge_left[0].y > 0)
|
for (size_t i = 0, length = right_edge_x.size(); i < length; i++)
|
||||||
memset(image.data, R_COLOR, static_cast<size_t>(edge_left[0].y) * step);
|
{
|
||||||
|
int pix = right_edge_x[i];
|
||||||
if (edge_left.back().y < image.rows - 1)
|
if (pix < image.cols - 1 && pix > 0)
|
||||||
memset(image.data + static_cast<size_t>(edge_left.back().y) * step, R_COLOR,
|
memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast<size_t>(pix * image.channels()));
|
||||||
static_cast<size_t>(image.rows - edge_left.back().y) * step);
|
}
|
||||||
}
|
|
||||||
|
if (edge_left[0].y > 0)
|
||||||
void fillPolys(cv::Mat& image, const std::vector<std::vector<cv::Point>>& contours, const cv::Scalar& color)
|
memset(image.data, R_COLOR, static_cast<size_t>(edge_left[0].y) * step);
|
||||||
{
|
|
||||||
if (contours.empty()) return;
|
if (edge_left.back().y < image.rows - 1)
|
||||||
|
memset(image.data + static_cast<size_t>(edge_left.back().y) * step, R_COLOR,
|
||||||
size_t count = contours.size();
|
static_cast<size_t>(image.rows - edge_left.back().y) * step);
|
||||||
cv::Point** pointss = new cv::Point*[count];
|
}
|
||||||
int* npts = new int[count];
|
|
||||||
|
void fillPolys(cv::Mat& image, const std::vector<std::vector<cv::Point>>& contours, const cv::Scalar& color)
|
||||||
for (size_t i = 0; i < count; i++)
|
{
|
||||||
{
|
if (contours.empty()) return;
|
||||||
size_t length = contours[i].size();
|
|
||||||
npts[i] = length;
|
size_t count = contours.size();
|
||||||
pointss[i] = new cv::Point[length];
|
cv::Point** pointss = new cv::Point*[count];
|
||||||
for (size_t j = 0; j < length; j++)
|
int* npts = new int[count];
|
||||||
pointss[i][j] = contours[i][j];
|
|
||||||
}
|
for (size_t i = 0; i < count; i++)
|
||||||
cv::fillPoly(image, const_cast<const cv::Point**>(pointss), npts, count, color);
|
{
|
||||||
|
size_t length = contours[i].size();
|
||||||
for (size_t i = 0; i < count; i++)
|
npts[i] = length;
|
||||||
delete[] pointss[i];
|
pointss[i] = new cv::Point[length];
|
||||||
|
for (size_t j = 0; j < length; j++)
|
||||||
delete[] pointss;
|
pointss[i][j] = contours[i][j];
|
||||||
delete[] npts;
|
}
|
||||||
}
|
cv::fillPoly(image, const_cast<const cv::Point**>(pointss), npts, count, color);
|
||||||
|
|
||||||
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
for (size_t i = 0; i < count; i++)
|
||||||
{
|
delete[] pointss[i];
|
||||||
CvMat c_image;
|
|
||||||
CV_DbgAssert(src.dims <= 2);
|
delete[] pointss;
|
||||||
c_image = cvMat(src.rows, src.dims == 1 ? 1 : src.cols, src.type(), src.data);
|
delete[] npts;
|
||||||
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());
|
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
||||||
CvSeq* _ccontours = nullptr;
|
{
|
||||||
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint({ offset.x,offset.y }));
|
#if CV_VERSION_REVISION <= 6
|
||||||
|
CvMat c_image = src;
|
||||||
if (!_ccontours)
|
#else
|
||||||
{
|
CvMat c_image;
|
||||||
contours.clear();
|
c_image = cvMat(src.rows, src.cols, src.type(), src.data);
|
||||||
return;
|
c_image.step = src.step[0];
|
||||||
}
|
c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG);
|
||||||
cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
#endif
|
||||||
size_t total = all_contours.size();
|
cv::MemStorage storage(cvCreateMemStorage());
|
||||||
contours.resize(total);
|
CvSeq* _ccontours = nullptr;
|
||||||
|
|
||||||
cv::SeqIterator<CvSeq*> it = all_contours.begin();
|
#if CV_VERSION_REVISION <= 6
|
||||||
for (size_t i = 0; i < total; i++, ++it)
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset));
|
||||||
{
|
#else
|
||||||
CvSeq* c = *it;
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint{ offset.x, offset.y });
|
||||||
reinterpret_cast<CvContour*>(c)->color = static_cast<int>(i);
|
#endif
|
||||||
int count = c->total;
|
if (!_ccontours)
|
||||||
int* data = new int[static_cast<size_t>(count * 2)];
|
{
|
||||||
cvCvtSeqToArray(c, data);
|
contours.clear();
|
||||||
for (int j = 0; j < count; j++)
|
return;
|
||||||
{
|
}
|
||||||
contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1]));
|
cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
||||||
}
|
size_t total = all_contours.size();
|
||||||
delete[] data;
|
contours.resize(total);
|
||||||
}
|
|
||||||
|
cv::SeqIterator<CvSeq*> it = all_contours.begin();
|
||||||
hierarchy.resize(total);
|
for (size_t i = 0; i < total; i++, ++it)
|
||||||
it = all_contours.begin();
|
{
|
||||||
for (size_t i = 0; i < total; i++, ++it)
|
CvSeq* c = *it;
|
||||||
{
|
reinterpret_cast<CvContour*>(c)->color = static_cast<int>(i);
|
||||||
CvSeq* c = *it;
|
int count = c->total;
|
||||||
int h_next = c->h_next ? reinterpret_cast<CvContour*>(c->h_next)->color : -1;
|
int* data = new int[static_cast<size_t>(count * 2)];
|
||||||
int h_prev = c->h_prev ? reinterpret_cast<CvContour*>(c->h_prev)->color : -1;
|
cvCvtSeqToArray(c, data);
|
||||||
int v_next = c->v_next ? reinterpret_cast<CvContour*>(c->v_next)->color : -1;
|
for (int j = 0; j < count; j++)
|
||||||
int v_prev = c->v_prev ? reinterpret_cast<CvContour*>(c->v_prev)->color : -1;
|
{
|
||||||
hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev);
|
contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1]));
|
||||||
}
|
}
|
||||||
|
delete[] data;
|
||||||
storage.release();
|
}
|
||||||
}
|
|
||||||
|
hierarchy.resize(total);
|
||||||
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour)
|
it = all_contours.begin();
|
||||||
{
|
for (size_t i = 0; i < total; i++, ++it)
|
||||||
if (contour.empty()) return {};
|
{
|
||||||
|
CvSeq* c = *it;
|
||||||
cv::RotatedRect rect = minAreaRect(contour);
|
int h_next = c->h_next ? reinterpret_cast<CvContour*>(c->h_next)->color : -1;
|
||||||
if (rect.angle < -45)
|
int h_prev = c->h_prev ? reinterpret_cast<CvContour*>(c->h_prev)->color : -1;
|
||||||
{
|
int v_next = c->v_next ? reinterpret_cast<CvContour*>(c->v_next)->color : -1;
|
||||||
rect.angle += 90;
|
int v_prev = c->v_prev ? reinterpret_cast<CvContour*>(c->v_prev)->color : -1;
|
||||||
float temp = rect.size.width;
|
hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev);
|
||||||
rect.size.width = rect.size.height;
|
}
|
||||||
rect.size.height = temp;
|
|
||||||
}
|
storage.release();
|
||||||
|
}
|
||||||
if (rect.angle > 45)
|
|
||||||
{
|
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour)
|
||||||
rect.angle -= 90;
|
{
|
||||||
float temp = rect.size.width;
|
if (contour.empty()) return {};
|
||||||
rect.size.width = rect.size.height;
|
|
||||||
rect.size.height = temp;
|
cv::RotatedRect rect = minAreaRect(contour);
|
||||||
}
|
if (rect.angle < -45)
|
||||||
|
{
|
||||||
return rect;
|
rect.angle += 90;
|
||||||
}
|
float temp = rect.size.width;
|
||||||
|
rect.size.width = rect.size.height;
|
||||||
std::vector<cv::Point> getMaxContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy)
|
rect.size.height = temp;
|
||||||
{
|
}
|
||||||
std::vector<cv::Point> maxContour;
|
if (rect.angle > 45)
|
||||||
if (contours.size() < 1) return {};
|
{
|
||||||
|
rect.angle -= 90;
|
||||||
for (size_t i = 0, length = hierarchy.size(); i < length; i++)
|
float temp = rect.size.width;
|
||||||
if (hierarchy[i][3] == -1)
|
rect.size.width = rect.size.height;
|
||||||
for (const auto &item : contours[i])
|
rect.size.height = temp;
|
||||||
maxContour.push_back(item);
|
}
|
||||||
|
|
||||||
return maxContour;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<cv::Point> getVertices(const cv::RotatedRect& rect)
|
std::vector<cv::Point> getMaxContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy)
|
||||||
{
|
{
|
||||||
cv::Point2f box[4];
|
std::vector<cv::Point> maxContour;
|
||||||
rect.points(box);
|
if (contours.size() < 1) return {};
|
||||||
std::vector<cv::Point> points;
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0, length = hierarchy.size(); i < length; i++)
|
||||||
points.push_back(cv::Point(box[i]));
|
if (hierarchy[i][3] == -1)
|
||||||
|
for (const auto &item : contours[i])
|
||||||
return points;
|
maxContour.push_back(item);
|
||||||
}
|
|
||||||
|
return maxContour;
|
||||||
void polyIndent(std::vector<cv::Point>& points, const cv::Point& center, int indent)
|
}
|
||||||
{
|
|
||||||
static cv::Point zero(0, 0);
|
std::vector<cv::Point> getVertices(const cv::RotatedRect& rect)
|
||||||
for (cv::Point& item : points)
|
{
|
||||||
{
|
cv::Point2f box[4];
|
||||||
#if 0
|
rect.points(box);
|
||||||
cv::Point vec = item - center;
|
std::vector<cv::Point> points;
|
||||||
if (vec != zero)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
points.push_back(cv::Point(box[i]));
|
||||||
int length = vec.x * vec.x + vec.y * vec.y;
|
|
||||||
float x = cv::sqrt(static_cast<float>(vec.x * vec.x / length)) * indent;
|
return points;
|
||||||
float y = cv::sqrt(static_cast<float>(vec.y * vec.y / length)) * indent;
|
}
|
||||||
|
|
||||||
if (vec.x < 0) x *= -1.0f;
|
void polyIndent(std::vector<cv::Point>& points, const cv::Point& center, int indent)
|
||||||
if (vec.y < 0) y *= -1.0f;
|
{
|
||||||
|
static cv::Point zero(0, 0);
|
||||||
item.x -= static_cast<int>(x);
|
for (cv::Point& item : points)
|
||||||
item.y -= static_cast<int>(y);
|
{
|
||||||
}
|
#if 0
|
||||||
#else
|
cv::Point vec = item - center;
|
||||||
if (item.x > center.x)
|
if (vec != zero)
|
||||||
item.x -= indent;
|
{
|
||||||
else
|
int length = vec.x * vec.x + vec.y * vec.y;
|
||||||
item.x += indent;
|
float x = cv::sqrt(static_cast<float>(vec.x * vec.x / length)) * indent;
|
||||||
|
float y = cv::sqrt(static_cast<float>(vec.y * vec.y / length)) * indent;
|
||||||
if (item.y > center.y)
|
|
||||||
item.y -= indent;
|
if (vec.x < 0) x *= -1.0f;
|
||||||
else
|
if (vec.y < 0) y *= -1.0f;
|
||||||
item.y += indent;
|
|
||||||
#endif
|
item.x -= static_cast<int>(x);
|
||||||
}
|
item.y -= static_cast<int>(y);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
cv::Mat transforColor(const cv::Mat& src)
|
if (item.x > center.x)
|
||||||
{
|
item.x -= indent;
|
||||||
if (src.channels() == 1) return src.clone();
|
else
|
||||||
|
item.x += indent;
|
||||||
std::vector<cv::Mat> channels(3);
|
|
||||||
cv::split(src, channels);
|
if (item.y > center.y)
|
||||||
|
item.y -= indent;
|
||||||
cv::Mat temp, dst;
|
else
|
||||||
bitwise_or(channels[0], channels[1], temp);
|
item.y += indent;
|
||||||
bitwise_or(channels[2], temp, dst);
|
#endif
|
||||||
temp.release();
|
}
|
||||||
|
}
|
||||||
for (cv::Mat& index : channels)
|
|
||||||
index.release();
|
cv::Mat transforColor(const cv::Mat& src)
|
||||||
return dst;
|
{
|
||||||
}
|
if (src.channels() == 1) return src.clone();
|
||||||
|
|
||||||
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre)
|
std::vector<cv::Mat> channels(3);
|
||||||
{
|
cv::split(src, channels);
|
||||||
if (src.channels() == 3)
|
|
||||||
{
|
cv::Mat temp, dst;
|
||||||
#ifdef USE_ONENCL
|
bitwise_or(channels[0], channels[1], temp);
|
||||||
if (cl_res.context)
|
bitwise_or(channels[2], temp, dst);
|
||||||
transforColor_threshold_opencl(src, dst, static_cast<uchar>(thre));
|
temp.release();
|
||||||
else
|
|
||||||
#endif
|
for (cv::Mat& index : channels)
|
||||||
{
|
index.release();
|
||||||
cv::Mat gray = transforColor(src);
|
return dst;
|
||||||
cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY);
|
}
|
||||||
gray.release();
|
|
||||||
}
|
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre)
|
||||||
}
|
{
|
||||||
else
|
if (src.channels() == 3)
|
||||||
cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY);
|
{
|
||||||
}
|
#ifdef USE_ONENCL
|
||||||
|
if (cl_res.context)
|
||||||
cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat)
|
transforColor_threshold_opencl(src, dst, static_cast<uchar>(thre));
|
||||||
{
|
else
|
||||||
double src_data[3] = { static_cast<double>(p.x), static_cast<double>(p.y), 1 };
|
#endif
|
||||||
cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1
|
{
|
||||||
|
cv::Mat gray = transforColor(src);
|
||||||
cv::Mat dst = warp_mat * src;
|
cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY);
|
||||||
double* ptr = reinterpret_cast<double*>(dst.data);
|
gray.release();
|
||||||
return cv::Point(static_cast<int>(ptr[0]), static_cast<int>(ptr[1]));
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
int distanceP2P(const cv::Point& p1, const cv::Point& p2)
|
cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY);
|
||||||
{
|
}
|
||||||
return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2));
|
|
||||||
}
|
cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat)
|
||||||
|
{
|
||||||
float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2)
|
double src_data[3] = { static_cast<double>(p.x), static_cast<double>(p.y), 1 };
|
||||||
{
|
cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1
|
||||||
//求直线方程
|
|
||||||
int A = 0, B = 0, C = 0;
|
cv::Mat dst = warp_mat * src;
|
||||||
A = l1.y - l2.y;
|
double* ptr = reinterpret_cast<double*>(dst.data);
|
||||||
B = l2.x - l1.x;
|
return cv::Point(static_cast<int>(ptr[0]), static_cast<int>(ptr[1]));
|
||||||
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));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,123 +1,130 @@
|
||||||
/*
|
/*
|
||||||
* ====================================================
|
* ====================================================
|
||||||
|
|
||||||
* 功能:公共图像处理算法。部分功能可能会在ImageProcess里面多个类反复使用
|
* 功能:公共图像处理算法。部分功能可能会在ImageProcess里面多个类反复使用
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/4/21
|
* 生成时间:2020/4/21
|
||||||
* 最近修改时间:2020/4/21
|
* 最近修改时间:2020/4/21
|
||||||
* 版本号:v1.0
|
* 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
|
|
||||||
|
#ifndef IMAGE_PROCESS_PUBLIC_H
|
||||||
#include <opencv2/opencv.hpp>
|
#define IMAGE_PROCESS_PUBLIC_H
|
||||||
#include <vector>
|
|
||||||
|
#include "opencv2/opencv.hpp"
|
||||||
namespace hg
|
#include <vector>
|
||||||
{
|
|
||||||
/*
|
namespace hg
|
||||||
* 功能:计算源点集的凸多边形轮廓,输出轮廓点集
|
{
|
||||||
* src: 源点集
|
/*
|
||||||
* dst: 目标点集
|
* 功能:计算源点集的凸多边形轮廓,输出轮廓点集
|
||||||
* clockwise: true为顺时针排序,false为逆时针排序
|
* src: 源点集
|
||||||
*/
|
* dst: 目标点集
|
||||||
void convexHull(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, bool clockwise = false);
|
* clockwise: true为顺时针排序,false为逆时针排序
|
||||||
|
*/
|
||||||
/*
|
void convexHull(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, bool clockwise = false);
|
||||||
* 功能:填充凸多边形,默认颜色为白色
|
|
||||||
* image: 填充图像
|
/*
|
||||||
* points: 凸多边形轮廓点集(逆时针排序)
|
* 功能:填充凸多边形,默认颜色为白色
|
||||||
*/
|
* image: 填充图像
|
||||||
void fillConvexHull(cv::Mat& image, const std::vector<cv::Point>& points);
|
* points: 凸多边形轮廓点集(逆时针排序)
|
||||||
|
*/
|
||||||
/*
|
void fillConvexHull(cv::Mat& image, const std::vector<cv::Point>& points);
|
||||||
* 功能:填充凹多边形
|
|
||||||
* image: 填充图像
|
/*
|
||||||
* contours: 凹多边形轮廓点集(逆时针排序)
|
* 功能:填充凹多边形
|
||||||
* color: 填充颜色
|
* image: 填充图像
|
||||||
*/
|
* contours: 凹多边形轮廓点集(逆时针排序)
|
||||||
void fillPolys(cv::Mat& image, const std::vector<std::vector<cv::Point>>& contours, const cv::Scalar& color);
|
* color: 填充颜色
|
||||||
|
*/
|
||||||
/*
|
void fillPolys(cv::Mat& image, const std::vector<std::vector<cv::Point>>& contours, const cv::Scalar& color);
|
||||||
* 功能:获取连通区域轮廓
|
|
||||||
* src: 源图像
|
/*
|
||||||
* contours: 结果轮廓集
|
* 功能:获取连通区域轮廓
|
||||||
* hierarchy: 轮廓集的排序关系。与contours的数量对应,受retr选项不同,排序会有变化
|
* src: 源图像
|
||||||
* retr: 轮廓集排序方式,默认为链式排序
|
* contours: 结果轮廓集
|
||||||
* method: 查找算法选择,默认为普通查找
|
* hierarchy: 轮廓集的排序关系。与contours的数量对应,受retr选项不同,排序会有变化
|
||||||
* offset: 查找起始点,默认为(0,0)点
|
* retr: 轮廓集排序方式,默认为链式排序
|
||||||
*/
|
* method: 查找算法选择,默认为普通查找
|
||||||
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy,
|
* offset: 查找起始点,默认为(0,0)点
|
||||||
int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0));
|
*/
|
||||||
|
void findContours(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy,
|
||||||
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour);
|
int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓
|
* 功能:获取覆盖点集的最小外接矩形
|
||||||
* contours: 轮廓集(每个轮廓由点集组成)
|
* contour: 点集
|
||||||
* hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应
|
* 返回值: 旋转矩形
|
||||||
* 返回值: 凸多边形轮廓点集
|
*/
|
||||||
*/
|
cv::RotatedRect getBoundingRect(const std::vector<cv::Point>& contour);
|
||||||
std::vector<cv::Point> getMaxContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓
|
||||||
* 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓
|
* contours: 轮廓集(每个轮廓由点集组成)
|
||||||
* contours: 轮廓集(每个轮廓由点集组成)
|
* hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应
|
||||||
* hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应
|
* 返回值: 凸多边形轮廓点集
|
||||||
* 返回值: 凸多边形轮廓点集
|
*/
|
||||||
*/
|
std::vector<cv::Point> getMaxContour(const std::vector<std::vector<cv::Point>>& contours, const std::vector<cv::Vec4i>& hierarchy);
|
||||||
std::vector<cv::Point> getVertices(const cv::RotatedRect& rect);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓
|
||||||
* 功能: 轮廓缩进
|
* contours: 轮廓集(每个轮廓由点集组成)
|
||||||
* points: 轮廓点集
|
* hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应
|
||||||
* center: 围绕center点缩进
|
* 返回值: 凸多边形轮廓点集
|
||||||
* indent: 缩进像素
|
*/
|
||||||
*/
|
std::vector<cv::Point> getVertices(const cv::RotatedRect& rect);
|
||||||
void polyIndent(std::vector<cv::Point>& points, const cv::Point& center, int indent);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 轮廓缩进
|
||||||
* 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值
|
* points: 轮廓点集
|
||||||
* src: 源图
|
* center: 围绕center点缩进
|
||||||
* dst: 目标图
|
* indent: 缩进像素
|
||||||
* thre: 阈值
|
*/
|
||||||
*/
|
void polyIndent(std::vector<cv::Point>& points, const cv::Point& center, int indent);
|
||||||
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值
|
||||||
* 功能: 彩色转灰度,灰度图取三个通道的最大值
|
* src: 源图
|
||||||
* src: 源图
|
* dst: 目标图
|
||||||
* 返回值: 灰度图
|
* thre: 阈值
|
||||||
*/
|
*/
|
||||||
cv::Mat transforColor(const cv::Mat& src);
|
void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 功能: 获取点的仿射变换
|
* 功能: 彩色转灰度,灰度图取三个通道的最大值
|
||||||
* p: 原点
|
* src: 源图
|
||||||
* warp_mat: 仿射变换系数矩阵
|
* 返回值: 灰度图
|
||||||
* 返回值: 变换后的点
|
*/
|
||||||
*/
|
cv::Mat transforColor(const cv::Mat& src);
|
||||||
cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 获取点的仿射变换
|
||||||
* 功能: 点到点距离
|
* p: 原点
|
||||||
* p1: 点1
|
* warp_mat: 仿射变换系数矩阵
|
||||||
* p2: 点2
|
* 返回值: 变换后的点
|
||||||
* 返回值: 点到点距离
|
*/
|
||||||
*/
|
cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat);
|
||||||
int distanceP2P(const cv::Point& p1, const cv::Point& p2);
|
|
||||||
|
/*
|
||||||
/*
|
* 功能: 点到点距离
|
||||||
* 功能: 点到直线距离
|
* p1: 点1
|
||||||
* p: 点
|
* p2: 点2
|
||||||
* l1: 直线端点1
|
* 返回值: 点到点距离
|
||||||
* l2: 直线端点2
|
*/
|
||||||
* 返回值: 点到直线距离
|
int distanceP2P(const cv::Point& p1, const cv::Point& p2);
|
||||||
*/
|
|
||||||
float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2);
|
/*
|
||||||
}
|
* 功能: 点到直线距离
|
||||||
|
* p: 点
|
||||||
#endif // !IMAGE_PROCESS_C_H
|
* l1: 直线端点1
|
||||||
|
* l2: 直线端点2
|
||||||
|
* 返回值: 点到直线距离
|
||||||
|
*/
|
||||||
|
float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !IMAGE_PROCESS_C_H
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <opencv2/opencv.hpp>
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
class MatEx {
|
class MatEx {
|
||||||
public:
|
public:
|
||||||
MatEx() :
|
MatEx() :
|
||||||
mat(cv::Mat())
|
mat(cv::Mat())
|
||||||
, Bpp(-1) {
|
, Bpp(-1) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MatEx(cv::Mat &mat, int bpp) :
|
MatEx(cv::Mat mat, int bpp) :
|
||||||
mat(cv::Mat())
|
mat(cv::Mat())
|
||||||
, Bpp(bpp)
|
, Bpp(bpp)
|
||||||
{
|
{
|
||||||
this->mat = mat;
|
this->mat = mat.clone();
|
||||||
this->Bpp = bpp;
|
this->Bpp = bpp;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
int Bpp;
|
int Bpp;
|
||||||
cv::Mat mat;
|
cv::Mat mat;
|
||||||
};
|
};
|
|
@ -1,22 +1,21 @@
|
||||||
#ifndef IMAGE_PROCESS_DEFINES_H
|
#ifndef IMAGE_PROCESS_DEFINES_H
|
||||||
#define IMAGE_PROCESS_DEFINES_H
|
#define IMAGE_PROCESS_DEFINES_H
|
||||||
|
|
||||||
//#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
//# define HT_DECL_EXPORT __declspec(dllexport)
|
# define HT_DECL_EXPORT __declspec(dllexport)
|
||||||
//# define HT_DECL_IMPORT __declspec(dllimport)
|
# define HT_DECL_IMPORT __declspec(dllimport)
|
||||||
//#elif defined(__linux__) || defined(__linux)
|
#elif defined(__linux__) || defined(__linux)
|
||||||
//# define HT_DECL_EXPORT __attribute__((visibility("default")))
|
# define HT_DECL_EXPORT __attribute__((visibility("default")))
|
||||||
//# define HT_DECL_IMPORT __attribute__((visibility("default")))
|
# define HT_DECL_IMPORT __attribute__((visibility("default")))
|
||||||
//# define HT_DECL_HIDDEN __attribute__((visibility("hidden")))
|
# define HT_DECL_HIDDEN __attribute__((visibility("hidden")))
|
||||||
//#endif
|
#endif
|
||||||
//
|
|
||||||
//#if defined(GIMGPROC_LIBRARY_BUILD)
|
#if defined(GIMGPROC_LIBRARY_BUILD)
|
||||||
//#define HT_DECL_EXPORT
|
#define GIMGPROC_LIBRARY_API HT_DECL_EXPORT
|
||||||
//#elif defined(_DIRECT_BUILD)
|
#elif defined(_DIRECT_BUILD)
|
||||||
//#define
|
#define GIMGPROC_LIBRARY_API
|
||||||
//#else
|
#else
|
||||||
////#define HT_DECL_IMPORT
|
#define GIMGPROC_LIBRARY_API HT_DECL_IMPORT
|
||||||
//#endif
|
#endif
|
||||||
#define IMAGE_PROCESS_DEFINES_H
|
|
||||||
|
#endif // !IMAGE_PROCESS_DEFINES_H
|
||||||
#endif // !IMAGE_PROCESS_DEFINES_H
|
|
||||||
|
|
|
@ -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 <class X> X convertToUnsignedPrimitive() const;
|
||||||
|
template <class X, class UX> 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
|
|
@ -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
|
|
@ -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"
|
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef BIGINTEGERUTILS_H
|
||||||
|
#define BIGINTEGERUTILS_H
|
||||||
|
|
||||||
|
#include "BigInteger.hh"
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/* 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 <class T>
|
||||||
|
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 <class T>
|
||||||
|
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
|
|
@ -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<unsigned long> {
|
||||||
|
|
||||||
|
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<Blk>::Index Index;
|
||||||
|
using NumberlikeArray<Blk>::N;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Creates a BigUnsigned with a capacity; for internal use.
|
||||||
|
BigUnsigned(int, Index c) : NumberlikeArray<Blk>(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<Blk>() {}
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
BigUnsigned(const BigUnsigned &x) : NumberlikeArray<Blk>(x) {}
|
||||||
|
|
||||||
|
// Assignment operator
|
||||||
|
void operator=(const BigUnsigned &x) {
|
||||||
|
NumberlikeArray<Blk>::operator =(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor that copies from a given array of blocks.
|
||||||
|
BigUnsigned(const Blk *b, Index blen) : NumberlikeArray<Blk>(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 <class X> void initFromPrimitive (X x);
|
||||||
|
template <class X> 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 <class X> X convertToSignedPrimitive() const;
|
||||||
|
template <class X> X convertToPrimitive () const;
|
||||||
|
public:
|
||||||
|
|
||||||
|
// BIT/BLOCK ACCESSORS
|
||||||
|
|
||||||
|
// Expose these from NumberlikeArray directly.
|
||||||
|
using NumberlikeArray<Blk>::getCapacity;
|
||||||
|
using NumberlikeArray<Blk>::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<Blk>::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<Blk>::operator ==(x);
|
||||||
|
}
|
||||||
|
bool operator !=(const BigUnsigned &x) const {
|
||||||
|
return NumberlikeArray<Blk>::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 <class X>
|
||||||
|
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 <class X>
|
||||||
|
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 <class X>
|
||||||
|
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 <class X>
|
||||||
|
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<Primitive>: "
|
||||||
|
"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 <class X>
|
||||||
|
X BigUnsigned::convertToSignedPrimitive() const {
|
||||||
|
X x = convertToPrimitive<X>();
|
||||||
|
if (x >= 0)
|
||||||
|
return x;
|
||||||
|
else
|
||||||
|
throw "BigUnsigned::to(Primitive): "
|
||||||
|
"Value is too big to fit in the requested type";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,122 @@
|
||||||
|
#ifndef BIGUNSIGNEDINABASE_H
|
||||||
|
#define BIGUNSIGNEDINABASE_H
|
||||||
|
|
||||||
|
#include "NumberlikeArray.hh"
|
||||||
|
#include "BigUnsigned.hh"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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<unsigned short> {
|
||||||
|
|
||||||
|
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<Digit>(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<Digit>(), base(2) {}
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
BigUnsignedInABase(const BigUnsignedInABase &x) : NumberlikeArray<Digit>(x), base(x.base) {}
|
||||||
|
|
||||||
|
// Assignment operator
|
||||||
|
void operator =(const BigUnsignedInABase &x) {
|
||||||
|
NumberlikeArray<Digit>::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<Digit>::getCapacity;
|
||||||
|
using NumberlikeArray<Digit>::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<Digit>::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<Digit>::operator ==(x);
|
||||||
|
}
|
||||||
|
bool operator !=(const BigUnsignedInABase &x) const { return !operator ==(x); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,177 @@
|
||||||
|
#ifndef NUMBERLIKEARRAY_H
|
||||||
|
#define NUMBERLIKEARRAY_H
|
||||||
|
|
||||||
|
// Make sure we have NULL.
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A NumberlikeArray<Blk> 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 Blk>
|
||||||
|
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<Blk> &x);
|
||||||
|
|
||||||
|
// Assignment operator
|
||||||
|
void operator=(const NumberlikeArray<Blk> &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<Blk> &x) const;
|
||||||
|
|
||||||
|
bool operator !=(const NumberlikeArray<Blk> &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 <class Blk>
|
||||||
|
const unsigned int NumberlikeArray<Blk>::N = 8 * sizeof(Blk);
|
||||||
|
|
||||||
|
template <class Blk>
|
||||||
|
void NumberlikeArray<Blk>::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 <class Blk>
|
||||||
|
void NumberlikeArray<Blk>::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 <class Blk>
|
||||||
|
NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &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 <class Blk>
|
||||||
|
void NumberlikeArray<Blk>::operator=(const NumberlikeArray<Blk> &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 <class Blk>
|
||||||
|
NumberlikeArray<Blk>::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 <class Blk>
|
||||||
|
bool NumberlikeArray<Blk>::operator ==(const NumberlikeArray<Blk> &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
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef _LIBICONV_H
|
||||||
|
#define _LIBICONV_H
|
||||||
|
#include <stddef.h>
|
||||||
|
#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
|
|
@ -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 <limits.h>
|
||||||
|
|
||||||
|
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||||
|
// compiling for ARM we should wrap <wchar.h> 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 <wchar.h>
|
||||||
|
#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 <wchar.h>
|
||||||
|
#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_ ]
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,202 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <string>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,187 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <exception>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,329 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <assert.h>
|
||||||
|
#include <iterator>
|
||||||
|
#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
|
|
@ -0,0 +1,130 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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
|
|
@ -0,0 +1,223 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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
|
|
@ -0,0 +1,169 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <qwidget.h>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,72 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <qimage.h>
|
||||||
|
#include <zbar.h>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,162 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <stdio.h>
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,541 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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 <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
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<std::input_iterator_tag, Point> {
|
||||||
|
|
||||||
|
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<std::input_iterator_tag, Symbol> {
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,170 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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
|
|
@ -0,0 +1,136 @@
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
//
|
||||||
|
// 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
|
|
@ -0,0 +1,215 @@
|
||||||
|
/*------------------------------------------------------------------------
|
||||||
|
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
||||||
|
*
|
||||||
|
* 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 <glib.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <gtk/gtktable.h>
|
||||||
|
|
||||||
|
#include <zbar.h>
|
||||||
|
|
||||||
|
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
|
|
@ -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__
|
|
@ -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 <zxing/LuminanceSource.h>
|
||||||
|
#include <zxing/common/BitArray.h>
|
||||||
|
#include <zxing/common/BitMatrix.h>
|
||||||
|
#include <zxing/common/Counted.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
class Binarizer : public Counted {
|
||||||
|
private:
|
||||||
|
Ref<LuminanceSource> source_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Binarizer(Ref<LuminanceSource> source);
|
||||||
|
virtual ~Binarizer();
|
||||||
|
|
||||||
|
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row) = 0;
|
||||||
|
virtual Ref<BitMatrix> getBlackMatrix() = 0;
|
||||||
|
|
||||||
|
Ref<LuminanceSource> getLuminanceSource() const;
|
||||||
|
virtual Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) = 0;
|
||||||
|
|
||||||
|
int getWidth() const;
|
||||||
|
int getHeight() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* BINARIZER_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 <zxing/common/Counted.h>
|
||||||
|
#include <zxing/common/BitMatrix.h>
|
||||||
|
#include <zxing/common/BitArray.h>
|
||||||
|
#include <zxing/Binarizer.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
class BinaryBitmap : public Counted {
|
||||||
|
private:
|
||||||
|
Ref<Binarizer> binarizer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BinaryBitmap(Ref<Binarizer> binarizer);
|
||||||
|
virtual ~BinaryBitmap();
|
||||||
|
|
||||||
|
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);
|
||||||
|
Ref<BitMatrix> getBlackMatrix();
|
||||||
|
|
||||||
|
Ref<LuminanceSource> getLuminanceSource() const;
|
||||||
|
|
||||||
|
int getWidth() const;
|
||||||
|
int getHeight() const;
|
||||||
|
|
||||||
|
bool isRotateSupported() const;
|
||||||
|
Ref<BinaryBitmap> rotateCounterClockwise();
|
||||||
|
|
||||||
|
bool isCropSupported() const;
|
||||||
|
Ref<BinaryBitmap> crop(int left, int top, int width, int height);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BINARYBITMAP_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 <zxing/ReaderException.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
class ChecksumException : public ReaderException {
|
||||||
|
typedef ReaderException Base;
|
||||||
|
public:
|
||||||
|
ChecksumException() throw();
|
||||||
|
ChecksumException(const char* msg) throw();
|
||||||
|
~ChecksumException() throw();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __CHECKSUM_EXCEPTION_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 <zxing/BarcodeFormat.h>
|
||||||
|
#include <zxing/ResultPointCallback.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
typedef unsigned int DecodeHintType;
|
||||||
|
class DecodeHints;
|
||||||
|
DecodeHints operator | (DecodeHints const&, DecodeHints const&);
|
||||||
|
|
||||||
|
class DecodeHints {
|
||||||
|
private:
|
||||||
|
DecodeHintType hints;
|
||||||
|
Ref<ResultPointCallback> 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<ResultPointCallback> const&);
|
||||||
|
Ref<ResultPointCallback> getResultPointCallback() const;
|
||||||
|
|
||||||
|
friend DecodeHints operator | (DecodeHints const&, DecodeHints const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -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 <string>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
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__
|
|
@ -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 <zxing/ReaderException.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
class FormatException : public ReaderException {
|
||||||
|
public:
|
||||||
|
FormatException();
|
||||||
|
FormatException(const char* msg);
|
||||||
|
~FormatException() throw();
|
||||||
|
|
||||||
|
static FormatException const& getFormatInstance();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // __FORMAT_EXCEPTION_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 <zxing/ReaderException.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
class IllegalStateException : public ReaderException {
|
||||||
|
public:
|
||||||
|
IllegalStateException() throw() {}
|
||||||
|
IllegalStateException(const char* msg) throw() : ReaderException(msg) {}
|
||||||
|
~IllegalStateException() throw() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __ILLEGAL_STATE_EXCEPTION_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 <zxing/ZXing.h>
|
||||||
|
#include <zxing/LuminanceSource.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
|
||||||
|
class InvertedLuminanceSource : public LuminanceSource {
|
||||||
|
private:
|
||||||
|
typedef LuminanceSource Super;
|
||||||
|
const Ref<LuminanceSource> delegate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InvertedLuminanceSource(Ref<LuminanceSource> const&);
|
||||||
|
|
||||||
|
ArrayRef<char> getRow(int y, ArrayRef<char> row) const;
|
||||||
|
ArrayRef<char> getMatrix() const;
|
||||||
|
|
||||||
|
boolean isCropSupported() const;
|
||||||
|
Ref<LuminanceSource> crop(int left, int top, int width, int height) const;
|
||||||
|
|
||||||
|
boolean isRotateSupported() const;
|
||||||
|
|
||||||
|
virtual Ref<LuminanceSource> invert() const;
|
||||||
|
|
||||||
|
Ref<LuminanceSource> rotateCounterClockwise() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* INVERTEDLUMINANCESOURCE_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 <zxing/common/Counted.h>
|
||||||
|
#include <zxing/common/Array.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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<char> getRow(int y, ArrayRef<char> row) const = 0;
|
||||||
|
virtual ArrayRef<char> getMatrix() const = 0;
|
||||||
|
|
||||||
|
virtual bool isCropSupported() const;
|
||||||
|
virtual Ref<LuminanceSource> crop(int left, int top, int width, int height) const;
|
||||||
|
|
||||||
|
virtual bool isRotateSupported() const;
|
||||||
|
|
||||||
|
virtual Ref<LuminanceSource> invert() const;
|
||||||
|
|
||||||
|
virtual Ref<LuminanceSource> rotateCounterClockwise() const;
|
||||||
|
|
||||||
|
operator std::string() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LUMINANCESOURCE_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 <zxing/Reader.h>
|
||||||
|
#include <zxing/common/BitArray.h>
|
||||||
|
#include <zxing/Result.h>
|
||||||
|
#include <zxing/DecodeHints.h>
|
||||||
|
|
||||||
|
namespace zxing {
|
||||||
|
class MultiFormatReader : public Reader {
|
||||||
|
private:
|
||||||
|
Ref<Result> decodeInternal(Ref<BinaryBitmap> image);
|
||||||
|
|
||||||
|
std::vector<Ref<Reader> > readers_;
|
||||||
|
DecodeHints hints_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MultiFormatReader();
|
||||||
|
|
||||||
|
Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||||
|
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||||
|
Ref<Result> decodeWithState(Ref<BinaryBitmap> image);
|
||||||
|
void setHints(DecodeHints hints);
|
||||||
|
~MultiFormatReader();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue