基础相机功能

2023-11-07
4.2 分
7 用户已评分

概述

为满足开发者对相机类负载设备的控制需求,PSDK 提供了控制相机执行拍照、录像、变焦及对焦等功能的接口,开发者需先实现相机拍照、录像以及测光等功能,再通过注册 PSDK 相机类的接口,开发出功能完善的相机类负载设备;通过使用 DJI Pilot 以及基于 MSDK 开发的移动端 App,用户能够控制使用 PSDK 开发的相机类负载设备执行指定的动作,获取负载设备中的信息和资源。

  • 基础功能:设置相机模式、拍照、录像、获取相机状态、SD 卡管理
  • 高级功能:变焦、测光、对焦、视频流传输、回放下载、媒体库管理

基础概念介绍

相机模式

使用相机类功能前,需要先设置相机类负载设备的模式,不同的模式指定了相机类负载设备在执行某个任务时的工作逻辑。

  • 拍照:在该模式下,用户能够触发相机类负载设备拍摄照片。
  • 录像:在该模式下,用户能够触发相机类负载设备录制影像。
  • 视频回放:在该模式下,用户可以在移动端 App 上播放或下载负载设备上的媒体文件。

注意: 相机只能在一种模式中执行相应的操作,如在录像模式下仅能录像无法拍照

拍照模式

使用 PSDK 开发的相机类负载设备支持以下拍照模式:

  • 单拍:下发拍照命令后,相机拍摄单张照片。
  • 连拍:下发拍照命令后,相机将连续拍摄指定数量的照片;当前支持 2/3/5/7/10/14 张连拍。
  • 定时拍照:下发拍照命令时,相机按照指定的时间间隔,拍摄指定数量的照片。
    • 当前支持 2/3/5/7/10 秒时间间隔;
    • 当前最大支持指定拍摄 254 张照片,当拍照张数为 255 的时候,相机将不间断地拍摄照片。

对焦模式

  • 自动对焦:Auto Focus,简称 AF。在自动对焦模式下,相机类负载设备根据光电传感器获取的影像状态(漫发射),计算出对焦结果实现对焦功能,获取清晰的影像。
  • 手动对焦:Manual Focus,简称 MF。在手动对焦模式下,用户通过调节对焦环能够获得清晰的影像。

对焦点

说明: 相机类负载设备的对焦点默认为传感器的中心位置。

在控制相机类负载设备对焦,需要先设置对焦点,该对焦点的值为当前对焦点在相机画面中的横纵比系数,如 图 1. 对焦点 所示。

  • 在自动对焦模式下,开发者需要制定相机对焦的策略,设置对焦点(该对焦点也称 “目标点”)。
  • 在手动对焦模式下,用户可根据实际需要调整对焦点,获得所需的影像。

图 1. 对焦点

对焦环

使用 PSDK 开发的具有变焦环(光学变焦)的相机类负载设备通过调用SetFocusRingValue接口,设置对焦环的值:

  • 对焦环的值默认为 0,表示无穷大和最接近的可能焦距。
  • 对焦环的值不为 0 时,用户可根据相机的实际参数设置对焦环的值。

对焦助手

在 AF 和 MF 模式下,对焦助手通过数字变焦的方式,能够放大用户指定的对焦区域,调用SetFocusAssistantSettings接口可设置对焦助手的状态,使用对焦助手,用户能够查看当前相机类负载设备的对焦质量。

变焦模式

  • 光学变焦,通过改变光学镜头的结构实现变焦,光学变焦倍数越大,能拍摄的景物就越远,反之则近;
  • 数码变焦,处理器使用特定的算法,通过改变传感器上每个像素的面积,实现数码变焦;
  • 连续变焦,相机类负载设备控制镜头以指定的速度沿指定的方向运动,相机类负载设备先控制镜头执行光学变焦,当光学变焦达到上限后,相机类负载设备再执行数码变焦,以此实现连续变焦的功能。当前变焦倍数 = 当前光学变焦倍数 × 当前数码变焦倍数;
  • 指点变焦,用户指定某一目标点后,基于 PSDK 开发的相机类负载设备能够控制云台转动,使指定的目标处于画面中心,控制相机类负载设备按照预设的变焦倍数放大图像。

变焦方向

  • ZOOM_IN :变焦倍数减小,图像由远到近
  • ZOOM_OUT :变焦倍数增大,图像由近到远

变焦速度

  • SLOWEST:以最慢的速度变焦
  • SLOW:以较慢的速度变焦
  • MODERATELY_SLOW:以比正常速度稍慢的速度变焦
  • NORMAL:镜头以正常的速度变焦
  • MODERATELY_FAST:以比正常速度稍快的速度变焦
  • FAST:以较快的速度变焦
  • FASTEST:以最快的速度变焦

测光模式

  • 平均测光,通过对画面整体亮度的分析,计算出画面的平均亮度的值,适合光照均匀的拍照场景;
  • 中央重点测光,仅对图像传感器中间区域测光,适合拍摄框架式构图的照片;
  • 点测光,对在以 “指定的点” 为中心的范围内测光,如 图 1. 点测光区域 所示,通过该方式能获得准确的测光结果,确保指定的对象能够曝光正确,适合光照复杂的拍摄场景。

图 1. 点测光区域

图像传感器被分为 12 列 8 行定义的 96 个点区域。行索引范围是[0,7],其中值在图像上从上到下递增;列索引范围是[0,11],其中值从左到右增加。

变焦模式

  • 光学变焦,通过改变光学镜头的结构实现变焦,光学变焦倍数越大,能拍摄的景物就越远,反之则近;
  • 数码变焦,处理器使用特定的算法,通过改变传感器上每个像素的面积,实现数码变焦;
  • 连续变焦,相机类负载设备控制镜头以指定的速度沿指定的方向运动,相机类负载设备先控制镜头执行光学变焦,当光学变焦达到上限后,相机类负载设备再执行数码变焦,以此实现连续变焦的功能。当前变焦倍数 = 当前光学变焦倍数 × 当前数码变焦倍数;
  • 指点变焦,用户指定某一目标点后,基于 PSDK 开发的相机类负载设备能够控制云台转动,使指定的目标处于画面中心,控制相机类负载设备按照预设的变焦倍数放大图像。

变焦方向

  • ZOOM_IN :变焦倍数减小,图像由远到近
  • ZOOM_OUT :变焦倍数增大,图像由近到远

变焦速度

  • SLOWEST:以最慢的速度变焦
  • SLOW:以较慢的速度变焦
  • MODERATELY_SLOW:以比正常速度稍慢的速度变焦
  • NORMAL:镜头以正常的速度变焦
  • MODERATELY_FAST:以比正常速度稍快的速度变焦
  • FAST:以较快的速度变焦
  • FASTEST:以最快的速度变焦

媒体文件管理

使用 PSDK 开发的相机类负载设备能够根据用户的指令,执行文件删除或下载等操作。

媒体文件预览功能

使用 PSDK 开发的相机类负载设备支持用户使用 DJI Pilot 或基于 MSDK 开发的移动端 App 预览负载设备中的媒体文件。

  • 静态预览:预览单个文件或文件列表

    • 缩略图,预览文件列表
      • 图像:负载设备按照文件的原始比例生成缩略图,请将预览图的宽度设置为 100 像素
      • 视频:截取视频某一帧的画面
    • 截屏图,预览单个文件
      • 图像:按原始比例,建议缩放图像成宽为 600 像素的预览图
      • 视频:截取视频某一帧的画面
    • 原始文件,如需获得相机类负载设备中原始的媒体文件,请使用下载功能获取指定的媒体文件。
  • 动态预览(视频预览):播放、暂停、停止、跳转(快进、快退和进度拖动)

    说明: 支持动态预览的文件格式:MP4、JPG、DNG 和 MOV,编码格式请参见视频标准open in new window

实现相机类基础功能

请开发者根据选用的开发平台以及行业应用实际的使用需求,按照 PSDK 中的结构体T_DjiCameraCommonHandler 构造实现相机类负载设备设置相机模式、拍照和录像等功能的函数,将相机功能的函数注册到 PSDK 中指定的接口后,用户通过使用 DJI Pilot 或基于 MSDK 开发的移动端 App 能够控制基于 PSDK 开发的相机类负载设备执行相应的动作。

    // 获取负载设备系统当前的状态
    s_commonHandler.GetSystemState = GetSystemState;
    // 实现设置相机类负载设备模式的功能
    s_commonHandler.SetMode = SetMode;
    s_commonHandler.GetMode = DjiTest_CameraGetMode;
    // 实现开始或停止录像的功能
    s_commonHandler.StartRecordVideo = StartRecordVideo;
    s_commonHandler.StopRecordVideo = StopRecordVideo;
    // 实现开始或停止拍照的功能
    s_commonHandler.StartShootPhoto = StartShootPhoto;
    s_commonHandler.StopShootPhoto = StopShootPhoto;
    // 实现设置相机类负载设备的拍照功能
    s_commonHandler.SetShootPhotoMode = SetShootPhotoMode;
    s_commonHandler.GetShootPhotoMode = GetShootPhotoMode;
    s_commonHandler.SetPhotoBurstCount = SetPhotoBurstCount;
    s_commonHandler.GetPhotoBurstCount = GetPhotoBurstCount;
    s_commonHandler.SetPhotoTimeIntervalSettings = SetPhotoTimeIntervalSettings;
    s_commonHandler.GetPhotoTimeIntervalSettings = GetPhotoTimeIntervalSettings;
    // 实现 SD 卡管理功能
    s_commonHandler.GetSDCardState = GetSDCardState;
    s_commonHandler.FormatSDCard = FormatSDCard;

基础功能初始化

使用 PSDK 开发负载设备的相机功能时,必须要初始化相机模块并注册相机类的功能。

相机类功能模块初始化

在使用相机类功能前,必须先调用接口DjiPayloadCamera_Init初始化相机类负载设备,确保相机类负载设备可正常工作。

T_PsdkReturnCode returnCode;

returnCode = DjiPayloadCamera_Init();
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
    USER_LOG_ERROR("payload camera init error:0x%08llX", returnCode);
}

注册相机类基础功能

开发者实现相机类负载设备设置相机模式、拍照和录像等功能后,需要通过DjiPayloadCamera_RegCommonHandler注册相机类基础功能。

returnCode = DjiPayloadCamera_RegCommonHandler(&s_commonHandler);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
    USER_LOG_ERROR("camera register common handler error:0x%08llX", returnCode);
}

使用 SD 卡管理功能

说明:

  • 使用 X-Port 开发的相机类负载设备需要实现存储媒体文件的功能并将该功能注册到 PSDK 指定的接口中。X-Port 上的存储卡仅支持存放 X-Port 日志信息,无法存储负载设备产生的媒体文件。
  • 本教程以模拟SD 卡管理功能为例,介绍使用 PSDK SD 卡管理功能的使用方法,如需开发具有 SD 卡管理功能的负载设备,请调用负载设备系统的接口实现 SD 卡管理功能。

SD 卡模块初始化

使用 SD 卡管理功能,需要开发者先开发并注册操作 SD 卡功能的函数,通过初始化 SD 卡管理模块,获取 SD 卡的状态信息。

    /* Init the SDcard parameters */
    s_cameraSDCardState.isInserted = true;
    s_cameraSDCardState.isVerified = true;
    s_cameraSDCardState.totalSpaceInMB = SDCARD_TOTAL_SPACE_IN_MB;
    s_cameraSDCardState.remainSpaceInMB = SDCARD_TOTAL_SPACE_IN_MB;
    s_cameraSDCardState.availableCaptureCount = SDCARD_TOTAL_SPACE_IN_MB / SDCARD_PER_PHOTO_SPACE_IN_MB;
    s_cameraSDCardState.availableRecordingTimeInSeconds = SDCARD_TOTAL_SPACE_IN_MB / SDCARD_PER_SECONDS_RECORD_SPACE_IN_MB;

获取 SD 卡的当前状态

基于 PSDK 开发的负载设备控制程序调用GetSDCardState接口能够获取负载设备上 SD 卡当前的状态,用户使用 DJI Pilot 以及基于 MSDK 开发的 APP 能够查看负载设备中 SD 卡的状态信息。

// 预估可拍照张数和可录像时长的功能。
if (s_cameraState.isRecording) {
    s_cameraState.currentVideoRecordingTimeInSeconds++;
    s_cameraSDCardState.remainSpaceInMB =
        s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_SECONDS_RECORD_SPACE_IN_MB;
    if (s_cameraSDCardState.remainSpaceInMB > SDCARD_TOTAL_SPACE_IN_MB) {
        s_cameraSDCardState.remainSpaceInMB = 0;
        s_cameraSDCardState.isFull = true;
    }
}
// 获取 SD 卡的状态
static T_DjiReturnCode GetSDCardState(T_DjiCameraSDCardState *sdCardState)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    memcpy(sdCardState, &s_cameraSDCardState, sizeof(T_DjiCameraSDCardState));

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

使用 SD 卡格式化功能

基于 PSDK 开发的负载设备控制程序调用FormatSDCard接口能够控制负载设备执行 SD 卡格式化,用户使用 DJI Pilot 以及基于 MSDK 开发的 APP 可获取负载设备中 SD 卡的状态信息并控制负载设备执行 SD 卡格式化功能,如 图 1. SD 卡管理功能 所示。

static T_DjiReturnCode FormatSDCard(void)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("format sdcard");

    memset(&s_cameraSDCardState, 0, sizeof(T_DjiCameraSDCardState));
    s_cameraSDCardState.isInserted = true;
    s_cameraSDCardState.isVerified = true;
    s_cameraSDCardState.totalSpaceInMB = SDCARD_TOTAL_SPACE_IN_MB;
    s_cameraSDCardState.remainSpaceInMB = SDCARD_TOTAL_SPACE_IN_MB;
    s_cameraSDCardState.availableCaptureCount = SDCARD_TOTAL_SPACE_IN_MB / SDCARD_PER_PHOTO_SPACE_IN_MB;
    s_cameraSDCardState.availableRecordingTimeInSeconds =
    SDCARD_TOTAL_SPACE_IN_MB / SDCARD_PER_SECONDS_RECORD_SPACE_IN_MB;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

图 1. SD 卡管理功能

使用模式设置功能

基于 PSDK 开发的负载设备控制程序调用SetModeGetMode接口能够设置相机的模式,用户使用 DJI Pilot 能够切换相机类负载设备的工作模式,如 图 2. 设置相机模式 所示。

static T_DjiReturnCode GetSystemState(T_DjiCameraSystemState *systemState)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *systemState = s_cameraState;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode SetMode(E_DjiCameraMode mode)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_cameraState.cameraMode = mode;
    USER_LOG_INFO("set camera mode:%d", mode);

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

T_DjiReturnCode DjiTest_CameraGetMode(E_DjiCameraMode *mode)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *mode = s_cameraState.cameraMode;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

图 2. 设置相机类负载设备的模式

使用拍照功能

说明:

  • 使用拍照功能前,用户需要在 DJI Pilot 或基于 MSDK 开发的移动端 App 上将相机类负载设备的工作模式设置为拍照模式。
  • 使用 PSDK 开发的负载设备在拍照时,会向 DJI Pilot 或基于 MSDK 开发的移动端 App 返回拍照状态(用于如触发移动端 App 拍照声音等功能)。

设置相机类负载设备的拍照模式

基于 PSDK 开发的负载设备控制程序调用SetShootPhotoModeGetShootPhotoMode接口能够设置并获取相机类负载设备的模式,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可设置并获取相机类负载设备的拍照模式。

static T_DjiReturnCode SetShootPhotoMode(E_DjiCameraShootPhotoMode mode)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_cameraShootPhotoMode = mode;
    USER_LOG_INFO("set shoot photo mode:%d", mode);

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetShootPhotoMode(E_DjiCameraShootPhotoMode *mode)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *mode = s_cameraShootPhotoMode;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);\
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

控制相机单拍

基于 PSDK 开发的负载设备控制程序调用StartShootPhotoStopShootPhoto接口控制相机类负载设备拍摄单张照片,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可控制相机类负载设备拍摄单张照片。

static T_DjiReturnCode StartShootPhoto(void)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("start shoot photo");
    s_cameraState.isStoring = true;

    if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_SINGLE) {
        s_cameraState.shootingState = DJI_CAMERA_SHOOTING_SINGLE_PHOTO;
    } else if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_BURST) {
        s_cameraState.shootingState = DJI_CAMERA_SHOOTING_BURST_PHOTO;
    } else if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_INTERVAL) {
        s_cameraState.shootingState = DJI_CAMERA_SHOOTING_INTERVAL_PHOTO;
        s_cameraState.isShootingIntervalStart = true;
        s_cameraState.currentPhotoShootingIntervalTimeInSeconds = s_cameraPhotoTimeIntervalSettings.timeIntervalSeconds;
    }

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode StopShootPhoto(void)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("stop shoot photo");
    s_cameraState.shootingState = DJI_CAMERA_SHOOTING_PHOTO_IDLE;
    s_cameraState.isStoring = false;
    s_cameraState.isShootingIntervalStart = false;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

控制相机连拍

基于 PSDK 开发的负载设备控制程序调用SetPhotoBurstCountGetPhotoBurstCount接口控制相机类负载设备连拍,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可设置相机类负载设备的连拍张数,控制相机类负载设备拍摄指定数量的照片。

static T_DjiReturnCode SetPhotoBurstCount(E_DjiCameraBurstCount burstCount)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_cameraBurstCount = burstCount;
    USER_LOG_INFO("set photo burst count:%d", burstCount);

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetPhotoBurstCount(E_DjiCameraBurstCount *burstCount)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *burstCount = s_cameraBurstCount;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

控制相机定时拍照

基于 PSDK 开发的负载设备控制程序调用SetPhotoTimeIntervalSettingsGetPhotoTimeIntervalSettings接口控制相机类负载设备定时拍照,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可设置相机类负载设备的拍照间隔,控制相机类负载设备按照指定的时间间隔拍摄照片。

static T_DjiReturnCode SetPhotoTimeIntervalSettings(T_DjiCameraPhotoTimeIntervalSettings settings)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_cameraPhotoTimeIntervalSettings.captureCount = settings.captureCount;
    s_cameraPhotoTimeIntervalSettings.timeIntervalSeconds = settings.timeIntervalSeconds;
    USER_LOG_INFO("set photo interval settings count:%d seconds:%d", settings.captureCount,
                  settings.timeIntervalSeconds);
    s_cameraState.currentPhotoShootingIntervalCount = settings.captureCount;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetPhotoTimeIntervalSettings(T_DjiCameraPhotoTimeIntervalSettings *settings)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    memcpy(settings, &s_cameraPhotoTimeIntervalSettings, sizeof(T_DjiCameraPhotoTimeIntervalSettings));

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

拍照状态管理

在 DJI Pilot 以及使用 MSDK 开发的移动端 App 中点击 “拍照” 按钮后,使用 PSDK 开发的相机类负载设备在自定义时间内(如 0.5s)在线程中执行拍照、照片存储和内存状态更新的操作。

确认拍照状态

使用 PSDK 开发的相机类负载设备在执行完拍照动作后,需要获取负载设备的拍照状态。

if (s_cameraState.shootingState != PSDK_CAMERA_SHOOTING_PHOTO_IDLE &&
    photoCnt++ > TAKING_PHOTO_SPENT_TIME_MS_EMU / (1000 / PAYLOAD_CAMERA_EMU_TASK_FREQ)) {
    s_cameraState.isStoring = false;
    s_cameraState.shootingState = PSDK_CAMERA_SHOOTING_PHOTO_IDLE;
    photoCnt = 0;
}

存储照片

相机类负载设备在执行完拍照后,使用 PSDK 开发的相机类负载设备将相机拍摄的照片存储在相机类负载设备上的内存卡中。

  • 存储单拍模式下相机类负载设备拍摄的照片
if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_SINGLE) {
    s_cameraSDCardState.remainSpaceInMB =
        s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_PHOTO_SPACE_IN_MB;
    s_cameraState.isStoring = false;
    s_cameraState.shootingState = DJI_CAMERA_SHOOTING_PHOTO_IDLE;
}
  • 存储连拍模式下相机类负载设备拍摄的照片
else if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_BURST) {
    s_cameraSDCardState.remainSpaceInMB =
        s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_PHOTO_SPACE_IN_MB * s_cameraBurstCount;
    s_cameraState.isStoring = false;
    s_cameraState.shootingState = DJI_CAMERA_SHOOTING_PHOTO_IDLE;
}
  • 存储定时拍照模式下相机类负载设备拍摄的照片
else if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_INTERVAL) {
    if (isStartIntervalPhotoAction == true) {
        s_cameraState.isStoring = false;
        s_cameraState.shootingState = DJI_CAMERA_SHOOTING_PHOTO_IDLE;
        s_cameraSDCardState.remainSpaceInMB =
            s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_PHOTO_SPACE_IN_MB;
    }
}

检查存储空间

为确保相机类负载设备中的 SD 卡在相机类负载设备执行拍照动作后,有充足的存储空间存储照片或视频,建议在使用 PSDK 开发的相机类负载设备中添加检查 SD 卡存储空间的功能。

  • 检查相机类负载设备执行单拍和连拍后 SD 卡剩余的存储空间。
if (s_cameraSDCardState.remainSpaceInMB > SDCARD_TOTAL_SPACE_IN_MB) {
    s_cameraSDCardState.remainSpaceInMB = 0;
    s_cameraSDCardState.isFull = true;
}
  • 检查相机类负载设备执行定时拍照后 SD 卡剩余的存储空间
if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_INTERVAL) {
    if (isStartIntervalPhotoAction == true) {
        s_cameraState.isStoring = false;
        s_cameraState.shootingState = DJI_CAMERA_SHOOTING_PHOTO_IDLE;
        s_cameraSDCardState.remainSpaceInMB =
            s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_PHOTO_SPACE_IN_MB;
    }
}

使用遥控器可以控制相机类负载设备执行拍照动作,如 图 3. 拍照 所示。

图 3. 拍照

在单拍模式下,可执行拍照动作,如 图 4. 单拍 所示。

图 4. 单拍

在连拍模式下,设置相机类负载设备的连拍张数后,相机类负载设备即可执行连拍动作,如 图 5. 连拍 所示。

图 5. 连拍

在定时拍照模式下,设置相机类负载设备拍照的间隔时间,相机类负载设备可执行定时拍照动作,如 图 6. 定时拍照 所示。

图 6. 定时拍照

使用录像功能

说明:

  • 相机类负载设备在录像的过程中无法拍照和测光;
  • 开发者可根据用户的使用需要,设置相机类负载设备录像时如 ISO、曝光以及对焦等参数的默认值;
  • 使用相机类负载设备的录像功能前,用户需要在 DJI Pilot 或基于 MSDK 开发的移动端 App 上将相机类负载设备的模式设置为录像模式。

控制相机录像

基于 PSDK 开发的负载设备控制程序调用StartRecordVideoStopRecordVideo接口控制相机类负载设备录像,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可控制相机类负载设备录像。

static T_DjiReturnCode StartRecordVideo(void)
{
    T_DjiReturnCode djiStat;
    T_DjiReturnCode returnCode = DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    djiStat = osalHandler->MutexLock(s_commonMutex);
    if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", djiStat);
        return djiStat;
    }

    if (s_cameraState.isRecording != false) {
        USER_LOG_ERROR("camera is already in recording state");
        returnCode = DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT_IN_CURRENT_STATE;
        goto out;
    }

    s_cameraState.isRecording = true;
    USER_LOG_INFO("start record video");

out:
    djiStat = osalHandler->MutexUnlock(s_commonMutex);
    if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", djiStat);
        return djiStat;
    }

    return returnCode;
}

static T_DjiReturnCode StopRecordVideo(void)
{
    T_DjiReturnCode djiStat;
    T_DjiReturnCode returnCode = DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    djiStat = osalHandler->MutexLock(s_commonMutex);
    if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", djiStat);
        return djiStat;
    }

    if (s_cameraState.isRecording != true) {
        USER_LOG_ERROR("camera is not in recording state");
        returnCode = DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT_IN_CURRENT_STATE;
        goto out;
    }

    s_cameraState.isRecording = false;
    s_cameraState.currentVideoRecordingTimeInSeconds = 0;
    USER_LOG_INFO("stop record video");

out:
    djiStat = osalHandler->MutexUnlock(s_commonMutex);
    if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", djiStat);
        return djiStat;
    }

    return returnCode;
}

录像状态更新

使用 PSDK 开发的相机类负载设备控制程序,默认以 10Hz 的频率更新相机的状态。

说明: 相机开始录像后,DJI Pilot 及基于 MSDK 开发的移动端 App 会显示当前正在录像的时间,相机停止录像时,该时间将归 0。

if (s_cameraState.isRecording) {
    s_cameraState.currentVideoRecordingTimeInSeconds++;
    s_cameraSDCardState.remainSpaceInMB =
        s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_SECONDS_RECORD_SPACE_IN_MB;
    if (s_cameraSDCardState.remainSpaceInMB > SDCARD_TOTAL_SPACE_IN_MB) {
        s_cameraSDCardState.remainSpaceInMB = 0;
        s_cameraSDCardState.isFull = true;
    }
}

static T_DjiReturnCode GetSystemState(T_DjiCameraSystemState *systemState)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *systemState = s_cameraState;

    returnCode = osalHandler->MutexUnlock(s_commonMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

在 DJI Pilot 或基于 MSDK 开发的移动端 App 上向负载设备发送录像指令后(也可通过遥控器向负载设备发送录像指令),相机类负载设备根据用户发送的指令控制负载设备录像,如 图 7. 相机录像 所示。

图 7. 相机录像

实现对焦功能

请开发者根据选用的开发平台以及行业应用实际的使用需求,按照 PSDK 中的结构体T_DjiCameraFocusHandler 构造实现相机类负载设备对焦功能的函数,将对焦功能的函数注册到 PSDK 中指定的接口后,用户通过使用 DJI Pilot 或基于 MSDK 开发的移动端 App 能够控制基于 PSDK 开发的相机类负载设备对焦。

    // 实现设置对焦模式的功能
    s_focusHandler.SetFocusMode = SetFocusMode;
    s_focusHandler.GetFocusMode = GetFocusMode;
    // 实现设置对焦点的功能
    s_focusHandler.SetFocusTarget = SetFocusTarget;
    s_focusHandler.GetFocusTarget = GetFocusTarget;
    // 实现设置对焦助手的功能
    s_focusHandler.SetFocusAssistantSettings = SetFocusAssistantSettings;
    s_focusHandler.GetFocusAssistantSettings = GetFocusAssistantSettings;
    // 实现设置对焦环的功能
    s_focusHandler.SetFocusRingValue = SetFocusRingValue;
    s_focusHandler.GetFocusRingValue = GetFocusRingValue;
    s_focusHandler.GetFocusRingValueUpperBound = GetFocusRingValueUpperBound;

使用对焦功能

注册对焦功能

开发者实现相机类负载设备的对焦功能后,需要通过DjiPayloadCamera_RegFocusHandler注册对焦功能,方便用户通过使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 控制相机类负载设备对焦。

    returnCode = DjiPayloadCamera_RegFocusHandler(&s_focusHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("camera register adjustable focal point handler error:0x%08llX", returnCode);
        return returnCode;
    }

设置对焦模式

基于 PSDK 开发的负载设备控制程序调用SetFocusModeGetFocusMode接口能够设置相机类负载设备的对焦模式,用户使用 DJI Pilot 能够切换相机类负载设备的对焦模式。

static T_DjiReturnCode SetFocusMode(E_DjiCameraFocusMode mode)
{
    USER_LOG_INFO("set focus mode:%d", mode);
    s_cameraFocusMode = mode;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetFocusMode(E_DjiCameraFocusMode *mode)
{
    *mode = s_cameraFocusMode;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

设置对焦点

基于 PSDK 开发的负载设备控制程序调用SetFocusTargetGetFocusTarget接口能够设置相机类负载设备的对焦点,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够设置或获取相机类负载设备的对焦点。

static T_DjiReturnCode SetFocusTarget(T_DjiCameraPointInScreen target)
{
    USER_LOG_INFO("set focus target x:%.2f y:%.2f", target.focusX, target.focusY);
    memcpy(&s_cameraFocusTarget, &target, sizeof(T_DjiCameraPointInScreen));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetFocusTarget(T_DjiCameraPointInScreen *target)
{
    memcpy(target, &s_cameraFocusTarget, sizeof(T_DjiCameraPointInScreen));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

设置对焦环

基于 PSDK 开发的负载设备控制程序调用SetFocusRingValueGetFocusRingValueUpperBoundGetFocusRingValueUpperBound接口能够设置相机类负载设备对焦环的值,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够设置或获取相机类负载设备对焦环的当前的值和最大值。

static T_DjiReturnCode SetFocusRingValue(uint32_t value)
{
    USER_LOG_INFO("set focus ring value:%d", value);
    s_cameraFocusRingValue = value;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetFocusRingValue(uint32_t *value)
{
    *value = s_cameraFocusRingValue;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetFocusRingValueUpperBound(uint32_t *value)
{
    *value = FOCUS_MAX_RINGVALUE;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

使用对焦助手

基于 PSDK 开发的负载设备控制程序调用SetFocusAssistantSettingsGetFocusAssistantSettings接口能够设置相机类负载设备对焦环的值,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够设置或获取相机类负载设备对焦助手的状态。

static T_DjiReturnCode SetFocusAssistantSettings(T_DjiCameraFocusAssistantSettings settings)
{
    USER_LOG_INFO("set focus assistant setting MF:%d AF:%d", settings.isEnabledMF, settings.isEnabledAF);
    memcpy(&s_cameraFocusAssistantSettings, &settings, sizeof(T_DjiCameraFocusAssistantSettings));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetFocusAssistantSettings(T_DjiCameraFocusAssistantSettings *settings)
{
    memcpy(settings, &s_cameraFocusAssistantSettings, sizeof(T_DjiCameraFocusAssistantSettings));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

实现相机类负载设备的对焦功能后,在自动对焦模式下,相机类负载设备需要设置对焦点 如 图 2. 自动对焦 所示;在手动对焦模式下,用户可根据实际需要调整对焦点,如 图 3. 手动对焦 所示。

说明: 若按钮为黄色,表示当前为测光功能,点击后,即可切换为对焦模式。

图 2. 自动对焦

图 3. 手动对焦

实现测光功能

请开发者根据选用的开发平台以及行业应用实际的使用需求,按照 PSDK 中的结构体T_DjiCameraExposureMeteringHandler 构造实现相机类负载设备测光功能的函数,将测光功能的函数注册到 PSDK 中指定的接口后,用户通过使用 DJI Pilot 或基于 MSDK 开发的移动端 App 能够控制相机类负载设备测光。

    // 实现设置测光模式的功能
    s_exposureMeteringHandler.SetMeteringMode = SetMeteringMode;
    s_exposureMeteringHandler.GetMeteringMode = GetMeteringMode;
    // 实现控制负载设备测光的功能
    s_exposureMeteringHandler.SetSpotMeteringTarget = SetSpotMeteringTarget;
    s_exposureMeteringHandler.GetSpotMeteringTarget = GetSpotMeteringTarget;

使用测光功能

注册测光功能

开发者实现相机类负载设备的测光功能后,需要通过PsdkPayloadCamera_RegExposureMeteringHandler注册测光功能;调用指定的接口后,用户通过使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 即可控制相机类负载设备测光,如 图 2. 测光功能

    returnCode = DjiPayloadCamera_RegExposureMeteringHandler(&s_exposureMeteringHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("camera register exposure metering handler error:0x%08llX", returnCode);
        return returnCode;
    }

设置测光模式

基于 PSDK 开发的负载设备控制程序调用SetMeteringModeGetMeteringMode接口能够设置或获取相机类负载设备的测光模式,用户使用 DJI Pilot 以及基于 MSDK 开发的 APP 能够查看负载设备的测光模式,如 图 3. 指点测光 和 图 4. 中央重点测光 所示。

static T_DjiReturnCode SetMeteringMode(E_DjiCameraMeteringMode mode)
{
    USER_LOG_INFO("set metering mode:%d", mode);
    s_cameraMeteringMode = mode;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetMeteringMode(E_DjiCameraMeteringMode *mode)
{
    *mode = s_cameraMeteringMode;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

设置测光对象

相机类负载设备在调用SetSpotMeteringTargetGetSpotMeteringTarget接口后,使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 可设置或获取相机类负载设备的测光对象。

static T_DjiReturnCode SetSpotMeteringTarget(T_DjiCameraSpotMeteringTarget target)
{
    USER_LOG_INFO("set spot metering area col:%d row:%d", target.col, target.row);
    memcpy(&s_cameraSpotMeteringTarget, &target, sizeof(T_DjiCameraSpotMeteringTarget));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetSpotMeteringTarget(T_DjiCameraSpotMeteringTarget *target)
{
    memcpy(target, &s_cameraSpotMeteringTarget, sizeof(T_DjiCameraSpotMeteringTarget));

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

图 2. 测光功能

图 3. 中央重点测光

图 4. 指点测光

说明: 在 DJI Pilot 上使用相机类负载设备的测光功能时,若按钮为绿色,表示当前为对焦功能,点击后,即可切换为测光模式。

实现变焦功能

请开发者根据选用的开发平台以及行业应用实际的使用需求,按照 PSDK 中的结构体T_DjiCameraTapZoomHandler 构造实现相机类负载设备变焦功能的函数,将变焦功能的函数注册到 PSDK 中指定的接口后,用户通过使用 DJI Pilot 或基于 MSDK 开发的移动端 App 能够控制相机类负载设备变焦。

    // 实现控制负载设备执行数码变焦的功能
    s_digitalZoomHandler.SetDigitalZoomFactor = SetDigitalZoomFactor;
    s_digitalZoomHandler.GetDigitalZoomFactor = GetDigitalZoomFactor;
    // 实现控制负载设备执行光学变焦的功能
    s_opticalZoomHandler.SetOpticalZoomFocalLength = SetOpticalZoomFocalLength;
    s_opticalZoomHandler.GetOpticalZoomFocalLength = GetOpticalZoomFocalLength;
    s_opticalZoomHandler.GetOpticalZoomFactor = GetOpticalZoomFactor;
    s_opticalZoomHandler.GetOpticalZoomSpec = GetOpticalZoomSpec;
    s_opticalZoomHandler.StartContinuousOpticalZoom = StartContinuousOpticalZoom;
    s_opticalZoomHandler.StopContinuousOpticalZoom = StopContinuousOpticalZoom;
    // 实现控制负载设备执行指点变焦的功能
    s_tapZoomHandler.GetTapZoomState = GetTapZoomState;
    s_tapZoomHandler.SetTapZoomEnabled = SetTapZoomEnabled;
    s_tapZoomHandler.GetTapZoomEnabled = GetTapZoomEnabled;
    s_tapZoomHandler.SetTapZoomMultiplier = SetTapZoomMultiplier;
    s_tapZoomHandler.GetTapZoomMultiplier = GetTapZoomMultiplier;
    s_tapZoomHandler.TapZoomAtTarget = TapZoomAtTarget;

使用变焦功能

注册变焦功能

开发者实现相机类负载设备的变焦功能后,需要通过注册接口注册各个变焦功能的函数;基于 PSDK 开发的负载设备通过调用指定的接口,即可控制相机类负载设备执行变焦,方便用户通过使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 控制相机类负载设备变焦。

  • 注册数码变焦功能
returnCode = DjiPayloadCamera_RegDigitalZoomHandler(&s_digitalZoomHandler);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
    USER_LOG_ERROR("camera register digital zoom handler error:0x%08llX", returnCode);
    return returnCode;
}
  • 注册光学变焦功能
returnCode = DjiPayloadCamera_RegOpticalZoomHandler(&s_opticalZoomHandler);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
    USER_LOG_ERROR("camera register optical zoom handler error:0x%08llX", returnCode);
    return returnCode;
}
  • 注册指点变焦功能
returnCode = DjiPayloadCamera_RegTapZoomHandler(&s_tapZoomHandler);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
    USER_LOG_ERROR("camera register tap zoom handler error:0x%08llX", returnCode);
    return returnCode;
}

使用数码变焦功能

基于 PSDK 开发的负载设备控制程序调用SetDigitalZoomFactorGetDigitalZoomFactor接口能够控制负载设备执行数码变焦,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够控制相机类负载设备的执行数码变焦,同时获取负载设备数码变焦的系数。

static T_DjiReturnCode SetDigitalZoomFactor(dji_f32_t factor)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("set digital zoom factor:%.2f", factor);
    s_cameraDigitalZoomFactor = factor;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

T_DjiReturnCode DjiTest_CameraGetDigitalZoomFactor(dji_f32_t *factor)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    *factor = s_cameraDigitalZoomFactor;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

使用光学变焦功能

基于 PSDK 开发的负载设备控制程序调用SetOpticalZoomFocalLengthGetOpticalZoomFocalLength接口能够控制负载设备执行光学变焦,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够控制相机类负载设备执行光学变焦,同时获取负载设备光学变焦的系数。

  • 设置光学变焦相机的焦距
static T_DjiReturnCode SetOpticalZoomFocalLength(uint32_t focalLength)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("set optical zoom focal length:%d", focalLength);
    s_isOpticalZoomReachLimit = false;
    s_cameraDigitalZoomFactor = ZOOM_DIGITAL_BASE_FACTOR;
    s_cameraOpticalZoomFocalLength = ZOOM_OPTICAL_FOCAL_MIN_LENGTH;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

T_DjiReturnCode DjiTest_CameraGetOpticalZoomFactor(dji_f32_t *factor)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    //Formula:factor = currentFocalLength / minFocalLength
    *factor = (dji_f32_t) s_cameraOpticalZoomFocalLength / ZOOM_OPTICAL_FOCAL_MIN_LENGTH;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
  • 获取相机类负载设备的变焦系数
    获取相机类负载设备当前的光学焦距后,根据变焦系数的计算公式,能够计算相机类负载设备当前的变焦系数(变焦系数 = 当前焦距 ÷ 最短焦距)。
T_DjiReturnCode DjiTest_CameraGetOpticalZoomFactor(dji_f32_t *factor)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    //Formula:factor = currentFocalLength / minFocalLength
    *factor = (dji_f32_t) s_cameraOpticalZoomFocalLength / ZOOM_OPTICAL_FOCAL_MIN_LENGTH;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
  • 获取光学变焦的范围
static T_DjiReturnCode GetOpticalZoomSpec(T_DjiCameraOpticalZoomSpec *spec)
{
    spec->maxFocalLength = ZOOM_OPTICAL_FOCAL_MAX_LENGTH;
    spec->minFocalLength = ZOOM_OPTICAL_FOCAL_MIN_LENGTH;
    spec->focalLengthStep = ZOOM_OPTICAL_FOCAL_LENGTH_STEP;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

使用连续变焦功能

基于 PSDK 开发的负载设备控制程序调用StartContinuousOpticalZoomStopContinuousOpticalZoom接口能够控制负载设备开始或停止执行连续变焦,用户使用 DJI Pilot 以及基于 MSDK 开发的移动端 App 能够控制相机类负载设备执行连续变焦。

  • 控制相机类负载设备开始变焦
static T_DjiReturnCode StartContinuousOpticalZoom(E_DjiCameraZoomDirection direction, E_DjiCameraZoomSpeed speed)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("start continuous optical zoom direction:%d speed:%d", direction, speed);
    s_isStartContinuousOpticalZoom = true;
    s_cameraZoomDirection = direction;
    s_cameraZoomSpeed = speed;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
  • 控制相机类负载设备停止变焦
static T_DjiReturnCode StopContinuousOpticalZoom(void)
{
    T_DjiReturnCode returnCode;
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    USER_LOG_INFO("stop continuous optical zoom");
    s_isStartContinuousOpticalZoom = false;
    s_cameraZoomDirection = DJI_CAMERA_ZOOM_DIRECTION_OUT;
    s_cameraZoomSpeed = DJI_CAMERA_ZOOM_SPEED_NORMAL;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
  • 控制相机持续变焦
if (s_isStartContinuousOpticalZoom == true) {
    tempDigitalFactor = s_cameraDigitalZoomFactor;
    tempFocalLength = (int32_t) s_cameraOpticalZoomFocalLength;
    if (s_isOpticalZoomReachLimit == false) {
        if (s_cameraZoomDirection == DJI_CAMERA_ZOOM_DIRECTION_IN) {
            tempFocalLength += ((int) s_cameraZoomSpeed - DJI_CAMERA_ZOOM_SPEED_SLOWEST + 1) * ZOOM_OPTICAL_FOCAL_LENGTH_CTRL_STEP;
        } else if (s_cameraZoomDirection == DJI_CAMERA_ZOOM_DIRECTION_OUT) {
            tempFocalLength -= ((int) s_cameraZoomSpeed - DJI_CAMERA_ZOOM_SPEED_SLOWEST + 1) * ZOOM_OPTICAL_FOCAL_LENGTH_CTRL_STEP;
        }

        if (tempFocalLength > ZOOM_OPTICAL_FOCAL_MAX_LENGTH) {
            s_isOpticalZoomReachLimit = true;
            tempFocalLength = ZOOM_OPTICAL_FOCAL_MAX_LENGTH;
        }

        if (tempFocalLength < ZOOM_OPTICAL_FOCAL_MIN_LENGTH) {
            tempFocalLength = ZOOM_OPTICAL_FOCAL_MIN_LENGTH;
        }
    } else {
        if (s_cameraZoomDirection == DJI_CAMERA_ZOOM_DIRECTION_IN) {
            tempDigitalFactor += (dji_f32_t) ZOOM_DIGITAL_STEP_FACTOR;
        } else if (s_cameraZoomDirection == DJI_CAMERA_ZOOM_DIRECTION_OUT) {
            tempDigitalFactor -= (dji_f32_t) ZOOM_DIGITAL_STEP_FACTOR;
        }

        if (tempDigitalFactor > (dji_f32_t) ZOOM_DIGITAL_MAX_FACTOR) {
            tempDigitalFactor = (dji_f32_t) ZOOM_DIGITAL_MAX_FACTOR;
        }

        if (tempDigitalFactor < (dji_f32_t) ZOOM_DIGITAL_BASE_FACTOR) {
            s_isOpticalZoomReachLimit = false;
            tempDigitalFactor = ZOOM_DIGITAL_BASE_FACTOR;
        }
    }
    s_cameraOpticalZoomFocalLength = (uint16_t) tempFocalLength;
    s_cameraDigitalZoomFactor = tempDigitalFactor;
}

持续按住变焦按钮可改变变焦倍数,如 图 1. 连续变焦 所示。

  • T : 放大焦距(放大变焦倍数)

  • W : 缩小焦距(缩小变焦倍数)

  • R : 还原相机的焦距

    说明: 根据实际的使用需要,可设置相机类负载设备默认的变焦倍数,当前为 1.0。

图 1. 连续变焦

实现指点变焦功能

当用户开始使用 “指点变焦” 功能后,使用 PSDK 开发的相机类负载设备将根据用户指定的目标点位置以及当前的焦距,先控制云台旋转,将目标对象置于画面中心,再控制负载设备变焦。

通过注册回调函数的方式实现指点变焦功能

  • 设置指点变焦的变焦系数
static T_DjiReturnCode SetTapZoomMultiplier(uint8_t multiplier)
{
    USER_LOG_INFO("set tap zoom multiplier: %d.", multiplier);
    s_tapZoomMultiplier = multiplier;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

static T_DjiReturnCode GetTapZoomMultiplier(uint8_t *multiplier)
{
    *multiplier = s_tapZoomMultiplier;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
  • 获取指点变焦的对象
    使用 PSDK 开发的相机类负载设备通过TapZoomAtTarget接口获取用户在移动端 App 中指定的变焦对象,在确认指点变焦功能开启后,根据目标点位置和混合焦距,计算云台转动角度,控制相机转动。
static T_DjiReturnCode TapZoomAtTarget(T_DjiCameraPointInScreen target)
{
    T_DjiReturnCode returnCode;
    E_DjiGimbalRotationMode rotationMode;
    T_DjiGimbalRotationProperty rotationProperty = {0};
    T_DjiAttitude3d rotationValue = {0};
    float hybridFocalLength = 0; // unit: 0.1mm
    T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();

    USER_LOG_INFO("tap zoom at target: x %f, y %f.", target.focusX, target.focusY);

    if (s_isTapZoomEnabled != true) {
        USER_LOG_WARN("tap zoom is not enabled.");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }

    if (s_isTapZooming || s_isStartTapZoom) {
        USER_LOG_WARN("The last tap zoom process is not over.");
        return DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT_IN_CURRENT_STATE;
    }

    rotationMode = DJI_GIMBAL_ROTATION_MODE_RELATIVE_ANGLE;
    rotationProperty.relativeAngleRotation.actionTime = TAP_ZOOM_DURATION / 10;

    returnCode = osalHandler->MutexLock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    /* Calculation formula: rotation angle = arctan((coordinate of target in sensor - coordinate of center point in
     * sensor) / hybrid focal length). Here, suppose that images of all pixels of sensor are displayed in screen,
     * and that center of the image sensor coincides with center of rotation of the gimbal, and that optical axis of
     * camera coincides with x-axis of gimbal. */
    hybridFocalLength = (dji_f32_t) s_cameraOpticalZoomFocalLength * s_cameraDigitalZoomFactor;

    returnCode = osalHandler->MutexUnlock(s_zoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    rotationValue.pitch = (int32_t) (
        atan2f((target.focusY - CENTER_POINT_IN_SCREEN_Y_VALUE) * IMAGE_SENSOR_Y_SIZE, hybridFocalLength) * 1800 /
        DJI_PI);
    rotationValue.yaw = (int32_t) (
        atan2f((target.focusX - CENTER_POINT_IN_SCREEN_X_VALUE) * IMAGE_SENSOR_X_SIZE, hybridFocalLength) * 1800 /
        DJI_PI);

    returnCode = osalHandler->MutexLock(s_tapZoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("lock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_tapZoomNewestGimbalRotationArgument.rotationMode = rotationMode;
    s_tapZoomNewestGimbalRotationArgument.rotationProperty = rotationProperty;
    s_tapZoomNewestGimbalRotationArgument.rotationValue = rotationValue;
    s_tapZoomNewestTargetHybridFocalLength = (uint32_t) (hybridFocalLength * (float) s_tapZoomMultiplier);

    returnCode = osalHandler->MutexUnlock(s_tapZoomMutex);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("unlock mutex error: 0x%08llX.", returnCode);
        return returnCode;
    }

    s_isStartTapZoom = true;

    return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

在线程中实现指点变焦功能

为避免负载设备在旋转云台和控制变焦时,阻塞负载设备控制程序的主线程,请在线程中实现指点变焦功能。

if (s_isStartTapZoom) {
    s_isStartTapZoom = false;
    s_isTapZooming = true;

    returnCode = osalHandler->GetTimeMs(&s_tapZoomStartTime);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("get start time error: 0x%08llX.", returnCode);
    }

    returnCode = DjiTest_CameraRotationGimbal(s_tapZoomNewestGimbalRotationArgument);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
        USER_LOG_ERROR("rotate gimbal error: 0x%08llX.", returnCode);
    else
        s_cameraTapZoomState.isGimbalMoving = true;

    returnCode = DjiTest_CameraHybridZoom(s_tapZoomNewestTargetHybridFocalLength);
    if (returnCode == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        s_cameraTapZoomState.zoomState = (dji_f32_t) s_tapZoomNewestTargetHybridFocalLength >
            ((dji_f32_t) s_cameraOpticalZoomFocalLength *
             s_cameraDigitalZoomFactor)
            ? DJI_CAMERA_TAP_ZOOM_STATE_ZOOM_IN
            : DJI_CAMERA_TAP_ZOOM_STATE_ZOOM_OUT;
    } else if (returnCode == DJI_ERROR_SYSTEM_MODULE_CODE_OUT_OF_RANGE) {
        USER_LOG_ERROR("hybrid zoom focal length beyond limit.");
        s_cameraTapZoomState.zoomState = DJI_CAMERA_TAP_ZOOM_STATE_ZOOM_LIMITED;
    } else {
        USER_LOG_ERROR("hybrid zoom error: 0x%08llX.", returnCode);
    }
} else if (s_isTapZooming) {
    returnCode = osalHandler->GetTimeMs(&currentTime);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        USER_LOG_ERROR("get start time error: 0x%08llX.", returnCode);
    }

    if ((currentTime - s_tapZoomStartTime) >= TAP_ZOOM_DURATION) {
        s_cameraTapZoomState.zoomState = DJI_CAMERA_TAP_ZOOM_STATE_IDLE;
        s_cameraTapZoomState.isGimbalMoving = false;
        s_isTapZooming = false;
    }
}
若您对文档有意见或疑惑,点击可快速反馈,我们会与您联系。