2016-06-05 37 views
10
üzerinde işleme

iOS'ta 120 fps'de gerçek zamanlı video işleme yapıyorum ve GPU'daki ilk ön işlem görüntüsünü istiyorum (örneğin, dönüştürmeme rengi vb.) OpenCV kullanarak CPU üzerinde daha hızlı işlemci ve daha sonra işlem sonrası çerçeve.GPU (metal) ve CPU (OpenCV) üzerindeki kamera besleme verilerini iPhone

Fotoğraf makinesi beslemesini GPU ve CPU arasında Metal kullanarak paylaşmanın en hızlı yolu nedir? gibi

Başka bir deyişle boru görünecektir: Ben CMSampleBufferRef dönüştürme ediyorum

CMSampleBufferRef -> MTLTexture or MTLBuffer -> OpenCV Mat 

- benim metal gölgelendirici ben OpenCV için MTLTexture dönüştürmek finised sonra> Aşağıdaki şekilde

CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 

// textureRGBA 
{ 
    size_t width = CVPixelBufferGetWidth(pixelBuffer); 
    size_t height = CVPixelBufferGetHeight(pixelBuffer); 
    MTLPixelFormat pixelFormat = MTLPixelFormatBGRA8Unorm; 

    CVMetalTextureRef texture = NULL; 
    CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &texture); 
    if(status == kCVReturnSuccess) { 
     textureBGRA = CVMetalTextureGetTexture(texture); 
     CFRelease(texture); 
    } 
} 

MTLTexture

cv::Mat image; 
... 
CGSize imageSize = CGSizeMake(drawable.texture.width, drawable.texture.height); 
int imageByteCount = int(imageSize.width * imageSize.height * 4); 
int mbytesPerRow = 4 * int(imageSize.width); 

MTLRegion region = MTLRegionMake2D(0, 0, int(imageSize.width), int(imageSize.height)); 
CGSize resSize = CGSizeMake(drawable.texture.width, drawable.texture.height); 
[drawable.texture getBytes:image.data bytesPerRow:mbytesPerRow fromRegion:region mipmapLevel:0]; 

Bazı gözlemler:?

1) Ne yazık ki MTLTexture.getBytes CPU'ya GPU dan pahalı (veri kopyalamayı görünüyor) ve bazı insanlar fark) çok fazla ~ 100fps

2'de işliyor iphone'umda 5S üzerinde 5ms sürer aşağıdaki yöntem ile yerine MTLTexture arasında MTLBuffer kullanımı: metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared) (bakınız: Memory write performance - GPU CPU Shared Memory)

Ancak CMSampleBufferRef ve CVPixelBufferRef birlikte CoreVideo tarafından yönetilen tahmindir edilir.

+0

Tüm çözünürlükler için GPU desteklenmiyor. Biliyorum, cevabın değil. GPU hakkında bir bilgi verdim. –

+0

GPUImage'ı denediniz https://github.com/BradLarson/GPUImage –

+0

GPUImage'ı denedim ancak en büyük sorun GPU'dan CPU'ya veri aktarıyor. GPUImage, OpenGL'i iyi ve tersi durumda kullanır, Metal API'nin paylaşımlı belleği olamaz. – pzo

cevap

4

Bunu yapmanın en hızlı yolu, bir MTLBuffer tarafından desteklenen bir MTLTexture kullanmaktır; MTLBuffer ile bellek paylaşan özel bir MTLTexture türüdür. Ancak, C işleminiz (openCV) bir çerçeve veya iki arka arkaya çalışacaktır, bu GPU (kodlama) komutlarını göndermeniz gerektiğinden ve GPU'nun GPU’dan emin olmak için waitUntilCompleted komutunu kullanmanız gerektiğinde GPU’nun bunu oluşturması gerektiğinden dolayı bu kaçınılmazdır. Sadece CPU çiğnemek ve savurganlık bitti.

Dolayısıyla işlem şöyle olurdu: önce MTLBuffer'ı yaratırsınız, sonra özel MTLTexture oluşturmak için "newTextureWithDescriptor: offset: bytesPerRow:" MTLBuffer yöntemini kullanırsınız. Önceden özel MTLTexture oluşturmalısınız (örnek değişken olarak), daha sonra CMSampleBufferRef'ten oluşturulmuş MTLTexture'ı alacak ve bunu özel MTLTexture uygulamanıza aktaran standart bir oluşturma pipeline (bilgi işlem gölgelendiricileri kullanmaktan daha hızlı) kurmanız gerekir. Bu geçiş, alt ölçeklendirme yapabilir ve tek geçişte gerektiği şekilde herhangi bir renk dönüşümü yapabilir. Daha sonra, komut tamponunu gpu'ya gönderirsiniz, daha sonraki bir geçişte, sadece [MTLbuffer içeriği] 'yi çağırarak, özel MTLTexture'nizi openCV'de kullanmak üzere geri döndüren baytları yakalayabilirsiniz.

CPU/GPU davranışında bir durmayı zorlayan herhangi bir teknik, hiçbir zaman verimli olmayacaktır, çünkü bu süre, CPU'nun GPU'nun bitmesini bekler ve GPU, bir sonraki kodlamalar için de beklemek zorunda kalır. GPU, CPU'nun bir sonraki kareyi kodlamasını ve GPU'nun bitmesini beklemek yerine herhangi bir openCV işi yapmasını istediğinizde çalışıyor. Ayrıca, insanlar normalde gerçek zamanlı işlemeye başvurduklarında, genellikle gerçek zamanlı geri bildirim (görsel) ile bazı işlemlerden bahsediyorlarsa, 4s ve üzeri tüm modern iOS aygıtları 60Hz ekran yenileme hızına sahiptir, bu nedenle her türlü geri bildirim daha hızlı sunulması anlamsızdır ancak 2 kare (120Hz'de) 1'e (60Hz'de) ihtiyacınız varsa, özel bir zamanlayıcıya sahip olmanız veya CADisplayLink'i değiştirmeniz gerekir.

+0

GPU görüntülemenin (doku gölgelendiricileri) 60 fps ile sınırlı olabileceği iyi bir ipucu - mantıklı. Aslında mümkün olan en küçük gecikmeye ihtiyacım var - Görüntülemeyi görüntülemek yerine kullanıcıya geri bildirim olarak sesi kullanan özel doğal kullanıcı arayüzüne sahibim. CPU'nun GPU'yu bitirmesini beklemiyorum - GPU'ya çok hızlı bir şekilde ön işlem yapmayı (kontrastı ayarla, renk filtresini yeniden boyutlandır), GPU'da çok hızlı olduklarını ve CPU'da oldukça yavaş çalıştıklarını (NEON ile olayı) sıkı hesaplama bütçemi düşünerek . Kontur analizi gibi GPU’ya başka parçalar taşıyamaz (imkansız gibi görünüyor mu?). Görünüşe göre GPU benim için bir çıkmaz. – pzo

+0

Ben bir çıkmaz olduğunu düşünmüyorum, en azından 60Hz'de çalışan bir boru hattı kurmanın nispeten kolay olması, her kareyi kodlama yaptığınız ve her kareyi yaptığınız ve aynı zamanda GPU'nun gerekli ön işleme tabi tutulduğu zaman 60Hz'de (Metal Çerçeve Hata Ayıklayıcı ve Metal Sistem İzlemesi çok kullanışlı araçlar) ilerleyip en iyi duruma getirin. Zamanlayıcıları veya CADisplayLink'i hiç kullanmamayı denedim, bu yüzden size yardım edemem, ancak şu adrese bir göz atın: http://stackoverflow.com/questions/23885638/change-interval-of-cadisplaylink. – Gary

+0

Ayrıca, kontur analizine çok aşina değilim, fakat Metal'in hesaplama işlevini kullanarak, kontrast ayarı veya yeniden boyutlandırma GPU'yu etkilemeyeceğinden, bunu yapabileceksiniz (filtre karmaşık bir LUT kullanıyorsa)). Standart köşe ve parça gölgelendiricilerde bile, GPU'da kolay olmayan GPU'lar yapabilmemizin hileleri vardır, Metal kullanarak bağlı bir bileşen etiketleme algoritması uygulamıştım ve küçük görüntüler için C versiyonundan çok uzak değildi – Gary