Использование видеопотока DJI с Vision Framework

Я работаю над приложением, которое использует видеопоток от DJI Mavic 2 и запускает его через модель машинного обучения для идентификации объектов.

Мне удалось получить мое приложение для предварительного просмотра канала с дрона с помощью этого примера проекта DJI, но у меня много проблем с попыткой перевести видеоданные в формат, который можно использовать Vision рамки.

Я использовал этот пример от Apple в качестве руководства для создания моей модели (которая работает!), Но, похоже, мне нужно создать VNImageRequestHandler объект, который создан с cvPixelBuffer типа CMSampleBuffer для того, чтобы использовать 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: Вот проблема, которую я создал на GitHub для платформы DJIWidget

РЕДАКТИРОВАТЬ 3: Обновленный фрагмент кода с дополнительными методами для VideoFrameProcessor, удаляя старый код из videoFeed метод

1 ответ

Шаги:

  1. Вызов DJIVideoPreviewer"s push:length: метод и введите rawData, внутри DJIVideoPreviewer, если вы использовали VideoPreviewerSDKAdapter пожалуйста, пропустите это. (Шаги синтаксического анализа и декодирования H.264 будут выполнены, как только вы это сделаете.)

  2. Соответствовать VideoFrameProcessor протокол и вызов DJIVideoPreviewer.registFrameProcessor зарегистрировать VideoFrameProcessor протокольный объект.

  3. VideoFrameProcessor пРОТОКОЛ videoProcessFrame: метод выведет VideoFrameYUV данные.

  4. Получить CVPixelBuffer данные. VideoFrameYUV структура имеет cv_pixelbuffer_fastupload поле, эти данные на самом деле имеют тип CVPixelBuffer когда аппаратное декодирование включено. Если вы используете программное декодирование, вам нужно будет создать CVPixelBuffer самостоятельно и скопируйте данные из VideoFrameYUV"s luma, chromaB а также chromaR поле.


Код:

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);
Другие вопросы по тегам