6

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

我设法让我的应用程序使用这个示例 DJI 项目预览来自无人机的提要,但是我在尝试将视频数据转换为Vision框架可用的格式时遇到了很多麻烦。

我使用Apple 的这个示例作为创建我的模型的指南(它正在工作!)但看起来我需要创建一个使用类型创建的VNImageRequestHandler对象才能使用.cvPixelBufferCMSampleBufferVision

知道如何进行这种转换吗?有一个更好的方法吗?

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:这是我在 GitHub 上为 DJIWidget 框架创建的问题

编辑 3:使用附加方法更新代码片段,从方法中VideoFrameProcessor删除旧代码videoFeed

编辑 4:有关如何成功提取像素缓冲区并利用它的详细信息,请参阅GitHub 的此评论

4

1 回答 1

3

步骤:</p>

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

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

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

  4. 获取CVPixelBuffer数据。VideoFrameYUVstruct 有一个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);
于 2018-09-20T04:33:28.987 回答