Skip to content

SDK 简介

简介

功能说明

Smart Vision SDK为开发者提供:

  • 操作获取相机照片数据的API接口。所获相机照片数据用于后续人工智能模型推理。
  • IO/TCP信号输出API接口。信号输出可发送NG/Alarm/Alarm Clear信号。

Smart Vision SDK提供了C++和python两种类型的接口。开发者可以根据自身情况选择使用。

开发环境

Smart Vision SDK运行于Aidlux智能相机环境中。

类别要求
操作系统Ubuntu22.04
Aidluxaidlux_2.x.x.x
支持语言接口Python3.10.12/ C++

限制

只能运行在开发环境所要求的运行条件下。

安装/卸载

可通过应用中心安装或卸载Smart Vision SDK。关于应用中心操作介绍,请参考相应文档。

也可以通过命令在线安装或卸载,例如:

bash
安装:
sudo aid-pkg install smartvision-sdk

卸载:
sudo aid-pkg remove smartvision-sdk

打开相机流程介绍

流程图

alt text

流程详细步骤介绍

  1. 实例化Camera类,创建一个Camera对象。
  2. 调用Camera对象的Open()函数打开相机(可选择是否带参)。
  3. 有参模式打开相机需要事先实例化结构体DeviceParam,设置相机配置文件,并将该对象作为入参传入Open()函数。具体可参考有参模式打开相机API接口介绍。关于相机配置文件,请参考相机配置文件
  4. 无参模式打开相机则可以直接调用start_camera_without_parameter()函数,入参仅需要回调函数名。具体可参考无参模式打开相机API接口介绍。
  5. 如果成功打开相机,则打开流开关。否则退出。
  6. 设置抓图开关及循环业务流,在循环中持续抓取回调函数中的图片数据。具体可参考代码样例。
  7. 根据业务需求关闭流开关,退出业务。
text
- 无参模式即打开相机的时候不需要传入相机配置参数,SDK使用相机当前配置的参数来打开相机。
- 有参模式即打开相机的时候需要传入相机配置参数,SDK使用传入的配置的参数来打开相机。。
- 从使用场景的角度,配置相机可通过SVE界面设置,相对更方便易懂。因此使用无参模式配合SVE界面设置更灵活易用。
- 有参模式可作为后台编程的一种灵活可选项。

日志功能

SDK日志功能分为:

  • 打印日志,即控制台输出
  • 保存日志,即日志保存到文件
  • 动态设置日志等级,即可通过命令动态改变当前日志等级配置(影响文件输出)
  • 关闭日志,即关闭日志文件输出

动态修改日志级别

text
格式:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool <Command> <Module> <Key> <Value>

其中,Command为:set或者'-s'。
Module为smartvisionsdk_<pid>。
Key为log_level。

Value为:
off:关闭日志
err:打印错误日志
warn:打印警告日志
info:打印信息日志

例如:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool set smartvisionsdk_1234 log_level info

其中,查询当前引用smartvision sdk的执行程序的pid可通过以下命令:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool query smartvisionsdk camera_process_id

关于rtcm_tool工具更多用法,请参考其帮助信息。

修改日志文件路径

text
格式:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool <Command> <Module> <Key> <Value>

其中,Command为:set或者'-s'。
Module为smartvisionsdk_<pid>。
Key为log_file_path。
Value为日志文件路径。如:/home/aidlux/,表示将在/home/aidlux路径下创建日志文件。(注:SDK初始日志默认存储在/tmp/smartvisionsdk/目录下)

例如:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool set smartvisionsdk_1234 log_file_path /home/aidlux/

日志文件路径默认值为应用程序所在路径。

其中,查询当前引用smartvision sdk的执行程序的pid可通过以下命令:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool query smartvisionsdk camera_process_id

关于rtcm_tool工具更多用法,请参考其帮助信息。

查询日志级别配置

text
格式:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool <Command> <Module> <Key>

其中,Command为:query或者'-q'。
Module为smartvisionsdk_<pid>。
Key为log_level。

例如:
/opt/aidlux/cpf/aid-rtcm/tools/rtcm_tool query smartvisionsdk_1234 log_level

日志保存于应用执行程序同一目录。例如:

text
$ ls -rlt 
-rwxr-xr-x. 1 aidlux aidlux 127032 Jun 21 11:50 demo
-rw-r--r--. 1 aidlux aidlux 919473 Jun 21 13:34 aidclog_smartvisionsdk_logger_115125_429_2024-06-21.aidclog

C++示例代码

MIPI相机

cpp
#include "smart_vision.hpp"
using namespace std;
using namespace Aidlux::SmartVision;

int stop_sign = 0;
const char* camera_path = "/home/aidlux/param.json";
int8_t preview = 1;  // 0: 不打开预览   1: 打开预览
bool data_sign = false;
int idx = 0;
cv::Mat sdk_frame;

// 回调函数my_get_img_cb定义
int8_t my_get_img_cb(const Aidlux::SmartVision::Image & cap_img, const SVSdkMemfdInfo &idx)
{
    t_count++;
    cout << "Image - w: " << cap_img.w << ", h: " << cap_img.h << "Image - w: " << cap_img.srcWidth << ", h: " << cap_img.srcHeight << ", length: " << cap_img.length << ", rt fps: " << cap_img.rt_fps << ", ma fps: " << cap_img.ma_fps << endl;
    // 添加处理程序,当data_sign为真才处理
    if(data_sign){
        bool res = yuv_to_bgr(sdk_frame, cap_img.srcHeight, cap_img.srcWidth, cap_img.planeOffset, (void *)cap_img.data, idx);
        data_sign = false;
    }
    return 0;
}

int main(int argc, char * argv[]) {
    configure_camera_parameter(camera_path, 1, 0);
    if (start_camera_without_parameter(my_get_img_cb, preview, idx) != 0)
    {
        printf("Start camera %d failed.\n", idx);
        CLOGI("Start camera %d failed.", idx);
        return -1;
    }
    start_camera_capture(idx);
    string file_name;
    while(!stop_sign){
        data_sign = true;
        while(data_sign && (!stop_sign)){
            usleep(10000);
        }
        if(stop_sign)
            break;
    }

    stop_camera_capture(idx);
    close_camera(idx);
    return 0;
}

C++示例代码精解

首先是激活配置文件相机配置文件

cpp
configure_camera_parameter(camera_path, 1, 0);

然后调用start_camera_without_parameter函数打开相机。

如果是无参设置,则直接传入回调函数名my_get_img_cb。(注:MIPI相机相关配置。) 如果是有参设置,则还需要实例化结构体DeviceParam,并设置相机配置文件名及路径。然后在open()函数中传入DeviceParam实例和回调函数名。

cpp
// 无参设置
int res = start_camera_without_parameter(my_get_img_cb, 1, 0);
// 有参设置
int res = start_camera_with_parameter(cb, conf_file, 1, 0)`;

其次,如果打开相机成功,则调用start_camera_capture函数打开流开关。

接着设计while循环语句,在循环体内,源源不断获取从回调函数中拷贝出来的图像数据。

由于所获数据是YUV原始数据,需要转换为BGR格式,因此需要调用yuv_to_bgr API进行转换。

cpp
// sdk_frame为mat对象,转换后的数据存入sdk_frame对象带出。 cap_img.data则为原始数据指针
// mem_info.srcSliceHeight为YUV数据的高度,mem_info.srcYPlaneStride为YUV数据的宽度
yuv_to_bgr(sdk_frame, mem_info.srcSliceHeight, mem_info.srcYPlaneStride, mem_info.planeOffset, (void*)cap_img.data, idx=0);

转换出来的数据用于AI推理及结果预览等。

最后,当不再需要获取数据的时候,调用stop_camera_capture函数关闭流开关,调用close_camera函数关闭摄像头,最后退出程序。

Python示例代码

python
from pysmartvision import smartvisionsdk
import numpy as np
import time
import os

# 全局变量
stop_sign = False
camera_path = "/home/aidlux/param.json"
preview = 1  # 1: 打开预览, 0: 不打开
data_sign = False
idx = 0
sdk_frame = None

def yuv_to_bgr(yuv_data, height, width, plane_offsets, dtype=np.uint8):
    """
    将 YUV 数据(NV12/NV21)转换为 BGR 图像
    注意:这里简化处理,实际需根据 planeOffset 和 data 结构解析
    """
    # 假设是 NV12 格式 (Y + UV)
    y_size = width * height
    uv_size = width * height // 2

    y = np.frombuffer(yuv_data[0:y_size], dtype=dtype).reshape((height, width))
    uv = np.frombuffer(yuv_data[y_size:y_size+uv_size], dtype=dtype).reshape((height//2, width//2, 2))

    yuv = cv2.merge([y, uv[:,:,0], uv[:,:,1]])
    bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV12)
    return bgr

# 回调函数
def my_get_img_cb(cap_img: Image):
    global data_sign, sdk_frame, stop_sign
    print(f"Image - w: {cap_img.w}, h: {cap_img.h}, "
          f"srcWidth: {cap_img.srcWidth}, srcHeight: {cap_img.srcHeight}, "
          f"length: {cap_img.length}, rt_fps: {cap_img.rt_fps}, ma_fps: {cap_img.ma_fps}")

    if data_sign:
        try:
            bgr_img = yuv_to_bgr(cap_img.data, cap_img.srcHeight, cap_img.srcWidth, cap_img.planeOffset)
            sdk_frame = bgr_img
            data_sign = False
        except Exception as e:
            print(f"YUV to BGR conversion error: {e}")
        return 0

def main():
    global stop_sign, data_sign, idx
    ret = smartvisionsdk.configure_camera_parameter(camera_path, 1, idx)
    if ret != 0:
        print(f"Failed to configure camera {idx}, error: {ret}")
        return -1

    ret = smartvisionsdk.start_camera_without_parameter(my_get_img_cb, preview, idx)
    if ret != 0:
        print(f"Start camera {idx} failed.")
        return -1

    start_camera_capture(idx)

    print("Camera started. Waiting for frames...")

    try:
        while not stop_sign:
            data_sign = True
            # 等待数据处理完成,最多等待5秒
            timeout = 0
            while data_sign and not stop_sign:
                time.sleep(0.1)  # 替代msleep(100)
                timeout += 1
                if timeout > 50:  # 5秒超时
                    print("Frame processing timeout")
                    break
    except KeyboardInterrupt:
        print("User interrupted")
        stop_sign = True

    stop_camera_capture(idx)
    close_camera(idx)

    print("Camera stopped.")
    return 0

if __name__ == "__main__":
    main()

Python示例代码精解

首先是激活配置文件相机配置文件

python
configure_camera_parameter(camera_path, 1, 0)

然后调用open()函数打开相机。

如果是无参设置,则直接传入回调函数名my_get_img_cb。

如果是有参设置,则还需要实例化结构体DeviceParam,并设置相机配置文件名及路径。然后在open()函数中传入DeviceParam实例和回调函数名。

python
// 无参设置
res = start_camera_without_parameter(my_get_img_cb, 1, 0)
// 有参设置
res = start_camera_with_parameter(cb, conf_file, 1, 0)

其次,如果打开相机成功,则调用start_capture函数打开流开关。

接着设计while循环语句,在循环体内,源源不断获取从回调函数中拷贝出来的图像数据。而在回调函数中,则通过接口get_cvimage获取图像数据。(注:该图像数据已转为BGR数据)

python
im = smartvisionsdk.get_cvimage(cap_img)

所获图像数据用于AI推理等。

最后,当不再需要获取数据的时候,调用stop_capture函数关闭流开关,退出主程序。