#include "imgprc_mgr.h" #include #include #include #include #include "./algs/rebuild.h" #include "./algs/stretch.h" #include "./algs/auto_crop.h" #include "./algs/color_correct.h" #include "./algs/ImageProcess_Public.h" #include "./algs/image_encoder.h" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // imgproc_mgr #define ADD_IMG_PROCESSOR(cls) \ { \ cls *obj = new cls(); \ opts_->add(obj); \ processors_.push_back(obj); \ } static std::string device_opt_json[] = { "{\"is-multiout\":{\"cat\":\"base\",\"group\":\"base\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\",\"desc\":\"\\u540c\\u65f6\\u8f93\\u51fa\\u591a\\u79cd\\u989c\\u8272\\u6a21\\u5f0f\\u7684\\u56fe\\u50cf\",\"type\":\"bool\",\"fix-id\":34817,\"ui-pos\":10,\"auth\":0,\"size\":4,\"cur\":false,\"default\":false},\"multiout-type\":{\"cat\":\"base\",\"group\":\"base\",\"title\":\"\\u591a\\u6d41\\u8f93\\u51fa\\u7c7b\\u578b\",\"desc\":\"\\u9009\\u62e9\\u591a\\u6d41\\u8f93\\u51fa\\u7684\\u7c7b\\u578b\",\"type\":\"string\",\"fix-id\":34818,\"ui-pos\":11,\"auth\":0,\"enabled\":false,\"size\":66,\"cur\":\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"default\":\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"range\":[\"\\u5f69\\u8272+\\u7070\\u5ea6+\\u9ed1\\u767d\",\"\\u5f69\\u8272+\\u7070\\u5ea6\",\"\\u5f69\\u8272+\\u9ed1\\u767d\",\"\\u7070\\u5ea6+\\u9ed1\\u767d\"],\"depend\":\"is-multiout==true\"},\"mode\":{\"cat\":\"base\",\"group\":\"base\",\"title\":\"\\u989c\\u8272\\u6a21\\u5f0f\",\"desc\":\"\\u9009\\u62e9\\u8272\\u5f69\\u6a21\\u5f0f\",\"type\":\"string\",\"fix-id\":34819,\"ui-pos\":15,\"auth\":0,\"size\":24,\"cur\":\"24\\u4f4d\\u5f69\\u8272\",\"default\":\"24\\u4f4d\\u5f69\\u8272\",\"range\":[\"24\\u4f4d\\u5f69\\u8272\",\"256\\u7ea7\\u7070\\u5ea6\",\"\\u9ed1\\u767d\",\"\\u989c\\u8272\\u81ea\\u52a8\\u8bc6\\u522b\"],\"depend\":\"is-multiout!=true\"},\"dump-img\":{\"cat\":\"base\",\"group\":\"\\u9ad8\\u7ea7\\u8bbe\\u7f6e\",\"title\":\"\\u8f93\\u51fa\\u4e2d\\u95f4\\u56fe\\u50cf\",\"desc\":\"\\u8f93\\u51fa\\u5404\\u7b97\\u6cd5\\u4e2d\\u95f4\\u7ed3\\u679c\\u56fe\\u50cf\",\"type\":\"bool\",\"ui-pos\":10,\"auth\":0,\"affect\":2,\"size\":4,\"cur\":false,\"default\":false},\"cis-rebuild\":{\"cat\":\"advanced\",\"group\":\"\\u9ad8\\u7ea7\\u8bbe\\u7f6e\",\"title\":\"\\u56fe\\u50cf\\u62fc\\u63a5\",\"desc\":\"\\u4eceCIS\\u6570\\u636e\\u6d41\\u91cd\\u5efa\\u56fe\\u50cf\",\"type\":\"bool\",\"ui-pos\":20,\"auth\":0,\"affect\":2,\"size\":4,\"cur\":true,\"default\":true},\"stretch\":{\"cat\":\"advanced\",\"group\":\"\\u9ad8\\u7ea7\\u8bbe\\u7f6e\",\"title\":\"\\u56fe\\u50cf\\u62c9\\u4f38\",\"desc\":\"\\u5c06\\u786c\\u4ef6\\u5206\\u8fa8\\u7387\\u62c9\\u4f38\\u5230\\u7528\\u6237\\u6307\\u5b9a\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"bool\",\"ui-pos\":30,\"auth\":0,\"affect\":2,\"size\":4,\"cur\":true,\"default\":true}}" }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // imgproc_mgr imgproc_mgr::imgproc_mgr(std::function sender , device_option* devopts , CHK_RES_FUNC res ) : img_sender_(sender), opts_(devopts), prc_que_("prcimg") , res_(res) { prc_que_.enable_wait_log(false); ADD_THIS_JSON(); if(!res_) { DECL_CHK_RES_FUNC(&, r) { return true; }; res_ = r; } if (opts_) opts_->add_ref(); else opts_ = new device_option(true); load_processor(nullptr); first_.reset(new rebuild()); last_.reset(new img_encoder()); opts_->add(first_.get()); opts_->add(last_.get()); auto thrd = [&](void) -> void { thread_worker(); }; auto restart = [this](const char* thread_name) ->void { auto thrd = [this](void) -> void { thread_worker(); }; workers_.stop(thread_name); add_busy_worker(-1); printf("\nrestart imgproc_mgr::thread_worker\n\n"); workers_.start(thrd, SIZE_MB(0), "imgproc_mgr::thread_worker", (void*)&imgproc_mgr::thread_worker); }; workers_.set_exception_handler(restart); workers_.start(thrd, SIZE_MB(0), "thread_worker1", (void*)&imgproc_mgr::thread_worker); workers_.start(thrd, SIZE_MB(0), "thread_worker2", (void*)&imgproc_mgr::thread_worker); workers_.start(thrd, SIZE_MB(0), "thread_worker3", (void*)&imgproc_mgr::thread_worker); workers_.start(thrd, SIZE_MB(0), "thread_worker4", (void*)&imgproc_mgr::thread_worker); } imgproc_mgr::~imgproc_mgr() { clear(); opts_->release(); } bool imgproc_mgr::sort_processor_by_pos(image_processor* l, image_processor* r) { return l->get_position() < r->get_position(); } bool imgproc_mgr::sort_image_packet(image_packet_ptr l, image_packet_ptr r) { return l->get_paper_index() < r->get_paper_index(); } data_source_ptr imgproc_mgr::scan_finished_packet(uint32_t scanid, uint32_t err) { dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), PACK_CMD_SCAN_FINISHED_ROGER, scanid, err); reply->set_len(sizeof(PACK_BASE)); return reply; } uint32_t imgproc_mgr::add_busy_worker(int inc) { SIMPLE_LOCK(working_cnt_lock_); working_cnt_ += inc; return working_cnt_; } void imgproc_mgr::thread_worker(void) { RAWIMG img; while(run_) { while(!res_(TASK_IMG_PROCESSOR, true, 3000)) { if(!run_) break; } if(!run_) break; if(prc_que_.take(img, true)) { add_busy_worker(); // try // { process(&img); // } // catch(const std::exception& e) // { // printf("exception occurs when process paper %d: %s!\n", img.info.pos.paper_ind, e.what()); // } add_busy_worker(-1); } } } void imgproc_mgr::process(RAWIMG* img) { if(img->img) { std::vector in, out, *src = &in, *dst = &out, *swp = nullptr; chronograph watch; auto realdump = [this](std::vector* arr, LPPACKIMAGE info, cv::Mat* mat, char* infoex, size_t infexl, bool last) -> void { if(arr) send_image(*arr, last); else send_image(info, *mat, infoex, infexl, last); }; auto emptydump = [this](std::vector* arr, LPPACKIMAGE info, cv::Mat* mat, char* infoex, size_t infexl, bool last) -> void {}; std::function* arr, LPPACKIMAGE info, cv::Mat* mat, char* infoex, size_t infexl, bool last)> dump = realdump; if(dump_img_) { cv::Mat mat(img->info.width, img->info.height, CV_8UC1, img->data->ptr()); send_image(&img->info, mat, nullptr, 0, false); } else dump = emptydump; if(do_rebuild_) { first_->do_rebuild(&img->info, img->data->ptr(), in); utils::to_log(LOG_LEVEL_ALL, "Rebuild paper %d spend %llu milliseconds.\n", img->info.pos.paper_ind, watch.elapse_ms()); dump(&in, nullptr, nullptr, nullptr, 0, false); } else { PROCIMGINFO i; i.info = img->info; i.img = cv::Mat(img->info.width, img->info.height, CV_8UC1, img->data->ptr()); in.push_back(i); } img->data->release(); for(auto& v: processors_) { if(v->is_enable()) { process(v, src, dst); src->clear(); swp = src; src = dst; dst = swp; dump(src, nullptr, nullptr, nullptr, 0, false); } } send_image(*src, true); } else { data_source_ptr ptr = imgproc_mgr::scan_finished_packet(scan_id_, img->info.data_size); uint32_t wait = 0, que = 0; ptr->set_session_id(session_id_); while((que = add_busy_worker(0)) > 1) { if(wait++ == 0) utils::to_log(LOG_LEVEL_DEBUG, "Received scan completed event while processing %u paper(s), wait ...\n", que - 1); std::this_thread::sleep_for(std::chrono::milliseconds(5)); } img_sender_(ptr); ptr->release(); } } void imgproc_mgr::process(image_processor* prc, std::vector* in, std::vector* out) { try { prc->process(*in, *out); } catch(const exception_ex& e) { std::string msg(std::string("image process '") + prc->from() + "': " + e.what()); throw(exception_ex(msg.c_str())); } catch(const std::exception& e) { std::string msg(std::string("image process '") + prc->from() + "': " + e.what()); throw(exception_ex(msg.c_str())); } } void imgproc_mgr::send_image(LPPACKIMAGE head, cv::Mat& mat, void* info, size_t info_l, bool last) { auto ovr = [&](uint64_t total, uint64_t cur_size, uint32_t err, void* user_data) -> int { if(total == FINAL_NOTIFY && cur_size == FINAL_NOTIFY) printf("~%p\n", user_data); return 0; }; PACKIMAGE h(*head); std::shared_ptr> compd(last_->encode(&h, mat)); image_packet_ptr ptr = nullptr; if(last) { h.life = chronograph::from_process_born() - h.life; } else { h.prc_stage = head->prc_stage; h.prc_time = head->prc_time; } ptr = new image_packet(&h, compd, scan_id_, info, info_l); ptr->set_session_id(session_id_); img_sender_(ptr); ptr->release(); } void imgproc_mgr::send_image(std::vector& imgs, bool last) { for(auto& v: imgs) send_image(&v.info, v.img, v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length(), last); } int imgproc_mgr::set_value(const char* name, void* val) { int ret = SCANNER_ERR_OK; if(strcmp(name, SANE_OPT_NAME(DUMP_IMG)) == 0) dump_img_ = *(bool*)val; else if(strcmp(name, SANE_OPT_NAME(CIS_REBUILD)) == 0) do_rebuild_ = *(bool*)val; else if(strcmp(name, SANE_OPT_NAME(CIS_STRETCH)) == 0) { if(*(bool*)val) { if(stretcher_) { processors_.push_back(stretcher_); stretcher_ = nullptr; std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos); } } else { for(size_t i = 0; i < processors_.size(); ++i) { if(strcmp(processors_[i]->from(), "stretch") == 0) { stretcher_ = processors_[i]; processors_.erase(processors_.begin() + i); break; } } } } else ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; return ret; } int imgproc_mgr::load_processor(const char* path) { int ret = SCANNER_ERR_OK; // ADD_IMG_PROCESSOR(rebuild); ADD_IMG_PROCESSOR(stretch); ADD_IMG_PROCESSOR(auto_crop); ADD_IMG_PROCESSOR(color_correct); // ADD_IMG_PROCESSOR(img_encoder); std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos); return ret; } int imgproc_mgr::clear(void) { for (auto& v : processors_) v->release(); processors_.clear(); if(stretcher_) stretcher_->release(); stretcher_ = nullptr; return 0; } int imgproc_mgr::process(LPPACKIMAGE info, dyn_mem_ptr data, bool img) { RAWIMG ri; int ret = SCANNER_ERR_OK; ri.data = data; if(img) data->add_ref(); if(img) ri.info = *info; else ri.info.data_size = (uint32_t)(long)info; ri.img = img; prc_que_.save(ri, true); return ret; } void imgproc_mgr::stop(void) { run_ = false; prc_que_.trigger(); workers_.stop(nullptr); } bool imgproc_mgr::is_busy(void) { SIMPLE_LOCK(working_cnt_lock_); return working_cnt_; } void imgproc_mgr::start_new_turn(uint32_t scanid, uint32_t sessionid) { scan_id_ = scanid; sent_ind_ = 0; session_id_ = sessionid; }