二値化

チャンネル入れ替え,グレースケールに続き今回は画像の二値化をSwiftで実装してみました。

UIImageのピクセル情報を取得している部分のコードは特に変化なかった為以前の記事で作成したPixelBufferクラスを再利用しています。

二値化

2値化とは、画像を白と黒の2階調に変換する処理のことである。 2値化では、あらかじめ閾値を決めておき、画素のが閾値より大きければ白、小さければ黒に変換する。 2値化は、ぼやけている画像を鮮明にできるという特徴がある。 一方、閾値の設定や画像の明るさによって、画像が黒一色、または、白一色になってしまう場合もある。

https://www.weblio.jp/content/2%E5%80%A4%E5%8C%96

今回は閾値を128(0.5)に設定して変換を行うメソッドを作成しました。

入力画像

出力画像

二値化のコード

グレースケールを作成していた部分のコードに白か黒かの判定をつけるだけで簡単に実装することができました!

extension UIImage {
    func createBinarizedImage(r:[CGFloat], g: [CGFloat], b:[CGFloat], a:[CGFloat]) -> UIImage{
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        let wid:Int = Int(size.width)
        let hei:Int = Int(size.height)
        let threshold:CGFloat = 128/255
        for w in 0..<wid {
            for h in 0..<hei {
                let index = (w * wid) + h
                var color = 0.2126 * r[index] + 0.7152 * g[index] + 0.0722 * b[index]
                if color > threshold {
                    color = 255
                } else {
                    color = 0
                }
                UIColor(red: color, green: color, blue: color, alpha: a[index]).setFill()
                let drawRect = CGRect(x: w, y: h, width: 1, height: 1)
                UIRectFill(drawRect)
                draw(in: drawRect, blendMode: .destinationIn, alpha: 1)
            }
        }
        let binarizeImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return binarizeImage
    }
}

おまけ

R, G, B各1チェンネル画像の作成を行ってみました。

Redチャンネル

Blueチャンネル

Greenチャンネル

コード

extension UIImage {
    func createRecChannelImage(r:[CGFloat], a:[CGFloat]) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        let wid:Int = Int(size.width)
        let hei:Int = Int(size.height)
        
        for w in 0..<wid {
            for h in 0..<hei {
                let index = (w * wid) + h
                UIColor(red: r[index], green: 0, blue: 0, alpha: a[index]).setFill()
                let drawRect = CGRect(x: w, y: h, width: 1, height: 1)
                UIRectFill(drawRect)
                draw(in: drawRect, blendMode: .destinationIn, alpha: 1)
            }
        }
        let redImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return redImage
    }
    func createBlueChannelImage(b:[CGFloat], a:[CGFloat]) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        let wid:Int = Int(size.width)
        let hei:Int = Int(size.height)
        
        for w in 0..<wid {
            for h in 0..<hei {
                let index = (w * wid) + h
                UIColor(red: 0, green: 0, blue: b[index], alpha: a[index]).setFill()
                let drawRect = CGRect(x: w, y: h, width: 1, height: 1)
                UIRectFill(drawRect)
                draw(in: drawRect, blendMode: .destinationIn, alpha: 1)
            }
        }
        let blueImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return blueImage
    }
    func createGreenChannelImage(g:[CGFloat], a:[CGFloat]) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        let wid:Int = Int(size.width)
        let hei:Int = Int(size.height)
        
        for w in 0..<wid {
            for h in 0..<hei {
                let index = (w * wid) + h
                UIColor(red: 0, green: g[index], blue: 0, alpha: a[index]).setFill()
                let drawRect = CGRect(x: w, y: h, width: 1, height: 1)
                UIRectFill(drawRect)
                draw(in: drawRect, blendMode: .destinationIn, alpha: 1)
            }
        }
        let greenImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return greenImage
    }
}