2
3

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 3 years have passed since last update.

セグメンテーション・マスクの境界を滑らかにする

Last updated at Posted at 2020-10-05

背景との境界のカクカクを滑らかにします。iOSで使えるフィルターで実現できます。

機械学習のセマンティックセグメンテーションは、出力サイズが512,512程度なので、拡大してマスク画像として用いると、オブジェクトのエッジ境界がカクカクしてしまいます。
2222.png

中央値フィルターという平滑化フィルターを用いることで、境界を滑らかにできます。
222.png

中央値フィルターとは?:ピクセル値を、その周りのピクセル値の中央値に変えるフィルターだそうです。

iOSではMPSImageMedianフィルターが使えます。

#使い方
このフィルターを、拡大後のマスク画像に適用すると、エッジがスムースになります。
引数の「kernelDiameter」は、中央値をとる対象の周囲のピクセルの直径で3以上の奇数を指定する必要があります。


func edgeSmoothing(cgImage image:CGImage) -> CGImage {
    let commandBuffer = self.commandQueue!.makeCommandBuffer()!
    let median = MPSImageMedian(device: self.device as! MTLDevice, kernelDiameter: 15)
    // kernelDiameter:中央値をとる対象の周囲のピクセルの直径

    let textureLoader = MTKTextureLoader(device: self.device as! MTLDevice)
    let options: [MTKTextureLoader.Option : Any]? = nil
    let srcTex = try! textureLoader.newTexture(cgImage: image, options: options)

    let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: srcTex.pixelFormat,
                                                        width: srcTex.width,
                                                        height: srcTex.height,
                                                        mipmapped: false)
    desc.pixelFormat = .rgba8Unorm
    desc.usage = [.shaderRead, .shaderWrite]

    let medTex = self.device!.makeTexture(descriptor: desc)!

    median.encode(commandBuffer: commandBuffer, sourceTexture: srcTex, destinationTexture: medTex)

    #if os(macOS)
    let blitCommandEncoder = commandBuffer.makeBlitCommandEncoder()!
    blitCommandEncoder.synchronize(resource: medTex)
    blitCommandEncoder.endEncoding()
    #endif

    commandBuffer.commit()
    commandBuffer.waitUntilCompleted()

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue
    let bytesPerRow = lapTex.width * 4
    let bitmapContext = CGContext(data: nil,
                                  width: medTex.width,
                                  height: medTex.height,
                                  bitsPerComponent: 8,
                                  bytesPerRow: bytesPerRow,
                                  space: colorSpace,
                                  bitmapInfo: bitmapInfo)!
    medTex.getBytes(bitmapContext.data!,
                    bytesPerRow: bytesPerRow,
                    from: MTLRegionMake2D(0, 0, medTex.width, medTex.height),
                    mipmapLevel: 0)
    return bitmapContext.makeImage()
}

🐣


お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

Twitter
Medium

2
3
0

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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?