8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

YUV(YCbCr)のCVPixelBufferをBGRAに高速に変換する

Last updated at Posted at 2020-07-20

ARKitのcapturedImageをmediapipeで利用する時など、CVPixelBufferのpixelFormatを変換する必要があることがあります。

以前の記事ではvImageを利用しましたが、vImageはCPUでの計算に最適化されており映像処理などには向かないものでした。
https://qiita.com/noppefoxwolf/items/b12d56e052664a21d8b6

そこで、GPUを利用してYCbCrをBGRAに変換するライブラリを作りました。Xcode12のSwiftPMで簡単に導入することができます。
https://github.com/noppefoxwolf/BlueDress

使い方

簡単に使うことができます。


import BlueDress

let converter = YCbCrImageBufferConverter()
let bgraBuffer = try converter.convertToBGRA(imageBuffer: imageBuffer)

変換の流れ

実際は変換ではなく、新規に新しいBGRAのPixelBufferを作ってそこにYCbCrを焼いています。

YCbCrのPixelBufferは、内部に2枚の画像を持っておりそれぞれ

  • Y: 輝度
  • CbCr 青と赤の色差

をサイズ違いでもっています。
YCbCrは以下の計算式で変換することが出来るので、Metalシェーダを使ってこの計算を行うというわけです。

R = 1.164(Y-16)                 + 1.596(Cr-128)
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128)
B = 1.164(Y-16) + 2.018(Cb-128)

実装で詰まりがちなところ

各PlaneのPixelFormat

YCbCrから2枚のPlaneを取り出す際に、最初はそれぞれをBGRAとして取り出していたのですがこれは間違いでそれぞれ

  • Y: r8Unorm
  • CbCr: rg8Unorm

で取り出す必要があります。
よく考えれば当然なのですが、ARKitのMetalテンプレートを読んで気がつきました。

CVPixelBufferとMTLTextureの関係

MTLTextureはあくまでCVPixelBufferの参照を持つ概念なので、MTLTextureに対して行った描画処理は特に取り出す必要はなく、MTLTextureのソースとして渡したCVPixelBufferに適用されます。

MTLTextureが-6660エラーで作れない

最終描画先の空のMTLTextureを作りたくて、そのソースとなる空のCVPixelBufferを自前で作っていたのですがどうもエラーでMTLTextureが作れませんでした。
MTLTextureを作る場合は、CVPixelBufferを生成する時にkCVPixelBufferMetalCompatibilityKey:trueを与えるのを忘れないようにしましょう。

8
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?