龙芯MIPS64上实现C++,Python一维码,二维码识别
Dynamsoft最近提供了支持MIPS64的一维码,二维码的C++ SDK。我在统信UOS上用C++和Python上做了测试,可以正常使用。
SDK下载
统信UOS环境配置
使用sudo apt update
的时候可能会碰到错误:无法安全地用该源进行更新,所以默认禁用该源
。解决方法是在/etc/apt/sources.list
中更换源 deb http://mirrors.aliyun.com/debian stable main contrib non-free
。
C++识别一维码,二维码
创建一个CMake工程,包含CMakeLists.txt
,BarcodeReaderDemo.cpp
, DynamsoftBarcodeReader.h
, DynamsoftCommon.h
以及libDynamsoftBarcodeReader.so
。
CMakeLists.txt
文件很简单。配置一下头文件,库文件路径以及源文件:
cmake_minimum_required(VERSION 3.0.0)
project(BarcodeReaderDemo)
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../include")
LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../lib")
add_executable(BarcodeReaderDemo BarcodeReaderDemo.cpp)
target_link_libraries (BarcodeReaderDemo "DynamsoftBarcodeReader")
C++的实现很简单:读取图片文件,调用文件解码接口:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fstream>
#include <streambuf>
#include <iostream>
#include <sstream>
#if defined(_WIN64) || defined(_WIN32)
#include <windows.h>
#include <conio.h>
#define snprintf sprintf_s
#else
#include <sys/time.h>
#endif
#include "DynamsoftBarcodeReader.h"
#include "DynamsoftCommon.h"
using namespace dynamsoft::dbr;
void decode(CBarcodeReader& reader, const char *file)
{
unsigned long ullTimeBegin = 0;
unsigned long ullTimeEnd = 0;
ullTimeBegin = GetTiming();
int ret = reader.DecodeFile(file, "");
ullTimeEnd = GetTiming();
OutputResult(reader, ret, (((float)(ullTimeEnd - ullTimeBegin)) / 1000));
}
int main(int argc, const char* argv[])
{
if (argc != 3)
{
printf("Usage: BarcodeReader <license_file> <image_file>\r\n");
return 0;
}
// License file
std::ifstream licenseFile(argv[1]);
std::stringstream strStream;
strStream << licenseFile.rdbuf();
std::string licenseStr = strStream.str();
// Image file
std::string sImageFile = argv[2];
BarcodeFormatSet iBarcodeFormatId = { 0,0 };
char pszBuffer[512] = { 0 };
char pszImageFile[512] = { 0 };
int iIndex = 0;
int iRet = -1;
char * pszTemp = NULL;
char * pszTemp1 = NULL;
size_t iLen = 0;
FILE* fp = NULL;
bool bExit = false;
char szErrorMsg[256];
PublicRuntimeSettings runtimeSettings;
printf("*************************************************\r\n");
printf("Welcome to Dynamsoft Barcode Reader Demo\r\n");
printf("*************************************************\r\n");
printf("Hints: Please input 'Q' or 'q' to quit the application.\r\n");
CBarcodeReader reader;
reader.InitLicense(licenseStr.c_str());
//Best coverage settings
reader.InitRuntimeSettingsWithString("{\"ImageParameter\":{\"Name\":\"BestCoverage\",\"DeblurLevel\":9,\"ExpectedBarcodesCount\":512,\"ScaleDownThreshold\":100000,\"LocalizationModes\":[{\"Mode\":\"LM_CONNECTED_BLOCKS\"},{\"Mode\":\"LM_SCAN_DIRECTLY\"},{\"Mode\":\"LM_STATISTICS\"},{\"Mode\":\"LM_LINES\"},{\"Mode\":\"LM_STATISTICS_MARKS\"}],\"GrayscaleTransformationModes\":[{\"Mode\":\"GTM_ORIGINAL\"},{\"Mode\":\"GTM_INVERTED\"}]}}", CM_OVERWRITE, szErrorMsg, 256);
//Best speed settings
//reader.InitRuntimeSettingsWithString("{\"ImageParameter\":{\"Name\":\"BestSpeed\",\"DeblurLevel\":3,\"ExpectedBarcodesCount\":512,\"LocalizationModes\":[{\"Mode\":\"LM_SCAN_DIRECTLY\"}],\"TextFilterModes\":[{\"MinImageDimension\":262144,\"Mode\":\"TFM_GENERAL_CONTOUR\"}]}}",CM_OVERWRITE,szErrorMsg,256);
//Balance settings
//reader.InitRuntimeSettingsWithString("{\"ImageParameter\":{\"Name\":\"Balance\",\"DeblurLevel\":5,\"ExpectedBarcodesCount\":512,\"LocalizationModes\":[{\"Mode\":\"LM_CONNECTED_BLOCKS\"},{\"Mode\":\"LM_STATISTICS\"}]}}",CM_OVERWRITE,szErrorMsg,256);
reader.GetRuntimeSettings(&runtimeSettings);
runtimeSettings.barcodeFormatIds = BF_ALL;
iRet = reader.UpdateRuntimeSettings(&runtimeSettings, szErrorMsg, 256);
decode(reader, sImageFile.c_str());
if (iRet != DBR_OK)
{
printf("Error code: %d. Error message: %s\n", iRet, szErrorMsg);
return -1;
}
while (1)
{
bExit = GetImagePath(pszImageFile);
if (bExit)
break;
bExit = SetBarcodeFormat(&iBarcodeFormatId);
if (bExit)
break;
reader.GetRuntimeSettings(&runtimeSettings);
runtimeSettings.barcodeFormatIds = iBarcodeFormatId.barcodeFormatIds;
runtimeSettings.barcodeFormatIds_2 = iBarcodeFormatId.barcodeFormatIds_2;
iRet = reader.UpdateRuntimeSettings(&runtimeSettings, szErrorMsg, 256);
decode(reader, pszImageFile);
}
return 0;
}
从Dynamsoft官网获取一个SDK序列号保存到license.txt
中。编译运行程序:
mkdir build
cd build
cmake ..
cmake --build .
./BarcodeReaderDemo ../../license.txt ../../test.png
Python(加载C++动态链接库)识别一维码,二维码
考虑到越来越多的人喜欢用Python,这里分享下Python Ctypes动态加载的方法。
Python Ctypes可以让开发者用纯Python代码来调用C++的接口。但是要访问C的结构体数据比较麻烦,需要在Python层再对应定义一遍。如果结构体过于复杂,就容易出现问题。这里因为返回数据的结构体过于复杂。我又写了一点桥接用的C代码,便于简化Python层的定义。
首先创建一个桥接的CMake工程,用于编译出一个bridge.so
动态链接库。
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.0.0)
project(bridge)
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../../include")
LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../lib")
add_library(${PROJECT_NAME} SHARED bridge.c)
target_link_libraries (${PROJECT_NAME} "DynamsoftBarcodeReader")
bridge.h
:
# include "DynamsoftBarcodeReader.h"
#if !defined(_WIN32) && !defined(_WIN64)
#define EXPORT_API
#else
#define EXPORT_API __declspec(dllexport)
#endif
typedef struct {
char* format;
char* text;
} ResultInfo;
typedef struct {
int size;
ResultInfo** pResultInfo;
} ResultList;
EXPORT_API ResultList* dbr_get_results(void* barcodeReader);
EXPORT_API void dbr_free_results(ResultList* resultList);
bridge.c
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "bridge.h"
ResultList* dbr_get_results(void* barcodeReader)
{
TextResultArray *pResults;
int ret = DBR_GetAllTextResults(barcodeReader, &pResults);
int count = pResults->resultsCount;
TextResult **results = pResults->results;
ResultInfo** pResultInfo = (ResultInfo**)malloc(sizeof(ResultInfo*) * count);
ResultList* resultList = (ResultList*)malloc(sizeof(ResultList));
resultList->size = count;
resultList->pResultInfo = pResultInfo;
for (int i = 0; i < count; i++)
{
TextResult* pResult = results[i];
ResultInfo* pInfo = (ResultInfo*)malloc(sizeof(ResultInfo));
pInfo->format = NULL;
pInfo->text = NULL;
pResultInfo[i] = pInfo;
// printf("Barcode format: %s, text: %s\n", pResult->barcodeFormatString, pResult->barcodeText);
pInfo->format = (char *)calloc(strlen(pResult->barcodeFormatString) + 1, sizeof(char));
strncpy(pInfo->format, pResult->barcodeFormatString, strlen(pResult->barcodeFormatString));
pInfo->text = (char *)calloc(strlen(pResult->barcodeText) + 1, sizeof(char));
strncpy(pInfo->text, pResult->barcodeText, strlen(pResult->barcodeText));
}
DBR_FreeTextResults(&pResults);
return resultList;
}
void dbr_free_results(ResultList* resultList)
{
int count = resultList->size;
ResultInfo** pResultInfo = resultList->pResultInfo;
for (int i = 0; i < count; i++)
{
ResultInfo* resultList = pResultInfo[i];
if (resultList)
{
if (resultList->format != NULL)
free(resultList->format);
if (resultList->text != NULL)
free(resultList->text);
free(resultList);
}
}
if (pResultInfo != NULL)
free(pResultInfo);
}
这里实现了获取结果和释放结果两个接口,并把结果通过自定义的结构体保存下来返回到Python。
接下来在Python的脚本文件里导入两个库:
import os
import sys
from ctypes import *
def read_text(filename):
f = open(filename, 'r')
text = f.read().strip()
f.close()
return text
try:
license = read_text(sys.argv[1])
except Exception as e:
print(e)
exit()
class ResultInfo(Structure):
_fields_ = [("format", c_char_p), ("text", c_char_p)]
class ResultList(Structure):
_fields_ = [("size", c_int), ("pResultInfo", POINTER(POINTER(ResultInfo)))]
dbr = CDLL(os.path.join(os.path.abspath('.'), '..//lib/libDynamsoftBarcodeReader.so'))
bridge = CDLL(os.path.join(os.path.abspath('.'), 'bridge/build/libbridge.so'))
注意,Linux上要小心导入顺序。
接下来通过调用对应动态链接库里的接口就可以实现Python读码程序:
# DBR_CreateInstance
DBR_CreateInstance = dbr.DBR_CreateInstance
DBR_CreateInstance.restype = c_void_p
instance = dbr.DBR_CreateInstance()
# DBR_InitLicense
DBR_InitLicense = dbr.DBR_InitLicense
DBR_InitLicense.argtypes = [c_void_p, c_char_p]
DBR_InitLicense.restype = c_int
ret = DBR_InitLicense(instance, c_char_p(license.encode('utf-8'))) # http://www.dynamsoft.com/customer/license/trialLicense?product=dbr
print(ret)
# DBR_DecodeFile
DBR_DecodeFile = dbr.DBR_DecodeFile
DBR_DecodeFile.argtypes = [c_void_p, c_char_p, c_char_p]
DBR_DecodeFile.restype = c_int
ret = DBR_DecodeFile(instance, c_char_p('../test.png'.encode('utf-8')), c_char_p(''.encode('utf-8')))
print(ret)
# dbr_get_results
dbr_get_results = bridge.dbr_get_results
dbr_get_results.argtypes = [c_void_p]
dbr_get_results.restype = c_void_p
address = dbr_get_results(instance)
data = cast(address, POINTER(ResultList))
size = data.contents.size
results = data.contents.pResultInfo
for i in range(size):
result = results[i]
print('Format: %s' % result.contents.format.decode('utf-8'))
print('Text: %s' % result.contents.text.decode('utf-8'))
# dbr_free_results
dbr_free_results = bridge.dbr_free_results
dbr_free_results.argtypes = [c_void_p]
if bool(address):
dbr_free_results(address)
# DBR_DestroyInstance
DBR_DestroyInstance = dbr.DBR_DestroyInstance
DBR_DestroyInstance.argtypes = [c_void_p]
DBR_DestroyInstance(instance)
视频
http://www.bilibili.com/video/av249186065?zw
源码
- 龙芯MIPS64上实现C ,Python一维码,二维码识别
- 费尽周折,终于在华为watch3上成功运行hello world
- Web端QR二维码扫描实现
- Flutter C 插件:Linux桌面应用开发
- Flutter Web插件实现:打通JavaScript和Dart
- 使用C 实现Flutter Windows插件
- 国产操作系统上实现基于Web的文档扫描应用
- 如何用Java和Kotlin实现高性能桌面条形码扫描
- 如何在Travis CI中为Windows, Linux和macOS配置Python环境
- 在统信UOS上运行GUI条形码识别程序
- 如何在手机浏览器中控制扫描仪做文档扫描
- 使用Travis CI实现C CMake工程多平台编译
- 如何用Qt和Python创建跨平台的桌面扫码程序
- Apple M1上如何用pip安装x86的Python Wheel包
- 控制Tello无人机扫描条形码
- 从头开始训练一个检测QR二维码区域的YOLOv3模型