写真に対してVision.Frameworkで顔認識させる時の注意点


はじめに

動画と写真に対してVisionを使って顔認識を行ったが、
写真の時だけ条件をクリアできない場合があった。
その原因と解決策を備忘録としてまとめる。

環境

Swift5
Xcode 11.4.1

使用端末
iPad iOS 13以降

前提

端末の使用方法

iPad向き: 横向き (LandscapeRight, LandscapeLeft)
カメラ: インカメラ

今回のフロー
1. 動画で写ったものに対して顔認識
2. 1で条件*を満たしたら写真撮影
3. 撮影した写真に対して顔認識
4. 3で条件を満たしたらAPIを飛ばす

条件*:顔が写っているか、顔が正面か等

写真撮影時のブレなどを考慮し、
2回顔認識を行い条件*を満たしているかを確認した

問題

LandScapeLeft時に写真に対しての顔認識だけ条件*をクリアできない

端末に撮影画像を保存して確認すると、
横で撮影した写真が90度回転して(縦になった状態で)保存されていた…

原因

写真の向きを変換させる処理を行っていなかった

試してみたこと

Visonを使用するにはCGImageで画像を渡す必要があるため
撮影後のUIImageにorientationを設定してcgImageに変換→×

UIImageにorientationを設定してcgImageに変換しても、
cgImageはorientationの情報を持たないため向きは変わらない

よって、向きを正しくした画像(UIImage)を再生成する必要がある

解決策

UIImageの再生成についてextensionを載せている人がいたため
真似して変換してみたらうまくいった

参考:AVCaptureOutputで撮影した写真のimageOrientationを修正する

今回端末横向き使用のために作ったextensionがこちら

UIImage+Direction.swift

extension UIImage {

    func fixedOrientation() -> UIImage? {
        guard let cgImage = base.cgImage,
            let colorSpace = cgImage.colorSpace,
            let ctx = CGContext(data: nil,
                                width: Int(base.size.height), height: Int(base.size.width),
                                bitsPerComponent: cgImage.bitsPerComponent,
                                bytesPerRow: 0, space: colorSpace,
                                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return nil }

        var transform: CGAffineTransform = CGAffineTransform.identity

        switch UIDevice.current.orientation {
        case .landscapeLeft:
            transform = transform.translatedBy(x: base.size.height, y: base.size.width)
            transform = transform.rotated(by: CGFloat.pi)
        default:
            break
        }

        ctx.concatenate(transform)
        ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: base.size.height, height: base.size.width))

        if let newCGImage = ctx.makeImage() {
            return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
        } else {
            return nil
        }
    }
}

おわりに

事象については、参考URLでわかりやすく説明されていたのでご確認ください

参考URL

AVCaptureOutputで撮影した写真のimageOrientationを修正する