修复sem_timewait参数错误;增加CIS复原图像算法

This commit is contained in:
gb 2024-01-19 16:54:58 +08:00
parent ccf2a60dae
commit bdf1b11c7e
17 changed files with 396 additions and 59 deletions

View File

@ -31,6 +31,23 @@
},
"range": [300, 600]
},
"y-dpi": {
"cat": "none",
"group": "CIS",
"title": "走纸分辨率",
"desc": "走纸方向的图像采集分辨率",
"type": "int",
"ui-pos": 13,
"auth": 0,
"bind": true,
"size": 4,
"default": {
"resolution>200 && resolution<400": 300,
"resolution>400": 600,
"default": 200
},
"range": [200, 300, 600]
},
"cis-led": {
"cat": "none",
"group": "CIS",
@ -280,8 +297,8 @@
"ui-pos": 23,
"auth": 0,
"size": 4,
"cur": 256,
"default": 256
"cur": 201,
"default": 201
},
"paper-on": {
"cat": "none",
@ -485,7 +502,7 @@
"cis-mode==灰度 && cis-dpi==300": 2637,
"cis-mode==彩色 && cis-dpi==600": 1531,
"cis-mode==灰度 && cis-dpi==600": 4595,
"default": 878
"default": 816
}
},
"expo-fr": {

View File

@ -0,0 +1,16 @@
{
"rebuild": {
"cat": "imgp",
"group": "imgp",
"title": "CIS图像还原",
"desc": "将从CIS输出的原始数据流还原为BMP图片并拆分正反面",
"type": "bool",
"ui-pos": 1,
"auth": 0,
"visible": 0,
"size": 4,
"auto": false,
"cur": true,
"default": true
}
}

View File

@ -455,4 +455,14 @@ void FpgaComm::resetADC() {
bool FpgaComm::is_ok(void)
{
return ok_;
}
void FpgaComm::setVsp(unsigned int Aside,unsigned int BSide)
{
CISVSP vsp;
vsp.bits.ASide_VSP = Aside;
vsp.bits.BSide_VSP = BSide;
vsp.bits.reserved=0;
this->write(13, vsp.value);
}

View File

@ -92,6 +92,17 @@ typedef struct CIS_LED_UV
unsigned short int ledBSide;
} CisLedUv;
typedef union CIS_VSP
{
struct
{
unsigned int ASide_VSP:9;
unsigned int BSide_VSP:9;
unsigned int reserved : 14;
} bits;
int value;
} CISVSP;
typedef union Fpga_Params
{
struct
@ -113,6 +124,7 @@ typedef union Fpga_Params
unsigned int ExpIncr; //0x0a
unsigned int TrigMode; //0x0b
unsigned int DelayTime; //0x0c
CISVSP vsp; // 0x0d
CisLedUv UVLed;
};
unsigned int regs[MAX_REGS];
@ -177,8 +189,6 @@ public:
FpgaComm(int bauds = 921600, bool query = false);
virtual ~FpgaComm(){}
enum { CIS_SECTOR_COUNT = 6 }; // how many sectors of ONE CIS
void reset();
void regsAccess_reset(bool enable);
void setRegs(int addr, int value);
@ -231,6 +241,7 @@ public:
virtual bool read(unsigned int addr, unsigned int& val);
bool is_ok(void);
void setVsp(unsigned int Aside,unsigned int BSide);
private:
FpgaParams fpgaParams;

View File

@ -0,0 +1,26 @@
#include "cis_param.h"
namespace cis
{
int get_sector_pixels(int sec_num, int dpi, bool side)
{
// both side and all sectors has the same pixel
if(dpi == 600)
return 1296;
else
return 648;
}
int get_line_stream_length(int dpi, bool color)
{
int l = get_sector_pixels(0, dpi, true) * CIS_SECTOR_COUNT;
if(color)
l *= 3;
return l;
}
}

26
hardware/cis/cis_param.h Normal file
View File

@ -0,0 +1,26 @@
// parameters of CIS
//
// Date: 2024-01-19
#pragma once
#define CIS_SECTOR_COUNT 6 // how many sectors of ONE CIS
namespace cis
{
// Function: how many pixels one sector generated
//
// Parameter: sec_num - sector index, from Zero to CIS_SECTOR_COUNT - 1
//
// dpi - this sector or CIS resolution
//
// side - true: front, false: back
int get_sector_pixels(int sec_num, int dpi, bool side);
// Function: get pixels for ONE scan line
//
// Parameter: dpi - this sector or CIS resolution
//
// color - true: color, false: gray
int get_line_stream_length(int dpi, bool color);
};

File diff suppressed because one or more lines are too long

View File

@ -19,12 +19,19 @@
// bool: true - image, dyn_mem_ptr is image data buffer; false - dyn_mem_ptr is an uint32_t code of hardware event
//
// LPPACKIMAGE: image information, or uint32_t event data when bool is false
//
// NOTE: LPPACKIMAGE->channels always be 1 as gray bitmap!
//
// real channels(color mode) should judge by
//
// LPPACKIMAGE->width / 2 sides / cis::get_line_stream_length(LPPACKIMAGE->resolution_x, false)
#define IMAGE_HANDLER_PROTO void(dyn_mem_ptr, bool, LPPACKIMAGE)
#include "./cis/FpgaComm.h"
#include "./cis/cis_param.h"
class GVideoISP1;
class gVideo;
class MotorBoard;
class FpgaComm;
class scanner_hw : public sane_opt_provider
{
@ -58,14 +65,15 @@ class scanner_hw : public sane_opt_provider
int cis_length_ = 3888;
bool cis_led_ = true;
int dpi_ = 300;
int dpi_y_ = 300;
int baud_ = 921600;
int delay_ = 1000;
int frame_h_ = 12;
int sample_ = 256;
int sample_ = 201; // 256;
int sp_ = 816;
int exposure_[SIDE_COUNT][COLOR_IND_COUNT];
int gain_[SIDE_COUNT][FpgaComm::CIS_SECTOR_COUNT];
int off_[SIDE_COUNT][FpgaComm::CIS_SECTOR_COUNT];
int gain_[SIDE_COUNT][CIS_SECTOR_COUNT];
int off_[SIDE_COUNT][CIS_SECTOR_COUNT];
double stretch_h_ = 1.0f;
double stretch_v_ = 1.0f;
@ -106,6 +114,6 @@ public:
int open(std::function<IMAGE_HANDLER_PROTO> image_handler);
int start_scan(void);
int stop_scan(void);
int close(void);
int close(bool from_worker = false);
bool is_scanning(void);
};

View File

@ -70,9 +70,20 @@ void MotorBoard::start(void)
void MotorBoard::stop()
{
printf("MotorBoard Stop \n");
unsigned int val;
SMBCONFIG *smbc = (SMBCONFIG *)(&val);
SMBSTATUS *status = (SMBSTATUS*)&val;
if(this->read(MB_PORT_STATUS, val))
{
if(!status->scan_pulse)
{
utils::to_log(LOG_LEVEL_DEBUG, "ignore 'MotorBoard::stop' command for device is not in working(0x%08x).\n", val);
return;
}
}
printf("MotorBoard Stop \n");
read(0, val);
smbc->enable = 0;
write(0, val);

123
imgproc/algs/rebuild.cpp Normal file
View File

@ -0,0 +1,123 @@
#include "rebuild.h"
#include <huagao/hgscanner_error.h>
#include <sane/sane_ex.h>
#include <cis/cis_param.h>
static std::string device_opt_json[] = {
"{\"rebuild\":{\"cat\":\"imgp\",\"group\":\"imgp\",\"title\":\"CIS\\u56fe\\u50cf\\u8fd8\\u539f\",\"desc\":\"\\u5c06\\u4eceCIS\\u8f93\\u51fa\\u7684\\u539f\\u59cb\\u6570\\u636e\\u6d41\\uff0c\\u8fd8\\u539f\\u4e3aBMP\\u56fe\\u7247\\uff0c\\u5e76\\u62c6\\u5206\\u6b63\\u53cd\\u9762\",\"type\":\"bool\",\"ui-pos\":1,\"auth\":0,\"visible\":0,\"size\":4,\"auto\":false,\"cur\":true,\"default\":true}}"
};
rebuild::rebuild() : image_processor("rebuild")
{
std::string t("");
for(auto& v: device_opt_json)
t += v;
image_processor::set_opt_json_text(&t[0]);
}
rebuild::~rebuild()
{}
int rebuild::do_rebuild(PROCIMGINFO& in, std::vector<PROCIMGINFO>& out)
{
int ret = SCANNER_ERR_OK,
secl = cis::get_sector_pixels(0, in.info.resolution_x, true),
linel = cis::get_line_stream_length(in.info.resolution_x, false),
size = in.info.height * in.info.width / 2;
PROCIMGINFO o;
o.info = in.info;
if(in.info.pos.paper_side != PAPER_SIDE_BACK &&
in.info.pos.paper_side != PAPER_SIDE_FRONT)
linel *= 2;
if(in.info.width == linel) // gray
{
}
else // color
{
uint8_t *srcd = in.img.data + in.info.width * (in.info.height - 1), // line reverse
*dstf = (uint8_t*)malloc(size),
*dstb = (uint8_t*)malloc(size),
*df = dstf, *db = dstb,
soff[] = {11, 10, 9, 2, 1, 0};
o.info.channels = 3;
o.info.width /= 3 * 2;
o.info.prc_stage = get_position();
printf("rebuild (%d * %d * 8) to (%d * %d * 24), front = %p, back = %p, size = %u ...\n", in.info.width, in.info.height
, o.info.width, o.info.height, dstf, dstb, size);
for(int h = 0; h < in.info.height; ++h)
{
for(int w = 0; w < o.info.width; ++w)
{
int s = w / secl;
*df++ = srcd[(soff[s] + 0) * secl + (w % secl)];
*df++ = srcd[(soff[s] + 6) * secl + (w % secl)];
*df++ = srcd[(soff[s] + 3) * secl + (w % secl)];
*db++ = srcd[in.info.width / 2 + (soff[s] + 6) * secl + (w % secl)];
*db++ = srcd[in.info.width / 2 + (soff[s] + 0) * secl + (w % secl)];
*db++ = srcd[in.info.width / 2 + (soff[s] + 3) * secl + (w % secl)];
}
srcd -= in.info.width;
}
printf(" bits data ready, construct cv::Mat(front = %u, back = %u) ...\n", df - dstf, db - dstb);
o.info.pos.paper_side = PAPER_SIDE_FRONT;
o.img = cv::Mat(o.info.height, o.info.width, CV_8UC3, (void*)dstf, size);
out.push_back(o);
// free(dstf);
o.info.pos.paper_side = PAPER_SIDE_BACK;
o.img = (cv::Mat(o.info.height, o.info.width, CV_8UC3, (void*)dstb, size));
out.push_back(o);
// free(dstb);
}
return ret;
}
int rebuild::set_value(const char* name/*nullptr for all options*/, void* val/*nullptr for restore*/)
{
int ret = SCANNER_ERR_OK;
if(strcmp(name, SANE_FULL_NAME(CIS_REBUILD)) == 0)
rebuild_ = *(bool*)val;
else
ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
return ret;
}
void rebuild::enable(const char* name, bool able)
{
enabled_ = able;
}
int rebuild::process(std::vector<PROCIMGINFO>& in, std::vector<PROCIMGINFO>& out)
{
int ret = SCANNER_ERR_OK;
if(is_enable() && rebuild_)
{
for(auto& v: in)
{
ret = do_rebuild(v, out);
}
}
else
{
out = std::move(in);
for(auto& v: out)
v.info.prc_stage = get_position();
}
return ret;
}

26
imgproc/algs/rebuild.h Normal file
View File

@ -0,0 +1,26 @@
// rebuild CIS data stream to view-able image (rebuild)
//
// Date: 2024-01-18
#pragma once
#include <imgprc/img_processor.h>
class rebuild : public image_processor
{
bool rebuild_ = true;
int do_rebuild(PROCIMGINFO& in, std::vector<PROCIMGINFO>& out);
public:
rebuild();
protected:
~rebuild();
public:
virtual int set_value(const char* name/*nullptr for all options*/, void* val/*nullptr for restore*/) override;
virtual void enable(const char* name, bool able) override;
public:
virtual int process(std::vector<PROCIMGINFO>& in, std::vector<PROCIMGINFO>& out) override;
};

View File

@ -5,6 +5,7 @@
#include <huagao/hgscanner_error.h>
#include <base/packet.h>
#include "./algs/rebuild.h"
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\"},\"resolution\":{\"cat\":\"base\",\"group\":\"base\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u56fe\\u50cf\\u7684\\u5206\\u8fa8\\u7387\",\"type\":\"int\",\"fix-id\":34840,\"ui-pos\":20,\"auth\":0,\"size\":4,\"cur\":200,\"default\":200,\"range\":{\"min\":100,\"max\":{\"default\":600,\"paper==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8\\u81ea\\u52a8\\u88c1\\u5207 || paper==\\u6700\\u5927\\u626b\\u63cf\\u5c3a\\u5bf8 || paper==\\u4e09\\u8054\\u8bd5\\u5377\":500},\"step\":1}},\"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}}"
@ -35,7 +36,8 @@ imgproc_mgr::imgproc_mgr(std::function<void(data_source_ptr)> sender
if (opts_)
opts_->add_ref();
else
opts_ = new device_option();
opts_ = new device_option(true);
load_processor(nullptr);
auto thrd = [&](void) -> void
{
@ -82,15 +84,23 @@ uint32_t imgproc_mgr::add_busy_worker(int inc)
void imgproc_mgr::thread_worker(void)
{
RAWIMG img;
while(prc_que_.take(img, true))
while(run_)
{
add_busy_worker();
if(prc_que_.take(img, true))
{
add_busy_worker();
process(&img);
if(img.img)
img.data->release();
// 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);
add_busy_worker(-1);
}
}
}
void imgproc_mgr::process(RAWIMG* img)
@ -103,6 +113,9 @@ void imgproc_mgr::process(RAWIMG* img)
ele.ext_info = "";
ele.info = img->info;
ele.img = cv::Mat(ele.info.height, ele.info.width, CV_8UC1, (void*)img->data->ptr(), img->data->get_rest());
// ele.img.create(img->info.height, img->info.width, CV_8UC1);
// memcpy(ele.img.ptr(), img->data->ptr(), img->data->get_rest());
img->data->release();
in.push_back(ele);
if(dump_img_)
@ -135,19 +148,20 @@ void imgproc_mgr::process(RAWIMG* img)
}
void imgproc_mgr::send_image(std::vector<PROCIMGINFO>& imgs, bool clear_after_send)
{
printf("send image %d - %d:\n", imgs[0].info.pos.paper_ind, imgs[0].info.prc_stage);
for(auto& v: imgs)
{
uint32_t size = v.img.total() * v.img.channels();
dyn_mem_ptr mem(dyn_mem::memory(size));
printf("image bits: %p + %u\n", mem->ptr(), size);
// printf(" %d - image bits: %p + %u, src = %p([0] = %02x)\n", v.info.pos.paper_side, mem->ptr(), size, v.img.data, v.img.data[0]);
mem->put(v.img.data, size);
// if(clear_after_send)
// v.img.deallocate();
// printf(" consturct image packet ...\n");
image_packet_ptr ptr = imgproc_mgr::image_sent_packet(&v.info, mem, scan_id_, &v.ext_info[0], v.ext_info.length());
ptr->set_session_id(session_id_);
printf("sending image packet: %p + %u\n", ptr->ptr(), ptr->get_rest());
// printf(" sending image packet: %p + %u\n", ptr->ptr(), ptr->get_rest());
img_sender_(ptr);
ptr->release();
mem->release();
@ -170,13 +184,15 @@ int imgproc_mgr::load_processor(const char* path)
{
int ret = SCANNER_ERR_OK;
#define ADD_IMG_PROCESSOR(cls) \
{ \
cls *obj = new cls(); \
opts_->add(obj); \
obj->release(); \
#define ADD_IMG_PROCESSOR(cls) \
{ \
cls *obj = new cls(); \
opts_->add(obj); \
processors_.push_back(obj); \
}
ADD_IMG_PROCESSOR(rebuild);
std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos);
return ret;
@ -196,6 +212,8 @@ int imgproc_mgr::process(LPPACKIMAGE info, dyn_mem_ptr data, bool img)
int ret = SCANNER_ERR_OK;
ri.data = data;
if(img)
data->add_ref();
if(img)
ri.info = *info;
else

View File

@ -3,10 +3,11 @@ add_rules("mode.debug", "mode.release")
target("imgproc")
set_kind("static")
add_syslinks("pthread", "dl", "opencv_imgcodecs", "opencv_core")
add_includedirs("../sdk")
add_includedirs("../sdk", "../hardware")
add_files("*.cpp", "./algs/*.c*", "../sdk/base/*.c*", "../sdk/imgprc/*.c*", "../sdk/json/*.c*", "../sdk/sane/*.c*", "../sdk/sane_opt_json/*.c*")
--add_deps("gusb", "applog")
--add_rules("utils.bin2c",{linewidth = 32,extension = {".bin"}})
--add_files("table.bin")
add_packages("sdk")
add_deps("hardware")

View File

@ -1707,7 +1707,10 @@ int __stdcall sem_init(sem_t* handle, int, int)
*handle = CreateEvent(NULL, TRUE, FALSE, NULL);
if (*handle)
{
ResetEvent(*handle);
return 0;
}
else
{
errno = GetLastError();
@ -1783,9 +1786,16 @@ bool platform_event::wait(unsigned timeout)
sem_wait(&sem_);
else
{
struct timespec to;
to.tv_sec = timeout / 1000;
to.tv_nsec = (long)((timeout % 1000) * 1000 * 1000);
struct timespec to = {0};
#if !OS_WIN
if(clock_gettime(CLOCK_REALTIME, &to) == -1)
{
utils::to_log(LOG_LEVEL_DEBUG, "clock_gettime failed: %d - %s\n", errno, strerror(errno));
to.tv_sec = time(nullptr);
}
#endif
to.tv_sec += timeout / 1000;
to.tv_nsec += (long)((timeout % 1000) * 1000 * 1000);
waited = sem_timedwait(&sem_, &to) == 0;
}
if (log_)
@ -1798,6 +1808,10 @@ void platform_event::trigger(void)
{
sem_post(&sem_);
}
void platform_event::reset(void)
{
sem_init(&sem_, 0, 0);
}
bool platform_event::is_waiting(void)
{
return waiting_;

View File

@ -270,6 +270,7 @@ public:
bool try_wait(void);
bool wait(unsigned timeout = USB_TIMEOUT_INFINITE/*ms*/); // USB_TIMEOUT_INFINITE is waiting unfinite, true when watied and false for wait timeout
void trigger(void);
void reset(void);
bool is_waiting(void);
void enable_log(bool enable);
@ -335,11 +336,12 @@ public:
return cnt + 1;
}
bool take(T& t, bool wait = false)
bool take(T& t, bool wait = false, uint32_t to_ms = USB_TIMEOUT_INFINITE)
{
if (wait && size() == 0)
{
wait_->wait();
if(!wait_->wait(to_ms))
return false;
}
{
@ -369,6 +371,7 @@ public:
SIMPLE_LOCK(lock_);
que_.clear();
wait_->reset();
}
void trigger(void)
{

View File

@ -235,6 +235,7 @@ enum opt_visible_level // "visible" field
#define SANE_STD_OPT_NAME_DUMP_IMG "dump-img" // 是否输出算法各阶段中间图像
#define SANE_STD_OPT_NAME_DUMP_IMG_PATH "dump-path" // 中间图像输出路径
#define SANE_STD_OPT_NAME_CIS_LENGTH "cis-len" // CIS 长度(采集图像的最大宽度)
#define SANE_STD_OPT_NAME_CIS_REBUILD "rebuild" // 复原从CIS出来的数据流为原始图像
// PART II: 参数类型与华高不一致需要通过“hgsane”组件在中间转换
#define SANE_STD_OPT_NAME_PAGE_W "page-width" // OPTION_TITLE_ZZCC
@ -246,6 +247,7 @@ enum opt_visible_level // "visible" field
// PART III: inner option on device
#define SANE_STD_OPT_NAME_CIS_MODE "cis-mode"
#define SANE_STD_OPT_NAME_CIS_DPI "cis-dpi"
#define SANE_STD_OPT_NAME_Y_DPI "y-dpi"
#define SANE_STD_OPT_NAME_CIS_BAUD "baud"
#define SANE_STD_OPT_NAME_CIS_DELAY "act-after"
#define SANE_STD_OPT_NAME_CIS_FRAME_H "frame-h"

View File

@ -60,8 +60,8 @@ add_packagedirs("sdk")
add_defines("BUILD_AS_DEVICE")
add_defines("VER_MAIN=2")
add_defines("VER_FAMILY=200")
add_defines("VER_DATE=20240117")
add_defines("VER_BUILD=12")
add_defines("VER_DATE=20240119")
add_defines("VER_BUILD=40")
target("conf")
set_kind("phony")