【问题标题】:Using DJI video feed with Vision Framework将 DJI 视频源与 Vision Framework 结合使用
【发布时间】:2018-09-18 18:32:55
【问题描述】:

我正在开发一个应用程序,该应用程序使用来自 DJI Mavic 2 的视频源并通过机器学习模型运行它以识别对象。

我设法让我的应用程序使用 sample DJI project 预览来自无人机的提要,但我在尝试将视频数据转换为 Vision framework 可用的格式时遇到了很多麻烦。

我使用this example from Apple 作为创建模型的指南(它正在工作!)但看起来我需要创建一个VNImageRequestHandler 对象,该对象是使用cvPixelBuffer 类型的cvPixelBuffer 创建的,以便使用Vision.

知道如何进行这种转换吗?有没有更好的方法来做到这一点?

class DJICameraViewController: UIViewController, DJIVideoFeedListener, DJISDKManagerDelegate, DJICameraDelegate, VideoFrameProcessor {

// ...

func videoFeed(_ videoFeed: DJIVideoFeed, didUpdateVideoData rawData: Data) {
    let videoData = rawData as NSData
    let videoBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: videoData.length)
    videoData.getBytes(videoBuffer, length: videoData.length)
    DJIVideoPreviewer.instance().push(videoBuffer, length: Int32(videoData.length))        
}

// MARK: VideoFrameProcessor Protocol Implementation
func videoProcessorEnabled() -> Bool {
    // This is never called
    return true
}

func videoProcessFrame(_ frame: UnsafeMutablePointer<VideoFrameYUV>!) {
    // This is never called
    let pixelBuffer = frame.pointee.cv_pixelbuffer_fastupload as! CVPixelBuffer

    let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: exifOrientationFromDeviceOrientation(), options: [:])

    do {
        try imageRequestHandler.perform(self.requests)
    } catch {
        print(error)
    }
}
} // End of DJICameraViewController class

编辑:根据我从 DJI 的(参差不齐的)文档中收集到的信息,看起来视频源是 H264 压缩的。他们声称DJIWidget 包含用于解压的辅助方法,但我没有成功理解如何正确使用它们,因为没有关于它使用的文档。

编辑 2:这是 DJIWidget 框架的 issue I created on GitHub

编辑 3:使用 VideoFrameProcessor 的其他方法更新代码 sn-p,从 videoFeed 方法中删除旧代码

编辑4:关于如何成功提取像素缓冲区并利用它的详细信息可以在this comment from GitHub

中找到

【问题讨论】:

  • 请把所有的跟进和 cmets 放在这里。不要在 GitHub 上创建问题。我们已弃用对 GitHub 问题的支持

标签: ios swift dji-sdk ios-vision


【解决方案1】:

步骤:

  1. 调用DJIVideoPreviewerpush:length:方法,输入rawData。在DJIVideoPreviewer 里面,如果你用过VideoPreviewerSDKAdapter 请跳过这个。 (执行此操作后将执行 H.264 解析和解码步骤。)

  2. 符合VideoFrameProcessor协议,调用DJIVideoPreviewer.registFrameProcessor注册VideoFrameProcessor协议对象。

  3. VideoFrameProcessor协议的videoProcessFrame:方法会输出VideoFrameYUV数据。

  4. 获取CVPixelBuffer 数据。 VideoFrameYUV struct 有一个cv_pixelbuffer_fastupload 字段,当硬件解码打开时,这个数据实际上是CVPixelBuffer 类型。如果您使用软件解码,则需要自己创建一个CVPixelBuffer,并从VideoFrameYUVlumachromaBchromaR 字段中复制数据。


代码:

VideoFrameYUV* yuvFrame; // the VideoFrameProcessor output
CVPixelBufferRef pixelBuffer = NULL;
CVReturn resulst = CVPixelBufferCreate(kCFAllocatorDefault,
                                       yuvFrame-> width,
                                       yuvFrame -> height, 
                                  kCVPixelFormatType_420YpCbCr8Planar,
                                       NULL,
                                       &pixelBuffer);
if (kCVReturnSuccess != CVPixelBufferLockBaseAddress(pixelBuffer, 0) || pixelBuffer == NULL) {
    return;
}
long yPlaneWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
long yPlaneHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer,0);
long uPlaneWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
long uPlaneHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
long vPlaneWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 2);
long vPlaneHeight =  CVPixelBufferGetHeightOfPlane(pixelBuffer, 2);
uint8_t* yDestination = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
memcpy(yDestination, yuvFrame->luma, yPlaneWidth * yPlaneHeight);
uint8_t* uDestination = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memcpy(uDestination, yuvFrame->chromaB, uPlaneWidth * uPlaneHeight);
uint8_t* vDestination = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2);
memcpy(vDestination, yuvFrame->chromaR, vPlaneWidth * vPlaneHeight);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

【讨论】:

  • 看起来我的 VideoFrameProcessor 方法从未被调用...知道为什么会这样吗?关于软件解码,我怎么知道启用了哪个(硬件/软件)??
  • 您已经实现了VideoFrameProcessor 协议方法,但看起来您可能缺少注册VideoFrameProcessor 协议的registFrameProcessor 调用。
  • 我们越来越近了;现在正在调用这些方法,但现在我无法访问cv_pixelbuffer_fastupload。我试图通过frame.pointee.cv_pixelbuffer_fastupload as! CVPixelBuffer 得到它,但我收到一个错误:'Optional&lt;UnsafeMutablePointer&lt;VideoFrameYUV&gt;&gt;' must be unwrapped to refer to member 'pointee' of wrapped base type。我做错了什么?
  • cv_pixelbuffer_fastupload 为 nil,因为未启用硬件解码。 DJIVideoPreviwer 有一个名为 enableHardwareDecode 的属性需要设置为 YES。
  • @spencer 你有没有让它工作并且能够提取一个可以在应用程序中使用的像素缓冲区?对你的进展感兴趣。可以分享源代码吗?
猜你喜欢
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-08
  • 1970-01-01
相关资源
最近更新 更多