添加图像压缩算法

This commit is contained in:
gb 2024-02-27 12:03:51 +08:00
parent a040422b7b
commit a0461ff354
11 changed files with 236 additions and 51 deletions

View File

@ -0,0 +1,41 @@
{
"img-fmt": {
"cat": "imgp",
"group": "output",
"title": "图片格式",
"desc": "设备输出的图片文件格式",
"type": "string",
"ver": 1,
"pos": 9900,
"ui-pos": 10,
"auth": 0,
"visible": 0,
"size": 16,
"cur": "JPEG",
"default": "JPEG",
"range": ["JPEG", "PNG", "BMP"]
},
"jpeg-quality": {
"cat": "imgp",
"group": "output",
"title": "JPEG质量",
"desc": "设置JPEG压缩质量质量越高压缩率越低",
"type": "int",
"ver": 1,
"pos": 9901,
"ui-pos": 11,
"auth": 0,
"affect": 4,
"unit": "%",
"visible": 0,
"size": 4,
"cur": 100,
"default": 100,
"range": {
"min": 10,
"max": 100,
"step": 1
},
"depend": "img-fmt==JPEG"
}
}

View File

@ -382,14 +382,14 @@ void scanner_hw::thread_image_capture(bool paper_ready)
scanstream.err = 0; scanstream.err = 0;
devui::send_message(devui::UI_STATUS_SCANNING, (uint8_t*)&scanstream, sizeof(scanstream)); devui::send_message(devui::UI_STATUS_SCANNING, (uint8_t*)&scanstream, sizeof(scanstream));
while(scanning_) // auto scan cycle ... while(scanning_) // auto scan cycle ...
{
// scanning ONE turn ...
if(paper_ready) // auto_scan_ ignore no paper
{ {
err = start_and_wait_lifter(to_lifter_, &over_msg_id); err = start_and_wait_lifter(to_lifter_, &over_msg_id);
if(err) if(err)
break; break;
// scanning ONE turn ...
if(paper_ready) // auto_scan_ ignore no paper
{
motor_->pick_paper(); motor_->pick_paper();
err = scan_one_turn(&img, &avail_mem, &used_v4l2_mem, &over_msg_id); err = scan_one_turn(&img, &avail_mem, &used_v4l2_mem, &over_msg_id);
if(err || !auto_scan_ || !scanning_) if(err || !auto_scan_ || !scanning_)

View File

@ -0,0 +1,110 @@
#include "image_encoder.h"
#include <huagao/hgscanner_error.h>
#include <sane/sane_ex.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// img_encoder
static std::string device_opt_json[] = {
"{\"img-fmt\":{\"cat\":\"imgp\",\"group\":\"output\",\"title\":\"\\u56fe\\u7247\\u683c\\u5f0f\",\"desc\":\"\\u8bbe\\u5907\\u8f93\\u51fa\\u7684\\u56fe\\u7247\\u6587\\u4ef6\\u683c\\u5f0f\",\"type\":\"string\",\"ver\":1,\"pos\":9900,\"ui-pos\":10,\"auth\":0,\"visible\":0,\"size\":16,\"cur\":\"JPEG\",\"default\":\"JPEG\",\"range\":[\"JPEG\",\"PNG\",\"BMP\"]},\"jpeg-quality\":{\"cat\":\"imgp\",\"group\":\"output\",\"title\":\"JPEG\\u8d28\\u91cf\",\"desc\":\"\\u8bbe\\u7f6eJPEG\\u538b\\u7f29\\u8d28\\u91cf\\uff0c\\u8d28\\u91cf\\u8d8a\\u9ad8\\uff0c\\u538b\\u7f29\\u7387\\u8d8a\\u4f4e\",\"type\":\"int\",\"ver\":1,\"pos\":9901,\"ui-pos\":11,\"auth\":0,\"affect\":4,\"unit\":\"%\",\"visible\":0,\"size\":4,\"cur\":100,\"default\":100,\"range\":{\"min\":10,\"max\":100,\"step\":1},\"depend\":\"img-fmt==JPEG\"}}"
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// img_encoder
img_encoder::img_encoder() : image_processor("img_encoder")
{
ADD_THIS_JSON();
// if (!bwimg)
// {
// compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
// compression_params.push_back(100);
// }
// else{
// compression_params.push_back(CV_IMWRITE_PNG_STRATEGY);
// compression_params.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED);
// }
param_.push_back(cv::IMWRITE_JPEG_QUALITY);
param_.push_back(jpeg_quality_);
}
img_encoder::~img_encoder()
{}
int img_encoder::set_value(const char* name, void* val)
{
int ret = SCANNER_ERR_OK;
if(strcmp(name, SANE_OPT_NAME(OUT_FORMAT)) == 0)
{
fmt_ = (char*)val;
if(fmt_ == "JPEG")
{
fmt_ = ".jpg";
param_.clear();
param_.push_back(cv::IMWRITE_JPEG_QUALITY);
param_.push_back(jpeg_quality_);
}
else if(fmt_ == "PNG")
{
fmt_ = ".png";
param_.clear();
param_.push_back(CV_IMWRITE_PNG_STRATEGY);
param_.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED);
}
else
{
fmt_ = ".bmp";
param_.clear();
}
}
else if(strcmp(name, SANE_OPT_NAME(JPEG_QUALITY)) == 0)
{
jpeg_quality_ = *(int*)val;
}
else
{
ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
}
return ret;
}
int img_encoder::process(std::vector<PROCIMGINFO>& in, std::vector<PROCIMGINFO>& out)
{
for(auto& v: in)
{
v.info.prc_stage = get_position();
v.info.prc_time = 0;
out.push_back(v);
}
return SCANNER_ERR_OK;
}
std::shared_ptr<std::vector<uchar>> img_encoder::encode(LPPACKIMAGE head, cv::Mat& mat)
{
std::shared_ptr<std::vector<uchar>> ptr;
chronograph watch;
head->prc_stage = get_position();
if(fmt_ == ".bmp")
{
size_t size = mat.total() * mat.channels();
ptr.reset(new std::vector<uchar>(size));
memcpy(ptr->data(), mat.data, size);
head->prc_time = watch.elapse_ms();
head->format = IMG_FMT_BMP;
}
else
{
ptr.reset(new std::vector<uchar>());
head->format = fmt_ == ".jpg" ? IMG_FMT_JPEG : IMG_FMT_PNG;
cv::imencode(fmt_.c_str(), mat, *ptr, param_);
head->prc_time = watch.elapse_ms();
printf("encode to '%s' in %ums: %u\n", fmt_.c_str(), head->prc_time, ptr->size());
}
return ptr;
}

View File

@ -0,0 +1,30 @@
// encoder bmp to given format
//
// Date: 2024-02-26
#pragma once
#include <imgprc/img_processor.h>
#include <memory>
#include <vector>
class img_encoder : public image_processor
{
std::string fmt_ = ".jpg";
int jpeg_quality_ = 100;
std::vector<int> param_;
public:
img_encoder();
protected:
~img_encoder();
public:
virtual int set_value(const char* name/*nullptr for all options*/, void* val/*nullptr for restore*/) override;
public:
virtual int process(std::vector<PROCIMGINFO>& in, std::vector<PROCIMGINFO>& out) override;
public:
std::shared_ptr<std::vector<uchar>> encode(LPPACKIMAGE head, cv::Mat& mat);
};

View File

@ -10,6 +10,7 @@
#include "./algs/auto_crop.h" #include "./algs/auto_crop.h"
#include "./algs/color_correct.h" #include "./algs/color_correct.h"
#include "./algs/ImageProcess_Public.h" #include "./algs/ImageProcess_Public.h"
#include "./algs/image_encoder.h"
@ -54,7 +55,11 @@ imgproc_mgr::imgproc_mgr(std::function<void(data_source_ptr)> sender
else else
opts_ = new device_option(true); opts_ = new device_option(true);
load_processor(nullptr); load_processor(nullptr);
rebuild_.reset(new rebuild()); first_.reset(new rebuild());
last_.reset(new img_encoder());
opts_->add(first_.get());
opts_->add(last_.get());
auto thrd = [&](void) -> void auto thrd = [&](void) -> void
{ {
@ -96,12 +101,6 @@ data_source_ptr imgproc_mgr::scan_finished_packet(uint32_t scanid, uint32_t err)
return reply; return reply;
} }
image_packet_ptr imgproc_mgr::image_sent_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid, void* info, size_t info_l)
{
image_packet_ptr pimg = new image_packet(head, img, scanid, info, info_l);
return pimg;
}
uint32_t imgproc_mgr::add_busy_worker(int inc) uint32_t imgproc_mgr::add_busy_worker(int inc)
{ {
@ -148,7 +147,7 @@ void imgproc_mgr::process(RAWIMG* img)
if(do_rebuild_) if(do_rebuild_)
{ {
rebuild_->do_rebuild(&img->info, img->data->ptr(), in); 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()); utils::to_log(LOG_LEVEL_ALL, "Rebuild paper %d spend %llu milliseconds.\n", img->info.pos.paper_ind, watch.elapse_ms());
} }
else else
@ -161,12 +160,15 @@ void imgproc_mgr::process(RAWIMG* img)
if(dump_img_) if(dump_img_)
{ {
send_image(&img->info, img->data->ptr(), img->info.width * img->info.height); {
cv::Mat mat(img->info.width, img->info.height, CV_8UC1, img->data->ptr());
send_image(&img->info, mat);
}
img->data->release(); img->data->release();
for(auto& v: processors_) for(auto& v: processors_)
{ {
send_image(*src, false); send_image(*src);
if(v->is_enable()) if(v->is_enable())
{ {
process(v, src, dst); process(v, src, dst);
@ -196,7 +198,7 @@ void imgproc_mgr::process(RAWIMG* img)
v.info.prc_time = t; v.info.prc_time = t;
} }
send_image(*src, true); send_image(*src);
} }
else else
{ {
@ -234,7 +236,7 @@ void imgproc_mgr::process(image_processor* prc, std::vector<PROCIMGINFO>* in, st
throw(exception_ex(msg.c_str())); throw(exception_ex(msg.c_str()));
} }
} }
void imgproc_mgr::send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void* info, size_t info_l) void imgproc_mgr::send_image(LPPACKIMAGE head, cv::Mat& mat, void* info, size_t info_l)
{ {
auto ovr = [&](uint64_t total, uint64_t cur_size, uint32_t err, void* user_data) -> int auto ovr = [&](uint64_t total, uint64_t cur_size, uint32_t err, void* user_data) -> int
{ {
@ -244,31 +246,18 @@ void imgproc_mgr::send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void*
return 0; return 0;
}; };
dyn_mem_ptr mem(dyn_mem::memory(size)); PACKIMAGE h(*head);
image_packet_ptr ptr = nullptr; std::shared_ptr<std::vector<uchar>> compd(last_->encode(&h, mat));
image_packet_ptr ptr = new image_packet(&h, compd, scan_id_, info, info_l);
// mem->set_progress_notify(ovr, mem);
mem->put(data, size);
ptr = imgproc_mgr::image_sent_packet(head, mem, scan_id_, info, info_l);
// ptr->set_progress_notify(ovr, ptr);
// printf("+dyn_mem(%p)\n+image_packet(%p)\n", mem, ptr);
mem->release();
ptr->set_session_id(session_id_); ptr->set_session_id(session_id_);
img_sender_(ptr); img_sender_(ptr);
ptr->release(); ptr->release();
} }
void imgproc_mgr::send_image(std::vector<PROCIMGINFO>& imgs, bool clear_after_send) void imgproc_mgr::send_image(std::vector<PROCIMGINFO>& imgs)
{ {
for(auto& v: imgs) for(auto& v: imgs)
{ send_image(&v.info, v.img, v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length());
if(clear_after_send)
v.info.prc_stage = -1;
send_image(&v.info, v.img.ptr(), v.img.total() * v.img.channels()
, v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length());
// if(clear_after_send)
// v.img.release();
}
} }
int imgproc_mgr::set_value(const char* name, void* val) int imgproc_mgr::set_value(const char* name, void* val)
@ -317,6 +306,7 @@ int imgproc_mgr::load_processor(const char* path)
ADD_IMG_PROCESSOR(stretch); ADD_IMG_PROCESSOR(stretch);
ADD_IMG_PROCESSOR(auto_crop); ADD_IMG_PROCESSOR(auto_crop);
ADD_IMG_PROCESSOR(color_correct); ADD_IMG_PROCESSOR(color_correct);
// ADD_IMG_PROCESSOR(img_encoder);
std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos); std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos);

View File

@ -17,6 +17,7 @@ typedef std::shared_ptr<std::vector<char>> dcptr;
class device_option; class device_option;
class rebuild; class rebuild;
class img_encoder;
class imgproc_mgr : public sane_opt_provider class imgproc_mgr : public sane_opt_provider
{ {
@ -27,7 +28,8 @@ class imgproc_mgr : public sane_opt_provider
bool img; bool img;
}RAWIMG; }RAWIMG;
refer_guard<rebuild> rebuild_; refer_guard<rebuild> first_;
refer_guard<img_encoder> last_;
image_processor* stretcher_ = nullptr; image_processor* stretcher_ = nullptr;
bool do_rebuild_ = true; bool do_rebuild_ = true;
volatile bool run_ = true; volatile bool run_ = true;
@ -48,14 +50,13 @@ class imgproc_mgr : public sane_opt_provider
static bool sort_processor_by_pos(image_processor* l, image_processor* r); static bool sort_processor_by_pos(image_processor* l, image_processor* r);
static bool sort_image_packet(image_packet_ptr l, image_packet_ptr r); static bool sort_image_packet(image_packet_ptr l, image_packet_ptr r);
static data_source_ptr scan_finished_packet(uint32_t scanid, uint32_t err = 0); static data_source_ptr scan_finished_packet(uint32_t scanid, uint32_t err = 0);
static image_packet_ptr image_sent_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid, void* info = nullptr, size_t info_l = 0);
uint32_t add_busy_worker(int inc = 1); uint32_t add_busy_worker(int inc = 1);
void thread_worker(void); void thread_worker(void);
void process(RAWIMG* img); void process(RAWIMG* img);
void process(image_processor* prc, std::vector<PROCIMGINFO>* in, std::vector<PROCIMGINFO>* out); void process(image_processor* prc, std::vector<PROCIMGINFO>* in, std::vector<PROCIMGINFO>* out);
void send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void* info = nullptr, size_t info_l = 0); void send_image(LPPACKIMAGE head, cv::Mat& mat, void* info = nullptr, size_t info_l = 0);
void send_image(std::vector<PROCIMGINFO>& imgs, bool clear_after_send); void send_image(std::vector<PROCIMGINFO>& imgs);
public: public:
imgproc_mgr(std::function<void(data_source_ptr)> sender, device_option* devopts, CHK_RES_FUNC res = CHK_RES_FUNC()); imgproc_mgr(std::function<void(data_source_ptr)> sender, device_option* devopts, CHK_RES_FUNC res = CHK_RES_FUNC());

View File

@ -928,7 +928,8 @@ uint8_t* file_map::buffer(void)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// image_packet // image_packet
image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid image_packet::image_packet(LPPACKIMAGE head, std::shared_ptr<std::vector<uchar>> img
, uint32_t scanid
, const void* info, size_t info_size) , const void* info, size_t info_size)
: img_(img), offset_(0), info_over_(false) : img_(img), offset_(0), info_over_(false)
{ {
@ -936,7 +937,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
LPPACKIMAGE pimg = nullptr; LPPACKIMAGE pimg = nullptr;
paper_ind_ = head->pos.paper_ind; paper_ind_ = head->pos.paper_ind;
img->add_ref();
if(info && info_size) if(info && info_size)
info_ = std::string((const char*)info, info_size); info_ = std::string((const char*)info, info_size);
else else
@ -949,7 +949,7 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
pack->payload_len = sizeof(PACKIMAGE); pack->payload_len = sizeof(PACKIMAGE);
memcpy(pimg, head, sizeof(*pimg)); memcpy(pimg, head, sizeof(*pimg));
pimg->data_size = img->get_rest(); pimg->data_size = img->size();
pimg->info_size = info_size; pimg->info_size = info_size;
head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE));
@ -970,7 +970,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
image_packet::~image_packet() image_packet::~image_packet()
{ {
head_->release(); head_->release();
img_->release();
} }
bool image_packet::is_memory_block(void) bool image_packet::is_memory_block(void)
@ -979,7 +978,7 @@ bool image_packet::is_memory_block(void)
} }
uint32_t image_packet::get_rest(void) uint32_t image_packet::get_rest(void)
{ {
return head_->get_rest() + info_.length() + img_->get_rest() - offset_; return head_->get_rest() + info_.length() + img_->size() - offset_;
} }
// following API valid when is_memory_block() return true // following API valid when is_memory_block() return true
@ -1023,15 +1022,15 @@ int image_packet::fetch_data(void* buf, uint32_t* size)
} }
else else
{ {
if(*size + offset_ >= img_->get_rest()) if(*size + offset_ >= img_->size())
{ {
memcpy(buf, img_->ptr() + offset_, img_->get_rest() - offset_); memcpy(buf, img_->data() + offset_, img_->size() - offset_);
*size = img_->get_rest() - offset_; *size = img_->size() - offset_;
offset_ = img_->get_rest(); offset_ = img_->size();
} }
else else
{ {
memcpy(buf, img_->ptr() + offset_, *size); memcpy(buf, img_->data() + offset_, *size);
offset_ += *size; offset_ += *size;
} }
} }

View File

@ -11,6 +11,9 @@
#include <functional> #include <functional>
#define CLS_PTR(cls) typedef cls* cls##_ptr; #define CLS_PTR(cls) typedef cls* cls##_ptr;
#ifndef uchar
typedef unsigned char uchar;
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -309,7 +312,8 @@ public:
class image_packet : public data_source class image_packet : public data_source
{ {
dyn_mem* img_; // dyn_mem* img_;
std::shared_ptr<std::vector<uchar>> img_;
dyn_mem* head_; dyn_mem* head_;
uint32_t offset_; uint32_t offset_;
uint32_t paper_ind_ = 0; uint32_t paper_ind_ = 0;
@ -318,7 +322,7 @@ class image_packet : public data_source
std::string pos_str_; std::string pos_str_;
public: public:
image_packet(LPPACKIMAGE head, dyn_mem* img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0); image_packet(LPPACKIMAGE head, std::shared_ptr<std::vector<uchar>> img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0);
protected: protected:
virtual ~image_packet(); virtual ~image_packet();

View File

@ -185,6 +185,9 @@ extern uint64_t GetCurrentThreadId(void);
#define pid_t int #define pid_t int
#define pthread_t HANDLE #define pthread_t HANDLE
#define _GLIBCXX_TXN_SAFE_DYN
#define _GLIBCXX_USE_NOEXCEPT
#endif #endif

View File

@ -298,6 +298,10 @@ public:
{ {
return obj_; return obj_;
} }
T* get(void)
{
return obj_;
}
}; };
// time utility // time utility

View File

@ -187,6 +187,9 @@
#define SANE_STD_OPT_NAME_LUT_FILE "lut-file" #define SANE_STD_OPT_NAME_LUT_FILE "lut-file"
#define SANE_STD_OPT_NAME_PHASE_FRONT "phase-f" #define SANE_STD_OPT_NAME_PHASE_FRONT "phase-f"
#define SANE_STD_OPT_NAME_PHASE_BACK "phase-b" #define SANE_STD_OPT_NAME_PHASE_BACK "phase-b"
#define SANE_STD_OPT_NAME_OUT_FORMAT "img-fmt"
#define SANE_STD_OPT_NAME_JPEG_QUALITY "jpeg-quality"