얼굴 인식 기능 실습

얼굴 인식 기능은 Vision framework 를 사용한다.

import Vision

vision Framework

여러 명의 얼굴을 인식할 수 있는 이미지를 준비한 뒤, 이미지를 분석할 analyzeImage 함수를 정의한다

    func analyzeImage(image: UIImage) {
         let handler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:])
         let request = VNDetectFaceRectanglesRequest(completionHandler: handleFaceRecognition)
         try! handler.perform([request])
     }

     func handleFaceRecognition(request: VNRequest, error: Error?) {
         guard let foundFaces = request.results as? [VNFaceObservation] else {
             fatalError("Can't find a face in the picture")
         }
         message = "Found \(foundFaces.count) faces in the picture"
     }

얼굴 인식

VNImageRequestHandler

An object that processes one or more image analysis requests pertaining to a single image.


VNImageRequestHandler에는 core graphics Image, 줄여서 cgImage라는 싱글 이미지를 파라미터로 받는다. 그렇기 때문에 UIImage를 CGImage로 변환하여 VNImageRequestHandler를 초기화 한다.

이를 통해 단일 이미지를 Vision 프레임워크에 요청을 수행할 수 있는 핸들러를 인스턴스화할 수 있다.

그리고 이미지 안에 있는 페이스를 찾기 위한 요청(얼굴인식)인 VNDetectFaceRectanglesRequest를 초기화 한다. 얼굴 인식 작업 자체는 시간이 꽤 걸리는 작업이기에, 콜백함수. completionHandler 파라미터로 handleFaceRecognition 을 전달하는 것이다.

(handleFaceRecognition 함수는 얼굴 인식 작업이 완료된 후에 호출되는 클로저로, 즉시 실행되는 것이 아니라 비동기적으로 실행.)

그리고 아까 초기화한 handleFaceRecognition를 호출한다

요약

analyzeImage 함수 호출: UIImage 객체를 전달받아 시작.

핸들러 및 요청 객체 생성: VNImageRequestHandler와 VNDetectFaceRectanglesRequest 객체를 생성.

얼굴 인식 요청 수행: handler.perform([request])를 호출하여 비동기적으로 얼굴 인식 작업 시작.

얼굴 인식 작업 완료: 얼굴 인식 작업이 백그라운드에서 완료되면 handleFaceRecognition 함수가 호출됨.

결과 처리: handleFaceRecognition 함수에서 인식된 얼굴 수를 확인하고 메시지로 저장.

func perform(_ requests: [VNRequest]) throws

얼굴에 강조, 표시 기능 추가(드로잉)

인식한 얼굴에 드로잉을 추가해보겠다.

VNDetectFaceLandmarksRequest 를 사용.

    func analyzeImage(image: UIImage) {
        let handler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:])
        let request = VNDetectFaceLandmarksRequest(completionHandler: handleFaceRecognition)
        try! handler.perform([request])
    }
    
    func handleFaceRecognition(request: VNRequest, error: Error?) {
        guard let foundFaces = request.results as? [VNFaceObservation] else {
            fatalError("Can't find a face in the picture")
        }
        message = "Found \(foundFaces.count) faces in the picture"
        
        guard let image = UIImage(named: photoArray[arrayIndex]) else { return }
        
        // 이미지 생성을 위한 컨텍스트 시작
        UIGraphicsBeginImageContextWithOptions(image.size, false, 0.0)

        // 컨텍스트 변수 가져오기
        let context = UIGraphicsGetCurrentContext()!
                
        // 컨텍스트 내에 이미지 그리기
        image.draw(in: CGRect(origin: .zero, size: image.size))
        
        // 이미지를 그린 후 좌표계를 변환합니다.
        context.translateBy(x: 0, y: image.size.height)
        context.scaleBy(x: 1.0, y: -1.0)
        
        // 얼굴 주변 사각형을 그리기 위한 선 색상과 두께 설정
        context.setStrokeColor(UIColor.red.cgColor)
        context.setLineWidth(10)

        for faceObservation in foundFaces {
            // 정규화 된 얼굴 인식 위치값(CGRect) 가져오기
            let faceRect = VNImageRectForNormalizedRect(faceObservation.boundingBox, Int(image.size.width), Int(image.size.height))
            // 가져온 위치에 테두리 그리기
            context.stroke(faceRect)
        }
        // 컨텍스트를 종료하고, 컨텍스트 결과를 이미지 변수에 할당
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        // 커밋 (위의 컨텍스트 명령을 실행함)
        UIGraphicsEndImageContext()
        
        // 만들어진 이미지를 화면에 출력
        analyzedImage = newImage
    }

위 코드에서 핵심은, 이미지를 그린 후 좌표계를 변환한 시점 부터의 코드다.

context에는 각각의 얼굴의 위치를 가지고 있는데, 여기에 setStrokeColor나 setLineWidth로 라인을 그려줄 수 있을 것이다.

실행결과

시뮬레이터나 프리뷰에서는 facial Recognition이 되지 않고, 실제 기기에서 테스트해볼 수 있다.

image1 image2 image3