1.增加snowflake 随机生成文件名,避免出现重名情况缓存覆盖导致的丢图;

2.代码中增加UV模式,涉及UI 协议 配置类 UV图像合并算法;
3.重构ImageMatQueue 实现,去除冗余接口、类设计、简化代码;
4.为适应UV模式图像处理算法,增加自动裁切以及旋转接口;
5.增加UV json配置记忆功能;
6.去除IScanner接口中没用接口;
This commit is contained in:
lovelyyoung 2021-06-30 21:58:13 +08:00
parent 61f4917aee
commit 9c02a0c0f0
31 changed files with 904 additions and 441 deletions

1
.gitignore vendored
View File

@ -3,7 +3,6 @@
################################################################################
/huagao/.vs/huagaotwds/v15
/3rdparty/nick
/huagao/debug/qmake
/huagao/debug
/huagao/Win32/Debug

106
3rdparty/nick/snowflake.h vendored Normal file
View File

@ -0,0 +1,106 @@
#pragma once
#include <cstdint>
#include <chrono>
#include <stdexcept>
#include <mutex>
class snowflake_nonlock
{
public:
void lock()
{
}
void unlock()
{
}
};
template<int64_t Twepoch, typename Lock = snowflake_nonlock>
class snowflake
{
using lock_type = Lock;
static constexpr int64_t TWEPOCH = Twepoch;
static constexpr int64_t WORKER_ID_BITS = 5L;
static constexpr int64_t DATACENTER_ID_BITS = 5L;
static constexpr int64_t MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;
static constexpr int64_t MAX_DATACENTER_ID = (1 << DATACENTER_ID_BITS) - 1;
static constexpr int64_t SEQUENCE_BITS = 12L;
static constexpr int64_t WORKER_ID_SHIFT = SEQUENCE_BITS;
static constexpr int64_t DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
static constexpr int64_t TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
static constexpr int64_t SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1;
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
time_point start_time_point_ = std::chrono::steady_clock::now();
int64_t start_millsecond_ = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
int64_t last_timestamp_ = -1;
int64_t workerid_ = 0;
int64_t datacenterid_ = 0;
int64_t sequence_ = 0;
lock_type lock_;
public:
snowflake() = default;
snowflake(const snowflake&) = delete;
snowflake& operator=(const snowflake&) = delete;
void init(int64_t workerid, int64_t datacenterid)
{
if (workerid > MAX_WORKER_ID || workerid < 0) {
throw std::runtime_error("worker Id can't be greater than 31 or less than 0");
}
if (datacenterid > MAX_DATACENTER_ID || datacenterid < 0) {
throw std::runtime_error("datacenter Id can't be greater than 31 or less than 0");
}
workerid_ = workerid;
datacenterid_ = datacenterid;
}
int64_t nextid()
{
std::lock_guard<lock_type> lock(lock_);
//std::chrono::steady_clock cannot decrease as physical time moves forward
auto timestamp = millsecond();
if (last_timestamp_ == timestamp)
{
sequence_ = (sequence_ + 1)&SEQUENCE_MASK;
if (sequence_ == 0)
{
timestamp = wait_next_millis(last_timestamp_);
}
}
else
{
sequence_ = 0;
}
last_timestamp_ = timestamp;
return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT)
| (datacenterid_ << DATACENTER_ID_SHIFT)
| (workerid_ << WORKER_ID_SHIFT)
| sequence_;
}
private:
int64_t millsecond() const noexcept
{
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time_point_);
return start_millsecond_ + diff.count();
}
int64_t wait_next_millis(int64_t last) const noexcept
{
auto timestamp = millsecond();
while (timestamp <= last)
{
timestamp = millsecond();
}
return timestamp;
}
};

View File

@ -138,6 +138,7 @@ void CBasicPage::DoDataExchange(CDataExchange* pDX)
DDX_Check(pDX, IDC_CKBSIZEDETECT, m_enableSizeCheck);
DDX_Control(pDX, IDC_SLIDERDPI, m_Slider_Dpi);
DDX_Control(pDX, IDC_EDITDPI, m_Edit_Dpi);
DDX_Check(pDX, IDC_CKBENABLEUV, m_bUV);
}
BOOL CBasicPage::OnInitDialog()
@ -166,6 +167,9 @@ BOOL CBasicPage::OnInitDialog()
m_cmBoxColorMode->SetCurSel(0);
m_cmBoxDuplex->SetCurSel(0);
#ifndef UV
GetDlgItem(IDC_CKBENABLEUV)->ShowWindow(FALSE);
#endif
return true;
}

View File

@ -46,6 +46,7 @@ protected:
std::function<void()> m_dataChange;
public:
BOOL m_bUV;
afx_msg void OnClickedBtndiscardsetting();
void SetScannerInfo(std::string hdVersion, std::string serialNum);
private:

View File

@ -160,6 +160,9 @@ void CTwainUI::UpdateUI()
m_pageBasic->m_cmBoxSS->SetCurSel(getPaparSizeIndex(settings->papertype, settings->paperAlign)); //!< 纸张类型
m_pageBasic->m_enableSizeCheck = settings->en_sizecheck==1?TRUE:FALSE;//!< 尺寸检测
m_pageBasic->m_bswitchfrontback = settings->is_switchfrontback ? TRUE : FALSE; //!< 交换正反面
#ifdef UV
m_pageBasic->m_bUV = settings->hardwarecaps.en_uv == 1 ? TRUE : FALSE;
#endif
m_pageBasic->UpdateData(FALSE);
if(getCmbDuplexIndex()==2|| getCmbDuplexIndex()==3)
m_pageBasic->GetDlgItem(IDC_BTNDISCARDSETTING)->EnableWindow(true);
@ -403,6 +406,9 @@ void CTwainUI::UpDateScanParam(PCONFIGPARAMS configItem, bool updateDs)
configItem->EnDiscardBlank = configItem->Duplex == 2;//自动跳骨空白页通用
configItem->EnDiscardBlankVince = configItem->Duplex == 3;//自动跳骨空白页发票
configItem->EnFlod = configItem->Duplex == 4;
#ifdef UV
configItem->EnUVModel = m_pageBasic->m_bUV;
#endif
//configItem->DBlank_AreaNum = m_pageBasic->AreaNum;//!< 分区数
//configItem->DBlank_DevnMax = m_pageBasic->DevnMax;//!< 跳过阈值
@ -470,6 +476,9 @@ void CTwainUI::UpDateScanParam(PCONFIGPARAMS configItem, bool updateDs)
//settings->areanum = configItem->DBlank_AreaNum;
//settings->devnmax = configItem->DBlank_DevnMax;
settings->discardblank_percent = m_pageBasic->discardblank_percent;
#ifdef UV
settings->hardwarecaps.en_uv = configItem->EnUVModel;
#endif
//填充黑框
settings->fillbackground = configItem->EnFillBlack;
settings->autodescrew = configItem->EnAutoDescrew;

View File

@ -10,7 +10,11 @@ G400ScanConfig::G400ScanConfig(GScanCap& gcap)
cfg.params.isColor = 1;
else
cfg.params.isColor = SupPixelTypes[gcap.pixtype];
cfg.params.enableStable = 0;//gcap.hardwarecaps.en_stapledetect==0?0:1;
#ifdef UV
cfg.params.enableUV = gcap.hardwarecaps.en_uv;//gcap.hardwarecaps.en_stapledetect==0?0:1;
#else
cfg.params.enableUV = 0;
#endif
cfg.params.isCorrect = 1;//1 机器校正
PaperStatus ps = { gcap.papertype,gcap.paperAlign };
cfg.params.pageSize = SupPaperTyps[ps];

View File

@ -15,7 +15,7 @@ public:
unsigned int isColor : 1;
unsigned int dpi : 2;
unsigned int doubleFeeded : 1;
unsigned int enableStable : 1;
unsigned int enableUV : 1;
unsigned int enableLed : 1;
unsigned int sizedetect : 1;
unsigned int reversed1 : 5;

View File

@ -126,7 +126,10 @@ public:
IScanner() {
bFilterMsg = false; aquire_image_count = updata_image_count = updata_image_count = roller_num = lose_image_num = 0; is_AndroidOrLinux = false;
}
virtual ~IScanner() { bFilterMsg = true; }
virtual ~IScanner()
{
bFilterMsg = true;
}
void ResetMsgFiter() { bFilterMsg = true; }
int get_aquire_image_count() { return aquire_image_count; };
int get_updata_image_count() { return updata_image_count; };
@ -154,7 +157,6 @@ public:
virtual bool Get_IsImageQueueEmpty() = 0;
virtual void reset() = 0;
virtual void clear_hwerror() = 0;
virtual void setdecodepixtype(int twpixtype) = 0;
virtual UINT32 get_ErrorCode() = 0;
virtual void Set_ErrorCode(UINT32 value) = 0;
virtual int get_scanned_num() = 0;

View File

@ -111,10 +111,6 @@ void GScan200::clear_hwerror()
{
}
void GScan200::setdecodepixtype(int twpixtype)
{
pixType = (twpixtype == 0) ? 1 : 0;
}
UINT32 GScan200::get_ErrorCode()
{

View File

@ -25,7 +25,6 @@ public:
virtual bool Get_IsImageQueueEmpty() override;
virtual void reset() override;
virtual void clear_hwerror() override;
virtual void setdecodepixtype(int twpixtype) override;
virtual UINT32 get_ErrorCode() override;
virtual void Set_ErrorCode(UINT32 value) override;
virtual int get_scanned_num() override;

View File

@ -149,7 +149,11 @@ GScanO200::GScanO200() :
is_orginimgcount(true)
{
m_pImages.reset(new ImageMatQueue());
m_pImages->Getimagenumber = std::bind(&GScanO200::Getimagenumber,this, std::placeholders::_1);
auto getimgnum = [&](bool isadd)
{
isadd ? image_num++ : image_num--;
};
m_pImages->SetGetimgnumcall(getimgnum);
}
GScanO200::~GScanO200()
@ -159,27 +163,16 @@ GScanO200::~GScanO200()
m_threadUsb->join();
m_threadUsb.reset();
}
if (m_usb.get())
m_usb.reset();
}
void GScanO200::Getimagenumber(bool isadd)
{
if (isadd)
{
image_num++;
}
else
{
image_num--;
}
m_pImages.reset();
}
void GScanO200::DogEar_callback(std::function<void(int)> fun)
{
m_pImages->DogEarDetection_callback = fun;
m_pImages->SetDogEarCallback(fun);
}
void GScanO200::open(int vid, int pid)
@ -483,13 +476,7 @@ void GScanO200::ResetScanner()
USBCB usbcb = { INIT_HARDWARE_SYS ,0,0 };
if (m_usb.get() && m_usb->is_connected())
m_usb->write_bulk(&usbcb, sizeof(usbcb));
while (!m_pImages->m_imagepath.empty())
{
string path = m_pImages->m_imagepath.front();
if (isFileExist(path))
remove(path.c_str());
m_pImages->m_imagepath.pop();
}
m_pImages->clear();
}
bool GScanO200::Get_IsImageQueueEmpty()
@ -504,10 +491,6 @@ void GScanO200::reset()
}
void GScanO200::setdecodepixtype(int twpixtype)
{
}
UINT32 GScanO200::get_ErrorCode()
{
return Error_Code;
@ -662,20 +645,8 @@ void GScanO200::usbmain()
break;
}
m_usb->set_timeout(200);
//if(!m_pImages->get_isDogEar())
// m_pImages->pushMat(std::shared_ptr<IDecode>(new G200Decode(imgData)));
//string path = cv::tempfile();
m_pImages->m_data.push(imgData);
//string path = FileTools::get_appdata_path() + "image"+to_string(get_aquire_image_count())+".tmp";
//if (!access(path.c_str(), 0))
// remove(path.c_str());
//FILE* fd = fopen(path.c_str(), "wb+");
//if (fd)
//{
// fwrite(imgData->data(), imgData->size(), 1, fd);
// fclose(fd);
// m_pImages->m_imagepath.push(path);
//}
if(!m_pImages->get_isDogEar())
m_pImages->pushMat(std::shared_ptr<IDecode>(new G200Decode(imgData)));
Pop_Image();
set_aquire_image_count(get_aquire_image_count() + 1,get_updata_image_count());
FileTools::writelog(log_INFO, "´ÓɨÃèÒǽÓÊÕ"+to_string(get_aquire_image_count())+"·ÝÎļþ¡£");

View File

@ -27,7 +27,6 @@ public:
virtual void ResetScanner() override;
virtual bool Get_IsImageQueueEmpty() override;
virtual void reset() override;
virtual void setdecodepixtype(int twpixtype) override;
virtual UINT32 get_ErrorCode() override;
virtual void Set_ErrorCode(UINT32 value) override;
virtual int get_scanned_num() override;

View File

@ -151,7 +151,11 @@ GScanO400::GScanO400() :
m_bread_fixed_ratio_fromDSP(false)
{
m_pImages.reset(new ImageMatQueue());
m_pImages->Getimagenumber = std::bind(&GScanO400::Getimagenumber,this, std::placeholders::_1);
auto getimgnum = [&](bool isadd)
{
isadd ? image_num++ : image_num--;
};
m_pImages->SetGetimgnumcall(getimgnum);
}
GScanO400::~GScanO400()
@ -181,7 +185,7 @@ void GScanO400::Getimagenumber(bool isadd)
void GScanO400::DogEar_callback(std::function<void(int)> fun)
{
m_pImages->DogEarDetection_callback = fun;
m_pImages->SetGetimgnumcall(fun);
}
void GScanO400::open(int vid, int pid)
@ -514,18 +518,8 @@ void GScanO400::reset()
{
while (!m_pImages->empty())
m_pImages->clear();
while (!m_pImages->m_imagepath.empty())
{
string path = m_pImages->m_imagepath.front();
if (isFileExist(path))
remove(path.c_str());
m_pImages->m_imagepath.pop();
}
}
void GScanO400::setdecodepixtype(int twpixtype)
{
}
UINT32 GScanO400::get_ErrorCode()
{
@ -682,22 +676,9 @@ void GScanO400::usbmain()
{
FileTools::writelog(log_ERROR," get image data size error totalnum " + to_string(totalNum) + " imgdata size " + to_string(imgData->size()));
}
//if(!m_pImages->get_isDogEar())
//m_pImages->pushMat(std::shared_ptr<IDecode>(new G400Decode(imgData)));
m_pImages->m_data.push(imgData);
//string path = FileTools::get_appdata_path() + "image"+to_string(get_aquire_image_count())+".tmp";
//if (!access(path.c_str(), 0))
// remove(path.c_str());
//FILE* fd = fopen(path.c_str(), "wb+");
//if (fd)
//{
// if ((*imgData)[0] != -1 && (*imgData)[1] != -40 && (*imgData)[2] != -1 && (*imgData)[3] != -32)
// fwrite(imgData->data() + 12, imgData->size() - 12, 1, fd);
// else
// fwrite(imgData->data(), imgData->size(), 1, fd);
// fclose(fd);
// m_pImages->m_imagepath.push(path);
//}
if(!m_pImages->get_isDogEar())
m_pImages->pushMat(std::shared_ptr<IDecode>(new G400Decode(imgData)));
set_aquire_image_count(get_aquire_image_count() + 1,get_updata_image_count());
if(!is_AndroidOrLinux)
Pop_Image();

View File

@ -27,7 +27,6 @@ public:
virtual void ResetScanner() override;
virtual bool Get_IsImageQueueEmpty() override;
virtual void reset() override;
virtual void setdecodepixtype(int twpixtype) override;
virtual UINT32 get_ErrorCode() override;
virtual void Set_ErrorCode(UINT32 value) override;
virtual int get_scanned_num() override;

View File

@ -148,10 +148,6 @@ void GScanVirtual::reset()
}
}
void GScanVirtual::setdecodepixtype(int twpixtype)
{
pixType = twpixtype;
}
UINT32 GScanVirtual::get_ErrorCode()
{

View File

@ -25,7 +25,6 @@ public:
virtual void ResetScanner() override;
virtual bool Get_IsImageQueueEmpty() override;
virtual void reset() override;
virtual void setdecodepixtype(int twpixtype) override;
virtual UINT32 get_ErrorCode() override;
virtual void Set_ErrorCode(UINT32 value) override;
virtual int get_scanned_num() override;

View File

@ -6,7 +6,6 @@
#include "filetools.h"
#include <math.h>
#include "StopWatch.h"
//#include "JpegBuffer.h"
using namespace cv;
using namespace std;
@ -14,34 +13,6 @@ using namespace std;
#define DECODE_COLOR_BGR 1
#define DECODE_GRAY 6
G200Decode::G200Decode(std::shared_ptr<std::vector<char>> buff)
{
const int int_buffer_size = 1024;
int buffer_size = buff->size();
int b_buffer_size = 0;
int f_buffer_size = 0;
std::shared_ptr<std::vector<char>> buffB(new std::vector<char>(buff->size()));
std::shared_ptr<std::vector<char>> buffF(new std::vector<char>(buff->size()));;
unsigned char* bbuf = (unsigned char*)(buffB->data());
unsigned char* fbuf = (unsigned char*)(buffF->data());
unsigned char* buf = (unsigned char*)(buff->data());
for (int i = 0; i < (buffer_size / int_buffer_size); i++) {
if (buf[(i + 1) * int_buffer_size - 1] == 0) {
memcpy(bbuf + b_buffer_size, buf + i * int_buffer_size, int_buffer_size - 1);
b_buffer_size += (int_buffer_size - 1);
}
else if (buf[(i + 1) * int_buffer_size - 1] == 255) {
memcpy(fbuf + f_buffer_size, buf + i * int_buffer_size, int_buffer_size - 1);
f_buffer_size += (int_buffer_size - 1);
}
}
buffB->resize(b_buffer_size);
buffF->resize(f_buffer_size);
m_buffs.push_back(buffB);
m_buffs.push_back(buffF);
buff.reset();
}
ImageMatQueue::ImageMatQueue(void)
: bRun(false)
, is_scanning(false)
@ -49,15 +20,46 @@ ImageMatQueue::ImageMatQueue(void)
,fy(1.007)
,DogEar_index(0)
,is_DogEar(false)
,benablecache(false)
{
atm_orgin_image_remains = 0;
m_dogear.reset(new CImageApplyDogEarDetection(40,1.0,200));
m_snowflake.init(1, 1);
}
ImageMatQueue::~ImageMatQueue(void)
{
m_rawBuffs.Clear();
m_rawBuffs.ShutDown();
clear_cachefiles();
m_imgCacheinfo.ShutDown();
m_imagedata.Clear();
m_imagedata.ShutDown();
if (m_threadProc.get()) {
bRun = false;
m_threadProc->join();
m_threadProc.reset();
}
if (m_threadcache.get())
{
benablecache = false;
if (m_threadcache->joinable())
{
m_threadcache->join();
m_threadcache.reset();
}
}
}
void ImageMatQueue::run()
{
if (!m_threadProc) {
init_cachethread();
if (!m_threadProc.get()) {
bRun = true;
m_threadProc.reset(new thread(&ImageMatQueue::proc, this));
}
@ -91,24 +93,22 @@ void ImageMatQueue::updatefixratio(float& hratio, float& vratio)
}
}
ImageMatQueue::~ImageMatQueue(void)
void ImageMatQueue::SetGetimgnumcall(std::function<void(bool)> getimgnumcall)
{
m_rawBuffs.Clear();
m_imagedata.Clear();
m_rawBuffs.ShutDown();
m_imagedata.ShutDown();
if (m_threadProc) {
bRun = false;
m_threadProc->join();
m_threadProc.reset();
m_Getimagenumber = getimgnumcall;
}
void ImageMatQueue::SetDogEarCallback(std::function<void(int)> dogearcall)
{
m_DogEarDetection_callback = dogearcall;
}
static int paperIndex = 0;
void ImageMatQueue::pushMat(std::shared_ptr<IDecode> data)
{
Getimagenumber(true);
if(m_Getimagenumber)
m_Getimagenumber(true);
m_rawBuffs.Put(data);
atm_orgin_image_remains++;
//string paperindexinfo = "Get the index of "+to_string(++paperIndex)+" Paper";
@ -128,6 +128,7 @@ bool ImageMatQueue::valid()
void ImageMatQueue::clear()
{
m_rawBuffs.Clear();
clear_cachefiles();
m_imagedata.Clear();
atm_orgin_image_remains = 0;
}
@ -162,7 +163,7 @@ void ImageMatQueue::setparam(const GScanCap& param)
fixedSize = papersize.GetPaperSize(param.papertype, 200.0f, param.paperAlign);
#endif
m_iaList.push_back(shared_ptr<CImageApply>(new CImageApplyAutoCrop(islongcustomcrop ? islongcustomcrop : param.is_autocrop,
param.autodescrew, param.fillbackground, cv::Size(fixedSize.cx, fixedSize.cy), param.is_convex,false,param.AutoCrop_threshold,param.noise,param.indent)));
param.autodescrew, param.fillbackground, cv::Size(fixedSize.cx, fixedSize.cy), param.is_convex,param.AutoCrop_threshold,param.noise,param.indent)));
/* m_iaList.push_back(shared_ptr<CImageApply>(new CImageApplyAutoCrop(true, param.autodescrew, param.fillbackground, cv::Size(fixedSize.cx, fixedSize.cy), param.is_convex, false, param.AutoCrop_threshold, param.noise, param.indent)));
if(!(islongcustomcrop ? islongcustomcrop : param.is_autocrop))
@ -312,17 +313,94 @@ void ImageMatQueue::setparam(const GScanCap& param)
void ImageMatQueue::EnqueueBmpBuffer(std::shared_ptr<std::vector<unsigned char>> bmpdata)
{
m_imagedata.Put(bmpdata);
int aa = 0;
}
void ImageMatQueue::PaniusCount()
void ImageMatQueue::PaniusCount(int count)
{
atm_orgin_image_remains--;
Getimagenumber(false);
atm_orgin_image_remains-=count;
if(m_Getimagenumber)
m_Getimagenumber(false);
}
void ImageMatQueue::init_cachethread()
{
if(!m_threadcache.get())
{
benablecache = true;
m_threadcache.reset(new thread(&ImageMatQueue::cache_run, this));
}
}
static int index = 0;
void ImageMatQueue::cache_run()
{
StopWatch sw;
std::ios::sync_with_stdio(false);
while(benablecache)
{
if (m_rawBuffs.Size() == 0)
{
this_thread::sleep_for(chrono::milliseconds(2));
continue;
}
if (m_rawBuffs.Size() > 0)
{
CacheInfo info;
auto buffs = m_rawBuffs.Take()->getImageBuffs();
buffs.size() == 2 ? info.scannerType = ScannerSerial::G200Serial : info.scannerType = ScannerSerial::G400Serial;
for (auto& buf : buffs)
{
index++;
string path = FileTools::get_appdata_path() + to_string(m_snowflake.nextid()) + ".jpg";
if (!access(path.c_str(), 0))
{
remove(path.c_str());
FileTools::writelog(log_ERROR, "exist file "+ path+" maybe lost previous session scanned image");
}
CFile frb;
if (frb.Open(CString(path.c_str()), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
{
if (*(buf->data()) != -1 && *(buf->data() + 1) != -40 && *(buf->data() + 2) != -1 && *(buf->data() + 3) != -32)
{
frb.Write(buf->data() + 12, buf->size() - 12);
FileTools::writelog(log_ERROR, "usb data error -image data");
}
else
frb.Write(buf->data(), buf->size());
frb.Flush();
frb.Close();
info.path = path;
m_imgCacheinfo.Put(info);
buf->clear();
}
else
{
FileTools::writelog(log_ERROR, "error while openning cache file :" + path);
}
FileTools::writelog(log_INFO, " 磁盘写入图片数据耗时 " + to_string(sw.elapsed_ms()) + " buffer size = " + to_string(buf->size()));
sw.reset();
}
}
}
}
void ImageMatQueue::clear_cachefiles()
{
while (m_imgCacheinfo.Size() > 0)
{
auto tpath = m_imgCacheinfo.Take();
if (isFileExist(tpath.path))
remove(tpath.path.c_str());
}
}
bool ImageMatQueue::empty()
{
//return atm_orgin_image_remains <= 0 && m_imagedata.Size() == 0 && !is_scanning;
return m_imagepath.empty()&&(m_imagedata.Size()==0 )&& !is_scanning&&m_data.empty();
return m_imgCacheinfo.Size()==0&&(m_imagedata.Size()==0 )&&(m_rawBuffs.Size()==0)&& !is_scanning&& atm_orgin_image_remains==0;
}
bool ImageMatQueue::queuesempty()
@ -330,159 +408,76 @@ bool ImageMatQueue::queuesempty()
return atm_orgin_image_remains <= 0 && m_imagedata.Size() == 0;
}
static int index = 0;
void ImageMatQueue::proc()
{
//int dwnumber = std::thread::thread::hardware_concurrency();
//std::unique_ptr<ThreadPool> m_threadpool;
//m_threadpool.reset(new ThreadPool(dwnumber < 4 ? 1 : dwnumber / 2));
std::ios::sync_with_stdio(false);
while (bRun) {
while (m_imagedata.Size() > 0) {
this_thread::sleep_for(chrono::milliseconds(1));
}
//if (m_rawBuffs.Size() == 0)
//{
// this_thread::sleep_for(chrono::milliseconds(1));
// continue;
//}
//if (m_imagepath.empty())
//{
// this_thread::sleep_for(chrono::milliseconds(1));
// continue;
//}
if (m_data.empty())
StopWatch sw;
while (bRun)
{
this_thread::sleep_for(chrono::milliseconds(1));
string msg;
auto info = m_imgCacheinfo.Take();
if(info.path.length()==0 || !isFileExist(info.path))
{
msg = "error while checking file :" + info.path + " ,file lost";
FileTools::writelog(log_ERROR, msg);
continue;
}
if (m_data.size() > 0)
{
string path = FileTools::get_appdata_path() + "image" + to_string(index++) + ".tmp";
if (!access(path.c_str(), 0))
remove(path.c_str());
auto buff = m_data.front();
//if (!fw.get())
// fw.reset(new fstream());
//fw->open(path, std::ios::binary | std::ios::out);
//if (fw->is_open())
//{
// if ((*buff)[0] != -1 && (*buff)[1] != -40 && (*buff)[2] != -1 && (*buff)[3] != -32)
// {
// fw->write(buff->data() + 12, buff->size() - 12);
// FileTools::writelog(log_ERROR, "usb data error -image data");
// }
// else
// fw->write(buff->data(), buff->size());
// fw->flush();
// fw->close();
// m_imagepath.push(path);
// buff.reset(); m_data.pop();
// fw.reset();
//}
CFile frb;
if (frb.Open(CString(path.c_str()), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary))
{
if ((*buff)[0] != -1 && (*buff)[1] != -40 && (*buff)[2] != -1 && (*buff)[3] != -32)
{
frb.Write(buff->data() + 12, buff->size() - 12);
FileTools::writelog(log_ERROR, "usb data error -image data");
}
else
frb.Write(buff->data(), buff->size());
frb.Flush();
frb.Close();
m_imagepath.push(path);
buff.reset(); m_data.pop();
}
}
std::string path = m_imagepath.front();
long lenght= FileTools::get_file_size(path.c_str());
std::shared_ptr<std::vector<char>> buf(new std::vector<char>);
buf->resize(lenght);
StopWatch sw;
if (!access(path.c_str(),0))
{
//if (!fr.get())
// fr.reset(new fstream());
//fr->open(path, std::ios::binary | std::ios::in);
//if (fr->is_open())
//{
// fr->read(buf->data(), lenght);
// fr->close();
// fr.reset();
// remove(path.c_str());
//}
CFile fwb;
if (fwb.Open(CString(path.c_str()), CFile::modeRead |CFile::typeBinary))
{
fwb.Read(buf->data(), lenght);
fwb.Close();
remove(path.c_str());
}
else
{
FileTools::writelog(log_ERROR, "error while opening filename:" + path);
}
}
else
FileTools::writelog(log_ERROR, "open file error filename:" + path);
FileTools::writelog(log_INFO, " 获取磁盘图片数据耗时 " + to_string(sw.elapsed_ms())+" data size "+to_string(lenght));
sw.reset();
#ifdef G200
auto& buffs = G200Decode(buf).getImageBuffs();
#else
auto& buffs = G400Decode(buf).getImageBuffs();
#endif // G200
//auto& buffs = m_rawBuffs.Take()->getImageBuffs();
if (!m_rawBuffs.IsShutDown() && !buffs.empty()) {
//m_threadpool->enqueue(&ImageMatQueue::imageproceing, this, buffs);
//try {
// imageproceing(buffs);
//}
//catch (std::exception& e)
//{
// FileTools::writelog(log_ERROR, " image proc error " + std::string(e.what()));
//}
imageproceing(buffs);
}
m_imagepath.pop();
}
//m_threadpool.reset();
}
void ImageMatQueue::imageproceing(std::vector<std::shared_ptr<std::vector<char>>>& buffs)
{
vector<cv::Mat> mats;
for (auto& buf : buffs) {
ImreadModes rmc;
//int rm;
if (scanParam.filter != 3 || scanParam.enhance_color || scanParam.hsvcorrect) {
if (scanParam.filter != 3 || scanParam.enhance_color || scanParam.hsvcorrect)
rmc = IMREAD_COLOR;
//rm = 1;
}
else {
else
rmc = scanParam.pixtype == 2 ? IMREAD_COLOR : IMREAD_GRAYSCALE;
//rm = scanParam.pixtype == 2 ? 1 : 6;
}
try
std::vector<cv::Mat> mats;
std::vector<Mat> uvmats;
if(info.scannerType==ScannerSerial::G200Serial)
{
cv::Mat mat = cv::imdecode(*buf, rmc);
if (mat.empty()) {
FileTools::writelog(log_ERROR,"decode image data error");
auto back= m_imgCacheinfo.Take();
if(!isFileExist(back.path))
{
msg = "error while reading g200 back image " + back.path + " ,file not exist";
FileTools::writelog(log_ERROR,msg);
}
buf.reset();
#ifdef G200
cv::resize(mat, mat, cv::Size(), fx, fy);//用于修正与佳能机器幅面大小不匹配问题 此系数请勿轻易动
mats.push_back(mat);
mat.release();
#else // G200
sw.reset();
auto imgfront= imread(info.path, rmc);
msg = "reading image front time elapsed_ms:" + std::to_string(sw.elapsed_ms());
FileTools::writelog(log_ERROR, msg);
sw.reset();
auto imgback = imread(back.path, rmc);
msg = "reading image back time elapsed_ms:" + std::to_string(sw.elapsed_ms());
FileTools::writelog(log_ERROR, msg);
sw.reset();
if(!imgfront.empty()&&!imgback.empty())
{
mats.push_back(scanParam.is_switchfrontback? imgback:imgfront);
mats.push_back(scanParam.is_switchfrontback? imgfront:imgback);
remove(info.path.c_str());
remove(back.path.c_str());
}
else
{
msg = "get empty mat! empty ";
msg += (imgfront.empty() ? " front image" : " back image");
FileTools::writelog(log_ERROR, msg);
}
for (size_t i = 0; i < mats.size(); i++)
{
if(!mats[i].empty())
cv::resize(mats[i], mats[i], cv::Size(), fx, fy);//用于修正与佳能机器幅面大小不匹配问题 此系数请勿轻易动
}
if (scanParam.en_fold != 0) {
cv::flip(mats[0], mats[0], 1);
cv::flip(mats[0], mats[0], 0);
}
}
else
{
auto mat= imread(info.path, rmc);
if(!mat.empty())
{
Mat front = mat(Rect(0, 0, mat.cols / 2, mat.rows));
Mat back = mat(Rect(mat.cols / 2, 0, mat.cols / 2, mat.rows));
if (scanParam.imageRotateDegree != 0.0 && scanParam.imageRotateDegree != 180.0) {
@ -491,47 +486,63 @@ void ImageMatQueue::imageproceing(std::vector<std::shared_ptr<std::vector<char>>
}
mats.push_back(back);
mats.push_back(front);
}
else
{
msg = "g400 get empty mat! empty ";
FileTools::writelog(log_ERROR, msg);
}
#ifdef UV
if(scanParam.hardwarecaps.en_uv)//EN UV
{
auto uvinfo = m_imgCacheinfo.Take();
auto matuv = imread(uvinfo.path, IMREAD_COLOR);
if(!matuv.empty())
{
Mat front = mat(Rect(0, 0, mat.cols / 2, mat.rows));
Mat back = mat(Rect(mat.cols / 2, 0, mat.cols / 2, mat.rows));
uvmats.push_back(scanParam.is_switchfrontback ? back : front);
uvmats.push_back(scanParam.is_switchfrontback ? front : back);
front.release();
back.release();
}
}
#endif
}
catch (const std::exception& e)
{
//writelog(e.what());
FileTools::writelog(log_ERROR, e.what());
}
}
buffs.clear();
if (mats[0].empty() || mats[1].empty())
{
mats.clear();
PaniusCount();
return;
}
//DogEar_index++; //暂时屏蔽 2021.3.18
//StopWatch sw;
//sw.reset();
//if (ischeck_dogear)
//{
// m_dogear->apply(mats[0], 0);
// if (m_dogear->getResult())
// {
// DogEarDetection_callback(DogEar_index);
// m_rawBuffs.Clear();
// atm_orgin_image_remains = 0;
// is_DogEar = true;
// return;
// }
//}
//FileTools::write_log("1.txt", " dogear time " + to_string(sw.elapsed_ms()));
if (scanParam.is_switchfrontback)
swap(mats[0], mats[1]);
if (scanParam.en_fold != 0) {
cv::flip(mats[0], mats[0], 1);
cv::flip(mats[0], mats[0], 0);
}
StopWatch sw;
}//g400 serials
std::vector<cv::RotatedRect> rects;
std::vector<int> angleResults;
bool isDesaskew = false;
for (int j = 0; j < m_iaList.size(); j++) {
m_iaList[j]->apply(mats, scanParam.is_duplex);
CImageApply* ptr = m_iaList[j].get();
if (typeid(*ptr) == typeid(CImageApplyAutoCrop))
{
rects = dynamic_cast<CImageApplyAutoCrop*>(ptr)->rotatedROIs();
isDesaskew = dynamic_cast<CImageApplyAutoCrop*>(ptr)->isDesaskew();
}
else if (typeid(*ptr) == typeid(CImageApplyRotation))
angleResults = dynamic_cast<CImageApplyRotation*>(ptr)->angleResults();
}
#ifdef UV
if (!uvmats.empty())
{
//拼接原图和UV图
for (int j = 0; j < mats.size(); j++)
{
if (!scanParam.is_duplex && j == 1) {
mats[j].release();
break;
}
cv::Mat mergeOrgin_UV = ImageApplyUV::Apply(mats[j], uvmats[j], rects[j], isDesaskew, angleResults.size() > 0 ? angleResults[j] : 0);
if (!mergeOrgin_UV.empty())
mats[j] = mergeOrgin_UV;
}
uvmats.clear();
}
#endif
FileTools::writelog(log_INFO, "ͼÏñ´¦ÀíºÄʱ " + to_string(sw.elapsed_ms()));
for (int i = 0; i < mats.size(); i++) {
if (!scanParam.is_duplex && i == 1) {
@ -548,9 +559,6 @@ void ImageMatQueue::imageproceing(std::vector<std::shared_ptr<std::vector<char>>
mats[i].release();
auto data = idata.getBmpDataBuffer();
//FILE* fd=fopen("D:\\0.bmp","w+");
//fwrite(data->data(), data->size(),1 , fd);
//fclose(fd);
EnqueueBmpBuffer(data);
data.reset();
}
@ -581,10 +589,45 @@ void ImageMatQueue::imageproceing(std::vector<std::shared_ptr<std::vector<char>>
}
}
mats.clear();
#ifdef UV
PaniusCount(scanParam.hardwarecaps.en_uv ? 2 : 1);
#else
PaniusCount();
#endif
}
}
G400Decode::G400Decode(std::shared_ptr<std::vector<char>> buff)
{
m_buffs.push_back(buff);
}
G200Decode::G200Decode(std::shared_ptr<std::vector<char>> buff)
{
const int int_buffer_size = 1024;
int buffer_size = buff->size();
int b_buffer_size = 0;
int f_buffer_size = 0;
std::shared_ptr<std::vector<char>> buffB(new std::vector<char>(buff->size()));
std::shared_ptr<std::vector<char>> buffF(new std::vector<char>(buff->size()));;
unsigned char* bbuf = (unsigned char*)(buffB->data());
unsigned char* fbuf = (unsigned char*)(buffF->data());
unsigned char* buf = (unsigned char*)(buff->data());
for (int i = 0; i < (buffer_size / int_buffer_size); i++) {
if (buf[(i + 1) * int_buffer_size - 1] == 0) {
memcpy(bbuf + b_buffer_size, buf + i * int_buffer_size, int_buffer_size - 1);
b_buffer_size += (int_buffer_size - 1);
}
else if (buf[(i + 1) * int_buffer_size - 1] == 255) {
memcpy(fbuf + f_buffer_size, buf + i * int_buffer_size, int_buffer_size - 1);
f_buffer_size += (int_buffer_size - 1);
}
}
buffB->resize(b_buffer_size);
buffF->resize(f_buffer_size);
m_buffs.push_back(buffB);
m_buffs.push_back(buffF);
buff.reset();
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <thread>
#include <mutex>
#include <opencv2\opencv.hpp>
#include <opencv2/opencv.hpp>
#include "ImageProcess/ImageApplyHeaders.h"
#include "PublicFunc.h"
#include "BlockingQueue.h"
@ -9,6 +9,9 @@
//#include "threadpool.hpp"
#include "PaperSize.h"
#include "filetools.h"
//创建唯一 uuid
#include "snowflake.h"
using namespace std;
class IMat2Bmp {
public:
@ -145,18 +148,38 @@ protected:
class G200Decode : public IDecode{
public:
G200Decode(std::shared_ptr<std::vector<char>> buff);
virtual ~G200Decode()
{
}
};
class G400Decode : public IDecode {
public:
G400Decode(std::shared_ptr<std::vector<char>> buff);
virtual ~G400Decode()
{
}
};
enum ScannerSerial
{
G200Serial,
G400Serial
};
struct CacheInfo
{
std::string path;
ScannerSerial scannerType;
};
using snowflake_t = snowflake<1534832906275L, std::mutex>;
class ImageMatQueue
{
public:
ImageMatQueue(void);
virtual ~ImageMatQueue(void);
~ImageMatQueue(void);
void pushMat(std::shared_ptr<IDecode> buf);
std::shared_ptr<std::vector<unsigned char>> popBmpdata();
@ -172,29 +195,36 @@ public:
int orginimgcount();
void setscanflags(const bool flags) { is_scanning = flags; }
void updatefixratio(float& hratio, float& vratio);
std::function<void(int)> DogEarDetection_callback;
std::function<void(bool)> Getimagenumber;
std::queue<std::string> m_imagepath;
std::queue<std::shared_ptr<std::vector<char>>> m_data;
void SetGetimgnumcall(std::function<void(bool)> getimgnumcall);
void SetDogEarCallback(std::function<void(int)> dogearcall);
private:
void proc();
void imageproceing(std::vector<std::shared_ptr<std::vector<char>>>& buffs);
void EnqueueBmpBuffer(std::shared_ptr<std::vector<unsigned char>>);
void PaniusCount();
BlockingQueue<std::shared_ptr<std::vector<unsigned char>>>m_imagedata;
std::unique_ptr<thread> m_threadProc;
void PaniusCount(int count=1);
void init_cachethread();
void cache_run();
//清除缓存文件
void clear_cachefiles();
BlockingQueue<std::shared_ptr<std::vector<unsigned char>>> m_imagedata;//已处理图像队列
BlockingQueue<CacheInfo> m_imgCacheinfo;//缓存图像队列
BlockingQueue<std::shared_ptr<IDecode>> m_rawBuffs;//原图队列
std::unique_ptr<thread> m_threadProc;//图像处理线程
std::unique_ptr<thread> m_threadcache;//缓存线程
bool ischeck_dogear;
volatile int DogEar_index;
volatile bool is_DogEar;
volatile bool bRun;
volatile bool benablecache;
volatile int atm_orgin_image_remains;
volatile bool is_scanning;
std::unique_ptr<fstream> fw;
std::unique_ptr<fstream> fr;
GScanCap scanParam;
Device::PaperSize papersize;
std::shared_ptr<CImageApplyDogEarDetection> m_dogear;
std::vector<std::shared_ptr<CImageApply>> m_iaList; //ͼÏñ´¦Àíº¯Êý½Ó¿Ú
BlockingQueue<std::shared_ptr<IDecode>> m_rawBuffs;
float fx, fy;
std::function<void(int)> m_DogEarDetection_callback;
std::function<void(bool)> m_Getimagenumber;
snowflake_t m_snowflake;
};

View File

@ -28,6 +28,9 @@ const std::string CONFIG = "Config";
const std::string PIXTYPE = "iPixType";
const std::string AUTOMATICCOLOR = "bAutoMaticColorDetece";
const std::string AUTOMATICCOLORTYPR = "iAutoMaticColorDeteceType";
#ifdef UV
const std::string ENUVMODEL = "bUVmodel";
#endif
const std::string PAPARSIZE = "iPaparSize";
const std::string ENSIZECHECK = "iEnSizeCheck";
const std::string PAPERALIGN = "iPaperAlign";
@ -92,6 +95,9 @@ typedef struct tagCONFIGPARAMS
int PaperSize;
bool EnSizeCheck;
bool EnAutoCrop;
#ifdef UV
bool EnUVModel;
#endif
int Resolution;
int Duplex;
bool EnDiscardBlank;
@ -168,6 +174,9 @@ typedef struct tagHARDWAREPARAMS
byte en_skrewdetect;
byte skrewdetectlevel;
LowPowerMode lowpowermode;
#ifdef UV
byte en_uv;
#endif
}HardwareCaps;
typedef struct Scan_Rect {

View File

@ -28,6 +28,10 @@ GScanCap GscanJsonConfig::GetDefaultGscancapValue()
gcap.paperAlign = PaperAlign::Rot0;
gcap.papertype = 0;//TwSS::NONE
gcap.en_sizecheck = FALSE;
#ifdef UV
gcap.hardwarecaps.en_uv = FALSE;
#endif
gcap.is_autocrop = TRUE;//ĬÈÏ×Ô¶¯²ÃÇÐ
gcap.is_duplex = TRUE;
gcap.is_autodiscradblank_normal = FALSE;
@ -100,6 +104,9 @@ void GscanJsonConfig::SaveGscanCapConfig(const GScanCap & gcap, const std::strin
outJson["Config"].Add(FLOD, (bool)(gcap.en_fold), false);
outJson["Config"].Add(SWITCHFRONTBACK, (bool)(gcap.is_switchfrontback), false);
#ifdef UV
outJson["Config"].Add(ENUVMODEL, (bool)(gcap.hardwarecaps.en_uv), false);
#endif
outJson["Config"].Add(BRIGHTNESS, (int)(gcap.brightness));
outJson["Config"].Add(AUTOCONTRAST, (bool)(gcap.is_autocontrast), false);
outJson["Config"].Add(CONTRAST, (int)(gcap.contrast));
@ -155,6 +162,9 @@ void GscanJsonConfig::WriteJsonArrayToFile(std::vector<GScanCap> cfgArray, const
root["Config"].AddEmptySubArray(DISCARBLANK);
root["Config"].AddEmptySubArray(DISCARBLANKVINCE);
root["Config"].AddEmptySubArray(DISCARBLANK_VALUE);
#ifdef UV
root["Config"].AddEmptySubArray(ENUVMODEL);
#endif
//root["Config"].AddEmptySubArray(DB_AREANUM);
//root["Config"].AddEmptySubArray(DB_DEVNMAX);
root["Config"].AddEmptySubArray(FLOD);
@ -215,7 +225,9 @@ void GscanJsonConfig::WriteJsonArrayToFile(std::vector<GScanCap> cfgArray, const
//root["Config"][DB_DEVNMAX].Add(cfgArray[i].DBlank_DevnMax);
root["Config"][FLOD].Add(i, (bool)cfgArray[i].en_fold);
root["Config"][SWITCHFRONTBACK].Add(i,(bool)cfgArray[i].is_switchfrontback);
#ifdef UV
root["Config"][ENUVMODEL].Add(i, cfgArray[i].hardwarecaps.en_uv);
#endif
root["Config"][BRIGHTNESS].Add((int)cfgArray[i].brightness);
root["Config"][AUTOCONTRAST].Add(i, (bool)cfgArray[i].is_autocontrast);
root["Config"][CONTRAST].Add((int)cfgArray[i].contrast);
@ -378,8 +390,10 @@ std::vector<GScanCap> GscanJsonConfig::parseJsonFromString(const std::string str
root["Config"].Get(SWITCHFRONTBACK, itmEnSwitchFrontBack);
neb::CJsonObject itmdiscarbrank_value;
root["Config"].Get(DISCARBLANK_VALUE, itmdiscarbrank_value);
#ifdef UV
neb::CJsonObject itmEnUV;
root["Config"].Get(ENUVMODEL, itmEnUV);
#endif
neb::CJsonObject itmBrtnes;
root["Config"].Get(BRIGHTNESS, itmBrtnes);
neb::CJsonObject itmAutoCrnt;
@ -489,7 +503,10 @@ std::vector<GScanCap> GscanJsonConfig::parseJsonFromString(const std::string str
cfp.en_fold = b_value ? 1 : 0;
itmEnSwitchFrontBack.Get(i, b_value);
cfp.is_switchfrontback = b_value ? 1 : 0;
#ifdef UV
root["Config"].Get(ENUVMODEL, b_value);
cfp.hardwarecaps.en_uv = b_value ? 1 : 0;
#endif
itmBrtnes.Get(i, i_value);
cfp.brightness = i_value;
itmAutoCrnt.Get(i, b_value);

View File

@ -8,17 +8,17 @@ CImageApplyAutoCrop::CImageApplyAutoCrop()
, m_isConvexHull(true)
, m_isFillColor(false)
, m_threshold(40)
, m_noise(8)
, m_noise(2)
, m_indent(5)
{
}
CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor, double threshold, int noise, int indent)
CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, double threshold, int noise, int indent)
: m_isCrop(isCrop)
, m_isDesaskew(isDesaskew)
, m_isFillBlank(isFillBlank)
, m_isConvexHull(isConvex)
, m_isFillColor(isFillColor)
, m_isFillColor(false)
, m_threshold(threshold)
, m_noise(noise)
, m_indent(indent)
@ -54,11 +54,18 @@ void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
if (m_maxContour.size() == 0)
{
thre.release();
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit CImageApplyAutoCrop apply");
#endif // LOG
return;
}
thre.release();
dst.release();
cv::RotatedRect rect = hg::getBoundingRect(m_maxContour);
m_rect = rect;
cv::Rect boudingRect = cv::boundingRect(m_maxContour);
boudingRect.x -= 1;
boudingRect.y -= 1;
@ -70,14 +77,18 @@ void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
cv::Point2f srcTri[4];
cv::Point2f dstTri[3];
rect.points(srcTri);
for (cv::Point2f& p : srcTri)
{
p.x -= 0.5;
p.y -= 0.5;
}
dstTri[0] = cv::Point2f(0, rect.size.height - 1);
dstTri[1] = cv::Point2f(0, 0);
dstTri[2] = cv::Point2f(rect.size.width - 1, 0);
cv::Mat warp_mat;
warp_mat = cv::getAffineTransform(srcTri, dstTri);
//cv::warpAffine(src, dst, warp_mat, rect.size,cv::INTER_LANCZOS4);
cv::warpAffine(src, dst, warp_mat, rect.size);
cv::warpAffine(src, dst, warp_mat, rect.size, cv::INTER_NEAREST);
}
else
dst = src(boudingRect & cv::Rect(0, 0, src.cols, src.rows));
@ -149,9 +160,12 @@ void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side)
void CImageApplyAutoCrop::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
{
m_rects.clear();
if (mats.empty()) return;
if (!mats[0].empty()) {
apply(mats[0], 0);
m_rects.push_back(m_rect);
//cv::imwrite("1.bmp", mats[0]);
}
if (isTwoSide && mats.size() > 1)
@ -159,8 +173,11 @@ void CImageApplyAutoCrop::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
cv::Size dSize = m_fixedSize;
if (!mats[0].empty())
m_fixedSize = mats[0].size();
if (!mats[1].empty()) {
apply(mats[1], 1);
m_rects.push_back(m_rect);
//cv::imwrite("1.bmp", mats[0]);
}
if (!mats[0].empty())

View File

@ -37,7 +37,7 @@ public:
* noise [in]:noise宽度的背景竖条纹干扰40
* indent [in]:indent像素5
*/
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);
CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex = true, double threshold = 40, int noise = 8, int indent = 5);
virtual ~CImageApplyAutoCrop();
@ -55,6 +55,10 @@ public:
double threshold() { return m_threshold; }
const cv::RotatedRect& rotatedROI() { return m_rect; }
const std::vector<cv::RotatedRect>& rotatedROIs() { return m_rects; }
int noise() { return m_noise; }
int indent() { return m_indent; }
@ -95,7 +99,9 @@ private:
int m_noise;
int m_indent;
cv::Size m_fixedSize;
cv::RotatedRect m_rect;
std::vector<cv::Point> m_maxContour;
std::vector<cv::RotatedRect> m_rects;
};
#endif // !IMAGE_APPLY_AUTO_CROP_H

View File

@ -17,5 +17,5 @@
#include "ImageApplyHSVCorrect.h"
#include "ImageApplyDetachNoise.h"
#include "ImageApplyColorRecognition.h"
#include "ImageApplyUV.h"
#endif

View File

@ -30,6 +30,7 @@ CImageApplyRotation::~CImageApplyRotation()
void CImageApplyRotation::apply(cv::Mat& pDib, int side)
{
m_angleResult = 0;
#ifdef LOG
FileTools::write_log("imgprc.txt", "enter CImageApplyRotation apply");
#endif // LOG
@ -50,7 +51,7 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side)
if (m_dpi != 200)
{
double scale = 200 / static_cast<double>(m_dpi);
int new_w = static_cast<int>(pDib.cols * scale) / 4 * 4;
int new_w = (pDib.cols * scale + 3) / 4 * 4;
int new_h = pDib.rows * scale;
cv::resize(pDib, temp, cv::Size(new_w, new_h));
}
@ -69,16 +70,20 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side)
case 90:
cv::transpose(pDib, pDib);
cv::flip(pDib, pDib, 0);
m_angleResult = 90;
break;
case 180:
cv::flip(pDib, pDib, 0);
cv::flip(pDib, pDib, 1);
m_angleResult = 180;
break;
case 270:
cv::transpose(pDib, pDib);
cv::flip(pDib, pDib, 1);
m_angleResult = 270;
break;
default:
m_angleResult = 0;
break;
}
}
@ -92,11 +97,13 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side)
{
transpose(pDib, pDib);
flip(pDib, pDib, m_rotation == RotationType::Rotate_90_clockwise ? 0 : 1);
m_angleResult = m_rotation == RotationType::Rotate_90_clockwise ? 270 : 90;
}
else
{
flip(pDib, pDib, 1);
flip(pDib, pDib, 0);
flip(pDib, pDib, 1);
m_angleResult = 180;
}
}
}
@ -106,11 +113,13 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side)
{
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;
}
}
#ifdef LOG
@ -121,10 +130,12 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side)
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++;
}
}

View File

@ -1,16 +1,3 @@
/*
* ====================================================
*
*
* 2020/4/21
* v1.0 2020/4/21
v1.1 2020/8/12 稿BUG
* v1.1
* ====================================================
*/
#ifndef IMAGE_APPLY_ROTATION_H
#define IMAGE_APPLY_ROTATION_H
@ -21,22 +8,16 @@ class CImageApplyRotation : public CImageApply
public:
enum class RotationType
{
Invalid, //无效
Rotate_90_clockwise, //顺时针90°
Rotate_180, //180°
Rotate_90_anti_clockwise, //逆时针90°即270°
Invalid,
Rotate_90_clockwise,
Rotate_180,
Rotate_90_anti_clockwise,
AutoTextOrientation //自动文稿方向识别旋转
AutoTextOrientation
};
public:
/*
* rotation [in]:
* isBackTransposed [in]:true为背面180°
* dpi [in]:DPIrotation为AutoTextOrientation时生效稿200DPI进行识别
* tessadataPath [in]:rotation为AutoTextOrientation时生效
*/
CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr);
virtual ~CImageApplyRotation();
@ -49,6 +30,10 @@ public:
int getDPI() { return m_dpi; }
int angleResult() { return m_angleResult; }
const std::vector<int>& angleResults() { return m_angleResults; }
RotationType getRotationType() { return m_rotation; }
void setBackTransposed(bool enabled) { m_backTranspose = enabled; }
@ -63,6 +48,9 @@ private:
int m_dpi;
void* osd;
int m_angleResult;
std::vector<int> m_angleResults;
};
#endif // !IMAGE_APPLY_ROTATION_H

View File

@ -0,0 +1,230 @@
#include "ImageApplyUV.h"
using namespace cv;
#define SCA 50
ImageApplyUV::ImageApplyUV(): lut(1, 256, CV_8UC1)
{
}
ImageApplyUV::~ImageApplyUV()
{
}
void ImageApplyUV::update_lutData(int contrast)
{
unsigned char* ptr = lut.data;
int m_contrast = cv::max(-127, cv::min(contrast, 127));
for (int i = 0; i < 256; i++)
{
//update contrast
if (i < 128)
ptr[i] = static_cast<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 ImageApplyUV::Apply(cv::Mat& image, const cv::Mat& uv, int dpi, int thresh)
{
update_lutData(12);
cv::LUT(uv, lut, uv);
Mat uv_resize;
cv::resize(uv, uv_resize, cv::Size(uv.cols * SCA / dpi, uv.rows * SCA / dpi));
if (uv_resize.channels() == 3)
cv::cvtColor(uv_resize, uv_resize, cv::COLOR_BGR2GRAY);
cv::threshold(uv_resize, uv_resize, 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;
findContours1(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 ImageApplyUV::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 ImageApplyUV::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];
}
}
}
}
void ImageApplyUV::findContours1(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
{
CvMat c_image = src;
cv::MemStorage storage(cvCreateMemStorage());
CvSeq* _ccontours = nullptr;
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset));
if (!_ccontours)
{
contours.clear();
return;
}
cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
size_t total = all_contours.size();
contours.resize(total);
cv::SeqIterator<CvSeq*> 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);
int count = c->total;
int* data = new int[static_cast<size_t>(count * 2)];
cvCvtSeqToArray(c, data);
for (int j = 0; j < count; j++)
contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1]));
delete[] data;
}
hierarchy.resize(total);
it = all_contours.begin();
for (size_t i = 0; i < total; i++, ++it)
{
CvSeq* c = *it;
int h_next = c->h_next ? reinterpret_cast<CvContour*>(c->h_next)->color : -1;
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;
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);
}
storage.release();
}
cv::Scalar ImageApplyUV::getColor(const cv::Mat& image, int col, int threshold)
{
cv::Scalar color(0, 0, 0);
int num = 0;
for (int i = 0, length = image.rows; i < length; i++)
{
const uchar* ptr = image.ptr<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;
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <opencv2/opencv.hpp>
#include "ImageProcess/ImageProcess_Public.h"
class ImageApplyUV
{
public:
ImageApplyUV();
~ImageApplyUV();
void Apply(cv::Mat& image, const cv::Mat& uv, int dpi = 200, int thresh = 100);
static cv::Mat Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle);
private:
void purgeQR_kernal(cv::Mat& image, const cv::Rect& roi, std::map<int, cv::Scalar> map_color, int dpi, int threshold);
void findContours1(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy,
int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0));
cv::Scalar getColor(const cv::Mat& image, int col, int threshold);
void update_lutData(int contrast);
cv::Mat lut;
};

View File

@ -1867,6 +1867,32 @@ Result HuagaoDs::identityOpenDs(const Identity&) {
m_scanparam->hardwarecaps.lowpowermode, LowPowerMode::Min_30, (BYTE)m_scanparam->hardwarecaps.lowpowermode, 4);
};
#endif // LANXUM
#ifdef UV
m_query[(CapType)(CapTypeEx::TwEx_UVModel)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::TwEx_UVModel)] = [this](Msg msg, Capability& data)->Result {
switch (msg) {
case Msg::Get:
data = Capability::createEnumeration<Bool>((CapType)(CapTypeEx::TwEx_UVModel), { Bool(),Bool(true) }, Bool(m_scanparam->hardwarecaps.en_uv), 0);
return success();
case Msg::Reset:
m_scanparam->hardwarecaps.en_uv = false;
case Msg::GetCurrent:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_UVModel), m_scanparam->hardwarecaps.en_uv);
return success();
case Msg::GetDefault:
data = Capability::createOneValue<Bool>((CapType)(CapTypeEx::TwEx_UVModel), Bool(false));
return success();
case Msg::Set: {
auto mech = data.currentItem<Bool>();
m_scanparam->hardwarecaps.en_uv = mech;
return success();
}
default:
return capBadOperation();
}
};
#endif
return success();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.