From bc6243c4a06cbb5852c770c5a3913df49617ce5a Mon Sep 17 00:00:00 2001 From: 13038267101 Date: Fri, 22 Sep 2023 14:17:06 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B47010=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hgdriver/hgdev/common_setting.h | 24 ++- hgdriver/hgdev/hg_scanner.cpp | 11 +- hgdriver/hgdev/hg_scanner.h | 5 + hgdriver/hgdev/hg_scanner_300.cpp | 248 ++++++++++++++------- hgdriver/hgdev/hg_scanner_300.h | 19 +- hgdriver/hgdev/image_process.cpp | 347 +++++++++++++++++++++++++++++- hgdriver/hgdev/image_process.h | 9 +- 7 files changed, 575 insertions(+), 88 deletions(-) diff --git a/hgdriver/hgdev/common_setting.h b/hgdriver/hgdev/common_setting.h index 6429794..fc47f8f 100644 --- a/hgdriver/hgdev/common_setting.h +++ b/hgdriver/hgdev/common_setting.h @@ -10,6 +10,7 @@ #include #include #include "sane/sane_option_definitions.h" +#include ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 硬件配置项定义 // @@ -702,6 +703,26 @@ namespace setting_hardware //硬件协议定义 -OVER namespace setting3288dsp { + union FLAT_INFO + { + struct + { + unsigned int dpi : 5; + unsigned int colormode : 1; + unsigned int is_whiteimage : 1; + unsigned int status : 8; + unsigned int reversed : 1; + unsigned int datalen : 16; + }params; + unsigned int value; + }; + + struct FLAT_INFO_IMAGE + { + FLAT_INFO info; + cv::Mat flat_lut; + }; + struct HG_JpegCompressInfo { unsigned int data_type; @@ -914,7 +935,8 @@ namespace setting3288dsp GETMOTORPARAM = 0x202, GETMOTORPARMLEN = 0x203, SETMOTORPARAM = 0x204, - SETMOTORPARAMLEN = 0x205 + SETMOTORPARAMLEN = 0x205, + DEVICES_7010 = 0x7010 }; typedef enum tagUsbKeyWords UsbKeyWords, * PUsbKeyWords; //G300 G400 纸张类型协议 注:只支持3288 300 400 diff --git a/hgdriver/hgdev/hg_scanner.cpp b/hgdriver/hgdev/hg_scanner.cpp index 41885cd..04ad15b 100644 --- a/hgdriver/hgdev/hg_scanner.cpp +++ b/hgdriver/hgdev/hg_scanner.cpp @@ -3025,6 +3025,14 @@ hg_imgproc::IMGPRCPARAM hg_scanner::get_image_process_object(int model) param.double_side = img_conf_.is_duplex; param.dpi = img_conf_.resolution_dst; param.cis_image = is_cis_image; + param.width = 0; //目前只有7010使用到了 + param.height = 0 ; + if(firmware_sup_device_7010) + { + param.width = mat_width; + param.height = mat_height; + } + param.device_7010 = firmware_sup_device_7010; //img_conf_.brightness = (float)bright_; //img_conf_.contrast = (float)contrast_; @@ -4856,7 +4864,8 @@ void hg_scanner::image_process(std::shared_ptr& buffer, uint32_t id void* buf = NULL; hg_imgproc::load_buffer(ImagePrc_pHandle_, buffer); - hg_imgproc::decode(ImagePrc_pHandle_, pid_, &img_conf_, ¶m); + + hg_imgproc::decode(ImagePrc_pHandle_, pid_, &img_conf_, ¶m, correction_image_map_); (this->*dump_img_)(ImagePrc_pHandle_, "decode"); if (is_dpi_color_check) diff --git a/hgdriver/hgdev/hg_scanner.h b/hgdriver/hgdev/hg_scanner.h index 0cd1e99..33de5c4 100644 --- a/hgdriver/hgdev/hg_scanner.h +++ b/hgdriver/hgdev/hg_scanner.h @@ -384,6 +384,9 @@ protected: bool firmware_sup_morr_; //固件支持 摩尔纹 139 239-3C0518 bool firmware_sup_color_fill_; //固件支持 色彩填充 139 239 439 -3C bool firmware_sup_history_cnt; //固件支持 清除历史张数 3288 G300 220303 + bool firmware_sup_device_7010; //G300 设备但是7010 2023/9/21 + int mat_width; + int mat_height; SCANCONF img_conf_; //此参数外部不做任何改变,请在writedown_image_configuration做修改 std::string img_type_; @@ -399,6 +402,8 @@ protected: int stop_fatal_; BlockingQueue> imgs_; + std::mapcorrection_image_map_; + uint32_t fetching_id_; // for sane read image ext info. added on 2023-01-13 void change_setting_language(bool init); diff --git a/hgdriver/hgdev/hg_scanner_300.cpp b/hgdriver/hgdev/hg_scanner_300.cpp index e71b906..b5af0db 100644 --- a/hgdriver/hgdev/hg_scanner_300.cpp +++ b/hgdriver/hgdev/hg_scanner_300.cpp @@ -81,27 +81,43 @@ hg_scanner_300::hg_scanner_300(const char* dev_name,int pid, usb_io* io) : hg_scanner(G100Serial, dev_name, io,pid) ,papersize(pid) ,is_devs_sleep_(false) - ,pdata(NULL) ,index_ (0) + , first_frame_total(0) + , last_frame_total(0) { dsp_config.value = 0; dsp_config.params_3288.enableLed = 1; //默认值 dsp_config.params_3288.isCorrect = 1; - initdevice(); + + int ret = get_device_type(firmware_sup_device_7010); + if (firmware_sup_device_7010 && ret == SCANNER_ERR_OK) + { + get_correction_image(0, 1, 1); + get_correction_image(1, 1, 0); + get_correction_image(2, 2, 1); + get_correction_image(3, 2, 0); + get_correction_image(4, 3, 1); + get_correction_image(5, 3, 0); + } + else + { + initdevice(); - std::string fv(get_firmware_version()), - sn(get_serial_num()); - if (fv.empty() || sn.empty()) - return; + std::string fv(get_firmware_version()), + sn(get_serial_num()); + if (fv.empty() || sn.empty()) + return; - string dev = fv.substr(0, 2); - string ver = fv.substr(2, 3); - string date = fv.substr(5, 5); - string year = fv.substr(4, 2); - string devType; - string year_date = fv.substr(4, 6); + string dev = fv.substr(0, 2); + string ver = fv.substr(2, 3); + string date = fv.substr(5, 5); + string year = fv.substr(4, 2); + string devType; + string year_date = fv.substr(4, 6); + + firmware_sup_morr_ = year_date.compare("230724") >= 0 ? true : false; + } - firmware_sup_morr_ = year_date.compare("230724") >= 0 ? true : false; #ifndef MAPPING_FUNCTION_IN_BASE init_setting_map(setting_map_, ARRAY_SIZE(setting_map_));//优先初始化 @@ -253,6 +269,17 @@ void hg_scanner_300::thread_handle_usb_read(void) } if (ret == SCANNER_ERR_OK && usb.u32_Count > 0) { + + if (firmware_sup_device_7010) + { + ret = get_img_data_7010(); + if (ret != SCANNER_ERR_OK) + { + status_ = ret; + break; + } + continue; + } int totalNum = usb.u32_Count & 0x3fffffff; // 2022-08-04: 兼容Android,默认图片大小均在1GB以内 VLOG_MINI_2(LOG_LEVEL_WARNING, "Get Scaner Image Size:%d bytes,Image Num[%d]\n", totalNum,img_num); img_num++; @@ -553,92 +580,70 @@ int hg_scanner_300::get_img_data(std::shared_ptr &imagedata) return status_ = ret; } -int hg_scanner_300::get_img_data_7010(std::shared_ptr& imagedata) +static int k = 0; +int hg_scanner_300::get_img_data_7010() { - int total = imagedata->size(), - ret = SCANNER_ERR_OK, - index = 0, - block = total; + int ret = SCANNER_ERR_OK; - USBCB usb{ setting3288dsp::GET_IMAGE, 0, total }; + USBCB usb{ setting3288dsp::GET_IMAGE, 0, 0 }; { std::lock_guard lock(io_lock_); ret = writeusb(usb); - + io_->set_timeout(800); setting3288dsp::HG_JpegCompressInfo info; - - int len = sizeof(int) * 7; + StopWatch sw; + sw.reset(); + int len = sizeof(int) * 8; ret = io_->read_bulk(&info, &len); - std::vector jpgdata; - - jpgdata.resize(info.DataLength); - ret = io_->read_bulk(&jpgdata[0], (int*)&info.DataLength); - + int val = info.DataLength; int width = info.width; int hegiht = info.height; - int frame_total = info.index_frame; + + + //cv::Mat mat1 = cv::Mat(hegiht, width, CV_8UC1, jpgdata.data(), cv::Mat::AUTO_STEP); + //static int cnt = 0; + if (info.first_frame) { - pdata = (char*)malloc(width * hegiht * frame_total); + first_frame_total = info.index_frame; + jpgdata_.clear(); + jpgdata_.resize(width * hegiht * first_frame_total); + index_ = 0; } - cv::ImreadModes rmc = cv::IMREAD_GRAYSCALE; - - cv::Mat mat(cv::imdecode(jpgdata, rmc)); - //cv::imwrite("C://Users//modehua//Desktop//image//opencv"+to_string(cnt)+".jpg", mat); - //cnt++; - if (!pdata) - { - return SCANNER_ERR_INSUFFICIENT_MEMORY; - } - memcpy(pdata + index_, (void*)mat.data, mat.total() * mat.elemSize()); - index_ += mat.total() * mat.elemSize(); + ret = io_->read_bulk(&jpgdata_[index_], &val); + index_ += val; if (info.last_frame) { - cv::Mat mat = cv::Mat(hegiht * frame_total, width, CV_8UC1, pdata, cv::Mat::AUTO_STEP); - //cv::imwrite("C://Users//modehua//Desktop//image//2_opencv.jpg", mat); - if (mat.empty()) - { - return SCANNER_ERR_INSUFFICIENT_MEMORY; - } - int width = mat.cols; - int height = mat.rows; - cv::Mat m_dst = mat; - if (image_prc_param_.bits.color_mode == 2) - { - width = mat.cols / 3; - height = mat.rows; - m_dst = cv::Mat(height, width, CV_8UC3); - std::vector m_items; + //return 0; + last_frame_total = info.index_frame; - for (size_t i = 0; i < 3; i++) - { - cv::Mat t_item(mat(cv::Rect(width * i, 0, width, height))); - m_items.push_back(t_item); - } - cv::merge(m_items, m_dst); - } + int frame_ind = first_frame_total - last_frame_total; - cv::imwrite("C://Users//modehua//Desktop//image//1_opencv.jpg", m_dst); - std::shared_ptr image_data_(aquire_memory(width * hegiht * frame_total)); + mat_width = width; + mat_height = (hegiht * first_frame_total) - (hegiht * frame_ind); + std::shared_ptr image_data_(aquire_memory(mat_width * mat_height)); - unsigned int size = width * hegiht * frame_total;// bmpdata.size(); - void* l = image_data_->data(0, &size); - memcpy(l, m_dst.data, width * hegiht * frame_total); + unsigned int size1 = mat_height; + void* l = image_data_->data(0, &size1); + memcpy(l, jpgdata_.data(), mat_width * mat_height); - //ret = save_usb_data(image_data_); + //cv::Mat mat = cv::Mat(hegiht * first_frame_total, width, CV_8UC1, jpgdata_.data(), cv::Mat::AUTO_STEP); + //cv::imwrite("C://image//get_img_data_7010" + to_string(k) + ".jpg", mat); + k++; + ret = save_usb_data(image_data_); index_ = 0; - if (pdata) - { - free(pdata); - } + + std::vector().swap(jpgdata_); //回收空间 clear只能清空元素 + } - return SCANNER_ERR_OK; + float v = sw.elapsed_ms(); + return ret; } } int hg_scanner_300::writedown_device_configuration(bool type,setting_hardware::HGSCANCONF_3288 *d) @@ -922,6 +927,103 @@ void hg_scanner_300::printf_devconfig(setting_hardware::HGSCANCONF_3288 *d) VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"dsp_config.params_3288.enableSizeDetect:%d\r\n",d->params_3288.enableSizeDetect); VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO,"dsp_config.params_3288.value:%d\r\n",d->value); } + +int hg_scanner_300::get_device_type(bool &type) +{ + int ret = SCANNER_ERR_OK; + + USBCB cmd = { setting3288dsp::DEVICES_7010,0,0, }; + { + std::lock_guard lock(io_lock_); + ret = writeusb(cmd); + if (ret == SCANNER_ERR_OK) + ret = readusb(cmd); + + if (ret) + return ret; + type = cmd.u32_Data; + } + return ret; +} + +int hg_scanner_300::get_correction_image(int inx , int dpi, int mode) +{ + int ret = SCANNER_ERR_OK; + setting3288dsp::FLAT_INFO_IMAGE image_info; + + image_info.info.params.dpi = dpi; + image_info.info.params.colormode = mode; + + cv::Mat white_mat; + cv::Mat black_mat;; + for (size_t i = 0; i < 2; i++) //黑白一起保存下来 + { + vector imagedata; + + image_info.info.params.is_whiteimage = i; + int val = image_info.info.value; + USBCB cmd = { setting3288dsp::GET_FLAT_DATA,val,0, }; + { + std::lock_guard lock(io_lock_); + ret = writeusb(cmd); + if (ret == SCANNER_ERR_OK) + ret = readusb(cmd); + + if (ret) + return ret; + + image_info.info.value = cmd.u32_Data; + + if (image_info.info.params.status != 100) + { + VLOG_MINI_1(LOG_LEVEL_WARNING, "get_correction_image status:%d\n", image_info.info.params.status); + return SCANNER_ERR_NO_DATA; + } + int len = image_info.info.params.datalen; + imagedata.resize(len); + + + if (ret == SCANNER_ERR_OK) + ret = io_->read_bulk(&imagedata[0], &len); + if (imagedata.empty()) + { + return SCANNER_ERR_NO_DATA; + } + cv::ImreadModes rmc = image_info.info.params.colormode ? cv::IMREAD_COLOR : cv::IMREAD_GRAYSCALE; + cv::Mat mat = cv::imdecode(imagedata, rmc);//color BGR + + //if (mat.channels() == 3) + //cv::cvtColor(mat, mat, CV_BGR2RGB); + + if (mat.empty()) + { + VLOG_MINI_1(LOG_LEVEL_WARNING, "get_correction_image image is NULL:%d\n", image_info.info.params.status); + return SCANNER_ERR_NO_DATA; //只要有一张图没有 直接退了 + } + + if (i) + white_mat = mat; + else + black_mat = mat; + } + } + //cv::imwrite("C://image//correction_image_white_mat" + to_string(inx) + ".bmp", white_mat); + //cv::imwrite("C://image//correction_image_black_mat" + to_string(inx) + ".bmp", black_mat); + + ret = hg_imgproc::correction_image(ImagePrc_pHandle_, image_info.flat_lut, black_mat, white_mat); + + for (size_t j = 0; j < correction_image_map_.size(); j++) //以防重复添加 + { + if (correction_image_map_[j].info.params.dpi == dpi + && correction_image_map_[j].info.params.colormode == mode) + { + return ret; + } + } + correction_image_map_[inx] = image_info; + + return ret; +} std::string hg_scanner_300::get_firmware_version() { char buf[20] = { 0 }; diff --git a/hgdriver/hgdev/hg_scanner_300.h b/hgdriver/hgdev/hg_scanner_300.h index 2af80ec..66dd348 100644 --- a/hgdriver/hgdev/hg_scanner_300.h +++ b/hgdriver/hgdev/hg_scanner_300.h @@ -60,17 +60,32 @@ private: int pop_image(void); int get_scanner_status(USBCB &usb); int get_img_data(std::shared_ptr &imagedata); - int get_img_data_7010(std::shared_ptr& imagedata); + int get_img_data_7010(); int writedown_device_configuration(bool type =false,setting_hardware::HGSCANCONF_3288 *d = NULL); void writedown_image_configuration(void); void printf_devconfig(setting_hardware::HGSCANCONF_3288 *d = NULL); + int get_device_type(bool &type); + + setting3288dsp::HG_JpegCompressInfo frame_info_; + ///////////////////////7010专有协议,获取校正数据////////////////////// + //inx:序号// + //dpi:1--->200 2--->300 3--->600// + //mode:0 灰度 1彩色 + int get_correction_image(int inx ,int dpi,int mode); private: std::vector savestatus_; setting_hardware::HGSCANCONF_3288 dsp_config; Device::PaperSize papersize; bool is_devs_sleep_; + + + int first_frame_total; //设置的帧数 + int last_frame_total; //实际采集的帧数 + + + std::vector jpgdata_; int index_; - char* pdata; + public: //////////////固定的硬件信息设置或获取////////////// virtual std::string get_firmware_version(void)override; diff --git a/hgdriver/hgdev/image_process.cpp b/hgdriver/hgdev/image_process.cpp index 1914951..f914093 100644 --- a/hgdriver/hgdev/image_process.cpp +++ b/hgdriver/hgdev/image_process.cpp @@ -226,7 +226,7 @@ namespace hg_imgproc ,Dynamicopen_HGImageprc_pHandle_(NULL),isx86_Advan_(isx86_Advan) { if(!isx86_Advan_ || hg_log::ini_get("opencv", "speed-first") == "1") - cv::setUseOptimized(isx86_Advan_); //寮€鍏砪pu楂樼骇鎸囦护闆? + cv::setUseOptimized(isx86_Advan_); } ~imgproc() { @@ -446,7 +446,7 @@ namespace hg_imgproc return SCANNER_ERR_OK; } - int decode(int pid, LPSCANCONF img_param, LPIMGPRCPARAM param) + int decode(int pid, LPSCANCONF img_param, LPIMGPRCPARAM param, std::map& correction_image_map_) { if (!buffer_) return SCANNER_ERR_NO_DATA; @@ -492,11 +492,61 @@ namespace hg_imgproc rmc = cv::IMREAD_COLOR; } cv::Mat mat; - if (true) + bool f = true; + if (!param_.device_7010)/////只有7010需要从设备获取校正数据 mat = cv::imdecode(*buf, rmc); else - mat = cv::Mat(512 * 5, 15552 / 3, CV_8UC1, buf->data(), cv::Mat::AUTO_STEP).clone(); - //cv::imwrite("C:\\Users\\modehua\\Desktop\\image\\imdecode.jpg",mat); + { + static int img_idx = 0; + cv::Mat ds(param_.height, param_.width, CV_8UC1, buf->data(), cv::Mat::AUTO_STEP); + //cv::imwrite("C:\\image\\imdecode"+std::to_string(img_idx++) + ".jpg", ds); + cv::Mat m_dst(ds(cv::Rect(0, 2, ds.cols, ds.rows - 2))); //删除前几行 一定按照实际测试来,因为最上面会有白边影响校正裁切等 + + cv::Mat d; + if (param_.channels == 3) + { + int mat_width = m_dst.cols / 3; + int mat_height = m_dst.rows; + d = cv::Mat(mat_width, mat_height, CV_8UC3); + std::vector m_items; + std::vector list = { 0,2,1 }; //调整RGB顺序 opencv顺序是BRG + for (size_t i = 0; i < 3; i++) + { + cv::Mat t_item(m_dst(cv::Rect(mat_width * list[i], 0, mat_width, mat_height))); + m_items.push_back(t_item); + } + cv::merge(m_items, d); + mat = d.clone(); + } + else + mat = m_dst.clone(); + + cv::imwrite("C:\\image\\imdecode" + std::to_string(img_idx++) + ".jpg", mat); + int dpi = param_.dpi == 600 ? 3 : (param_.dpi < 599 && param_.dpi >= 300) ? 2 : 1; + int mode = param_.color_mode == COLOR_MODE_24_BITS ? 1 : 0; + for (size_t i = 0; i < correction_image_map_.size(); i++) + { + if (correction_image_map_[i].info.params.colormode == mode && correction_image_map_[i].info.params.dpi == dpi) + { + if (correction_image_map_[i].info.params.status != 100) + { + break; + } + correctColor(mat, correction_image_map_[i].flat_lut);//校正 + } + } + //cv::imwrite("C:\\image\\imdecode" + std::to_string(img_idx++) + ".jpg", mat); + + if (param_.dpi < 299)/////7010不支持 200dpi 所以需要手动拉伸宽度 + { + float xy = param_.dpi / 300.0; + cv::resize(mat, mat, cv::Size(), xy, 1); + + } + } + + //cv::imwrite("C:\\image\\imdecode4.png", mat); + //cv::imwrite("C:\\Users\\modehua\\Desktop\\image\\imdecode2.jpg",mat); if (mat.empty()) { @@ -523,7 +573,7 @@ namespace hg_imgproc catch (const std::exception& e) { LOG_INFO(LOG_LEVEL_FATAL, e.what()); - throw(e); // 缁х画鎶涘埌涓婂眰澶勭悊銆? + throw(e); } } @@ -535,7 +585,7 @@ namespace hg_imgproc if (pid_ == 0x100 || pid_ == 0x200 || pid_ == 0x300 || pid_ == 0x400 || pid == 0x402 || pid == 0x302) { - //////闄ょ┛瀛旂畻娉曠Щ鑷宠В鍘嬪浘鍍忎箣鍚? + double left = img_conf_.fillholeratio_left / 100.0; double right = img_conf_.fillholeratio_right / 100.0; double top = img_conf_.fillholeratio_up / 100.0; @@ -601,7 +651,7 @@ namespace hg_imgproc std::vector mats(mats_); mats_.clear(); - int colormode = 1; //默锟斤拷1 + int colormode = 1; if (img_conf_.filter == 3) colormode = img_conf_.pixtype; @@ -1348,6 +1398,13 @@ namespace hg_imgproc return ret; //cv::imwrite("CISTestImageProcess.jpg",mats[i]); } + + int correction_image(cv::Mat &flat_lut, cv::Mat black_mat, cv::Mat white_mat) + { + flat_lut = creatLUTData(black_mat, white_mat);//计算LUT 查值表 + return 0; + } + HGImage opencv_to_hgbase_image(const cv::Mat& mats) { HGImage image; @@ -1535,6 +1592,272 @@ namespace hg_imgproc LOG_INFO(LOG_LEVEL_ALL, "No image output in image_process!\n"); } } + + + + + + + + + + + + + + + + float gamma(float value, float ex) + { + return cv::pow(value / 255.0f, 1.0f / ex) * 255.0f + 0.5f; + } + + + std::vector caculate(const std::vector& points_x, const std::vector& points_y) + { + int MaxElement = points_x.size() - 1; + //计算常数f + double f = points_y[0]; + //求解 + int n, m; + // double a[MaxElement][MaxElement+1]; + std::vector> a; + // a.resize(MaxElement); + for (int i = 0; i < MaxElement; i++) + { + std::vector b; + b.resize(MaxElement + 1); + a.push_back(b); + } + + for (int i = 0; i < MaxElement; i++) + { + for (int j = 0; j < MaxElement; j++) + a[i][j] = cv::pow(points_x[i + 1], MaxElement - j); + a[i][MaxElement] = points_y[i + 1] - f; + } + + int i, j; + n = MaxElement; + + for (j = 0; j < n; j++) + { + double max = 0; + double imax = 0; + for (i = j; i < n; i++) + { + if (imax < cv::abs(a[i][j])) + { + imax = cv::abs(a[i][j]); + max = a[i][j]; //得到各行中所在列最大元素 + m = i; + } + } + if (cv::abs(a[j][j]) != max) + { + double b = 0; + for (int k = j; k < n + 1; k++) + { + b = a[j][k]; + a[j][k] = a[m][k]; + a[m][k] = b; + } + } + + for (int r = j; r < n + 1; r++) + { + a[j][r] = a[j][r] / max; //让该行的所在列除以所在列的第一个元素,目的是让首元素为1 + } + + for (i = j + 1; i < n; i++) + { + double c = a[i][j]; + if (c == 0.0) + continue; + for (int s = j; s < n + 1; s++) + { + a[i][s] = a[i][s] - a[j][s] * c; //前后行数相减,使下一行或者上一行的首元素为0 + } + } + } + for (i = n - 2; i >= 0; i--) + { + for (j = i + 1; j < n; j++) + { + a[i][n] = a[i][n] - a[j][n] * a[i][j]; + } + } + + std::vector result; + for (int k = 0; k < n; k++) + result.push_back(a[k][n]); + result.push_back(f); + return result; + } + + + + //设置一面的offset值 + void setOffset(int* config, int step) + { + for (int i = 0; i < 6; i++) + { + int* offset = config + i; + *offset += step; + if (*offset < 0) + *offset = 1; + if (*offset > 255) + *offset = 255; + } + } + + cv::Mat extractRepresentRow2(const cv::Mat& src) + { + cv::Mat BWbalenceSrc(1, src.cols * src.channels(), CV_8UC1); + + cv::Mat temp_imageBW(src.rows, src.cols * src.channels(), CV_8UC1, src.data); + + for (size_t i = 0; i < BWbalenceSrc.cols; i++) + BWbalenceSrc.at(0, i) = cv::mean(temp_imageBW(cv::Rect(i, 0, 1, temp_imageBW.rows)))[0]; + + return BWbalenceSrc; + } + + +#define GAMMA_EX 1.7f +#define BLACK_OFFSET 0 + + void fittingLUT(const std::vector& points, unsigned char min_value, unsigned char max_value, unsigned char* data) + { + float step = max_value - min_value + 1; + memset(data, min_value, 127); + memset(data + 127, max_value, 129); + int b = points[0]; + int w = points[1]; + int tb = min_value; + int tw = max_value; + + step = (cv::max)((float)(tw - tb + 1) / (float)(w - b + 1), 0.0f); + float temp; + for (int j = 0, length = (255 - b + 1); j < length; j++) + { + temp = gamma(tb + step * j, GAMMA_EX) - BLACK_OFFSET; + data[j + b] = (cv::min)(255, (cv::max)(0, static_cast(temp))); + } + } + + cv::Mat createLUT(const std::vector& mats, bool isTextCorrect) + { + int rows = mats[0].cols; + cv::Mat lut(rows, 256, CV_8UC1); + + double max_val, min_val; + cv::minMaxIdx(mats[0], &min_val, nullptr); + cv::minMaxIdx(mats[1], nullptr, &max_val); + for (size_t i = 0; i < rows; i++) + { + std::vector grayPoints; + for (size_t j = 0; j < mats.size(); j++) + grayPoints.push_back(mats[j].data[i]); + + fittingLUT(grayPoints, static_cast(min_val), static_cast(max_val), lut.data + i * 256); + } + if (isTextCorrect) + { + std::vector points_x = { 0, 25, 205, 255 }, points_y = { 0, 0, 230, 255 }; + std::vector coefficient = caculate(points_x, points_y); + + unsigned char buffer[256]; + for (int i = 0; i < 256; i++) + { + int temp = coefficient[0] * i * i * i + coefficient[1] * i * i + coefficient[2] * i + coefficient[3]; + buffer[i] = static_cast((cv::min)(255, (cv::max)(0, temp))); + } + + cv::Mat lut_lut(256, 1, CV_8UC1, buffer); + cv::LUT(lut, lut_lut, lut); + } + return lut; + } + + + + +#define CHANNEL 432 + cv::Mat calcLUT(const cv::Mat& black, const cv::Mat& white, bool isTextCorrection) + { + std::vector w; + w.push_back(black); + w.push_back(white); + cv::Mat lut = createLUT(w, isTextCorrection); + + for (size_t i = 0, block = lut.rows / CHANNEL; i < block; i++) + { + cv::Mat lutROI = lut(cv::Rect(0, i * CHANNEL, 256, CHANNEL)); + cv::Mat tran; + cv::transpose(lutROI, tran); + memcpy(lutROI.data, tran.data, tran.total()); + } + return lut; + } + + + cv::Mat loadLUT(const std::string& file) + { + cv::Mat dataFile = cv::imread(file, cv::IMREAD_ANYCOLOR); + long total = dataFile.total(); + int step = total / 256; + + int channel = 432; + + cv::Mat lut(step / channel, 256, CV_8UC(channel)); + memcpy(lut.data, dataFile.data, total); + return lut; + } + + void correctColor(cv::Mat& src, cv::Mat lut) + { + + cv::Mat image_temp(src.rows, src.cols * src.channels() / lut.channels(), CV_8UC(lut.channels()), src.data); + + for (size_t i = 0; i < image_temp.cols; i++) + cv::LUT(image_temp(cv::Rect(i, 0, 1, image_temp.rows)), lut(cv::Rect(0, i, 256, 1)), image_temp(cv::Rect(i, 0, 1, image_temp.rows))); + } + + cv::Mat creatLUTData(cv::Mat black, cv::Mat white) + { + printf("eneter creatLUTData \n"); + + cv::Mat lut; + cv::Mat twMat = white;// cv::imread(whitePath, colormode); + cv::Mat tbMat = black;// cv::imread(blackPath, colormode); + cv::Mat wMat, bMat; + if (black.channels() == 3 && white.channels() == 3) + { + wMat = cv::Mat(twMat.rows, twMat.cols * 3, CV_8UC1, twMat.data); + bMat = cv::Mat(twMat.rows, twMat.cols * 3, CV_8UC1, tbMat.data); + } + else + { + wMat = twMat; + bMat = tbMat; + } + + lut = calcLUT(bMat, wMat, true); + long total = lut.total(); + int step = total / 256; + int channel = 432; + cv::Mat ret = cv::Mat::zeros(step / channel, 256, CV_8UC(channel)); + memcpy(ret.data, lut.data, total); + return ret; + } + + cv::Mat create_lut(const cv::Mat& black, const cv::Mat& white, int dpi, bool colormode) + { + return calcLUT(black, white, false); + } + + }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // api ... @@ -1552,9 +1875,9 @@ namespace hg_imgproc { return ((imgproc*)himg)->load_file(path_file); } - int decode(HIMGPRC himg, int pid, LPSCANCONF img_param, LPIMGPRCPARAM param) + int decode(HIMGPRC himg, int pid, LPSCANCONF img_param, LPIMGPRCPARAM param, std::map& correction_image_map_) { - return ((imgproc*)himg)->decode(pid, img_param, param); + return ((imgproc*)himg)->decode(pid, img_param, param, correction_image_map_); } int init_auto_txt_hanld(HIMGPRC himg) { @@ -1689,6 +2012,10 @@ namespace hg_imgproc { return ((imgproc*)himg)->final(); } + int correction_image(HIMGPRC himg, cv::Mat& flat_lut, cv::Mat black_mat, cv::Mat white_mat) + { + return ((imgproc*)himg)->correction_image(flat_lut, black_mat, white_mat); + } int get_final_data(HIMGPRC himg, LPIMGHEAD pimh, void** buf, int index) { return ((imgproc*)himg)->get_final_data(pimh, buf, index); diff --git a/hgdriver/hgdev/image_process.h b/hgdriver/hgdev/image_process.h index 5425e3d..a316ee1 100644 --- a/hgdriver/hgdev/image_process.h +++ b/hgdriver/hgdev/image_process.h @@ -150,6 +150,10 @@ namespace hg_imgproc bool double_side; bool black_white; bool cis_image; //设置原图 + int width; // in pixel + int height; // in pixel + unsigned total_bytes;// total bytes + bool device_7010; }IMGPRCPARAM, *LPIMGPRCPARAM; typedef struct _img_header { @@ -168,7 +172,7 @@ namespace hg_imgproc int load_file(HIMGPRC himg, const char* path_file); //图像数据转换 - int decode(HIMGPRC himg,int pid, LPSCANCONF img_param, LPIMGPRCPARAM param); + int decode(HIMGPRC himg,int pid, LPSCANCONF img_param, LPIMGPRCPARAM param, std::map& correction_image_map_); int correct_text(HIMGPRC himg); int init_auto_txt_hanld(HIMGPRC himg); @@ -205,6 +209,9 @@ namespace hg_imgproc int color_cast_correction(HIMGPRC himg); int final(HIMGPRC himg); + + int correction_image(HIMGPRC himg, cv::Mat& flat_lut, cv::Mat black_mat, cv::Mat white_mat); + // pimh must not to be NULL, and pimh->total_bytes indicates the length of 'buf' // // if 'buf' was NULL, then return SCANNER_ERR_INSUFFICIENT_MEMORY