画像をグレースケールへ変換する(Metal編)
May 3, 2017 · iosmetalswift3
RGBのMTLTexture
をグレースケールのMTLTexture
に変換する方法
UIImage
を変換する方法はこちらを参照
Metal上でこういった画像処理をしたい場合は、MetalPerformanceShaders
を利用する。
今回のような色空間の変更だけでなく、各種フィルタ処理なども高速に処理できる(どれくらい高速かは未確認)
ただし、iOS10(iOS_GPUFamily2_v3)以降でしか使えない
使い方
色空間の変更にはMPSImageConversion
を利用する
色空間の定義はこちらのAccessing System-Defined Color Spaces
を参照
変換元と変換後の色空間を定義する
sRGB
からグレースケールの場合は以下のとおりlet srcColorSpace = CGColorSpace(name: CGColorSpace.sRGB)! let dstColorSpace = CGColorSpace(name: CGColorSpace.linearGray)! let conversionInfo = CGColorConversionInfo(src: srcColorSpace, dst: dstColorSpace)
フィルタ(カーネル)を生成する
let device = MTLCreateSystemDefaultDevice()! let conversion = MPSImageConversion(device: device, srcAlpha: .alphaIsOne, destAlpha: .alphaIsOne, backgroundColor: nil, conversionInfo: conversionInfo)
αは特に関係ないのでデフォルトの1に、背景色も指定しないので
nil
にしておく実行する
let commandQueue = device.makeCommandQueue() let commandBuffer = commandQueue.makeCommandBuffer() conversion.encode(commandBuffer: commandBuffer, sourceTexture: colorTexture, destinationTexture: grayTexture) // 必要に応じて他のMetalの処理 commandBuffer.commit()
これで
grayTexture
にグレースケール化された画像が入る
小ネタ
色空間の調べ方
変換先の色空間はともかく、変換元の色空間がなんなのか判らない場合、
UIImage
(CGImage
)であれば以下で取得できる
let image: UIImage = ...
let colorSpace = image.cgImage!.colorSpace
ちなみにnil
になる場合は、マスク画像が入っているらしい
MPSImageの場合
MPSをCNNで使っている場合などで、MTLTexture
ではなくMPSImage
がソースの場合は、
conversion.encode(commandBuffer: commandBuffer,
sourceTexture: colorImage.texture,
destinationTexture: grayImage.texture)
というように指定する
なお、この場合は、必ずMPSImage
のチャンネル数を合わせないと実行時にエラーとなるので注意
(RGBなら3、グレースケールなら1)
開発環境
- Xcode 8.3
- iOS 10.3.1
- iPhone 7+