#include "StdAfx.h" #include "ImageMatQueue.h" #include "PublicFunc.h" #include "ImageProcess/ImageApplyHeaders.h" #include "ImageMultiOutput.h" #include "filetools.h" #include #include "StopWatch.h" //#include "JpegBuffer.h" using namespace cv; 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) ,fx(1.001) ,fy(1.007) ,DogEar_index(0) ,is_DogEar(false) { atm_orgin_image_remains = 0; m_dogear.reset(new CImageApplyDogEarDetection(40,1.0,200)); } void ImageMatQueue::run() { if (!m_threadProc) { bRun = true; m_threadProc.reset(new thread(&ImageMatQueue::proc, this)); } } bool ImageMatQueue::get_isDogEar() { return is_DogEar; } void ImageMatQueue::reset_DogEar() { is_DogEar = false; DogEar_index = 0; } int ImageMatQueue::orginimgcount() { return atm_orgin_image_remains; } void ImageMatQueue::updatefixratio(float& hratio, float& vratio) { if (hratio > 0.10f && hratio < 3.0f && vratio >0.10f && vratio < 3.0f) { this->fx = hratio; this->fy = vratio; } else { FileTools::writelog(log_ERROR,"error horizental or vertical ratio"); } } ImageMatQueue::~ImageMatQueue(void) { m_rawBuffs.Clear(); m_imagedata.Clear(); m_rawBuffs.ShutDown(); m_imagedata.ShutDown(); if (m_threadProc) { bRun = false; m_threadProc->join(); m_threadProc.reset(); } } static int paperIndex = 0; void ImageMatQueue::pushMat(std::shared_ptr data) { Getimagenumber(true); m_rawBuffs.Put(data); atm_orgin_image_remains++; //string paperindexinfo = "Get the index of "+to_string(++paperIndex)+" Paper"; //FileTools::write_log("D:\\1.txt", paperindexinfo); } std::shared_ptr> ImageMatQueue::popBmpdata() { return m_imagedata.Take(); } bool ImageMatQueue::valid() { return m_imagedata.Size(); } void ImageMatQueue::clear() { m_rawBuffs.Clear(); m_imagedata.Clear(); atm_orgin_image_remains = 0; } void ImageMatQueue::rawBuffsclear() { m_rawBuffs.Clear(); } void ImageMatQueue::setparam(const GScanCap& param) { paperIndex = 0; ischeck_dogear = param.is_dogeardetection; //FileTools::write_log("D:\\1.txt", "RESET PAPER COUNT"); scanParam = param; //scanParam.is_duplex = 0; //scanParam.imageRotateDegree = 90.0f; m_iaList.clear(); if (scanParam.fillhole.is_fillhole) { float ratio = scanParam.fillhole.fillholeratio / 100.0; m_iaList.push_back(shared_ptr(new CImageOutHole(200, ratio, 50))); } //确保能够获取正反两面图 { bool islongcustomcrop = param.papertype == TwSS::USStatement; //bool isautocrop = param.papertype == TwSS::None; CSize fixedSize; #ifdef REAL300DPI fixedSize = papersize.GetPaperSize(param.papertype, param.resolution_dst > 240.0f ? 300.0f : 200.0f, param.paperAlign); #else // REAL300DPI 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))); /* 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)) m_iaList.push_back(shared_ptr(new CImageApplyResize(CImageApplyResize::ResizeType::DSIZE, cv::Size(fixedSize.cx, fixedSize.cy), 1.0, 1.0)));*/ } if (param.is_autodiscradblank_normal || param.is_autodiscradblank_vince) { //m_iaList.push_back(shared_ptr(new CImageApplyDiscardBlank())); CImageApplyDiscardBlank* disBlank = new CImageApplyDiscardBlank(); //跳过空白页阈值 int area = 200; int intensity = 15; int maxHeight = 3307;//A3 height //页面最大高度获取 if (param.papertype == TwSS::MaxSize) maxHeight = 6614; //阈值参数赋值 if (param.discardblank_percent < 10) { area = 70 + (int)((param.discardblank_percent - 1) * 13.33); intensity = 8 + param.discardblank_percent / 2; } else if (param.discardblank_percent < 20) { area = 190 + (param.discardblank_percent - 10) * 14; intensity = 15; } else if (param.discardblank_percent < 40) { area = 400 + (param.discardblank_percent - 20) * 10; intensity = 20; } else if (param.discardblank_percent < 60) { area = 600 + (param.discardblank_percent - 40) * 20; intensity = 20; } else if (param.discardblank_percent < 80) { area = 1000 + (param.discardblank_percent - 60) * 55; intensity = 30; } else { area = 2100 + (param.discardblank_percent - 80) * (maxHeight - 2100) / 20; intensity = 40; } //判断是否为跳过空白页发票 if (param.is_autodiscradblank_vince) { area *= 1.5; intensity *= 1.5; } //设置参数阈值 disBlank->setMinArea(area); disBlank->setIntensity(intensity); m_iaList.push_back(shared_ptr(disBlank)); //m_iaList.push_back(shared_ptr(new CImageApplyDiscardBlank(param.areanum,param.devnmax))); } //filter 0 r 1 g 2 b 3 none enhance color 0 none 1 r 2 g 3 b if (param.filter != 3 || param.enhance_color) { int channel = 0; //filter none r g b enhance none r g b if (param.filter != 3) { channel = param.filter; } else { channel = param.enhance_color + 4; } m_iaList.push_back(shared_ptr(new CImageApplyChannel(static_cast(channel)))); } if (param.brightness != 0 || param.contrast != 0 || param.gamma != 1.0) { double aa = (254 / 2000.0) * param.brightness + 0.5; int bright = ceil(aa);//[-127,128] 0.128=256.0/2000.0 int contrast=0.0; //= (int)(param.contrast * 0.036);;//[-36,36] 0.036=72.0/2000.0; if(param.contrast<0.0) // 暂不修改对比度,彩色文稿色偏 contrast = (int)(param.contrast * 0.036); else contrast = (int)(param.contrast * 0.018); m_iaList.push_back(shared_ptr(new CImageApplyAdjustColors(bright, contrast, param.gamma))); } //答题卡除红 if (scanParam.hsvcorrect) { m_iaList.push_back(shared_ptr(new CImageApplyHSVCorrect(CImageApplyHSVCorrect::CorrectOption::Red_Removal))); } //锐化 if (param.sharpen) { SharpenBlur sb = (SharpenBlur)param.sharpen; m_iaList.push_back(shared_ptr(new CImageApplySharpen(sb))); } //自动颜色识别 if (param.automaticcolor) m_iaList.push_back(shared_ptr(new CImageApplyColorRecognition(param.automaticcolortype==1? CImageApplyColorRecognition::ColorRecognitionMode::Color_Gray:CImageApplyColorRecognition::ColorRecognitionMode::Color_Mono))); //缩放 if (param.resolution_dst != param.resolution_native) { CImageApplyResize* apply; bool islongcustomcrop = false; if (param.papertype == TwSS::USStatement) islongcustomcrop = true; if (param.is_autocrop || islongcustomcrop) { double ratio = param.resolution_dst / 200.0;// apply = new CImageApplyResize(CImageApplyResize::ResizeType::RATIO, cv::Size(0, 0), ratio, ratio); } else { CSize dSize = papersize.GetPaperSize(param.papertype, param.resolution_dst, param.paperAlign); apply = new CImageApplyResize(CImageApplyResize::ResizeType::DSIZE, cv::Size(dSize.cx, dSize.cy), 1.0, 1.0); } m_iaList.push_back(shared_ptr< CImageApply>(apply)); } //二值化 if (param.pixtype == 0) //threshold m_iaList.push_back(shared_ptr(new CImageApplyBWBinaray(CImageApplyBWBinaray::ThresholdType::THRESH_BINARY))); //黑白降噪优化 if (scanParam.detachnoise.is_detachnoise&&scanParam.pixtype==0) { m_iaList.push_back(shared_ptr(new CImageApplyDetachNoise(scanParam.detachnoise.detachnoise))); } if (scanParam.en_fold) { m_iaList.push_back(shared_ptr(new CImageApplyConcatenation(CImageApplyConcatenation::horizontal,cv::Scalar(255,255,255)))); } if (param.imageRotateDegree != 0.0 || param.is_backrotate180 || param.is_autotext) { CImageApplyRotation::RotationType type; if (param.imageRotateDegree > 89.0f && param.imageRotateDegree < 91.0f) type = CImageApplyRotation::RotationType::Rotate_90_clockwise; else if (param.imageRotateDegree > 269.0f && param.imageRotateDegree < 271.0f) type = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; else if (param.imageRotateDegree > 179.0f && param.imageRotateDegree < 181.0f) type = CImageApplyRotation::RotationType::Rotate_180; else type = CImageApplyRotation::RotationType::Invalid; if (param.is_autotext) type = CImageApplyRotation::RotationType::AutoTextOrientation; TCHAR szIniFile[MAX_PATH] = { 0 }; SHGetSpecialFolderPath(NULL, szIniFile, CSIDL_WINDOWS, TRUE); #ifdef LANXUM _tcscat(szIniFile, _T("\\twain_32\\LANXUMSCAN\\tessdata")); #else _tcscat(szIniFile, _T("\\twain_32\\HuaGoScan\\tessdata")); #endif // int iLen = WideCharToMultiByte(CP_ACP, 0, szIniFile, -1, NULL, 0, NULL, NULL); char* chRtn = new char[iLen * sizeof(char)]; WideCharToMultiByte(CP_ACP, 0, szIniFile, -1, chRtn, iLen, NULL, NULL); m_iaList.push_back(shared_ptr(new CImageApplyRotation(type, param.is_backrotate180, param.resolution_dst, chRtn))); delete[] chRtn; } } void ImageMatQueue::EnqueueBmpBuffer(std::shared_ptr> bmpdata) { m_imagedata.Put(bmpdata); } void ImageMatQueue::PaniusCount() { atm_orgin_image_remains--; Getimagenumber(false); } 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(); } 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()) { this_thread::sleep_for(chrono::milliseconds(1)); 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> 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)) { 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>>& 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"); } 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); } 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(); 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++)); } } 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(); EnqueueBmpBuffer(data); data.reset(); } } } } mats.clear(); PaniusCount(); } G400Decode::G400Decode(std::shared_ptr> buff) { m_buffs.push_back(buff); }