Использование видеопотока DJI с Vision Framework - PullRequest
0 голосов
/ 18 сентября 2018

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

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

Я использовал этот пример от 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

EDIT : из того, что я собрал из документации DJI (пятнистая), похоже, что видеопоток сжат H264.Они утверждают, что DJIWidget включает вспомогательные методы для распаковки, но мне не удалось понять, как правильно их использовать, потому что нет документации, касающейся его использования.

EDIT 2 :Вот проблема , которую я создал на GitHub для платформы DJIWidget

EDIT 3 : обновленный фрагмент кода с дополнительными методами для VideoFrameProcessor, удаление старого кода из videoFeedmethod

EDIT 4 : Подробную информацию о том, как успешно извлечь буфер пикселей и использовать его, можно найти в этом комментарии из GitHub

1 Ответ

0 голосов
/ 20 сентября 2018

Шаги:

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

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

  3. VideoFrameProcessor Метод протокола videoProcessFrame: выведет данные VideoFrameYUV.

  4. Получите данные CVPixelBuffer.VideoFrameYUV struct имеет поле cv_pixelbuffer_fastupload, эти данные на самом деле имеют тип CVPixelBuffer, когда включено аппаратное декодирование.Если вы используете программное декодирование, вам нужно будет создать CVPixelBuffer самостоятельно и скопировать данные из полей VideoFrameYUV 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);
...