code_device/hgdriver/hgdev/image_process.cpp

1967 lines
52 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "image_process.h"
#include "../wrapper/hg_log.h"
#include <vector>
#include <string.h>
#if !defined(WIN32) && !defined(_WIN64)
#include <unistd.h>
#pragma pack(push)
#pragma pack(1)
typedef struct BITMAPFILEHEADER
{
u_int16_t bfType;
u_int32_t bfSize;
u_int16_t bfReserved1;
u_int16_t bfReserved2;
u_int32_t bfOffBits;
}BITMAPFILEHEADER;
typedef struct BITMAPINFOHEADER
{
u_int32_t biSize;
u_int32_t biWidth;
u_int32_t biHeight;
u_int16_t biPlanes;
u_int16_t biBitCount;
u_int32_t biCompression;
u_int32_t biSizeImage;
u_int32_t biXPelsPerMeter;
u_int32_t biYPelsPerMeter;
u_int32_t biClrUsed;
u_int32_t biClrImportant;
}BITMAPINFODEADER;
#pragma pack(pop)
#define BI_RGB 0
#define MAKEWORD(a, b) (((a) & 0x0ff) | (((b) & 0x0ff) << 8))
#define MAKELONG(a, b) (((a) & 0x0ffff) | (((b) & 0x0ffff) << 16))
#define _countof(a) (sizeof(a) / sizeof((a)[0]))
#else
#include <Windows.h>
#include <shlobj.h>
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "hanwangOCRdetect.lib")
#endif
#include <memory>
#include "ImageMatQueue.h"
#include "../ImageProcess/ImageApplyHeaders.h"
#include "ImageMultiOutput.h"
#include "PaperSize.h"
#include "imgproc/HGOCR.h"
#if defined(WIN32) || defined(_WIN64)
#include "scanner_manager.h"
#include "ocr/hanwangOCRdetect.h"
#else
#include <dlfcn.h>
extern "C"
{
#include "ocr/hanwangOCRdetect.h"
}
#endif
#include "hg_ipc.h"
#include "../ImageProcess/G4Tiff.h"
#include "base/HGImage.h"
#include <opencv2/imgcodecs.hpp>
#define CV_MAT_DEPTH_SET(flags, depth) (((flags) & ~(CV_MAT_DEPTH_MASK)) | (depth & CV_MAT_DEPTH_MASK))
using namespace std;
#define GET_BYTE(a) ((a) & 0x0ff)
#define MAKE_INT(a, b, c, d) (GET_BYTE(a) | (GET_BYTE(b) << 8) | (GET_BYTE(c) << 16) | (GET_BYTE(d) << 24))
#define IMAGE_DATA_BUF_CVMAT (void*)MAKE_INT('M', 'T', 'R', 'X')
#define IMAGE_DATA_BUF_CHAR (void*)MAKE_INT('C', 'H', 'A', 'R')
//动态打开库的命名
#ifdef OEM_HANWANG
#ifdef WIN32
#define IMGPRC_LIBNANE "HWImgProc.dll"
#define HGBASE_LIBNAME "HWBase.dll"
#else
#define IMGPRC_LIBNANE "libHwImgProc.so"
#define HGBASE_LIBNAME "libHwBase.so"
#endif
#elif defined(OEM_LISICHENG)
#ifdef WIN32
#define IMGPRC_LIBNANE "LSCImgProc.dll"
#define HGBASE_LIBNAME "LSCBase.dll"
#else
#define IMGPRC_LIBNANE "libLscImgProc.so"
#define HGBASE_LIBNAME "libLscBase.so"
#endif
#elif defined(OEM_CANGTIAN)
#ifdef WIN32
#define IMGPRC_LIBNANE "CtsImgProc.dll"
#define HGBASE_LIBNAME "CtsBase.dll"
#else
#define IMGPRC_LIBNANE "libCtsImgProc.so"
#define HGBASE_LIBNAME "libCtsBase.so"
#endif
#else
#ifdef WIN32
#define IMGPRC_LIBNANE "HGImgProc.dll"
#define HGBASE_LIBNAME "HGBase.dll"
#else
#define IMGPRC_LIBNANE "libHGImgProc.so"
#define HGBASE_LIBNAME "libHGBase.so"
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// functional ...
////////////////////////////////////////////////////////////////////////////////
//
#ifndef WIN32
#define __stdcall
#endif
#define SAFE_DELETE(p){ \
if (NULL != (p)) {delete []p; \
(p) = NULL; \
}\
}
#if defined(WIN32) || defined(_WIN64)
static int load_dll(const wchar_t* path_dll, HMODULE* dll)
{
HMODULE h = LoadLibraryW(path_dll);
int ret = GetLastError();
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L" = %d\r\n", ret);
OutputDebugStringW((L"[TWAIN]Load: " + std::wstring(path_dll) + info).c_str());
if (!h && ret == ERROR_MOD_NOT_FOUND)
{
std::wstring dir(path_dll);
size_t pos = dir.rfind(L'\\');
wchar_t path[MAX_PATH] = { 0 };
GetDllDirectoryW(_countof(path) - 1, path);
if (pos != std::wstring::npos)
dir.erase(pos);
OutputDebugStringW((L"[TWAIN]Load: try change directory to " + dir + L"\r\n").c_str());
SetDllDirectoryW(dir.c_str());
h = LoadLibraryW(path_dll);
ret = GetLastError();
swprintf_s(info, _countof(info) - 1, L" = %d\r\n", ret);
OutputDebugStringW((L"[TWAIN]Load: " + std::wstring(path_dll) + info).c_str());
OutputDebugStringW((L"[TWAIN]Load: restore directory to " + std::wstring(path) + L"\r\n").c_str());
SetDllDirectoryW(path);
}
if (dll)
*dll = h;
return ret;
}
static int strToWchar(string str, wchar_t* s)
{
if (str.empty() || !s)
{
return -1;
}
size_t size = str.length();
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), size, NULL, 0);
wchar_t* buffer = new wchar_t[size + 1];
MultiByteToWideChar(CP_ACP, 0, str.c_str(), size, buffer, len);
buffer[len] = '\0';
wcscpy(s, buffer);
if (!buffer || !s)
return -1;
delete []buffer;
buffer = NULL;
return 0;
}
#endif
namespace hg_imgproc
{
typedef union
{
unsigned char ch;
struct
{
unsigned char bit0 : 1;
unsigned char bit1 : 1;
unsigned char bit2 : 1;
unsigned char bit3 : 1;
unsigned char bit4 : 1;
unsigned char bit5 : 1;
unsigned char bit6 : 1;
unsigned char bit7 : 1;
}bits;
}BITS;
class bit_stream
{
unsigned char* byte_stream_;
bool lsb_first_; // whether the Lowest_bit is first pop ...
int offset_;
public:
bit_stream(unsigned char* data, bool lsb_first = true) : byte_stream_(data), lsb_first_(lsb_first)
, offset_(0)
{}
~bit_stream()
{}
public:
void reset(int off = 0)
{
offset_ = off;
}
unsigned char get(void)
{
unsigned char ret = 0;
if (lsb_first_)
ret = (byte_stream_[offset_ / 8] >> (offset_ % 8)) & 1;
else
ret = (byte_stream_[offset_ / 8] >> (7 - (offset_ % 8))) & 1;
offset_++;
return ret;
}
};
typedef unsigned int (__stdcall *SDKHGImgProc_InitOCR_)(unsigned int ocrtype, void** pstOcrHandle);
typedef unsigned int (__stdcall *SDKHGImgProc_FreeImage_)(void* pstOcrHandle);
typedef unsigned int (__stdcall *SDKHGImgProc_GetTextDir_)(void* pstOcrHandle, void* image, unsigned int* pDirect);
typedef unsigned int (__stdcall *SDKHGBase_CreateImage_)(void* data, void* imageinfo, void* image);
typedef unsigned int (__stdcall *SDKHGBase_FreeImage_)(void* image);
class imgproc
{
bool isx86_Advan_ = true;
std::string my_path_;
IMGPRCPARAM param_;
SCANCONF img_conf_;
std::shared_ptr<std::string> raw_data_;
std::shared_ptr<vector<char>> buffer_;
std::vector<cv::Mat> mats_;
int pid_;
Device::PaperSize papersize_;
SANE_Image_Statu img_statu_;
SDKHGImgProc_InitOCR_ ocrinit_;
SDKHGImgProc_GetTextDir_ ocrgetdirectimage_;
SDKHGImgProc_FreeImage_ ocrexit_;
SDKHGBase_CreateImage_ HGBase_CreatImg;
SDKHGBase_FreeImage_ HGBase_FreeImg;
void* Auto_Txt_pHanld;
#ifndef WIN32
void *Dynamicopen_HGBase_pHandle_;
void *Dynamicopen_HGImageprc_pHandle_;
#else
HINSTANCE Dynamicopen_HGBase_pHandle_;
HINSTANCE Dynamicopen_HGImageprc_pHandle_;
#endif
void swap_rgb(cv::Mat& mat)
{
unsigned char* first = (unsigned char*)mat.data,
* oper = first;
int line_bytes = mat.rows ? mat.total() * mat.channels() / mat.rows : mat.cols * mat.channels();
for (int i = 0; i < mat.rows; ++i)
{
oper = first;
for (int j = 0; j < mat.cols; ++j)
{
unsigned char ch = oper[0];
oper[0] = oper[2];
oper[2] = ch;
oper += 3;
}
first += line_bytes;
}
}
// construction
public:
imgproc(int pid, bool isx86_Advan) : pid_(pid),papersize_(pid_)
, img_statu_(SANE_Image_Statu_OK)
, my_path_(hg_log::pe_path())
,ocrinit_(NULL),ocrgetdirectimage_(NULL)
,ocrexit_(NULL),HGBase_CreatImg(NULL)
,HGBase_FreeImg(NULL),Auto_Txt_pHanld(NULL)
,Dynamicopen_HGBase_pHandle_(NULL)
,Dynamicopen_HGImageprc_pHandle_(NULL),isx86_Advan_(isx86_Advan)
{
cv::setUseOptimized(isx86_Advan_); //开关cpu高级指令集
}
~imgproc()
{
free_auto_txt_hanld();
}
// load data
public:
int load_raw_data(std::shared_ptr<tiny_buffer> buff)
{
int ret = SCANNER_ERR_INSUFFICIENT_MEMORY;
buffer_.reset(new std::vector<char>(buff->size()));
if (buffer_.get())
{
unsigned int total = buff->size(),
off = 0, size = total;
unsigned char* mem = buff->data(off, &size);
while (mem)
{
memcpy(buffer_->data(), mem, size);
off += size;
if (off >= total)
{
ret = SCANNER_ERR_OK;
break;
}
size = total - off;
mem = buff->data(off, &size);
}
}
mats_.clear();
img_statu_ = (SANE_Image_Statu)buff->get_image_statu();
return ret;
}
int load_file(const char* path_file)
{
mats_.clear();
FILE* src = fopen(path_file, "rb");
if (!src)
return SCANNER_ERR_OPEN_FILE_FAILED;
long len = 0;
fseek(src, 0, SEEK_END);
len = ftell(src);
fseek(src, 0, SEEK_SET);
if (len > 1 * 1024 * 1024 * 1024)
{
fclose(src);
return SCANNER_ERR_INSUFFICIENT_MEMORY;
}
raw_data_.reset(new std::string());
raw_data_->resize(len);
fread(&(*raw_data_)[0], 1, len, src);
fclose(src);
return SCANNER_ERR_OK;
}
// image-processing
public:
int init_auto_txt_hanld()
{
int ret = 0;
#ifndef WIN32
#ifdef OEM_HANWANG
string libname = "libhwdriver.so";
#elif defined(OEM_LISICHENG)
string libname = "liblscdriver.so";
#elif defined(OEM_CANGTIAN)
string libname = "libctsdriver.so";
#else
string libname = "libhgdriver.so";
#endif
string scanner_path = hg_log::get_module_full_path(libname.c_str());
if (scanner_path.empty())
{
return SCANNER_ERR_OUT_OF_RANGE;
}
scanner_path = scanner_path.substr(0, scanner_path.size() - libname.size());
string HGImagePrclib_path = scanner_path + IMGPRC_LIBNANE;
string HGBaselib_path = scanner_path + HGBASE_LIBNAME;
printf("get auto txt path is:%s\r\n", scanner_path.c_str());
if (access(HGBaselib_path.c_str(), F_OK) != 0 && access(HGImagePrclib_path.c_str(), F_OK) != 0)
{
return SCANNER_ERR_OUT_OF_RANGE;
}
printf("HGBaselib_path%s HGImagePrclib_path:%s\r\n",HGBaselib_path.c_str(),HGImagePrclib_path.c_str());
Dynamicopen_HGImageprc_pHandle_ = dlopen(HGImagePrclib_path.c_str(), RTLD_LAZY);
Dynamicopen_HGBase_pHandle_ = dlopen(HGBaselib_path.c_str(), RTLD_LAZY);
if (!Dynamicopen_HGBase_pHandle_ || !Dynamicopen_HGImageprc_pHandle_)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "auto txt open dll is error: %s\n", hg_scanner_err_name(SCANNER_ERR_INSUFFICIENT_MEMORY));
return SCANNER_ERR_INSUFFICIENT_MEMORY;
}
ocrinit_ = (SDKHGImgProc_InitOCR_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_CreateOCRMgr");
ocrgetdirectimage_ = (SDKHGImgProc_GetTextDir_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_ImageTextDirectOCR");
ocrexit_ = (SDKHGImgProc_FreeImage_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_DestroyOCRMgr");
HGBase_CreatImg = (SDKHGBase_CreateImage_)dlsym(Dynamicopen_HGBase_pHandle_,"HGBase_CreateImageWithData");
HGBase_FreeImg = (SDKHGBase_FreeImage_)dlsym(Dynamicopen_HGBase_pHandle_,"HGBase_DestroyImage");
#else
string scanner_path = hg_log::get_module_full_path("scanner.dll");
scanner_path = scanner_path.substr(0, scanner_path.size() - strlen("scanner.dll"));
string HGImagePrclib_path = scanner_path + IMGPRC_LIBNANE;
string HGBaselib_path = scanner_path + HGBASE_LIBNAME;
wchar_t* Prclibbuffer = new wchar_t[HGImagePrclib_path.length() + 1];
wchar_t* Baselibbuffer = new wchar_t[HGBaselib_path.length() + 1];
ret = strToWchar(HGImagePrclib_path, Prclibbuffer);
if (ret == -1 )
return SCANNER_ERR_INSUFFICIENT_MEMORY;
ret = strToWchar(HGBaselib_path, Baselibbuffer);
if (ret == -1)
return SCANNER_ERR_INSUFFICIENT_MEMORY;
load_dll(Baselibbuffer, &Dynamicopen_HGBase_pHandle_); //先加载后释放
load_dll(Prclibbuffer, &Dynamicopen_HGImageprc_pHandle_); //windows下可能会找不到他所在的依赖库导致直接打开动态库的时候找不到模块
SAFE_DELETE(Prclibbuffer);
SAFE_DELETE(Baselibbuffer);
//int l = GetLastError();
if (!Dynamicopen_HGBase_pHandle_ || !Dynamicopen_HGImageprc_pHandle_)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "auto txt open dll is error: %s\n", hg_scanner_err_name(SCANNER_ERR_INSUFFICIENT_MEMORY));
return SCANNER_ERR_INSUFFICIENT_MEMORY;
}
ocrinit_ = (SDKHGImgProc_InitOCR_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_CreateOCRMgr");
ocrgetdirectimage_ = (SDKHGImgProc_GetTextDir_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_ImageTextDirectOCR");
ocrexit_ = (SDKHGImgProc_FreeImage_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_DestroyOCRMgr");
HGBase_CreatImg = (SDKHGBase_CreateImage_)GetProcAddress(Dynamicopen_HGBase_pHandle_, "HGBase_CreateImageWithData");
HGBase_FreeImg = (SDKHGBase_FreeImage_)GetProcAddress(Dynamicopen_HGBase_pHandle_, "HGBase_DestroyImage");
#endif
ocrinit_(HGIMGPROC_OCRALGO_TESSERACT, &Auto_Txt_pHanld);
return ret;
}
int free_auto_txt_hanld()
{
int ret = 0;
if (Auto_Txt_pHanld)
{
int ret = ocrexit_(Auto_Txt_pHanld);
Auto_Txt_pHanld = NULL;
}
if (Dynamicopen_HGImageprc_pHandle_)
{
#if (!defined WIN32)
ret = dlclose(Dynamicopen_HGImageprc_pHandle_);
#else
ret = FreeLibrary(Dynamicopen_HGImageprc_pHandle_);
#endif
Dynamicopen_HGImageprc_pHandle_ = NULL;
}
if (Dynamicopen_HGBase_pHandle_)
{
#if (!defined WIN32)
ret = dlclose(Dynamicopen_HGBase_pHandle_);
#else
ret = FreeLibrary(Dynamicopen_HGBase_pHandle_); //貌似加载顺序不对,会导致这个地方的死锁???
#endif
Dynamicopen_HGBase_pHandle_ = NULL;
}
return ret;
}
int decode(int pid, LPSCANCONF img_param, LPIMGPRCPARAM param)
{
if (!buffer_)
return SCANNER_ERR_NO_DATA;
pid_ = pid;
img_conf_ = *img_param;
param_ = *param;
size_t origin = buffer_->size();
std::vector<std::shared_ptr<std::vector<char>>> buffs;
if(pid == 0x100 || pid == 0x200)
buffs = G200Decode(buffer_,img_conf_.is_duplex,img_conf_.is_switchfrontback).getImageBuffs();
else if(pid == 0x139 || pid == 0x239 ||pid == 0x439)
buffs = GRawDecode(buffer_).getImageBuffs();
else if(pid == 0x300 || pid == 0x400 ||pid == 0x402)
buffs = G400Decode(buffer_,img_conf_.is_duplex).getImageBuffs();
if(buffs.empty())
return -1;
buffer_.reset(new std::vector<char >());
int i=0;
for (auto& buf : buffs)
{
i++;
cv::ImreadModes rmc = param_.channels > 1 ? cv::IMREAD_COLOR : cv::IMREAD_GRAYSCALE;
try
{
if (buf->at(0) == -119 && buf->at(1) == 0x50 && buf->at(2) == 0x4e && buf->at(3) == 0x47)
{
rmc = cv::IMREAD_GRAYSCALE;
param_.black_white = true;
}
else
param_.black_white = false;
if((pid == 0x100 || pid == 0x200 || pid == 0x300 || pid == 0x400|| pid == 0x402)
&& (img_conf_.filter != 3
|| img_conf_.multiOutput == 1
|| img_conf_.multiOutput == 2
|| img_conf_.multiOutput == 0)&& img_conf_.pixtype == COLOR_MODE_24_BITS)
{
rmc = cv::IMREAD_COLOR;
}
cv::Mat mat(cv::imdecode(*buf, rmc));
//cv::imwrite("1.jpg",mat);
if (mat.empty())
{
LOG_INFO(LOG_LEVEL_FATAL, "decode image data error\n");
continue;
}
if (pid == 0x100 || pid == 0x200 || pid == 0x139 || pid == 0x239 || pid_ == 0x439)
{
mats_.push_back(mat);
//cv::imwrite(std::to_string(i)+"_decode.jpg",mat);
}
else if(pid == 0x300 || pid == 0x400|| pid == 0x402)
{
cv::Mat back = mat(cv::Rect(0, 0, mat.cols / 2, mat.rows));
cv::Mat front = mat(cv::Rect(mat.cols / 2, 0, mat.cols / 2, mat.rows));
if(img_conf_.is_duplex)
{
mats_.push_back(img_conf_.is_switchfrontback ? back :front);
mats_.push_back(img_conf_.is_switchfrontback ? front :back);
}
else
{
mats_.push_back(front);
}
back.release();
front.release();
}
//cv::imwrite(std::to_string(i)+"_decode.jpg",mat);
buffer_.reset(new std::vector<char >());
}
catch (const std::exception& e)
{
LOG_INFO(LOG_LEVEL_FATAL, e.what());
throw(e); // 继续抛到上层处理。
}
}
buffs.clear();
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Decode %u bytes to %u picture(s)\n", origin, mats_.size());
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
public:
int correct_text(void)
{
std::string sample(my_path_ + "/data/img/osd.traineddata");
CImageApplyRotation rot(CImageApplyRotation::RotationType::AutoTextOrientation, false, param_.dpi, sample.c_str());
rot.apply(mats_, img_conf_.is_duplex);
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int split(int split3399)
{
std::vector<cv::Mat> mats(mats_);
mats_.clear();
int colormode = 1; //Ĭ<><C4AC>1
if (img_conf_.filter == 3)
colormode = img_conf_.pixtype;
CImageApplySplit split(img_conf_.multiOutput, img_conf_.splitImage, img_conf_.multi_output_red, colormode);
auto matexs = split.SplitMats(mats, img_conf_.is_duplex);
std::string filename ;
int rotation01_ = 1;
int rotation02_ = 1;
if((pid_ == 0x139 || pid_ == 0x239 || pid_ == 0x100 || pid_ == 0x200 || pid_ == 0x439) && (split3399 % 2 ==0) && img_conf_.is_duplex)
{
rotation01_ = 0;
rotation02_ = 1;
}
int i = 0;
for(auto &matex : matexs)
{
cv::flip(matex.mat, matex.mat, rotation01_);
cv::flip(matex.mat,matex.mat,rotation02_);
if (i > 1 && ((pid_ == 0x402) || pid_ == 0x100 || pid_ == 0x400))
{
cv::flip(matex.mat,matex.mat,-1);
}
if(!matex.mat.empty())
mats_.push_back(matex.mat);
i++;
}
CImageApplyRotation::RotationType rotatetype = CImageApplyRotation::RotationType::Invalid;
if (pid_ == 0x402 || pid_ == 0x400 || pid_ == 0x239 || pid_ == 0x439)
rotatetype = CImageApplyRotation::RotationType::Rotate_90_clockwise;
else if(pid_ == 0x100)
rotatetype = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise;
CImageApplyRotation Rotation(rotatetype,false,img_conf_.resolution_native,"./tessdata");
Rotation.apply(mats_,img_conf_.is_duplex);
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int fadeback()
{
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyFadeBackGroudColor fade(100,0, img_conf_.fadebackrange);
for(size_t i = 0; i < mats.size();i++)
{
fade.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
// std::string filename = "/home/huagao/Desktop/fadeback("+std::to_string(num++)+").jpg";
// cv::imwrite(filename,mats_[i]);
// printf("fadeback.size :%d ,filename is =%s\r\n",mats_.size(),filename.c_str());
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int multi_out(int out_type)
{
std::vector<cv::Mat> mats(mats_);
std::vector<cv::Mat> mat;
mats_.clear();
IMageMulti output(out_type);
for(size_t i = 0;i < mats.size();i++)
{
mat = output.apply(mats[i]);
for(size_t j = 0;j < mat.size();j++)
{
//if (out_type != MULTI_COLOR_AND_GRAY && i == mats.size() - 1)
// mats_.push_back(convert_8bit_2_1bit(mat[j], 127, false, false));
//else
mats_.push_back(mat[j]);
// std::string filename = "multi_out("+std::to_string(num++)+").jpg";
// cv::imwrite(filename,mat[j]);
}
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int multi_out_red()
{
std::vector<cv::Mat> mats(mats_);
std::vector<cv::Mat> mat;
mats_.clear();
mat.clear();
ImageMultiOutputRed outred(2);
for(size_t i = 0;i < mats.size();i++)
{
mat = outred.apply(mats[i]);
for(size_t j = 0;j < mat.size();j++)
{
mats_.push_back(mat[j]);
}
// std::string filename = "/home/huagao/Desktop/multi_out_red("+std::to_string(num++)+").jpg";
// cv::imwrite(filename,mats_[i]);
// printf("fadeback.size :%d ,filename is =%s\r\n",mats_.size(),filename.c_str());
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int auto_matic_color(int color_type)
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
for(size_t i = 0;i < mats.size();i++)
{
CImageApplyColorRecognition ColorRecognition(color_type==1?
CImageApplyColorRecognition::ColorRecognitionMode::Color_Gray :
CImageApplyColorRecognition::ColorRecognitionMode::Color_Mono);
ColorRecognition.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
/*pixtype 0 colcor; 1 gray; 2 bw*/
int auto_crop()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
SIZE temp_Size = papersize_.GetPaperSize(img_conf_.papertype, img_conf_.resolution_dst,img_conf_.paperAlign);
cv::Size cvSize(temp_Size.cx, temp_Size.cy);
CImageApplyAutoCrop crop(img_conf_.is_autocrop,img_conf_.autodescrew,img_conf_.fillbackground,cvSize,img_conf_.is_convex,img_conf_.isfillcolor);
crop.apply(mats,img_conf_.is_duplex);
mats_ = mats;
//cv::imwrite("/home/huagao/Desktop/mats_.jpg",mats_[0]);
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int fillhole(float top,float low,float l,float r)
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
float scale = img_conf_.fillhole.fillholeratio / 100.0;
float val = img_conf_.resolution_dst / 10;
cv::Vec4f edgeScale;
edgeScale[0] = top;
edgeScale[1] = low;
edgeScale[2] = l;
edgeScale[3] = r;
CImageApplyOutHole outh(val, edgeScale,50);
outh.apply(mats,img_conf_.is_duplex);
mats_ = mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int resolution_change()
{
int ret = SCANNER_ERR_OK;
CImageApplyFilter::FilterMode sharpenType = CImageApplyFilter::FilterMode::None;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyResize::ResizeType resizeType;
double ratio = 1.0;
SIZE reSize = papersize_.GetPaperSize(img_conf_.papertype, img_conf_.resolution_dst,img_conf_.paperAlign);
cv::Size cvSize(reSize.cx, reSize.cy);
if (img_conf_.is_autocrop || img_conf_.cropRect.enable)
{
resizeType = CImageApplyResize::ResizeType::RATIO;
ratio = img_conf_.resolution_dst / (float)img_conf_.resolution_native;
}
else
resizeType = CImageApplyResize::ResizeType::DSIZE;
CImageApplyResize resize(resizeType,cvSize,ratio,ratio);
resize.apply(mats,img_conf_.is_duplex);
if (img_conf_.resolution_dst > 200 && img_conf_.sharpen == CImageApplyFilter::FilterMode::None)
{
if (img_conf_.resolution_dst <= 300)
sharpenType = CImageApplyFilter::FilterMode::Sharpen;
else if (img_conf_.resolution_dst > 300 && img_conf_.resolution_dst <= 600)
sharpenType = CImageApplyFilter::FilterMode::Sharpen_More;
CImageApplyFilter Filte(sharpenType);
for (size_t i = 0; i < mats.size(); ++i)
{
Filte.apply(mats[i], img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
}
else
{
if(!mats.empty())
mats_ = mats;
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int croprect()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyCustomCrop rect(cv::Rect(img_conf_.cropRect.x, img_conf_.cropRect.y, img_conf_.cropRect.width, img_conf_.cropRect.height));
for (size_t i = 0; i < mats.size(); ++i)
{
rect.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int channel()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyChannel chl((CImageApplyChannel::channel)(img_conf_.filter));
for (size_t i = 0; i < mats.size(); i++)
{
chl.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int adjust_color(unsigned char* gamma_table = nullptr, int tableLength = 0)
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
//VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "adjust_color: table len = %d, brightness = %f, contrast = %f, gamma = %f\n", tableLength
// , img_conf_.brightness, img_conf_.contrast, img_conf_.gamma);
if(gamma_table && tableLength)
{
CImageApplyCustomGamma gamme(gamma_table, tableLength);
gamme.apply(mats, img_conf_.is_duplex);
}
else if(pid_ != 0x0402 && pid_ != 0x0239 && pid_ != 0x439 && pid_ != 0x0302 && pid_ != 0x0139)
{
if (img_conf_.brightness != 128 ||img_conf_.contrast != 4 || ((img_conf_.gamma < (1.0f - 1e-2)) || (img_conf_.gamma > (1.0f + 1e-2))) )
{
int temp_contrast = (img_conf_.contrast - 4) * 12;
CImageApplyAdjustColors justColors(img_conf_.brightness - 128, temp_contrast, img_conf_.gamma);
for (size_t i = 0; i < mats.size(); ++i)
{
justColors.apply(mats[i],img_conf_.is_duplex);
}
}
//cv::imwrite("/home/huagao/Desktop/customgamma2.jpg",mats_[0]);
}
mats_ = mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int antiInflow(int permeate_lv)
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyRefuseInflow Inflow(permeate_lv);
for (size_t i = 0; i < mats.size(); ++i)
{
Inflow.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int colorCorrection()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyAutoContrast con;
con.apply(mats,img_conf_.is_duplex);
mats_= mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int orentation()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
mats_.resize(mats.size());
CImageApplyRotation::RotationType rotatetype = CImageApplyRotation::RotationType::Invalid;
switch ((CImageApplyRotation::RotationType)img_conf_.imageRotateDegree)
{
case CImageApplyRotation::RotationType::Rotate_90_clockwise:
rotatetype = CImageApplyRotation::RotationType::Rotate_90_clockwise;
break;
case CImageApplyRotation::RotationType::Rotate_180:
rotatetype = CImageApplyRotation::RotationType::Rotate_180;
break;
case CImageApplyRotation::RotationType::Rotate_90_anti_clockwise:
rotatetype = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise;
break;
default:
break;
}
if (img_conf_.is_autotext)
rotatetype = CImageApplyRotation::RotationType::AutoTextOrientation;
unsigned char back180 = false;
if (img_conf_.splitImage)
unsigned char back180 = false;
else
back180 = img_conf_.is_backrotate180;
CImageApplyRotation Rotation(rotatetype, back180,img_conf_.resolution_native,"./tessdata");
Rotation.apply(mats,img_conf_.is_duplex);
mats_ = mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int textureRemove()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyTextureRemoval Removal;
Removal.apply(mats,img_conf_.is_duplex);
mats_ = mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int sharpenType()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyFilter::FilterMode sharpenType = (CImageApplyFilter::FilterMode)img_conf_.sharpen;
CImageApplyFilter Filte(sharpenType);
for (size_t i = 0; i < mats.size(); ++i)
{
Filte.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int nosieDetach()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyDetachNoise Noise(img_conf_.detachnoise.detachnoise);
for (size_t i = 0; i < mats.size(); ++i)
{
Noise.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int errorextention()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyBWBinaray::ThresholdType thrtype;
if(img_conf_.errorExtention)
thrtype = CImageApplyBWBinaray::ThresholdType::ERROR_DIFFUSION;
else
thrtype = CImageApplyBWBinaray::ThresholdType::THRESH_BINARY;
CImageApplyBWBinaray BWBinaray(thrtype);
for (size_t i = 0; i < mats.size(); ++i)
{
BWBinaray.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int discardBlank()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
double threshold = 40;
int edge = 30;
if (img_conf_.is_autodiscradblank_vince)
img_conf_.discardblank_percent *= 1.5;
CImageApplyDiscardBlank discardblank(threshold, edge, img_conf_.discardblank_percent);
discardblank.apply(mats, mats.size());
for (size_t i = 0; i < mats.size(); ++i)
{
if (!mats[i].empty())
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int answerSheetFilterRed()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyHSVCorrect correct((CImageApplyHSVCorrect::Red_Removal));
for (size_t i = 0; i < mats.size(); ++i)
{
correct.apply(mats[i],img_conf_.is_duplex);
mats_.push_back(mats[i]);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int fold()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplyConcatenation fold((CImageApplyConcatenation::ConcatMode)img_conf_.fold_concatmode);
fold.apply(mats,img_conf_.is_duplex);
mats_= mats;
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int quality(int dpi_dst)
{
int ret = SCANNER_ERR_OK;
CImageApplyFilter::FilterMode sharpenType = CImageApplyFilter::FilterMode::None;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
//mats_.resize(mats.size());
float xy = (float)dpi_dst/200.0;
for (size_t i = 0; i < mats.size(); ++i)
{
cv::Mat out;
cv::resize(mats[i],out, cv::Size(),xy,xy);
mats_.push_back(out);
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int ocr_auto_txtdirect()
{
std::vector<cv::Mat> mats(mats_);
mats_.clear();
int pDirect = -1,
ret = SCANNER_ERR_OK;
void* pHanld = NULL;
typedef int (* SDKInitialize)(void** ppstOcrHandle);
typedef void(* SDKExit)(void* pstOcrHandle);
typedef int (* SDKGetFileDirectImage)(BYTE* pbImage, int nWidth, int nHeight, TColorType nColorType, void* pstHandle, int* pDirect);
SDKInitialize ocrinit = NULL;
SDKGetFileDirectImage ocrgetdirectimage = NULL;
SDKExit ocrexit = NULL;
#ifndef WIN32
#ifdef OEM_HANWANG
string libname = "libhwdriver.so";
#elif defined(OEM_LISICHENG)
string libname = "liblscdriver.so";
#else
string libname = "libhgdriver.so";
#endif
string scanner_path = hg_log::get_module_full_path(libname.c_str());
if(scanner_path.empty())
{
return SCANNER_ERR_OUT_OF_RANGE;
}
scanner_path = scanner_path.substr(0,scanner_path.size() - libname.size());
scanner_path+="libhwocrdetect.so";
printf("hwlib path:%s\r\n",scanner_path.c_str());
if(access(scanner_path.c_str(),F_OK) != 0)
{
return SCANNER_ERR_OUT_OF_RANGE;
}
#endif
#if ((!defined x86_64) && (!defined WIN32))
//linux x86_64
void *hanlde = dlopen(scanner_path.c_str(),RTLD_LAZY);
if(!hanlde)
{
return SCANNER_ERR_OUT_OF_RANGE;
}
ocrinit = (SDKInitialize)dlsym(hanlde , "HWOCR_SDKInitialize");
ocrgetdirectimage = (SDKGetFileDirectImage)dlsym(hanlde , "HWOCR_GetFileDirectImage");
ocrexit= (SDKExit)dlsym(hanlde , "HWOCR_SDKExit");
#else
#ifdef _WIN32
HINSTANCE handle = LoadLibrary(L"hanwangOCRdetect.dll");
if (handle)
{
ocrinit = (SDKInitialize)GetProcAddress(handle, "HWOCR_SDKInitialize");
ocrgetdirectimage = (SDKGetFileDirectImage)GetProcAddress(handle, "HWOCR_GetFileDirectImage");
ocrexit = (SDKExit)GetProcAddress(handle, "HWOCR_SDKExit");
}
#endif // WIN32
#endif
int r = ocrinit(&pHanld);
for (size_t i = 0; i < mats.size(); i++)
{
r = ocrgetdirectimage(const_cast<uchar*>(mats[i].data), mats[i].cols, mats[i].rows, mats[i].channels() == 1 ? TColorType::EGray256 : TColorType::EColor16M, pHanld, &pDirect);
if (pDirect == 1)
pDirect = 3;
else if (pDirect == 3)
pDirect = 1;
CImageApplyRotation(CImageApplyRotation::RotationType(pDirect)).apply(mats[i], false);
mats_.push_back(mats[i]);
}
ocrexit(pHanld);
#if ((!defined x86_64) && (!defined WIN32))
dlclose(hanlde);
#else
#endif
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int tesseract_auto_txtdirect()
{
if (!Auto_Txt_pHanld)
{
return SCANNER_ERR_NO_DATA;
}
std::vector<cv::Mat> mats(mats_);
mats_.clear();
unsigned int pDirect = 0,
ret = SCANNER_ERR_OK;
HGImage image;
if (ocrinit_ && ocrgetdirectimage_ && ocrexit_)
{
for (size_t i = 0; i < mats.size(); i++)
{
HGImage b = opencv_to_hgbase_image(mats[i]);
ret = ocrgetdirectimage_(Auto_Txt_pHanld, b, &pDirect);
HGBase_FreeImg(b);
//HGBase_DestroyImage(b);
switch (pDirect)
{
case HGIMGPROC_OCRTEXTDIRECT_ORI:
pDirect = (unsigned int)CImageApplyRotation::RotationType::Invalid;
break;
case HGIMGPROC_OCRTEXTDIRECT_RIGHT:
pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_90_anti_clockwise;
break;
case HGIMGPROC_OCRTEXTDIRECT_LEFT:
pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_90_clockwise;
break;
case HGIMGPROC_OCRTEXTDIRECT_180:
pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_180;
break;
default:
pDirect = (int)CImageApplyRotation::RotationType::Invalid;
break;
}
CImageApplyRotation(CImageApplyRotation::RotationType(pDirect)).apply(mats[i], false);
mats_.push_back(mats[i]);
}
}
if (mats_.empty())
{
return SCANNER_ERR_NO_DATA;
}
return SCANNER_ERR_OK;
}
int size_detection()
{
int ret = SCANNER_ERR_OK;
std::vector<cv::Mat> mats(mats_);
mats_.clear();
CImageApplySizeDetection paper(img_conf_.papertype);
for (size_t i = 0; i < mats.size(); ++i)
{
ret = paper.apply(mats[i]);
mats_.push_back(mats[i]);
}
if(ret == 1)
{
return SCANNER_ERR_DEVICE_SIZE_CHECK;
}
return SCANNER_ERR_OK;
}
HGImage opencv_to_hgbase_image(const cv::Mat& mats)
{
HGImage image;
HGImageInfo info;
info.height = mats.rows;
info.width = mats.cols;
info.origin = HGBASE_IMGORIGIN_TOP;
int bits = mats.channels() == 1 ? 8 : 24;
info.widthStep = mats.step; //opencv原始值
info.type = mats.channels() == 1 ? HGBASE_IMGTYPE_GRAY : HGBASE_IMGTYPE_BGR;
int ret = HGBase_CreatImg(const_cast<uchar*>(mats.data), &info, &image);
//int ret = HGBase_CreateImageWithData(const_cast<uchar*>(mats.data), &info, &image);
return image;
}
/// <summary>
/// 8位图转1位图
/// </summary>
/// <param name="image">8bit图</param>
/// <param name="threshold">阈值建议默认127</param>
/// <param name="reverse">true为反色即黑0白1反之亦然</param>
/// <param name="align">true为四字节对齐</param>
/// <returns>1位图</returns>
///
static cv::Mat convert_8bit_2_1bit(const cv::Mat& image, uchar threshold, bool reverse, bool align)
{
if (image.channels() != 1)
return cv::Mat();
int cols = align ? (((image.cols + 7) / 8 + 3) / 4 * 4) : ((image.cols + 7) / 8);
int rows = image.rows;
uchar tableData[256];
memset(tableData, reverse ? 0 : 1, 256);
memset(tableData, reverse ? 1 : 0, threshold);
int* index_dst = new int[image.cols];
int* index_carry = new int[image.cols];
for (size_t i = 0; i < image.cols; i++)
{
index_dst[i] = i / 8;
index_carry[i] = 7 - (i % 8);
}
cv::Mat dst = cv::Mat::zeros(rows, cols, CV_8UC1);
uchar* ptr_src, * ptr_dst;
for (size_t y = 0; y < rows; y++)
{
ptr_dst = dst.ptr<uchar>(y);
ptr_src = const_cast<uchar*>(image.ptr<uchar>(y));
for (size_t x = 0; x < image.cols; x++)
ptr_dst[index_dst[x]] += tableData[ptr_src[x]] << index_carry[x];
}
delete[] index_dst;
delete[] index_carry;
return dst;
}
// final
public:
int final(void)
{
std::vector<cv::Mat> mats(mats_);
mats_.clear();
for (size_t i = 0; i < mats.size(); ++i)
{
if (mats[i].empty())
continue;
int bpp = param_.black_white ? 8 : param_.bits * param_.channels;
MatEx out(mats[i], bpp);
if (out.mat.channels() == 3)
swap_rgb(out.mat);
mats_.push_back(out.mat);
//cv::imwrite(std::to_string(i++)+"_final.jpg",out.mat);
}
return SCANNER_ERR_OK;
}
int get_final_data(LPIMGHEAD pimh, void** buf, int index)
{
if ((index < 0 || index >= mats_.size()))
return SCANNER_ERR_NO_DATA;
pimh->width = mats_[index].cols;
pimh->height = mats_[index].rows;
pimh->bits = 8; //mats_[index].depth
pimh->channels = mats_[index].channels();
pimh->total_bytes = mats_[index].total() * pimh->channels;
pimh->line_bytes = pimh->height ? pimh->total_bytes / pimh->height : pimh->width * pimh->channels;
*buf = mats_[index].data;
pimh->statu = img_statu_;
//printf("pimh->channels = %d \r\n",pimh->channels);
return SCANNER_ERR_OK;
}
int get_final_data(LPIMGHEAD pimh, std::vector<unsigned char>* buf, int index)
{
if ((index < 0 || index >= mats_.size()))
return SCANNER_ERR_NO_DATA;
pimh->width = mats_[index].cols;
pimh->height = mats_[index].rows;
pimh->bits = 8; //mats_[index].depth
pimh->channels = mats_[index].channels();
pimh->statu = img_statu_;
if((pimh->width * pimh->channels) % 4)
{
int len = pimh->width * pimh->channels;
pimh->line_bytes = (len + 3) / 4 * 4;
pimh->total_bytes = pimh->line_bytes * pimh->height;
buf->resize(pimh->total_bytes);
//printf("pimh->total_bytes=%d pimh->line_bytes=%d\r\n",pimh->total_bytes,pimh->line_bytes);
unsigned char* src = mats_[index].data, *dst = buf->data();
for(int i = 0; i < pimh->height; ++i)
{
memcpy(dst, src, len);
dst += pimh->line_bytes;
src += len;
}
}
else
{
pimh->total_bytes = mats_[index].total() * pimh->channels;
pimh->line_bytes = pimh->height ? pimh->total_bytes / pimh->height : pimh->width * pimh->channels;
buf->resize(pimh->total_bytes);
memcpy(buf->data(), mats_[index].data, pimh->total_bytes);
//cv::imwrite(to_string(index)+"_final.jpg",mats_[index]);
}
//printf("pimh->channels_01 = %d \r\n",pimh->channels);
return SCANNER_ERR_OK;
}
int imgtypechange(std::string img_type_,void *buf,std::vector<unsigned char> &bmpdata)
{
int ret = SCANNER_ERR_OK;
if(!buf)
{
return SCANNER_ERR_NO_DATA;
}
cv::imencode(img_type_,*((cv::Mat*)buf),bmpdata);
return ret;
}
void dump_2_file(const char* local_file)
{
if (mats_.size())
{
cv::imwrite(local_file, mats_[0]);
if (mats_.size() > 1)
{
std::string path(local_file), name(""), ext("");
size_t pos = path.rfind(PATH_SEPARATOR[0]);
char sn[20] = { 0 };
if (pos++ != std::string::npos)
{
name = path.substr(pos);
path.erase(pos);
pos = name.rfind('.');
if (pos != std::string::npos)
{
ext = name.substr(pos);
name.erase(pos);
}
}
for (size_t i = 1; i < mats_.size(); ++i)
{
sprintf(sn, "(%d)", i);
cv::imwrite((path + name + sn + ext).c_str(), mats_[i]);
}
}
}
else
{
LOG_INFO(LOG_LEVEL_ALL, "No image output in image_process!\n");
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// api ...
HIMGPRC init(int pid,bool isx86_Advan_)
{
imgproc* obj = new imgproc(pid, isx86_Advan_);
return (HIMGPRC)obj;
}
int load_buffer(HIMGPRC himg, std::shared_ptr<tiny_buffer> buff)
{
return ((imgproc*)himg)->load_raw_data(buff);
}
int load_file(HIMGPRC himg, const char* path_file)
{
return ((imgproc*)himg)->load_file(path_file);
}
int decode(HIMGPRC himg, int pid, LPSCANCONF img_param, LPIMGPRCPARAM param)
{
return ((imgproc*)himg)->decode(pid, img_param, param);
}
int init_auto_txt_hanld(HIMGPRC himg)
{
return ((imgproc*)himg)->init_auto_txt_hanld();
}
int free_auto_txt_hanld(HIMGPRC himg)
{
return ((imgproc*)himg)->free_auto_txt_hanld();
}
int correct_text(HIMGPRC himg)
{
return ((imgproc*)himg)->correct_text();
}
int split(HIMGPRC himg,int split3399)
{
return ((imgproc*)himg)->split(split3399);
}
int fadeback(HIMGPRC himg)
{
return ((imgproc*)himg)->fadeback();
}
int multi_out(HIMGPRC himg,int out_type)
{
return ((imgproc*)himg)->multi_out(out_type);
}
int multi_out_red(HIMGPRC himg)
{
return ((imgproc*)himg)->multi_out_red();
}
int auto_matic_color(HIMGPRC himg,int color_type)
{
return ((imgproc*)himg)->auto_matic_color(color_type);
}
int auto_crop(HIMGPRC himg)
{
return ((imgproc*)himg)->auto_crop();
}
int fillhole(HIMGPRC himg, float top, float low, float l, float r)
{
return ((imgproc*)himg)->fillhole(top, low, l,r);
}
int resolution_change(HIMGPRC himg)
{
return ((imgproc*)himg)->resolution_change();
}
int croprect(HIMGPRC himg)
{
return ((imgproc*)himg)->croprect();
}
int channel(HIMGPRC himg)
{
return ((imgproc*)himg)->channel();
}
int adjust_color(HIMGPRC himg, unsigned char* table, int tableLength)
{
return ((imgproc*)himg)->adjust_color(table, tableLength);
}
int antiInflow(HIMGPRC himg,int permeate_lv)
{
return ((imgproc*)himg)->antiInflow(permeate_lv);
}
int colorCorrection(HIMGPRC himg)
{
return ((imgproc*)himg)->colorCorrection();
}
int orentation(HIMGPRC himg)
{
return ((imgproc*)himg)->orentation();
}
int textureRemove(HIMGPRC himg)
{
return ((imgproc*)himg)->textureRemove();
}
int sharpenType(HIMGPRC himg)
{
return ((imgproc*)himg)->sharpenType();
}
int nosieDetach(HIMGPRC himg)
{
return ((imgproc*)himg)->nosieDetach();
}
int errorextention(HIMGPRC himg)
{
return ((imgproc*)himg)->errorextention();
}
int discardBlank(HIMGPRC himg)
{
return ((imgproc*)himg)->discardBlank();
}
int answerSheetFilterRed(HIMGPRC himg)
{
return ((imgproc*)himg)->answerSheetFilterRed();
}
//img_type_ = jpg png bmp
int imgtypechange(HIMGPRC himg,std::string img_type_,void *buf,std::vector<unsigned char> &bmpdata)
{
return ((imgproc*)himg)->imgtypechange(img_type_,buf,bmpdata);
}
int fold(HIMGPRC himg)
{
return ((imgproc*)himg)->fold();
}
int quality(HIMGPRC himg,int dpi)
{
return ((imgproc*)himg)->quality(dpi);
}
int ocr_auto_txtdirect(HIMGPRC himg)
{
return ((imgproc*)himg)->ocr_auto_txtdirect();
}
int tesseract_auto_txtdirect(HIMGPRC himg)
{
return ((imgproc*)himg)->tesseract_auto_txtdirect();
}
int size_detection(HIMGPRC himg)
{
return ((imgproc*)himg)->size_detection();
}
int final(HIMGPRC himg)
{
return ((imgproc*)himg)->final();
}
int get_final_data(HIMGPRC himg, LPIMGHEAD pimh, void** buf, int index)
{
return ((imgproc*)himg)->get_final_data(pimh, buf, index);
}
int get_final_data(HIMGPRC himg, LPIMGHEAD pimh, std::vector<unsigned char>* buf, int index)
{
return ((imgproc*)himg)->get_final_data(pimh, buf, index);
}
void dump_2_file(HIMGPRC himg, const char* local_file)
{
((imgproc*)himg)->dump_2_file(local_file);
}
void release(HIMGPRC himg)
{
imgproc* obj = (imgproc*)himg;
delete obj;
}
// seperate utilites ...
static cv::Mat from_bmp_file_bits(const BITMAPINFOHEADER& bih, unsigned char* data, bool line_reverse, bool bw_reverse)
{
cv::Mat m;
int bytes = 0, align = 0;
unsigned char *dst = NULL;
m.create(bih.biHeight, bih.biWidth, bih.biBitCount > 8 ? CV_8UC3 : CV_8UC1);
dst = m.ptr();
bytes = (bih.biBitCount * bih.biWidth + 7) / 8;
align = (bytes + 3) / 4 * 4;
if (line_reverse)
{
data += align * (bih.biHeight - 1);
align *= -1;
}
if (bih.biBitCount >= 8)
{
if (bih.biBitCount == 8 && bw_reverse)
{
for (int i = 0; i < bih.biHeight; ++i)
{
for (int j = 0; j < bytes; ++j)
dst[j] = data[j] ^ 0x0ff;
dst += bytes;
data += align;
}
}
else
{
for (int i = 0; i < bih.biHeight; ++i)
{
memcpy(dst, data, bytes);
dst += bytes;
data += align;
}
}
}
else // if (bih.biBitCount == 1)
{
unsigned char bw[] = { !bw_reverse - 1, bw_reverse - 1};
bytes = bih.biWidth;
for (int i = 0; i < bih.biHeight; ++i)
{
bit_stream bs(data, false);
for (int j = 0; j < bih.biWidth; ++j)
dst[j] = bw[bs.get()];
dst += bytes;
data += align;
}
}
return m;
}
int convert_image_file(SANE_ImageFormatConvert* conv)
{
if (conv->src.fmt.img_format != SANE_IMAGE_TYPE_BMP &&
conv->src.fmt.compress.compression != SANE_COMPRESSION_NONE)
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
if(conv->dst.fmt.img_format != SANE_IMAGE_TYPE_JFIF &&
conv->dst.fmt.img_format != SANE_IMAGE_TYPE_TIFF &&
conv->dst.fmt.compress.compression != SANE_COMPRESSION_NONE &&
conv->dst.fmt.compress.compression != SANE_COMPRESSION_GROUP4)
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
int fh = sizeof(BITMAPFILEHEADER);
BITMAPINFOHEADER bih = { 0 };
unsigned char *bits = NULL;
std::shared_ptr<std::vector<unsigned char>> data;
if (conv->src.is_file)
{
BITMAPFILEHEADER bfh = { 0 };
FILE* src = fopen(conv->src.data, "rb");
long len = 0;
if (!src)
return SCANNER_ERR_OPEN_FILE_FAILED;
fseek(src, 0, SEEK_END);
len = ftell(src) - fh;
if (len <= 0)
{
fclose(src);
return SCANNER_ERR_DATA_DAMAGED;
}
fseek(src, 0, SEEK_SET);
fread(&bfh, sizeof(bfh), 1, src);
fread(&bih, sizeof(bih), 1, src);
if (len < bfh.bfOffBits)
{
fclose(src);
return SCANNER_ERR_DATA_DAMAGED;
}
// we consider pallete as gray, discard pallete here ...
fseek(src, bfh.bfOffBits, SEEK_SET);
len -= bfh.bfOffBits;
data.reset(new std::vector<unsigned char>(len));
fread(&(*data.get())[0], 1, len, src);
fclose(src);
bits = data.get()->data();
}
else
{
memcpy(&bih, conv->src.data + fh, sizeof(bih));
bits = (unsigned char*)conv->src.data + ((BITMAPFILEHEADER*)conv->src.data)->bfOffBits;
}
bool tiff = conv->dst.fmt.img_format == SANE_IMAGE_TYPE_TIFF;
int resolution = bih.biXPelsPerMeter / 39.37f + .5f,
threshold = (int)(long)conv->dst.fmt.compress.detail;
cv::Mat imsg = from_bmp_file_bits(bih, data->data(), tiff || conv->dst.fmt.img_format == SANE_IMAGE_TYPE_JFIF, tiff && conv->dst.fmt.compress.compression != SANE_COMPRESSION_GROUP4);
data.reset();
if (tiff)
{
if (bih.biBitCount == 24)
{
if (conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4)
cvtColor(imsg, imsg, cv::COLOR_RGB2GRAY);
else
{
for (int y = 0; y < bih.biHeight; ++y)
{
uint8_t* row = imsg.ptr(y);
for (int x = 0; x < bih.biWidth; ++x)
{
uint8_t t = row[x * 3 + 0];
row[x * 3 + 0] = row[x * 3 + 2];
row[x * 3 + 2] = t;
}
}
}
}
int compression = conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4 ? COMPRESSION_CCITT_T6 : COMPRESSION_NONE;
if (conv->dst.is_file)
{
G4Tiff tiff(imsg, G4Tiff::Mode::FileMode, conv->dst.data, threshold, resolution, compression);
tiff.SaveG4Tiff();
}
else
{
G4Tiff tiff(imsg, G4Tiff::Mode::MemoryMode, "", threshold, resolution, compression);
size_t bytes = 0;
conv->dst.data = (SANE_String_Const)tiff.get_compressed_data(&bytes, allocate_memory);
conv->dst.data_len = bytes;
}
}
else if (conv->dst.fmt.img_format == SANE_IMAGE_TYPE_JFIF)
{
// MSB word[7] and word[8] are x and y resolutions
std::vector<int> cpr;
unsigned short jpeg_r = (resolution << 8) | ((resolution >> 8) & 0x0ff);
int resolution_y = bih.biYPelsPerMeter / 39.37f + .5f;
cpr.push_back(CV_IMWRITE_JPEG_QUALITY);
cpr.push_back((int)(long)conv->dst.fmt.detail);
cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_UNIT);
cpr.push_back(1);
cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_X);
cpr.push_back(resolution);
cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_Y);
cpr.push_back(resolution_y);
if (conv->dst.is_file)
{
cv::imwrite(conv->dst.data, imsg, cpr);
//FILE* f = fopen(conv->dst.data, "rb+");
//if (f)
//{
// fseek(f, 0x0e, SEEK_SET);
// fwrite(&jpeg_r, sizeof(jpeg_r), 1, f);
// fwrite(&jpeg_r, sizeof(jpeg_r), 1, f);
// fclose(f);
//}
}
else
{
std::string tmpf(hg_log::temporary_path() + PATH_SEPARATOR + "imgtrans.tmp");
cv::imwrite(tmpf.c_str(), imsg, cpr);
size_t bytes = 0;
conv->dst.data = (SANE_String_Const)G4Tiff::load_mini_file(tmpf.c_str(), &bytes, allocate_memory);
conv->dst.data_len = bytes;
remove(tmpf.c_str());
//if (conv->dst.data_len > 0x20)
// ((unsigned short*)conv->dst.data)[7] = ((unsigned short*)conv->dst.data)[8] = jpeg_r;
}
}
else if (conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4)
{
std::vector<uchar> cmp;
if (bih.biBitCount == 24)
cvtColor(imsg, imsg, cv::COLOR_RGB2GRAY);
if (conv->dst.is_file)
{
G4Tiff tiff(imsg, G4Tiff::Mode::FileMode, conv->dst.data, threshold, resolution);
tiff.SaveG4Tiff();
}
else
{
G4Tiff tiff(imsg, G4Tiff::Mode::MemoryMode, "", threshold, resolution);
size_t bytes = 0;
conv->dst.data = (SANE_String_Const)tiff.get_compressed_data(&bytes, allocate_memory);
conv->dst.data_len = bytes;
}
}
return SCANNER_ERR_OK;
}
int save_2_bmp_file(const char* bmp_file, LPIMGHEAD head, void* buf, int resolution)
{
BITMAPINFOHEADER bih = { 0 };
BITMAPFILEHEADER fh = { 0 };
int pal_size = 0, line_len = (head->channels * head->bits * head->width + 31) / 32 * 4;
FILE *dst = fopen(bmp_file, "wb");
if (!dst)
return errno;
bih.biSize = sizeof(bih);
bih.biWidth = head->width;
bih.biBitCount = head->channels * head->bits;
bih.biSizeImage = head->height * line_len;
bih.biPlanes = 1;
bih.biHeight = head->height;
bih.biCompression = BI_RGB;
bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f;
if (bih.biBitCount == 1)
pal_size = 2 * sizeof(int);
else if (bih.biBitCount == 8)
pal_size = 256 * sizeof(int);
fh.bfType = MAKEWORD('B', 'M');
fh.bfOffBits = sizeof(fh) + sizeof(bih) + pal_size;
fh.bfSize = fh.bfOffBits + bih.biSizeImage;
fwrite(&fh, sizeof(fh), 1, dst);
fwrite(&bih, sizeof(bih), 1, dst);
if (bih.biBitCount == 1)
{
int pal[] = { 0, 0x0ffffff };
fwrite(pal, sizeof(pal), 1, dst);
}
else if (bih.biBitCount == 8)
{
static unsigned int g_bmp8_pallete[256] = { 0 };
if (g_bmp8_pallete[1] == 0)
{
for (int i = 1; i < _countof(g_bmp8_pallete); ++i)
g_bmp8_pallete[i] = MAKELONG(MAKEWORD(i, i), MAKEWORD(i, 0));
}
fwrite(g_bmp8_pallete, sizeof(g_bmp8_pallete), 1, dst);
}
if (line_len == head->line_bytes)
fwrite(buf, 1, head->total_bytes, dst);
else
{
unsigned char* ptr = (unsigned char*)buf;
unsigned int pad = 0;
int pad_l = 4 - (head->line_bytes % 4), step = head->line_bytes;
if (1)
{
ptr += head->total_bytes - head->line_bytes;
step *= -1;
}
for (int i = 0; i < head->height; ++i)
{
fwrite(ptr, head->line_bytes, 1, dst);
fwrite(&pad, 1, pad_l, dst);
ptr += step;
}
}
fclose(dst);
return 0;
}
static unsigned char reverse_bit(unsigned char v)
{
unsigned char r = 0;
for (int i = 0; i < 8; ++i)
{
r <<= 1;
r |= v & 1;
v >>= 1;
}
return r;
}
std::string bmp8_2_1bit(const unsigned char* data, int w, int h, int line_len, int threshold, bool reverse, bool align)
{
cv::Mat m;
unsigned char* dst = NULL;
m.create(h, w, CV_8UC1);
dst = m.ptr();// +w * (h - 1);
for (int i = 0; i < h; ++i)
{
memcpy(dst, data, w);
dst += w;
data += line_len;
}
cv::Mat bw = imgproc::convert_8bit_2_1bit(m, threshold, reverse, align);
//std::string ret("");
//dst = bw.ptr();
//for (int i = 0; i < bw.total(); ++i)
// dst[i] = reverse_bit(dst[i]);
return std::string((char*)bw.ptr(), bw.total());
}
}