はじめに
この記事は、
の続きの記事である。
この記事では、vision座標をUIKit座標に変換し、画面にその点を描画するところまで書く。
また、この記事内での「画面のサイズ」という言葉が頻出するが、「画面のサイズ」は「ポイント」のことであり、「ポイント」については、下記の記事参照。
UIKit座標への変換
Vision座標は画面左上が原点に対し、UIKit座標は画面右上が原点である。
また、Vision座標は0~1の画面に対する比率であり、UIKit座標は0~(画面のサイズ)である。
変換関数作成
まず、座標変換を行うクラスを作る。
class Transformation{
}
「import UIKit」と「import Vision」を挿入し、「CameraView」クラスの「previewLayer」を受け取る。
class CoordinateTransformation{
private var previewLayer:AVCaptureVideoPreviewLayer?
//previewLayerにlayerをセットするセッター
public func setlayer(layer: AVCaptureVideoPreviewLayer){
previewLayer = layer
}
}
次に、Vision座標からUIKit座標に変換する関数を作る。
class CoordinateTransformation{
private var previewLayer:AVCaptureVideoPreviewLayer?
//previewLayerにlayerをセットするセッター
public func setlayer(layer: AVCaptureVideoPreviewLayer){
previewLayer = layer
}
//Vision座標からUIKit座標に変換する関数
public func VisionToUikit(visionPoint:VNRecognizedPoint) -> CGPoint{
}
}
まず、VNRecognizedPointをCGPointに変換し、次にVision座標をAVFoundation座標に変換し、「layerPointConverted」関数を使いUIKit座標に変換する。その結果を返す。
class CoordinateTransformation{
//変数初期化
var viewsize = CGSize()
//viewsizeに値をセットするセッター
public func setSize(size: CGSize){
viewsize = size
//確認用
print(viewsize)
}
//Vision座標からUIKit座標に変換する関数
public func visionToUIKit(visionPoint:VNRecognizedPoint) -> CGPoint{
//VNRecognizedPointをCGPointに変換
let visionCGPoint = CGPoint(x:visionPoint.location.x, y:visionPoint.location.y)
//Vision座標をAVFoundation座標に変換する
let avFoundationPoint = CGPoint(x: visionCGPoint.x, y: 1 - visionCGPoint.y)
//AVFoundation座標をUIKit座標に変換する
let uiKitPoint = previewLayer?.layerPointConverted(fromCaptureDevicePoint: avFoundationPoint)
guard let newPoint = uiKitPoint else{
return CGPoint()
}
return newPoint
}
}
関数を使う
「CameraViewController.swift」の編集をする。
「Transformation」クラスのインスタンスを生成し、アプリ起動時にセッターを使い、「CameraView.previewlayer」をセットする。
class CameraViewController: UIViewController{
//略
private let transformation = Transformation()
overrrride func viewDidLoad(){
//略
transformation.setlayer(layer: cameraView.previewLayer)
}
}
関数が使えるか確認のために、「getHandObservations」オブジェクトに実装する。
private func getHandObservations(/*略*/){
//略
do{
//略
print(transformation.visionToUIKit(visionPoint: thumbTipPoint))
}catch{
//略
}
}
以下のような座標が表示されていれば変換成功。
(571.9337112903595, 177.07752585411072)
(576.660945892334, 183.00748586654663)
(592.9437434673309, 191.74261093139648)
(615.0112144947052, 192.16133773326874)
(636.4420087337494, 185.88124930858612)
認識ポイントの描画
「CameraView.swift」を編集する。
UIViewにサブレイヤーを追加するために必要な初期処理を入れる。
import UIKit
import AVFoundation
class CameraView: UIView{
//略
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder: NSCoder){
super.init(coder: coder)
}
}
指先のポイントを描画するためのサブレイヤーをつくるために「CAShapeLayer」クラスと「UIBezierPath」クラスのインスタンスを生成する。
import UIKit
import AVFoundation
class CameraView: UIView{
private var handoverlayer = CAShapeLayer()
private var handpointPath = UIBezierPath()
//略
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder: NSCoder){
super.init(coder: coder)
}
}
サブレイヤーの大きさを指定し、「previewLayer」にサブレイヤーを追加するオブジェクトを作成する。
import UIKit
import AVFoundation
class CameraView: UIView{
private var handoverlayer = CAShapeLayer()
private var handpointPath = UIBezierPath()
//略
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder: NSCoder){
super.init(coder: coder)
}
override func layoutSublayers(of layer: CALayer){
super.layoutSublayers(of: layer)
if layer == previewLayer{
handoverlayer.frame = layer.bounds
}
}
private func setupOverlay(){
previewLayer.addSublayer(handoverlayer)
}
}
描画するポイントに小さな点を描画するオブジェクトを作成する。
import UIKit
import AVFoundation
class CameraView: UIView{
private var handoverlayer = CAShapeLayer()
private var handpointPath = UIBezierPath()
//略
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder: NSCoder){
super.init(coder: coder)
}
override func layoutSublayers(of layer: CALayer){
super.layoutSublayers(of: layer)
if layer == previewLayer{
handoverlayer.frame = layer.bounds
}
}
private func setupOverlay(){
previewLayer.addSublayer(handoverlayer)
}
func handshowPoint(point:CGPoint){
handpointPath.addArc(withCenter: point, radius: 5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
handoverlayer.fillColor = UIColor.red.cgColor
CATransaction.begin()
CATransaction.setDisableActions(true)
handoverlayer.path = handpointPath.cgPath
CATransaction.commit()
}
}
次のポイントを描画するために今格納されているポイントを削除するオブジェクトを作成する。
import UIKit
import AVFoundation
class CameraView: UIView{
private var handoverlayer = CAShapeLayer()
private var handpointPath = UIBezierPath()
//略
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder: NSCoder){
super.init(coder: coder)
}
override func layoutSublayers(of layer: CALayer){
super.layoutSublayers(of: layer)
if layer == previewLayer{
handoverlayer.frame = layer.bounds
}
}
private func setupOverlay(){
previewLayer.addSublayer(handoverlayer)
}
func handshowPoint(point:CGPoint){
handpointPath.addArc(withCenter: point, radius: 5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
handoverlayer.fillColor = UIColor.red.cgColor
CATransaction.begin()
CATransaction.setDisableActions(true)
handoverlayer.path = handpointPath.cgPath
CATransaction.commit()
}
func handremovePoint(){
handpointPath.removeAllPoints()
}
}
「CameraViewController」の指認識のオブジェクトで描画するポイントを渡す。
さらに、ポイントパスを空にする。
private func getHandObservations(/*略*/){
//略
do{
//略
print(transformation.visionToUIKit(visionPoint: thumbTipPoint))
self.cameraView.handshowPoint(point: indexPoint)
self.cameraView.handremovePoint()
}catch{
//略
}
}
以上で描画をするための処理は終了である。ビルドして人差し指の位置に赤い点が描画されていれば成功である。
次へ
この記事では、Vision座標をUIKit座標に変換し、それを描画するところまで書いた。次の記事では、矩形認識を使い、A4サイズの紙(触図)を認識するところまでを書こうと思う。