5 SDK开发指南

本章介绍SDK概述、功能说明和开发示例。

5.1 SDK概述

介绍SDK的定义和组成,帮助用户更好的了解SDK。

5.1.1 SDK 简介

ED-AIC1000的SDK是一组软件工具开发包(Software Development Kit),给用户提供上层应用所需的接口,便于对Camera进行二次开发。

ED-AIC1000的SDK功能包含12-Pin M12接口中的状态指示灯的控制、报警指示灯的控制、1路DO的控制、RGB灯光、灯源、工作模式、增益、曝光时间、图像处理、自动变焦和解码的控制。

SDK在整个Camera系统中的位置如下图所示。

5.1.2 SDK组成

Camera的SDK是由多个头文件和库文件组成的,具体文件名和安装路径如下表。

功能类型文件类型文件名安装路径
IO控制头文件io.h/usr/include/eda/
库文件(C++)libeda_io.so/usr/lib/
库文件(Python)libedaio.so/lib/python3/dist-packages/
Camera Sensor控制头文件camera.h
cameramanger.h
/usr/include/eda/
库文件(C++)libeda_camera.so/usr/lib/
库文件(Python)libedacamera.so/lib/python3/dist-packages/

在开发过程中用户可以根据实际需要实现的功能,参考下文对应的功能代码来完成上层应用的开发。

5.2 功能说明

本章介绍各项功能对应代码的编写方法,帮助用户编写上层应用所需要的代码。

5.2.1 I/O控制(C++)

本节介绍指示灯控制、输出控制、灯光控制、对焦位置控制和相机拍照模式控制等的具体操作。

5.2.1.1 流程图

5.2.1.2 获取实例并初始化

在操作I/O前需要先获取I/O实例并对实例进行初始化,操作步骤如下。

  1. 获取I/O实例。
eda::Edalo* em = eda::Edalo::getInstance();
参数返回值
  • 类型:EdaIo*
  • 说明:
    • 成功:返回有效的单例指针
    • 失败:返回无效指针
  1. 对实例进行初始化。
em->setup();
参数返回值
void

5.2.1.3 控制I/O状态

通过I/O来控制状态指示灯的点亮/熄灭、报警指示灯的点亮/熄灭和1路输出信号的使能/禁用。

前提条件:

已完成实例的初始化。

操作说明:

  • 控制状态指示灯
em->openWorkLed();   // 打开工作指示灯
em->closeWorkLed();  // 关闭工作指示灯
参数返回值
void
  • 控制警报指示灯
em->openAlarmLed();  // 打开报警指示灯
em->closeAlarmLed(); // 关闭报警指示灯
参数返回值
void
  • 控制1路输出信号
em->setDo1High();    // 设置output1输出为高
em->setDo1Low();     // 设置output1输出为低
参数返回值
void

5.2.1.4 控制灯光

Camera侧面灯和区域灯均可控制。

前提条件:

已完成实例的初始化。

操作说明:

● 控制侧灯颜色

em->setRgbLight(LightColor light);
参数返回值
LightColor::Off:关闭
LightColor::Red:红色
LightColor::Green:绿色
LightColor::Blue:蓝色
LightColor::Yellow:黄色
LightColor::White:白色
void

● 控制区域灯源,分为3个区域(上方、中间和下方),每一个区域均支持独立控制。

  • 开启区域光源(默认状态为开启状态)
em->enableLightSection(LightSection section);
参数返回值
LightSection::Bottom:下方区域灯源
LightSection::Middle:中间区域灯源
LightDection::Top:上方区域灯源
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 关闭区域光源
em->disableLightSection(LightSection section);
参数返回值
LightSection::Bottom:下方区域灯源
LightSection::Middle:中间区域灯源
LightDection::Top:上方区域灯源
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 区域灯源的使能/禁用不是打开/关闭灯源,灯源与摄像头是联动的,只有当灯源已使能且摄像头打开的条件下灯源才会亮。
  • 控制区域灯源亮度

    em->setBrightnessValue(brightness);
    
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~100,默认值为50
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

5.2.1.5 控制对焦模组

Camera默认配备马达自动对焦模组,提供自动对焦功能。

  • 初始化马达对焦模块
em->initMotorVfm();
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0数值
  • 调远马达对焦模块的焦距
em->setMotorVfmFar(int distance);
参数返回值
  • 类型:Int
  • 取值范围:0~46000
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 调近马达对焦模块的焦距
em->setMotorVfmNear(int distance);
参数返回值
  • 类型:Int
  • 取值范围:0~46000
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

5.2.1.6 控制相机

Camera拍照的模式支持设置,包含连续模式、软/硬触发模式和软件触发模式。

  • 设置连续拍照模式下,连续触发的时间间隔
em->setContinuousInterval(int ms);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~250,默认值为30,单位为ms,由于传感器硬件公差,实际生效值可能存在轻微偏差。
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 连续触发的时间间隔应根据当前曝光时间合理配置;曝光时间越长,建议设置越大的连续触发时间间隔。

    • 若连续触发时间间隔较小,但实际曝光时间偏大,设备可能在上一帧曝光尚未完成时收到新的触发信号,从而导致触发异常、丢帧或图像采集失败。
    • 建议满足:实际曝光时间 ≤ 连续触发间隔 + 1 ms。
  • 在触发时间间隔固定的情况下,实际采集帧率并非随曝光时间连续变化,而是受实际硬件影响呈阶梯式变化。适当减小曝光时间有助于提升实际采集帧率,但达到当前帧率档位后,继续减小曝光时间通常不会带来进一步提升。

  • 设置软\硬触发模式下,单次触发相机拍摄次数
em->setTriggerNum(int count);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~250,默认值为1,单位为ms
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 设置为软件触发模式,兼容软/硬触发模式
em->callTrigger();
参数返回值
void

5.2.1.7 代码示例

IO控制Class(C++)

typedef void (*IoTrigger)(int level);

class EdaIo{
public:
    static EdaIo* getInstance();
    static void close_io();
    ~EdaIo();
    /**
     * @brief 打开工作指示灯
     * 
     */
    void openWorkLed();
    /**
     * @brief 关闭工作指示灯
     * 
     */
    void closeWorkLed();
    /**
     * @brief 打开alarm 指示灯
     * 
     */
    void openAlarmLed();
    /**
     * @brief 关闭alarm 指示灯
     * 
     */
    void closeAlarmLed();
    /**
     * @brief
     *
     * @param section: LightSection::Top 上方区域, LightSection::Middle 中间区域, LightSection::Bottom 下方区域
     * @return int
     */
    int enableLightSection(LightSection section);
    /**
     * @brief
     *
     * @param section LightSection::Top 上方区域, LightSection::Middle 中间区域, LightSection::Bottom 下方区域
     * @return int
     */
    int disableLightSection (LightSection section);
    /**
     * @brief 触发相机
     */
    void callTrigger();
    /**
     * @brief 设置连续触发时间间隔
     *
     * @param intervalMs 间隔时间,单位毫秒
     * @return int
     */
    int setContinuousInterval(int intervalMs);
    /**
     * @brief 设置触发次数
     *
     * @param count 触发次数
     * @return int
     */
    int setTriggerNum(int count);
    /**
     * @brief 初始化马达对焦模组
     * 
     * @return int
     */
    int initMotorVfm();
    /**
     * @brief 调远马达对焦模块的焦距
     *
     * @param distance 0~46000
     * @return int
     */
    int setMotorVfmFar(int distance);
    /**
     * @brief 调近马达对焦模块的焦距
     * 
     * @param distance 0~46000
     * @return int
     */
    int setMotorVfmNear(int distance);
    /**
     * @brief 设置output1 输出为高
     * 
     */
    void setDo1High();
    /**
     * @brief 设置output1 输出为低
     * 
     */
    void setDo1Low();
    /**
     * @brief set RGB light
     *
     * @param light LightColor::Red 红色, LightColor::Green 绿色, LightColor::Blue 蓝色, LightColor::Yellow 黄色, LightColor::White 白色, LightColor::Off 关闭
     * @return void
     */
    void setRgbLight(LightColor light);
    /**
     * @brief 
     *
     * @param brightness 光源亮度,范围0~100,默认亮度50 
     * @return int
     */
    int setBrightnessValue(int value);
    /**
     * @brief 
     *
     * @param mode Mode::Continuous 连续模式,Mode::Software 软触发模式, Mode::IoLevelUp 上升沿触发,Mode::IoLevelDown 下降沿触发,Mode::IoLevelBoth Level触发
     * @return int
     */
    int setWorkMode(Mode mode);
    /**
     * @brief 初始化IO 设置
     * 
     */
    void setup();
};

5.2.2 I/O控制(Python)

本节介绍指示灯控制、输出控制、灯光控制、对焦位置控制和相机拍照模式控制等的具体操作。

5.2.2.1 流程图

5.2.2.2 导入模块

在操作I/O前需要先导入模块。

from libedaio import Edalo, registerInput, registerTrigger, registerTune

5.2.2.3 获取实例并初始化

在导入模块后需要先获取I/O实例并对实例进行初始化,操作步骤如下。

  1. 获取IO实例。
edalo = Edalo.getInstance()
参数返回值
  • 类型:Edalo*
  • 说明:
    • 成功:返回有效的单例指针
    • 失败:返回无效指针
  1. 对实例进行初始化。
edalo.setup()
参数返回值
None

5.2.2.4 控制I/O状态

通过I/O来控制状态指示灯的点亮/熄灭、报警指示灯的点亮/熄灭和1路输出信号的使能/禁用。

前提条件:

已完成实例的初始化。

操作说明:

  • 控制状态指示灯
edalo.openWorkLed()   # 打开工作指示灯
edalo.closeWorkLed()  # 关闭工作指示灯
参数返回值
None
  • 控制警报指示灯
edalo.openAlarmLed()   # 打开报警指示灯
edalo.closeAlarmLed()  # 关闭报警指示灯
参数返回值
None
  • 控制1路输出信号
edalo.setDo1High()   # 设置第一路输出为高
edalo.setDo1Low()    # 设置第一路输出为低
参数返回值
None

5.2.2.5 控制灯光

Camera侧面灯和区域灯均可控制。

前提条件:

已完成实例的初始化。

操作说明:

● 控制侧灯颜色

edalo.setRgbLight(LightColor.Red)
参数返回值
LightColor.Off:关闭
LightColor.Red:红色
LightColor.Green:绿色
LightColor.Blue:蓝色
LightColor.Yellow:黄色
LightColor.White:白色
None

● 控制区域灯源,分为3个区域(上方、中间和下方),每一个区域均支持独立控制。

  • 开启区域光源(默认状态为开启状态)
edalo.enableLightSection(LightSection.Top)
参数返回值
LightSection.Bottom:下方区域灯源
LightSection.Middle:中间区域灯源
LightSection.Top:上方区域灯源
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 关闭区域光源
edalo.disableLightSection(LightSection.Top)
参数返回值
LightSection.Bottom:下方区域灯源
LightSection.Middle:中间区域灯源
LightSection.Top:上方区域灯源
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 区域灯源的使能/禁用不是打开/关闭灯源,灯源与摄像头是联动的,只有当灯源已使能且摄像头打开的条件下灯源才会亮。
  • 控制区域灯源亮度

    edalo.setBrightnessValue(brightness)
    
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~100,默认值为50
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

5.2.2.6 控制对焦模组

Camera默认配备马达自动对焦模组,提供自动对焦功能。

  • 初始化马达对焦模块
edalo.initMotorVfm()
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0数值
  • 调远马达对焦模块的焦距
edalo.setMotorVfmFar(distance)
参数返回值
  • 类型:Int
  • 取值范围:0~46000
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 调近马达对焦模块的焦距
edalo.setMotorVfmNear(distance)
参数返回值
  • 类型:Int
  • 取值范围:0~46000
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

5.2.2.7 控制相机

Camera拍照的模式支持设置,包含连续模式、软/硬触发模式和软件触发模式。

  • 设置连续拍照模式下,连续触发的时间间隔
edalo.setContinuousInterval(ms)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~250,默认值为30,单位为ms。由于传感器硬件公差,实际生效值可能存在轻微偏差。
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 连续触发的时间间隔应根据当前曝光时间合理配置;曝光时间越长,建议设置越大的连续触发时间间隔。

    • 若连续触发时间间隔较小,但实际曝光时间偏大,设备可能在上一帧曝光尚未完成时收到新的触发信号,从而导致触发异常、丢帧或图像采集失败。
    • 建议满足:实际曝光时间 ≤ 连续触发间隔 + 1 ms。
  • 在触发时间间隔固定的情况下,实际采集帧率并非随曝光时间连续变化,而是受实际硬件影响呈阶梯式变化。适当减小曝光时间有助于提升实际采集帧率,但达到当前帧率档位后,继续减小曝光时间通常不会带来进一步提升。

  • 设置软/硬触发模式下,单次触发相机拍摄次数
edalo.setTriggerNum(count)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~250,默认值为1
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 设置为软件触发模式,兼容软/硬触发模式
edalo.callTrigger()
参数返回值
None

5.2.2.8 代码示例

IO控制(Python3)

from libedaio import Edalo, registerInput, registerTrigger, registerTune
from libedaio import LightSection, Mode, LightColor

def func_trigger(v):
    print("[Debug] Trigger: trigger button!", v)

eda = Edalo.getInstance()      # 获取IO控制实例

eda.setup()                   # 初始化
eda.openWorkLed()             # 设置状态指示灯
eda.openAlarmLed()            # 打开警告指示灯
# eda.closeAlarmLed()         # 关闭警告指示灯
eda.setDo1High()              # 设置第一路输出
eda.setRgbLight(LightColor.Red)  # 设置侧灯

5.2.3 Camera Sensor控制(C++)

本节介绍打开摄像头、设置相机曝光时间和设置相机增益等的具体操作。

5.2.3.1 流程图

5.2.3.2 操作步骤

在操作Camera之前,需要先获取I/O实例并初始化,再进行如下操作。

  1. 获取实例
eda::Camera* t_camera = eda::loadDefault();
参数返回值
  • 类型:Camera*
  • 说明:
    • 成功:返回对应相机类型的Camera对象指针
    • 失败:返回无效指针
  1. 查询Sensor类型。
t_camera->getName()
参数返回值
eda::CameraName::SC132GS
  1. 打开摄像头并设置分辨率。
t_camera->open(width, height);
参数返回值
  • width:表示摄像头区域宽度
  • height:表示摄像头区域高度
  • 最大分辨率支持1024x1280
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 调用前必须先成功获取I/O库实例并完成初始化。
  • 函数会根据传入的 width和 height设定图像采集的目标尺寸。
  • 由于底层传感器和驱动存在对齐限制,实际生效的参数会自动进行向下对齐处理:
    • 宽度对齐:按 32像素​ 边界向下对齐。
    • 高度对齐:按 16像素​ 边界向下对齐。
  • 对齐后的采集区域将自动居中放置在传感器画面中。
  • 最终输出的图像分辨率将等于对齐后的尺寸,该尺寸可能略小于或等于传入的参数值。
  1. 设置增益和曝光参数。
  • 设置增益
t_camera->setGain(gain);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~100,默认值为20
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 设置曝光
t_camera->setExposure(exposure);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~2500,默认值为250
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 实际曝光时间 = 曝光值 × rowTime,SC132gs.rowTime = 6.17us,由于传感器硬件公差,实际生效值可能存在轻微偏差。
  • 当前可配置的最大曝光时间受限于相机的工作模式及触发间隔(实际曝光时间 ≤ 连续触发间隔 + 1 ms)。
  1. 通过回调方式获取摄像头数据。
t_camera->registerImageHandler(image_callback);
参数返回值
image_callback:用户定义的图像数据回调函数
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

回调函数中,推荐只获取数据不处理逻辑。

  1. 获取图像数据(获取一帧图像)。
t_camera->getImageData(char* img_buff, int img_len);
参数返回值
  • char *img_buff:用于接收图像数据的缓冲区,不能为空
  • int img_len:缓冲区大小,单位为字节,应不小于当前图像数据大小
  • 类型:Int
  • 说明:
    • 成功:返回值为实际复制的图像数据长度
    • 失败:返回值为-1

提示

  • 获取相机最近采集的一帧图像数据,并将其复制到用户提供的缓冲区。
  • 调用前应确保相机已开始采集,并且已经获取到至少一帧图像数据。
  • 仅获取,不触发相机。

5.2.3.3 代码示例

typedef int (*img_Callback)(char* img_buff, int img_len);

enum CameraName {
    SC132GS
};

class Camera {
public:
    /**
     * @brief 初始化摄像头
     * @param width
     * @param height
     * @return int
     */
    virtual int open(int width, int height) = 0;

    /**
     * @brief 关闭摄像头
     * @return int
     */
    virtual int close() = 0;

    /**
     * @brief 设置曝光时间
     * @param exp_value
     * @return int
     */
    virtual int setExposure(int exp_value) = 0;

    /**
     * @brief 获取曝光时间
     * @param exp_value
     * @return int
     */
    virtual int getExposure(int* exp_value) = 0;

    /**
     * @brief 设置增益
     * @param gain_value
     * @return int
     */
    virtual int setGain(int gain_value) = 0;

    /**
     * @brief 获取增益
     * @param gain_value
     * @return int
     */
    virtual int getGain(int* gain_value) = 0;

    /**
     * @brief 注册回调函数,获取图像数据
     * @param callback
     * @return int
     */
    virtual int registerImageHandler(img_Callback callback) = 0;

    virtual CameraName name() = 0;
};

5.2.4 Camera Sensor控制(Python)

本节介绍导入模块、打开摄像头、设置相机曝光时间和设置相机增益等的具体操作。

5.2.4.1 流程图

5.2.4.2 操作步骤

在操作Camera之前,需要先导入模块再获取I/O实例并初始化,具体操作如下。

  1. 导入模块。
from libedacamera import EdaCamera
  1. 获取Camera实例。
eda = EdaCamera.loadDefault()
参数返回值
  • 类型:Camera*
  • 说明:
    • 成功:返回对应相机类型的Camera对象指针
    • 失败:返回无效指针
  1. 查询Sensor类型。
eda.getName()
参数返回值
eda.CameraName.SC132GS
  1. 打开摄像头并设置分辨率。
ret = eda.open(t_width, t_height)
参数返回值
  • width:表示摄像头区域宽度
  • height:表示摄像头区域高度
  • 最大分辨率支持1024x1280
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 调用前必须先成功获取I/O库实例并完成初始化。
  • 函数会根据传入的 width和 height设定图像采集的目标尺寸。
  • 由于底层传感器和驱动存在对齐限制,实际生效的参数会自动进行向下对齐处理:
    • 宽度对齐:按 32像素​ 边界向下对齐。
    • 高度对齐:按 16像素​ 边界向下对齐。
  • 对齐后的采集区域将自动居中放置在传感器画面中。
  • 最终输出的图像分辨率将等于对齐后的尺寸,该尺寸可能略小于或等于传入的参数值。
  1. 设置增益和曝光参数。
  • 设置增益
eda.setGain(t_gain)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为0~100,默认值为20
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1
  • 设置曝光
eda.setExposure(t_exposure)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~2500,默认值为250
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

  • 实际曝光时间 = 曝光值 × rowTime,SC132gs.rowTime = 6.17us,由于传感器硬件公差,实际生效值可能存在轻微偏差。
  • 当前可配置的最大曝光时间受限于相机的工作模式及触发间隔(实际曝光时间 ≤ 连续触发间隔 + 1 ms)。
  1. 通过回调方式获取摄像头数据。
eda.registerImageHandler(func_image_data)
参数返回值
func_image_data:用户定义的图像数据回调函数
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为-1

提示

回调函数中,推荐只获取数据不处理逻辑。

  1. 获取图像数据(获取一帧图像)。
eda.getImageData(img_buff, img_len)
参数返回值
  • img_buff:用于接收图像数据的缓冲区,不能为空
  • img_len:缓冲区大小,单位为字节,应不小于当前图像数据大小
  • 类型:Int
  • 说明:
    • 成功:返回值为实际复制的图像数据长度
    • 失败:返回值为-1

提示

  • 获取相机最近采集的一帧图像数据,并将其复制到用户提供的缓冲区。
  • 调用前应确保相机已开始采集,并且已经获取到至少一帧图像数据。
  • 仅获取,不触发相机。

5.2.4.3 代码示例

PYBIND11_MODULE(libedacamera, m) {
    m.doc() = "EDATec Camera";
    m.add_object("_cleanup", py::capsule(cleanup_callback));

    py::enum_<eda::ImageEncode>(m, "ImageEncode")
        .value("GRAY", eda::ImageEncode::GRAY)
        .value("COLOR", eda::ImageEncode::COLOR);

    auto pyEdaCamera = py::class_<EdaCamera, std::shared_ptr<EdaCamera>>(m, "EdaCamera");
    pyEdaCamera.def("open", &EdaCamera::open)
        .def_static("loadDefault", []() {
            if(!gEda){
                gEda = new EdaCamera(eda::loadDefault());
            }

            return gEda;
        })
        .def("close", &EdaCamera::close)
        .def("setExposure", &EdaCamera::setExposure)
        .def("getExposure", &EdaCamera::getExposure)
        .def("setExposureRange", &EdaCamera::setExposureRange)
        .def("getExposureRange", &EdaCamera::getExposureRange)
        .def("setGain", &EdaCamera::setGain)
        .def("getGain", &EdaCamera::getGain)
        .def("getName", &EdaCamera::getName)
        .def("registerImageHandler", &EdaCamera::registerImageHandler,py::arg("callback"))
        .def("getImageData", [](EdaCamera *self, py::buffer img_buff, int img_len){
            py::buffer_info info = img_buff.request();
            char *img_data = static_cast<char*>(info.ptr);
            return self->getImageData(img_data, img_len);
        }, py::arg("img_buff"), py::arg("img_len"))
        .def("setImageEncode", &EdaCamera::setImageEncode, py::arg("encode"))
        .def("getImageEncode", &EdaCamera::getImageEncode)
        .def("setWhiteBalance", &EdaCamera::setWhiteBalance)
        .def("getWhiteBalance", &EdaCamera::getWhiteBalance);
}

5.2.5 Decoder (C++)

本节介绍设置码制、设置读码时长和设置最大解码数量等的具体操作。

5.2.5.1 流程图

5.2.5.2 操作步骤

在操作读码之前,需要先初始化读码器,再设置读码参数。

  1. 初始化读码器。
initDecoder();
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0
  1. 设置码制,默认支持的码制为Code128、Data Matrix和QR,码制支持按需设置。
代码描述
int enableDecoderC128()使能Code128码制
int disableDecoderC128()禁用Code128码制
int enableDecoderC93()使能Code93码制
int disableDecoderC93()禁用Code93码制
int enableDecoderC39()使能Code39码制
int disableDecoderC39()禁用Code39码制
int enableDecoderI25()使能Interleaved 2 of 5码制
int disableDecoderI25()禁用Interleaved 2 of 5码制
int enableDecoderUpc()使能UPC码制
int disableDecoderUpc()禁用UPC码制
int enableDecoderEan()使能EAN码制
int disableDecoderEan()禁用EAN码制
int enableDecoderQr()使能QR码制
int disableDecoderQr()禁用QR码制
int enableDecoderDm()使能Data Matrix码制
int disableDecoderDm()禁用Data Matrix码制
int enableDecoderPdf()使能PDF417码制
int disableDecoderPdf()禁用PDF417码制
int enableDecoderAll()使能所有码制
int disableDecoderAll()禁用所有码制
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0。
    • 失败:返回值为非0。
  1. 设置解码时长。
int setDecoderTimeout(int ms);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~500,默认值为200,单位为ms
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

运行解码函数的时间超过解码时长设定值后会退出解码。

  1. 设置最大解码数量。
int setDecoderResultMax(int max);
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~100,默认值为20
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

运行解码函数时,解码的数量超过设定值后会退出解码。

  1. 配置相似条码使能。
int disableIdenticalSymbols(int enable);
参数返回值
  • 类型:Int
  • 说明:enable为1,表示相似条码使能;enable为0,表示相似条码关闭
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

条形码在受损情况下可能会被识别为多个相同的码,会输出多个重复的内容,通过设置可以关闭或者使能。

  1. 运行解码函数。
int decoder(uint8_t* image, int width, int height, std::vector<DEC_RESULT>&results);
参数返回值
  • 类型:Int
  • 取值:
    • uint8_t* image:解码的图像数据缓冲区
    • int width:图像宽度
    • int height:图像高度
    • results:用于接收解码结果
  • 类型:Int
  • 说明:
    • 完成:返回值为0
    • 成功:返回值为大于0
    • 失败:返回值为非0

提示

从图像数据中解码并输出条码类型、条码内容和条码的位置,返回值为解码的数量。其中返回结果DEC_RESULT字段说明:

  • code_length:条码内容长度
  • code_string:条码内容字符串
  • center_x:目标中心点X坐标
  • center_y:目标中心点Y坐标
  • code_type:枚举类型,例如 CODE_TYPE_QR
  • bounds:4个角点坐标列表

示例:

   static const std::unordered_map<CodeType, const char*> code_type_names = {
       {CODE_TYPE_C128, "C128"},
       {CODE_TYPE_C93, "C93"},
       {CODE_TYPE_C39, "C39"},
       {CODE_TYPE_I25, "I25"},
       {CODE_TYPE_UPC, "UPC"},
       {CODE_TYPE_EAN, "EAN"},
       {CODE_TYPE_QR, "QR"},
       {CODE_TYPE_DM, "DM"},
       {CODE_TYPE_PDF, "PDF"},
   };
   
   std::vector<DEC_RESULT> results_vec;
   const int count = decoder(gray.data(), width, height, results_vec);
   std::cout << "decode_count=" << count << "\n";
   for (int i = 0; i < count && i < 16; ++i) {
       const auto& r = results_vec[i];
       std::cout << "[" << i << "]";
       std::cout << "type=" << code_type_names.at(r.code_type);
       std::cout << ", text=" << r.code_string;
       std::cout << ", center=(" << r.center_x << "," << r.center_y << ")\n";
       std::cout << " bounds=";
       for (int j = 0; j < 4; ++j) {
           std::cout << "(" << r.bounds.point[j].x << "," << r.bounds.point[j].y << ")";
           if (j < 3) {
               std::cout << ",";
           }
       }
       std::cout << "\n";
   }
  1. 关闭读码器。
int destroyDecoder();
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0。
    • 失败:返回值为非0。

5.2.5.3 代码示例

#ifdef __cplusplus
extern "C" {
#endif

enum CodeType {
    CODE_TYPE_C128 = 4,
    CODE_TYPE_C93 = 3,
    CODE_TYPE_C39 = 2,
    CODE_TYPE_I25 = 5,
    CODE_TYPE_UPC = 11,
    CODE_TYPE_EAN = 12,
    CODE_TYPE_QR = 18,
    CODE_TYPE_DM = 15,
    CODE_TYPE_PDF = 17,
};

typedef struct DEC_POINT {
    int x;
    int y;
} DEC_POINT;

typedef struct DEC_BOUNDS {
    DEC_POINT point[4];
} DEC_BOUNDS;

typedef struct DEC_RESULT {
    int code_length;
    char code_string[512];
    int center_x;
    int center_y;
    CodeType code_type;
    DEC_BOUNDS bounds;
} DEC_RESULT;

int initDecoder(void);
int decoder(uint8_t* image, int width, int height, std::vector<DEC_RESULT>& results);
int destroyDecoder(void);

int enableDecoderC128();
int disableDecoderC128();
int enableDecoderC93();
int disableDecoderC93();
int enableDecoderC39();
int disableDecoderC39();
int enableDecoderI25();
int disableDecoderI25();
int enableDecoderUpc();
int disableDecoderUpc();
int enableDecoderEan();
int disableDecoderEan();
int enableDecoderQr();
int disableDecoderQr();
int enableDecoderDm();
int disableDecoderDm();
int enableDecoderPdf();
int disableDecoderPdf();
int enableDecoderAll();
int disableDecoderAll();
int setDecoderTimeout(int timeout);
int setDecoderResultMax(int max);
int disableIdenticalSymbols(int enable);

#ifdef __cplusplus
}
#endif

5.2.6 Decoder (Python)

本节介绍设置码制、设置读码时长和设置最大解码数量等的具体操作。

5.2.6.1 流程图

5.2.6.2 操作步骤

在操作读码之前,需要先导入模块再初始化读码器,具体操作如下。

  1. 导入模块。
import libedaaidc
  1. 初始化读码器。
libedaaidc.initDecoder()
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0
  1. 设置码制,默认支持的码制为Code128、Data Matrix和QR,码制支持按需设置。
代码描述
libedaaidc.enableDecoderC128()使能Code128码制
libedaaidc.disableDecoderC128()禁用Code128码制
libedaaidc.enableDecoderC93()使能Code93码制
libedaaidc.disableDecoderC93()禁用Code93码制
libedaaidc.enableDecoderC39()使能Code39码制
libedaaidc.disableDecoderC39()禁用Code39码制
libedaaidc.enableDecoderI25()使能Interleaved 2 of 5码制
libedaaidc.disableDecoderI25()禁用Interleaved 2 of 5码制
libedaaidc.enableDecoderUpc()使能UPC码制
libedaaidc.disableDecoderUpc()禁用UPC码制
libedaaidc.enableDecoderEan()使能EAN码制
libedaaidc.disableDecoderEan()禁用EAN码制
libedaaidc.enableDecoderQr()使能QR码制
libedaaidc.disableDecoderQr()禁用QR码制
libedaaidc.enableDecoderDm()使能Data Matrix码制
libedaaidc.disableDecoderDm()禁用Data Matrix码制
libedaaidc.enableDecoderPdf()使能PDF417码制
libedaaidc.disableDecoderPdf()禁用PDF417码制
libedaaidc.enableDecoderAll()使能所有码制
libedaaidc.disableDecoderAll()禁用所有码制
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0
  1. 设置解码时长。
libedaaidc.setDecoderTimeout(ms)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~500,默认值为200,单位为ms,
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

运行解码函数时,解码的数量超过设定值后会退出解码。

  1. 设置最大解码数量。
libedaaidc.setDecoderResultMax(max)
参数返回值
  • 类型:Int
  • 取值:可设置的范围为1~100,默认值为20
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

运行解码函数时,解码的数量超过设定值后会退出解码。

  1. 配置相似条码使能。
libedaaidc.disableIdenticalSymbols(enable)
参数返回值
  • 类型:Int
  • 说明:enable为1,表示相似条码使能;enable为0,表示相似条码关闭
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

提示

条形码在受损情况下可能会被识别为多个相同的码,会输出多个重复的内容,通过设置可以关闭或者使能。

  1. 运行解码函数。
results = libedaaidc.decoder(image, width, height)
参数返回值
  • 类型:Int
  • 取值:
    • image:解码的图像数据缓冲区
    • width:图像宽度
    • height:图像高度
    • results:用于接收解码结果
  • 类型:Int
  • 说明:
    • 完成:返回值为0
    • 成功:返回值为大于0
    • 失败:返回值为非0

提示

从图像数据中解码并输出条码类型、条码内容和条码的位置,返回值为解码的数量。其中返回为列表形式,常见字段说明如下:

  • code_length:条码内容长度
  • code_string:条码内容字符串
  • center_x:目标中心点X坐标
  • center_y:目标中心点Y坐标
  • code_type:枚举类型,例如 CODE_TYPE_QR
  • bounds:4个角点坐标列表

示例:

   results = libedaaidc.decoder(image, width, height)
   print(f"decode_count={len(results)}")
   for i, r in enumerate(results):
       code_type = r["code_type"]
       code_type_name = code_type.name if hasattr(code_type, "name") else str(code_type)
       print(f"[{i}] type={code_type_name}, text={r['code_string']}, center=({r['center_x']},{r['center_y']})")
       print(f"bounds={r['bounds']}")
       for j, b in enumerate(r['bounds']):
           print(f"point[{j}]={b['x']},{b['y']}")
  1. 关闭读码器。
libedaaidc.destroyDecoder()
参数返回值
  • 类型:Int
  • 说明:
    • 成功:返回值为0
    • 失败:返回值为非0

5.2.6.3 代码示例

PYBIND11_MODULE(libedaaidc, m) {
    m.doc() = "EDATEC AIDC wrapper";

    py::enum_<CodeType>(m, "CodeType")
        .value("CODE_TYPE_C128", CODE_TYPE_C128)
        .value("CODE_TYPE_C93", CODE_TYPE_C93)
        .value("CODE_TYPE_C39", CODE_TYPE_C39)
        .value("CODE_TYPE_I25", CODE_TYPE_I25)
        .value("CODE_TYPE_UPC", CODE_TYPE_UPC)
        .value("CODE_TYPE_EAN", CODE_TYPE_EAN)
        .value("CODE_TYPE_QR", CODE_TYPE_QR)
        .value("CODE_TYPE_DM", CODE_TYPE_DM)
        .value("CODE_TYPE_PDF", CODE_TYPE_PDF);

    m.def("initDecoder", []() {
        return initDecoder();
    });
    m.def("destroyDecoder", []() {
        return destroyDecoder();
    });
    m.def("decoder", [](py::buffer image, int width, int height) {
        py::buffer_info info = image.request();
        auto* data = static_cast<uint8_t*>(info.ptr);
        std::vector<DEC_RESULT> results;
        int count = decoder(data, width, height, results);
        py::list pyResults;
        if (count <= 0) {
            return pyResults;
        }
        for (int i = 0; i < count; ++i) {
            auto& r = results[i];
            py::dict item;
            // 基本字段
            item["code_length"] = r.code_length;
            item["code_string"] = std::string(r.code_string, r.code_length);
            item["center_x"] = r.center_x;
            item["center_y"] = r.center_y;
            item["code_type"] = py::cast(r.code_type);
            // bounds -> list of points
            py::list points;
            for (int i = 0; i < 4; ++i) {
                py::dict pt;
                pt["x"] = r.bounds.point[i].x;
                pt["y"] = r.bounds.point[i].y;
                points.append(pt);
            }
            item["bounds"] = points;
            pyResults.append(item);
        }
        return pyResults;
    }, py::arg("image"), py::arg("width"), py::arg("height"));
    m.def("enableDecoderC128", []() {
        return enableDecoderC128();
    });
    m.def("disableDecoderC128", []() {
        return disableDecoderC128();
    });
        m.def("enableDecoderC93", []() {
        return enableDecoderC93();
    });
    m.def("disableDecoderC93", []() {
        return disableDecoderC93();
    });
    m.def("enableDecoderC39", []() {
        return enableDecoderC39();
    });
    m.def("disableDecoderC39", []() {
        return disableDecoderC39();
    });
    m.def("enableDecoderI25", []() {
        return enableDecoderI25();
    });
    m.def("disableDecoderI25", []() {
        return disableDecoderI25();
    });
    m.def("enableDecoderUpc", []() {
        return enableDecoderUpc();
    });
    m.def("disableDecoderUpc", []() {
        return disableDecoderUpc();
    });
    m.def("enableDecoderEan", []() {
        return enableDecoderEan();
    });
    m.def("disableDecoderEan", []() {
        return disableDecoderEan();
    });
    m.def("enableDecoderQr", []() {
        return enableDecoderQr();
    });
    m.def("disableDecoderQr", []() {
        return disableDecoderQr();
    });
    m.def("enableDecoderDm", []() {
        return enableDecoderDm();
    });
    m.def("disableDecoderDm", []() {
        return disableDecoderDm();
    });
    m.def("enableDecoderPdf", []() {
        return enableDecoderPdf();
    });
    m.def("disableDecoderPdf", []() {
        return disableDecoderPdf();
    });
    m.def("enableDecoderAll", []() {
        return enableDecoderAll();
    });
    m.def("disableDecoderAll", []() {
        return disableDecoderAll();
    });
    m.def("setDecoderTimeout", [](int timeout) {
        return setDecoderTimeout(timeout);
    });
    m.def("setDecoderResultMax", [](int max) {
        return setDecoderResultMax(max);
    });
    m.def("disableIdenticalSymbols", [](int enable) {
        return disableIdenticalSymbols(enable);
    });
}