swift 在Vision Framework中使用DJI视频源

gblwokeq  于 2023-06-21  发布在  Swift
关注(0)|答案(1)|浏览(92)

我正在开发一个应用程序,它使用DJI Mavic 2的视频源,并通过机器学习模型来识别物体。
我设法让我的应用程序使用这个sample DJI project预览来自无人机的馈送,但我在试图将视频数据转换为Vision framework可用的格式时遇到了很多麻烦。
我使用this example from Apple作为指导来创建我的模型(它正在工作!)但是看起来我需要创建一个VNImageRequestHandler对象,它是用CMSampleBuffer类型的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包含用于解压缩的helper方法,但我还没有成功地理解如何正确使用它们,因为没有关于其使用的文档。
编辑2:这里是DJIWidget框架的issue I created on GitHub
编辑3:更新了VideoFrameProcessor的代码片段,增加了VideoFrameProcessor的方法,删除了videoFeed方法中的旧代码
编辑4:关于如何成功提取像素缓冲区并利用它的详细信息可以在GitHub的这条评论中找到
编辑5:我已经很多年没有做这个了,但是因为这里仍然有一些活动,所以我创建了here's a relevant gist来帮助别人。我不记得具体是如何/为什么这是相关的,但希望它是有意义的!

enyaitl3

enyaitl31#

步骤:
1.调用DJIVideoPreviewerpush:length:方法并输入rawData。在DJIVideoPreviewer中,如果你使用过VideoPreviewerSDKAdapter,请跳过这一步。(执行此操作后,将执行H.264解析和解码步骤。)
1.符合VideoFrameProcessor协议,调用DJIVideoPreviewer.registFrameProcessor注册VideoFrameProcessor协议对象。

  1. VideoFrameProcessor协议的videoProcessFrame:方法将输出VideoFrameYUV数据。
    1.获取CVPixelBuffer数据。VideoFrameYUV结构体有一个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);

相关问题