diff --git a/.gitignore b/.gitignore index 9d558ac4..fbf41369 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ ################################################################################ /huagao/.vs/huagaotwds/v15 -/3rdparty/nick /huagao/debug/qmake /huagao/debug /huagao/Win32/Debug diff --git a/3rdparty/nick/snowflake.h b/3rdparty/nick/snowflake.h new file mode 100644 index 00000000..963aa69a --- /dev/null +++ b/3rdparty/nick/snowflake.h @@ -0,0 +1,106 @@ +#pragma once +#include +#include +#include +#include + +class snowflake_nonlock +{ +public: + void lock() + { + } + void unlock() + { + } +}; + +template +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; + + time_point start_time_point_ = std::chrono::steady_clock::now(); + int64_t start_millsecond_ = std::chrono::duration_cast(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(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::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; + } +}; \ No newline at end of file diff --git a/huagao/CBasicPage.cpp b/huagao/CBasicPage.cpp index 07017c4d..1c4fb66b 100644 --- a/huagao/CBasicPage.cpp +++ b/huagao/CBasicPage.cpp @@ -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; } diff --git a/huagao/CBasicPage.h b/huagao/CBasicPage.h index b968eba9..65c6211b 100644 --- a/huagao/CBasicPage.h +++ b/huagao/CBasicPage.h @@ -46,6 +46,7 @@ protected: std::function m_dataChange; public: + BOOL m_bUV; afx_msg void OnClickedBtndiscardsetting(); void SetScannerInfo(std::string hdVersion, std::string serialNum); private: diff --git a/huagao/CTwainUI.cpp b/huagao/CTwainUI.cpp index 1286d72b..94d722aa 100644 --- a/huagao/CTwainUI.cpp +++ b/huagao/CTwainUI.cpp @@ -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; diff --git a/huagao/Device/G400ScanConfig.cpp b/huagao/Device/G400ScanConfig.cpp index 064cf288..adc3a587 100644 --- a/huagao/Device/G400ScanConfig.cpp +++ b/huagao/Device/G400ScanConfig.cpp @@ -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]; diff --git a/huagao/Device/G400ScanConfig.h b/huagao/Device/G400ScanConfig.h index 7591c335..0002bee9 100644 --- a/huagao/Device/G400ScanConfig.h +++ b/huagao/Device/G400ScanConfig.h @@ -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; diff --git a/huagao/Device/GScan.h b/huagao/Device/GScan.h index 38339ffe..1a16b9db 100644 --- a/huagao/Device/GScan.h +++ b/huagao/Device/GScan.h @@ -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; diff --git a/huagao/Device/GScan200.cpp b/huagao/Device/GScan200.cpp index 6ad9cfea..e1f24f38 100644 --- a/huagao/Device/GScan200.cpp +++ b/huagao/Device/GScan200.cpp @@ -111,10 +111,6 @@ void GScan200::clear_hwerror() { } -void GScan200::setdecodepixtype(int twpixtype) -{ - pixType = (twpixtype == 0) ? 1 : 0; -} UINT32 GScan200::get_ErrorCode() { diff --git a/huagao/Device/GScan200.h b/huagao/Device/GScan200.h index 76866098..d9c85dda 100644 --- a/huagao/Device/GScan200.h +++ b/huagao/Device/GScan200.h @@ -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; diff --git a/huagao/Device/GScanO200.cpp b/huagao/Device/GScanO200.cpp index 8948c905..1b5b87a8 100644 --- a/huagao/Device/GScanO200.cpp +++ b/huagao/Device/GScanO200.cpp @@ -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 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(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(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())+"ļ"); diff --git a/huagao/Device/GScanO200.h b/huagao/Device/GScanO200.h index e7bf363b..6ac6739f 100644 --- a/huagao/Device/GScanO200.h +++ b/huagao/Device/GScanO200.h @@ -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; diff --git a/huagao/Device/GScanO400.cpp b/huagao/Device/GScanO400.cpp index 1fa7de8b..7c9b9a19 100644 --- a/huagao/Device/GScanO400.cpp +++ b/huagao/Device/GScanO400.cpp @@ -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 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(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(new G400Decode(imgData))); + set_aquire_image_count(get_aquire_image_count() + 1,get_updata_image_count()); if(!is_AndroidOrLinux) Pop_Image(); diff --git a/huagao/Device/GScanO400.h b/huagao/Device/GScanO400.h index 681fcb0e..86a66138 100644 --- a/huagao/Device/GScanO400.h +++ b/huagao/Device/GScanO400.h @@ -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; diff --git a/huagao/Device/GScanVirtual.cpp b/huagao/Device/GScanVirtual.cpp index fc238ebc..a95c1faa 100644 --- a/huagao/Device/GScanVirtual.cpp +++ b/huagao/Device/GScanVirtual.cpp @@ -148,10 +148,6 @@ void GScanVirtual::reset() } } -void GScanVirtual::setdecodepixtype(int twpixtype) -{ - pixType = twpixtype; -} UINT32 GScanVirtual::get_ErrorCode() { diff --git a/huagao/Device/GScanVirtual.h b/huagao/Device/GScanVirtual.h index 13dfa17a..f2b605c6 100644 --- a/huagao/Device/GScanVirtual.h +++ b/huagao/Device/GScanVirtual.h @@ -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; diff --git a/huagao/Device/ImageMatQueue.cpp b/huagao/Device/ImageMatQueue.cpp index 4e43fbea..52962c06 100644 --- a/huagao/Device/ImageMatQueue.cpp +++ b/huagao/Device/ImageMatQueue.cpp @@ -6,7 +6,6 @@ #include "filetools.h" #include #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> 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> buffB(new std::vector(buff->size())); - std::shared_ptr> buffF(new std::vector(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 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 dogearcall) +{ + m_DogEarDetection_callback = dogearcall; +} + + static int paperIndex = 0; void ImageMatQueue::pushMat(std::shared_ptr 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(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(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> 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,261 +408,226 @@ 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 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) + { + string msg; + auto info = m_imgCacheinfo.Take(); + if(info.path.length()==0 || !isFileExist(info.path)) { - this_thread::sleep_for(chrono::milliseconds(1)); + 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(); - //} + ImreadModes rmc; + if (scanParam.filter != 3 || scanParam.enhance_color || scanParam.hsvcorrect) + rmc = IMREAD_COLOR; + else + rmc = scanParam.pixtype == 2 ? IMREAD_COLOR : IMREAD_GRAYSCALE; - CFile frb; - if (frb.Open(CString(path.c_str()), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary)) + std::vector mats; + std::vector uvmats; + if(info.scannerType==ScannerSerial::G200Serial) + { + auto back= m_imgCacheinfo.Take(); + if(!isFileExist(back.path)) { - 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(); + msg = "error while reading g200 back image " + back.path + " ,file not exist"; + FileTools::writelog(log_ERROR,msg); } - } - - std::string path = m_imagepath.front(); - long lenght= FileTools::get_file_size(path.c_str()); - std::shared_ptr> buf(new std::vector); - 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)) + 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()) { - fwb.Read(buf->data(), lenght); - fwb.Close(); - remove(path.c_str()); + 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 { - FileTools::writelog(log_ERROR, "error while opening filename:" + path); + 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 - 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>>& buffs) -{ - vector mats; - for (auto& buf : buffs) { - ImreadModes rmc; - //int rm; - if (scanParam.filter != 3 || scanParam.enhance_color || scanParam.hsvcorrect) { - rmc = IMREAD_COLOR; - //rm = 1; - } - else { - rmc = scanParam.pixtype == 2 ? IMREAD_COLOR : IMREAD_GRAYSCALE; - //rm = scanParam.pixtype == 2 ? 1 : 6; - } - try { - cv::Mat mat = cv::imdecode(*buf, rmc); - if (mat.empty()) { - FileTools::writelog(log_ERROR,"decode image data error"); + 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) { + cv::flip(front, front, 0); + cv::flip(front, front, 1); + } + mats.push_back(back); + mats.push_back(front); } - buf.reset(); -#ifdef G200 - cv::resize(mat, mat, cv::Size(), fx, fy);//ܻСƥ ϵ׶ - mats.push_back(mat); - mat.release(); -#else // G200 - 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) { - cv::flip(front, front, 0); - cv::flip(front, front, 1); + 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(); + } } - mats.push_back(back); - mats.push_back(front); #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; - for (int j = 0; j < m_iaList.size(); j++) { - m_iaList[j]->apply(mats, scanParam.is_duplex); - } - FileTools::writelog(log_INFO, "ͼʱ " + to_string(sw.elapsed_ms())); - for (int i = 0; i < mats.size(); i++) { - if (!scanParam.is_duplex && i == 1) { - mats[i].release(); - break; - } - if (!mats[i].empty()) { - IMat2Bmp idata; - if (scanParam.pixtype == 1 && scanParam.hsvcorrect) - if (mats[i].channels() == 3) - cvtColor(mats[i], mats[i], cv::COLOR_BGR2GRAY); - idata = (scanParam.pixtype == 0 || (((scanParam.automaticcolortype == 0) && (scanParam.automaticcolor == true)) && (mats[i].channels() == 1))) ? (IMat2Bmp)Mat2BmpBw(mats[i], scanParam.resolution_dst) : Mat2Bmp(mats[i], scanParam.resolution_dst); - if (!scanParam.multi_output_red) - mats[i].release(); + }//g400 serials - auto data = idata.getBmpDataBuffer(); - //FILE* fd=fopen("D:\\0.bmp","w+"); - //fwrite(data->data(), data->size(),1 , fd); - //fclose(fd); - EnqueueBmpBuffer(data); - data.reset(); - } - else - { - FileTools::writelog(log_ERROR,"enqueue image is empty " + std::to_string(index++)); - } - } + std::vector rects; + std::vector angleResults; + bool isDesaskew = false; - if (scanParam.multi_output_red) { + 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(ptr)->rotatedROIs(); + isDesaskew = dynamic_cast(ptr)->isDesaskew(); + } + else if (typeid(*ptr) == typeid(CImageApplyRotation)) + angleResults = dynamic_cast(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 (!mats[i].empty()) { - ImageMultiOutput m_mlt; - Mat ret = m_mlt.GetMultiFilterMat(mats[i], 2); + if (!scanParam.is_duplex && i == 1) { mats[i].release(); - if (!ret.empty()) { - if (!scanParam.is_duplex && i == 1) { + break; + } + if (!mats[i].empty()) { + IMat2Bmp idata; + if (scanParam.pixtype == 1 && scanParam.hsvcorrect) + if (mats[i].channels() == 3) + cvtColor(mats[i], mats[i], cv::COLOR_BGR2GRAY); + idata = (scanParam.pixtype == 0 || (((scanParam.automaticcolortype == 0) && (scanParam.automaticcolor == true)) && (mats[i].channels() == 1))) ? (IMat2Bmp)Mat2BmpBw(mats[i], scanParam.resolution_dst) : Mat2Bmp(mats[i], scanParam.resolution_dst); + if (!scanParam.multi_output_red) + mats[i].release(); + + auto data = idata.getBmpDataBuffer(); + EnqueueBmpBuffer(data); + data.reset(); + } + else + { + FileTools::writelog(log_ERROR, "enqueue image is empty " + std::to_string(index++)); + } + } + + if (scanParam.multi_output_red) { + for (int i = 0; i < mats.size(); i++) { + if (!mats[i].empty()) { + ImageMultiOutput m_mlt; + Mat ret = m_mlt.GetMultiFilterMat(mats[i], 2); + mats[i].release(); + if (!ret.empty()) { + if (!scanParam.is_duplex && i == 1) { + ret.release(); + break; + } + Mat2Bmp mb(ret, scanParam.resolution_dst); + auto data = mb.getBmpDataBuffer(); ret.release(); - break; + EnqueueBmpBuffer(data); + data.reset(); } - Mat2Bmp mb(ret, scanParam.resolution_dst); - auto data = mb.getBmpDataBuffer(); - ret.release(); - EnqueueBmpBuffer(data); - data.reset(); } } } + mats.clear(); +#ifdef UV + PaniusCount(scanParam.hardwarecaps.en_uv ? 2 : 1); +#else + PaniusCount(); +#endif + } - mats.clear(); - PaniusCount(); } G400Decode::G400Decode(std::shared_ptr> buff) { m_buffs.push_back(buff); +} + + +G200Decode::G200Decode(std::shared_ptr> 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> buffB(new std::vector(buff->size())); + std::shared_ptr> buffF(new std::vector(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(); } \ No newline at end of file diff --git a/huagao/Device/ImageMatQueue.h b/huagao/Device/ImageMatQueue.h index f585e6b2..6b0baf42 100644 --- a/huagao/Device/ImageMatQueue.h +++ b/huagao/Device/ImageMatQueue.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #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> buff); + virtual ~G200Decode() + { + + } }; class G400Decode : public IDecode { public: G400Decode(std::shared_ptr> 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 buf); std::shared_ptr> popBmpdata(); @@ -172,29 +195,36 @@ public: int orginimgcount(); void setscanflags(const bool flags) { is_scanning = flags; } void updatefixratio(float& hratio, float& vratio); - std::function DogEarDetection_callback; - std::function Getimagenumber; - std::queue m_imagepath; - std::queue>> m_data; + void SetGetimgnumcall(std::function getimgnumcall); + void SetDogEarCallback(std::function dogearcall); + private: void proc(); - void imageproceing(std::vector>>& buffs); void EnqueueBmpBuffer(std::shared_ptr>); - void PaniusCount(); - BlockingQueue>>m_imagedata; - std::unique_ptr m_threadProc; + void PaniusCount(int count=1); + void init_cachethread(); + void cache_run(); + //清除缓存文件 + void clear_cachefiles(); + + BlockingQueue>> m_imagedata;//已处理图像队列 + BlockingQueue m_imgCacheinfo;//缓存图像队列 + BlockingQueue> m_rawBuffs;//原图队列 + std::unique_ptr m_threadProc;//图像处理线程 + std::unique_ptr 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 fw; - std::unique_ptr fr; GScanCap scanParam; Device::PaperSize papersize; std::shared_ptr m_dogear; std::vector> m_iaList; //ͼÏñ´¦Àíº¯Êý½Ó¿Ú - BlockingQueue> m_rawBuffs; float fx, fy; + std::function m_DogEarDetection_callback; + std::function m_Getimagenumber; + snowflake_t m_snowflake; }; \ No newline at end of file diff --git a/huagao/Device/PublicFunc.h b/huagao/Device/PublicFunc.h index c9ca89ff..d87c2891 100644 --- a/huagao/Device/PublicFunc.h +++ b/huagao/Device/PublicFunc.h @@ -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 { diff --git a/huagao/GscanJsonConfig.cpp b/huagao/GscanJsonConfig.cpp index 3b8c1ba1..059f55bd 100644 --- a/huagao/GscanJsonConfig.cpp +++ b/huagao/GscanJsonConfig.cpp @@ -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; @@ -99,7 +103,10 @@ void GscanJsonConfig::SaveGscanCapConfig(const GScanCap & gcap, const std::strin //outJson["Config"].Add(DB_DEVNMAX, (int)(pConfigItem->DBlank_DevnMax)); 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 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 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 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 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); diff --git a/huagao/ImageProcess/ImageApplyAutoCrop.cpp b/huagao/ImageProcess/ImageApplyAutoCrop.cpp index ec433521..d5f0896c 100644 --- a/huagao/ImageProcess/ImageApplyAutoCrop.cpp +++ b/huagao/ImageProcess/ImageApplyAutoCrop.cpp @@ -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& 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& 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()) diff --git a/huagao/ImageProcess/ImageApplyAutoCrop.h b/huagao/ImageProcess/ImageApplyAutoCrop.h index e75674ba..41a78827 100644 --- a/huagao/ImageProcess/ImageApplyAutoCrop.h +++ b/huagao/ImageProcess/ImageApplyAutoCrop.h @@ -21,23 +21,23 @@ #include "ImageApply.h" -class CImageApplyAutoCrop : public CImageApply +class CImageApplyAutoCrop : public CImageApply { public: CImageApplyAutoCrop(); - /* - * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剪 - * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 - * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 - * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像素 - * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true - * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false - * threshold [in]:二值化阈值,取值范围(0, 255),默认40 - * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默认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); + /* + * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剪 + * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 + * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 + * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像素 + * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true + * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false + * threshold [in]:二值化阈值,取值范围(0, 255),默认40 + * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默认40 + * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进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& 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 m_maxContour; + std::vector m_rects; }; #endif // !IMAGE_APPLY_AUTO_CROP_H diff --git a/huagao/ImageProcess/ImageApplyHeaders.h b/huagao/ImageProcess/ImageApplyHeaders.h index 6a94ede1..4cf6caab 100644 --- a/huagao/ImageProcess/ImageApplyHeaders.h +++ b/huagao/ImageProcess/ImageApplyHeaders.h @@ -17,5 +17,5 @@ #include "ImageApplyHSVCorrect.h" #include "ImageApplyDetachNoise.h" #include "ImageApplyColorRecognition.h" - +#include "ImageApplyUV.h" #endif diff --git a/huagao/ImageProcess/ImageApplyRotation.cpp b/huagao/ImageProcess/ImageApplyRotation.cpp index 801fcc02..8d51e35a 100644 --- a/huagao/ImageProcess/ImageApplyRotation.cpp +++ b/huagao/ImageProcess/ImageApplyRotation.cpp @@ -28,8 +28,9 @@ CImageApplyRotation::~CImageApplyRotation() #endif } -void CImageApplyRotation::apply(cv::Mat & pDib, int side) +void CImageApplyRotation::apply(cv::Mat& pDib, int side) { + m_angleResult = 0; #ifdef LOG FileTools::write_log("imgprc.txt", "enter CImageApplyRotation apply"); #endif // LOG @@ -44,44 +45,48 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side) if (m_rotation == RotationType::AutoTextOrientation) //�Զ��ı�����ʶ�� { #ifdef USE_TESSERCAT - if (osd) - { - cv::Mat temp; + if (osd) + { + cv::Mat temp; if (m_dpi != 200) { double scale = 200 / static_cast(m_dpi); - int new_w = static_cast(pDib.cols * scale) / 4 * 4; + int new_w = (pDib.cols * scale + 3) / 4 * 4; int new_h = pDib.rows * scale; cv::resize(pDib, temp, cv::Size(new_w, new_h)); } else temp = pDib(cv::Rect(0, 0, pDib.cols / 4 * 4, pDib.rows)).clone(); - if (temp.channels() == 3) - cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); - cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU); + if (temp.channels() == 3) + cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); + cv::threshold(temp, temp, 180, 255, cv::THRESH_OTSU); HG_OCR* ptr_osd = reinterpret_cast(osd); - int orientation = ptr_osd->orientation(temp.data, temp.cols, temp.rows, temp.channels(), 200); + int orientation = ptr_osd->orientation(temp.data, temp.cols, temp.rows, temp.channels(), 200); - switch (orientation) - { - case 90: - cv::transpose(pDib, pDib); + switch (orientation) + { + case 90: + cv::transpose(pDib, pDib); cv::flip(pDib, pDib, 0); - break; - case 180: + m_angleResult = 90; + break; + case 180: cv::flip(pDib, pDib, 0); cv::flip(pDib, pDib, 1); - break; - case 270: + m_angleResult = 180; + break; + case 270: cv::transpose(pDib, pDib); cv::flip(pDib, pDib, 1); - break; - default: - break; - } - } + m_angleResult = 270; + break; + default: + m_angleResult = 0; + break; + } + } #endif } else if (m_backTranspose && side == 1) //������ת180 @@ -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 @@ -120,11 +129,13 @@ void CImageApplyRotation::apply(cv::Mat & pDib, int side) void CImageApplyRotation::apply(std::vector& mats, bool isTwoSide) { - (void)isTwoSide; + (void)isTwoSide; + m_angleResults.clear(); int i = 0; for (cv::Mat& var : mats) { if (!var.empty()) { apply(var, i); + m_angleResults.push_back(m_angleResult); i++; } } diff --git a/huagao/ImageProcess/ImageApplyRotation.h b/huagao/ImageProcess/ImageApplyRotation.h index 2c706318..5412dd9f 100644 --- a/huagao/ImageProcess/ImageApplyRotation.h +++ b/huagao/ImageProcess/ImageApplyRotation.h @@ -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,27 +8,21 @@ 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]:ǰͼDPIòrotationΪAutoTextOrientationʱЧʶĸ巽ʱĬϽͼ任Ϊ200DPIʶ - * tessadataPath [in]:ѵļ·òrotationΪAutoTextOrientationʱЧ - */ CImageApplyRotation(RotationType rotation, bool isBackTransposed = false, int dpi = 200, const char* tessdataPath = nullptr); virtual ~CImageApplyRotation(); - virtual void apply(cv::Mat & pDib, int side) override; + virtual void apply(cv::Mat& pDib, int side) override; virtual void apply(std::vector& mats, bool isTwoSide); @@ -49,6 +30,10 @@ public: int getDPI() { return m_dpi; } + int angleResult() { return m_angleResult; } + + const std::vector& angleResults() { return m_angleResults; } + RotationType getRotationType() { return m_rotation; } void setBackTransposed(bool enabled) { m_backTranspose = enabled; } @@ -63,6 +48,9 @@ private: int m_dpi; void* osd; + + int m_angleResult; + std::vector m_angleResults; }; #endif // !IMAGE_APPLY_ROTATION_H diff --git a/huagao/ImageProcess/ImageApplyUV.cpp b/huagao/ImageProcess/ImageApplyUV.cpp new file mode 100644 index 00000000..c710074f --- /dev/null +++ b/huagao/ImageProcess/ImageApplyUV.cpp @@ -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(cv::max(0, cv::min(i - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(i + m_contrast, 255))); + } +} + +void ImageApplyUV::Apply(cv::Mat& image, const cv::Mat& uv, int dpi, int thresh) +{ + update_lutData(12); + cv::LUT(uv, lut, uv); + Mat uv_resize; + cv::resize(uv, uv_resize, cv::Size(uv.cols * SCA / dpi, uv.rows * SCA / dpi)); + if (uv_resize.channels() == 3) + cv::cvtColor(uv_resize, uv_resize, cv::COLOR_BGR2GRAY); + cv::threshold(uv_resize, uv_resize, 0, 255, THRESH_OTSU); + cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1500 / dpi, 1500 / dpi)); + cv::dilate(uv_resize, uv_resize, element); + std::vector> contours; + std::vector hierarchy; + findContours1(uv_resize, contours, hierarchy, cv::RETR_EXTERNAL); + + std::map map_color; + for (int i = 0; i < contours.size(); i++) + { + cv::Rect roi = cv::boundingRect(contours[i]); + roi.x *= dpi / SCA; + roi.y *= dpi / SCA; + roi.width *= dpi / SCA; + roi.height *= dpi / SCA; + + purgeQR_kernal(image, roi, map_color, dpi, thresh); + } +} + +cv::Mat ImageApplyUV::Apply(const cv::Mat& image, const cv::Mat& uv, const cv::RotatedRect& uvRoi, bool isDesaskew, int angle) +{ + 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 map_color, int dpi, int threshold) +{ + cv::Mat image_roi = image(roi); + cv::Mat mask; + cv::cvtColor(image_roi, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, 127, 255, cv::THRESH_OTSU); + cv::Mat image_resize; + cv::resize(image, image_resize, cv::Size(image.cols, 800)); + + for (int i = 0, cols = image_roi.cols, rows = image_roi.rows; i < cols; i++) + { + cv::Scalar color_fill; + if (map_color.find(i + roi.x) == map_color.end()) + { + color_fill = getColor(image_resize, roi.x + i, threshold); + map_color[i + roi.x] = color_fill; + } + else + color_fill = map_color[i + roi.x]; + + for (int j = 0; j < rows; j++) + { + if (*mask.ptr(j, i)) + { + uchar* color = image_roi.ptr(j, i); + color[0] = color_fill[0]; + color[1] = color_fill[1]; + color[2] = color_fill[2]; + } + } + } +} + +void ImageApplyUV::findContours1(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) +{ + CvMat c_image = 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 all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); + size_t total = all_contours.size(); + contours.resize(total); + + cv::SeqIterator it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + reinterpret_cast(c)->color = static_cast(i); + int count = c->total; + int* data = new int[static_cast(count * 2)]; + cvCvtSeqToArray(c, data); + for (int j = 0; j < count; j++) + contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); + + delete[] data; + } + + hierarchy.resize(total); + it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; + int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; + int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; + int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; + hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); + } + + storage.release(); +} + +cv::Scalar ImageApplyUV::getColor(const cv::Mat& image, int col, int threshold) +{ + cv::Scalar color(0, 0, 0); + int num = 0; + + for (int i = 0, length = image.rows; i < length; i++) + { + const uchar* ptr = image.ptr(i, col); + int gray = (ptr[0] * 30 + ptr[1] * 59 + ptr[2] * 11) / 100; + if (gray > threshold) + { + color[0] += ptr[0]; + color[1] += ptr[1]; + color[2] += ptr[2]; + num++; + } + } + + if (num) + color /= num; + else + color[0] = color[1] = color[2] = 255; + + return color; +} diff --git a/huagao/ImageProcess/ImageApplyUV.h b/huagao/ImageProcess/ImageApplyUV.h new file mode 100644 index 00000000..090ccebe --- /dev/null +++ b/huagao/ImageProcess/ImageApplyUV.h @@ -0,0 +1,21 @@ +#pragma once +#include +#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 map_color, int dpi, int threshold); + void findContours1(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, + int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0)); + cv::Scalar getColor(const cv::Mat& image, int col, int threshold); + void update_lutData(int contrast); + cv::Mat lut; +}; + diff --git a/huagao/huagaods.cpp b/huagao/huagaods.cpp index 7bea23e5..94701cbd 100644 --- a/huagao/huagaods.cpp +++ b/huagao/huagaods.cpp @@ -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((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((CapType)(CapTypeEx::TwEx_UVModel), m_scanparam->hardwarecaps.en_uv); + return success(); + case Msg::GetDefault: + data = Capability::createOneValue((CapType)(CapTypeEx::TwEx_UVModel), Bool(false)); + return success(); + case Msg::Set: { + auto mech = data.currentItem(); + m_scanparam->hardwarecaps.en_uv = mech; + return success(); + } + default: + return capBadOperation(); + } + }; +#endif return success(); } diff --git a/huagao/huagaotwds.rc b/huagao/huagaotwds.rc index 1210243d..0f4dec46 100644 Binary files a/huagao/huagaotwds.rc and b/huagao/huagaotwds.rc differ diff --git a/huagao/resource.h b/huagao/resource.h index bb3b2238..2c385f8b 100644 Binary files a/huagao/resource.h and b/huagao/resource.h differ diff --git a/huagao/stdafx.h b/huagao/stdafx.h index 5dd161db..3d2381a0 100644 Binary files a/huagao/stdafx.h and b/huagao/stdafx.h differ