添加图像压缩算法

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

@ -383,13 +383,13 @@ void scanner_hw::thread_image_capture(bool paper_ready)
devui::send_message(devui::UI_STATUS_SCANNING, (uint8_t*)&scanstream, sizeof(scanstream));
while(scanning_) // auto scan cycle ...
{
err = start_and_wait_lifter(to_lifter_, &over_msg_id);
if(err)
break;
// scanning ONE turn ...
if(paper_ready) // auto_scan_ ignore no paper
{
err = start_and_wait_lifter(to_lifter_, &over_msg_id);
if(err)
break;
motor_->pick_paper();
err = scan_one_turn(&img, &avail_mem, &used_v4l2_mem, &over_msg_id);
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/color_correct.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
opts_ = new device_option(true);
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
{
@ -96,12 +101,6 @@ data_source_ptr imgproc_mgr::scan_finished_packet(uint32_t scanid, uint32_t err)
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)
{
@ -148,7 +147,7 @@ void imgproc_mgr::process(RAWIMG* img)
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());
}
else
@ -161,12 +160,15 @@ void imgproc_mgr::process(RAWIMG* 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();
for(auto& v: processors_)
{
send_image(*src, false);
send_image(*src);
if(v->is_enable())
{
process(v, src, dst);
@ -196,7 +198,7 @@ void imgproc_mgr::process(RAWIMG* img)
v.info.prc_time = t;
}
send_image(*src, true);
send_image(*src);
}
else
{
@ -234,7 +236,7 @@ void imgproc_mgr::process(image_processor* prc, std::vector<PROCIMGINFO>* in, st
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
{
@ -244,31 +246,18 @@ void imgproc_mgr::send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void*
return 0;
};
dyn_mem_ptr mem(dyn_mem::memory(size));
image_packet_ptr ptr = nullptr;
PACKIMAGE h(*head);
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_);
img_sender_(ptr);
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)
{
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();
}
send_image(&v.info, v.img, v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length());
}
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(auto_crop);
ADD_IMG_PROCESSOR(color_correct);
// ADD_IMG_PROCESSOR(img_encoder);
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 rebuild;
class img_encoder;
class imgproc_mgr : public sane_opt_provider
{
@ -27,7 +28,8 @@ class imgproc_mgr : public sane_opt_provider
bool img;
}RAWIMG;
refer_guard<rebuild> rebuild_;
refer_guard<rebuild> first_;
refer_guard<img_encoder> last_;
image_processor* stretcher_ = nullptr;
bool do_rebuild_ = 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_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 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);
void thread_worker(void);
void process(RAWIMG* img);
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(std::vector<PROCIMGINFO>& imgs, bool clear_after_send);
void send_image(LPPACKIMAGE head, cv::Mat& mat, void* info = nullptr, size_t info_l = 0);
void send_image(std::vector<PROCIMGINFO>& imgs);
public:
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(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)
: 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;
paper_ind_ = head->pos.paper_ind;
img->add_ref();
if(info && info_size)
info_ = std::string((const char*)info, info_size);
else
@ -949,7 +949,7 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
pack->payload_len = sizeof(PACKIMAGE);
memcpy(pimg, head, sizeof(*pimg));
pimg->data_size = img->get_rest();
pimg->data_size = img->size();
pimg->info_size = info_size;
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()
{
head_->release();
img_->release();
}
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)
{
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
@ -1023,15 +1022,15 @@ int image_packet::fetch_data(void* buf, uint32_t* size)
}
else
{
if(*size + offset_ >= img_->get_rest())
if(*size + offset_ >= img_->size())
{
memcpy(buf, img_->ptr() + offset_, img_->get_rest() - offset_);
*size = img_->get_rest() - offset_;
offset_ = img_->get_rest();
memcpy(buf, img_->data() + offset_, img_->size() - offset_);
*size = img_->size() - offset_;
offset_ = img_->size();
}
else
{
memcpy(buf, img_->ptr() + offset_, *size);
memcpy(buf, img_->data() + offset_, *size);
offset_ += *size;
}
}

View File

@ -11,6 +11,9 @@
#include <functional>
#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
{
dyn_mem* img_;
// dyn_mem* img_;
std::shared_ptr<std::vector<uchar>> img_;
dyn_mem* head_;
uint32_t offset_;
uint32_t paper_ind_ = 0;
@ -318,7 +322,7 @@ class image_packet : public data_source
std::string pos_str_;
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:
virtual ~image_packet();

View File

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

View File

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

View File

@ -187,6 +187,9 @@
#define SANE_STD_OPT_NAME_LUT_FILE "lut-file"
#define SANE_STD_OPT_NAME_PHASE_FRONT "phase-f"
#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"