K230 CanMV Camera 模块API手册#

前言#

概述#

本文档主要介绍K230 CanMV平台Camera模块 API使用说明及应用示例。

读者对象#

本文档(本指南)主要适用于以下人员:

  • 技术支持工程师

  • 软件开发工程师

缩略词定义#

简称

说明

VICAP

Video Input Capture,图像输入采集模块

MCM

Multi Camera Management ,多摄像头管理

修订记录#

文档版本号

修改说明

修改者

日期

V1.0

初版

汪成根

2023-09-18

V1.1

添加多sensor MCM 相关的API

赵忠祥

2024-03-11

1. 概述#

该模块将在V1.0版本后废弃,请使用sensor模块

​ K230 CanMV平台Camera模块负责图像采集处理任务。本模块提供了一系列Highe Levl的API,应用开发者可以不用关注底层硬件细节,仅通过该模块提供的API即可获取不同格式和尺寸的图像。

​ K230 CanMV平台Camera模块包括三个独立的能力完全相同的camera设备,每个camera设备均可独立完成图像数据采集捕获处理,并可以同时输出3路图像数据。如下图所示:

cover

sensor 0,sensor 1,sensor 2表示三个图像传感器;Camera Device 0,Camera Device 1,Camera Device 2表示三个camera设备;output channel 0,output channel 1,output channel 2表示camera设备的三个输出通道。三个图像传感器可以通过软件配置映射到不同的camera 设备。

2. API描述#

K230 CanMV平台Camera模块提供camera静态类,该类提供以下章节描述的方法。

2.1 sensor_init#

【描述】

根据指定的camera设备和sensor类型执行初始化

【语法】

def sensor_init(cls, dev_num, type)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

sensor_type

sensor类型,CanMV平台定义的已经支持的各类sensor

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 这是使用camera模块需要调用的第一个方法。

用户不调用该方法,默认初始化camera设备0及sensor OV5647

【举例】

# 初始化camera设备0以及sensor OV5647
camera.sensor_init(CAM_DEV_ID_0, CAM_DEFAULT_SENSOR)

【相关主题】

2.2 set_inbufs#

【描述】

设置指定camera设备使用的输入缓冲区个数

【语法】

def set_inbufs(cls, dev_num, num)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

num

输入缓冲区个数

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 该方法仅在用户需要同时使用多个camera设备捕获图像时才有效。

当用户使用多个camera设备而不调用该方法时,将使用默认配置参数。这有可能存在默认配置输入缓冲区个数较少而引起丢帧问题。

【举例】

# 配置camera设备0 使用4个输入缓冲区
camera.set_inbufs(CAM_DEV_ID_0,4)

# 配置camera设备1 使用6个输入缓冲区
camera.set_inbufs(CAM_DEV_ID_1,6)

【相关主题】

2.3 set_outbufs#

【描述】

设置指定camera设备和通道的输出缓冲区个数

【语法】

def set_outbufs(cls, dev_num, chn_num, num)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

chn_num

camera输出通道号

输入

num

输出缓冲区个数

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 如果用户不调用方法,将使用默认配置。

【举例】

# 配置camera设备0,输出通道0, 使用4个输出缓冲区
camera.set_outbufs(CAM_DEV_ID_0, CAM_CHN_ID_0, 4)

# 配置camera设备0,输出通道1, 使用4个输出缓冲区
camera.set_outbufs(CAM_DEV_ID_0, CAM_CHN_ID_1, 4)

【相关主题】

2.4 set_outsize#

【描述】

设置指定camera设备和通道的输出图像尺寸

【语法】

def set_outsize(cls, dev_num, chn_num, width, height)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

chn_num

camera输出通道号

输入

width

输出图像宽度

输入

height

输出图像高度

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】

输出图像尺寸不能超过输入图像尺寸。

不同输出通道最大可输出图像尺寸由硬件限制。

用户不调用该方法,默认输出图像尺寸与输入图像一致。

【举例】

# 配置camera设备0,输出通道0, 输出图尺寸为640x480
camera.set_outsize(CAM_DEV_ID_0, CAM_CHN_ID_0, 640, 480)

# 配置camera设备0,输出通道1, 输出图尺寸为320x240
camera.set_outsize(CAM_DEV_ID_0, CAM_CHN_ID_1, 320, 240)

【相关主题】

2.5 set_outfmt#

【描述】

设置指定camera设备和通道的输出图像格式

【语法】

def set_outfmt(cls, dev_num, chn_num, pix_format)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

chn_num

camera输出通道号

输入

pix_format

输出图像格式

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 用户不调用方法,将使用默认配置。

【举例】

# 配置camera设备0,输出通道0, 输出NV12格式
camera.set_outfmt(CAM_DEV_ID_0, CAM_CHN_ID_0, CAM_OUT_NV12)

# 配置camera设备0,输出通道1, 输出RGB888格式
camera.set_outfmt(CAM_DEV_ID_0, CAM_CHN_ID_1, CAM_OUT_RGB888)

【相关主题】

2.5 start_stream#

【描述】

启动camera数据流

【语法】

def start_stream(cls, dev_num)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 用户不调用方法,将使用默认配置。

【举例】

# 启动camera设备0输出数据流
camera.start_stream(CAM_DEV_ID_0)

【相关主题】

2.6 stop_stream#

【描述】

停止camera数据流

【语法】

def stop_stream(cls, dev_num)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【注意】 用户不调用方法,将使用默认配置。

【举例】

# 停止camera设备0输出数据流
camera.stop_stream(CAM_DEV_ID_0)

【相关主题】

2.7 capture_image#

【描述】

从指定camera设备的支持输出通道中捕获一帧图像数据

【语法】

def capture_image(cls, dev_num, chn_num)

【参数】

参数名称

描述

输入/输出

dev_num

camera设备号

输入

chn_num

camera输出通道号

【返回值】

返回值

描述

image对象

成功

其他

失败

【注意】

该方法捕获的图像格式由set_outfmt方法指定。

【举例】

# 从camera设备0的通道0输出捕获一帧图像数据
camera.capture_image(CAM_DEV_ID_0, CAM_CHN_ID_0)

【相关主题】

2.7 start_mcm_stream#

【描述】

多sensor时,启动camera数据流。多sensor时一定要先配置好各个sensor的参数,然后调该函数启动数据流。

【语法】

def start_mcm_stream(cls)

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【举例】

# 启动camera设备0输出数据流
camera.start_mcm_stream()

【相关主题】

2.8 stop_mcm_stream#

【描述】

多sensor时,停止camera数据流。与start_mcm_stream配套使用。

【语法】

def stop_mcm_stream(cls, dev_num)

【返回值】

返回值

描述

0

成功。

非 0

失败,其值为[错误码]

【举例】

# 停止camera设备0输出数据流
camera.stop_mcm_stream()

【相关主题】

3. 数据结构描述#

K230 CanMV平台Camera模块包含如下描述的各个数据定义。

3.1 sensor类型#

【说明】

下面是目前Canmv-K230板micropython支持的Sensor。 其中CSI1/2是可以使用树莓派的ov5647模组,如果使用Canmv-K230 V1.0/1.1版的板子,要修改该模组的电压。

【定义】

CAM_IMX335_2LANE_1920X1080_30FPS_12BIT_USEMCLK_LINEAR                   # Imx335 CSI0
CAM_OV5647_1920X1080_30FPS_10BIT_USEMCLK_LINEAR                         # OV5647 CSI0
CAM_OV5647_1920X1080_CSI1_30FPS_10BIT_USEMCLK_LINEAR                    # OV5647 CSI1
CAM_OV5647_1920X1080_CSI2_30FPS_10BIT_USEMCLK_LINEAR                    # OV5647 CSI2
# the default sensor type
CAM_DEFAULT_SENSOR = CAM_OV5647_1920X1080_30FPS_10BIT_USEMCLK_LINEAR    # 默认的sensor使用OV5647 CSI0

【注意事项】

Canmv-K230 V1.0/1.1版的板子外设接口为1.8V,不能直接使用树莓派的ov5647模组,必须修改电压为1.8V。

ov5647_v1.8

【相关数据类型及接口】

3.2 输出图像尺寸#

【说明】

定义各个输出通道能够支持的输出图像最大尺寸和最小尺寸

【定义】

CAM_CHN0_OUT_WIDTH_MAX = 3072
CAM_CHN0_OUT_HEIGHT_MAX = 2160

CAM_CHN1_OUT_WIDTH_MAX = 1920
CAM_CHN1_OUT_HEIGHT_MAX = 1080

CAM_CHN2_OUT_WIDTH_MAX = 1920
CAM_CHN2_OUT_HEIGHT_MAX = 1080

CAM_OUT_WIDTH_MIN = 64
CAM_OUT_HEIGHT_MIN = 64

【注意事项】

【相关数据类型及接口】

4. 示例程序#

例程#

# 本示例程序包括以下内容:
# 1. 配置camera设备0同时输出三路图像数据
# 2. 通道0输出YUV格式用于预览显示,通道1、2输出RGB888P
# 3. 抓取三路输出的图像各100张
#

from media.camera import * #导入camera模块,使用camera相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
from time import * #导入time模块,使用time相关接口
import time
import image #导入image模块,使用image相关接口

def canmv_camera_test():
    print("canmv_camera_test")

    #初始化HDMI显示
    display.init(LT9611_1920X1080_30FPS)

    #初始化默认sensor配置(OV5647)
    camera.sensor_init(CAM_DEV_ID_0, CAM_DEFAULT_SENSOR)
    #camera.sensor_init(CAM_DEV_ID_0, CAM_IMX335_2LANE_1920X1080_30FPS_12BIT_LINEAR)

    out_width = 1920
    out_height = 1080
    # 设置输出宽度16字节对齐
    out_width = ALIGN_UP(out_width, 16)

    #设置通道0输出尺寸
    camera.set_outsize(CAM_DEV_ID_0, CAM_CHN_ID_0, out_width, out_height)
    #设置通道0输出格式
    camera.set_outfmt(CAM_DEV_ID_0, CAM_CHN_ID_0, PIXEL_FORMAT_YUV_SEMIPLANAR_420)

    #创建媒体数据源设备
    media_source = media_device(CAMERA_MOD_ID, CAM_DEV_ID_0, CAM_CHN_ID_0)
    #创建媒体数据接收设备
    media_sink = media_device(DISPLAY_MOD_ID, DISPLAY_DEV_ID, DISPLAY_CHN_VIDEO1)
    #创建媒体链路,数据从源设备流到接收设备
    media.create_link(media_source, media_sink)
    #设置显示输出平面的属性
    display.set_plane(0, 0, out_width, out_height, PIXEL_FORMAT_YVU_PLANAR_420, DISPLAY_MIRROR_NONE, DISPLAY_CHN_VIDEO1)

    out_width = 640
    out_height = 480
    out_width = ALIGN_UP(out_width, 16)

    #设置通道1输出尺寸
    camera.set_outsize(CAM_DEV_ID_0, CAM_CHN_ID_1, out_width, out_height)
    #设置通道1输出格式
    camera.set_outfmt(CAM_DEV_ID_0, CAM_CHN_ID_1, PIXEL_FORMAT_RGB_888)

    #设置通道2输出尺寸
    camera.set_outsize(CAM_DEV_ID_0, CAM_CHN_ID_2, out_width, out_height)
    #设置通道2输出格式
    camera.set_outfmt(CAM_DEV_ID_0, CAM_CHN_ID_2, PIXEL_FORMAT_RGB_888_PLANAR)

    #初始化媒体缓冲区
    ret = media.buffer_init()
    if ret:
        print("canmv_camera_test, buffer init failed")
        return ret

    #启动摄像头数据流
    camera.start_stream(CAM_DEV_ID_0)
    time.sleep(15)

    capture_count = 0
    while capture_count < 100:
        time.sleep(1)
        for dev_num in range(CAM_DEV_ID_MAX):
            if not camera.cam_dev[dev_num].dev_attr.dev_enable:
                continue

            for chn_num in range(CAM_CHN_ID_MAX):
                if not camera.cam_dev[dev_num].chn_attr[chn_num].chn_enable:
                    continue

                print(f"canmv_camera_test, dev({dev_num}) chn({chn_num}) capture frame.")
                #从指定设备和通道捕获图像
                img = camera.capture_image(dev_num, chn_num)
                if img == -1:
                    print("camera.capture_image failed")
                    continue

                if img.format() == image.YUV420:
                    suffix = "yuv420sp"
                elif img.format() == image.RGB888:
                    suffix = "rgb888"
                elif img.format() == image.RGBP888:
                    suffix = "rgb888p"
                else:
                    suffix = "unkown"

                filename = f"/sdcard/dev_{dev_num:02d}_chn_{chn_num:02d}_{img.width()}x{img.height()}_{capture_count:04d}.{suffix}"
                print("save capture image to file:", filename)

                with open(filename, "wb") as f:
                    if f:
                        img_data = uctypes.bytearray_at(img.virtaddr(), img.size())
                        # save yuv data to sdcard.
                        #f.write(img_data)
                    else:
                        print(f"capture_image, open dump file failed({filename})")

                time.sleep(1)
                #释放捕获的图像数据
                camera.release_image(dev_num, chn_num, img)

                capture_count += 1

    #停止摄像头输出
    camera.stop_stream(CAM_DEV_ID_0)

    #去初始化显示设备
    display.deinit()

    #销毁媒体链路
    media.destroy_link(media_source, media_sink)

    time.sleep(1)
    #去初始化媒体缓冲区资源
    ret = media.buffer_deinit()
    if ret:
        print("camera test, media_buffer_deinit failed")
        return ret

    print("camera test exit")
    return 0


canmv_camera_test()