はじめに
VisionKitで物体認識を行う際、boundingBoxがうまく表示されないことがあります。
原理は簡単ですが直し方が難しいので、コードでまとめておきます。
四角がうまく表示されない
今回は トマトを検出する アプリを参考にします。
こちらのアプリの作り方は以下の記事を参照:
ここで、以下のようなコードで検出された部分に四角を描画しようとします。
func drawBoundingBoxes(on image: UIImage, with observations: [VNRecognizedObjectObservation]) -> UIImage? {
let renderer = UIGraphicsImageRenderer(size: image.size)
let annotatedImage = renderer.image { context in
image.draw(at: .zero)
let ctx = context.cgContext
ctx.setLineWidth(2.0)
for observation in observations {
let boundingBox = observation.boundingBox
//描画する四角を生成
let rect = CGRect(
origin: CGPoint(
x: boundingBox.origin.x * image.size.width,
y: boundingBox.origin.y * image.size.height
),
size: CGSize(
width: boundingBox.width * image.size.width,
height: boundingBox.height * image.size.height
)
)
ctx.setStrokeColor(isFresh ? UIColor.green.cgColor : UIColor.red.cgColor)
ctx.stroke(rect)
}
}
return annotatedImage
}
しかしこれだと、若干ズレた位置に描画されてしまいます。
原因
実は、VNRecognizedObjectObservation
で得られる四角の座標系と、CGImageの座標系は 異なります!
このため座標が狂ってしまっています。
また、UIImageをCGImageに変換する際に向きの情報が失われる ことがあります。
これにより、座標系がごちゃごちゃになっている ことがうまく描画されない原因です。
解決方法
四角を生成するコードを変更します。
let rect = CGRect(
x: boundingBox.minX * image.size.width,
y: (1 - boundingBox.maxY) * image.size.height,
width: boundingBox.width * image.size.width,
height: boundingBox.height * image.size.height
)
こうすることで、正しい位置に表示することができます!
まとめ
このあたり、Appleが公式で変換用のコードを用意してくれたらいいのに…とずっと思ってます。