Использование видеопотока 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 ответ
Шаги:
Вызов
DJIVideoPreviewer
"spush:length:
метод и введитеrawData
, внутриDJIVideoPreviewer
, если вы использовалиVideoPreviewerSDKAdapter
пожалуйста, пропустите это. (Шаги синтаксического анализа и декодирования H.264 будут выполнены, как только вы это сделаете.)Соответствовать
VideoFrameProcessor
протокол и вызовDJIVideoPreviewer.registFrameProcessor
зарегистрироватьVideoFrameProcessor
протокольный объект.VideoFrameProcessor
пРОТОКОЛvideoProcessFrame:
метод выведетVideoFrameYUV
данные.Получить
CVPixelBuffer
данные.VideoFrameYUV
структура имеетcv_pixelbuffer_fastupload
поле, эти данные на самом деле имеют типCVPixelBuffer
когда аппаратное декодирование включено. Если вы используете программное декодирование, вам нужно будет создатьCVPixelBuffer
самостоятельно и скопируйте данные изVideoFrameYUV
"sluma
,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);