CoreML의 특징
이전 글 [iOS/Swift] CoreML (1) - Create ML으로 Model 만들기 에서도 이미 정리를 했지만 대략적으로 핵심만 알아봅시다.
- 사전에 훈련된 모델로 로드됩니다. (Static Model)
- 네트워크 연결 없이도 사용이 가능합니다.
- 보안 측면에서 개인 데이터를 네트워크를 통해 전송할 필요가 없으므로 상대적으로 안전합니다.
- 수요가 증가해도 서버부하와 직접적인 관련이 없어 확장성이 좋습니다.
- Apple 기기와의 빠른 호환성이 좋습니다.
사용 방법
오늘 만들어 볼 것은 이전 글 의 훈련된 이미지 모델(꽃 이름)을 갖고 CoreML 및 Vision 사용법을 알아보겠습니다.
간단히 소개하면 카메라를 통하여 훈련된 모델(꽃 이름)을 유추하는 앱을 만들어 보겠습니다.
1. CoreML
을 다루기 위해 프레임워크인 CoreML
및 Vision
를 import
를 해줍시다.
import CoreML
import Vision // CoreML과 작업을 할 때 이미지를 보다 쉽게 처리할 수 있게 도와주는 프레임워크
2. 카메라를 사용해야 하므로 UIImagePicker
를 통하여 이미지를 사용할 수 있게 만듭시다.
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
var imagePicker: UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .camera // 기본값은 카메라 라이브러리, 이미지를 찍을 수 있게 설정
picker.allowsEditing = true // 선택한 이미지나 동영상 편집 여부를 설정(Bool)
return picker
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func cameraTapped(_ sender: UIBarButtonItem) {
// UIImagePickerController도 ViewController 이므로 present로 불러와야 한다.
present(imagePicker, animated: true)
}
}
3. CoreML
과 Vision
으로 이미지를 처리하기 위해서 detect(image: CIImage)
란 함수를 만들어 봅시다.
CoreML
의 이미지를 읽기 위해서는 꼭 CIImage(Core Image)로 타입으로 변환을 해서 사용해야 합니다.- 훈련된 모델을 요청(
request
) 한 후handeler
로 처리해서 분석을 합니다.
// MARK: - CoreML 이미지 분류
extension ViewController {
// CoreML의 CIImage를 처리하고 해석하기 위한 메서드 생성, 이것은 모델의 이미지를 분류하기 위해 사용 됩니다.
func detect(image: CIImage) {
// CoreML의 모델인 FlowerClassifier를 객체를 생성 후,
// Vision 프레임워크인 VNCoreMLModel 컨터이너를 사용하여 CoreML의 model에 접근한다.
guard let coreMLModel = try? FlowerClassifier(configuration: MLModelConfiguration()),
let visionModel = try? VNCoreMLModel(for: coreMLModel.model) else {
fatalError("Loading CoreML Model Failed")
}
// Vision을 이용해 이미치 처리를 요청
let request = VNCoreMLRequest(model: visionModel) { request, error in
guard error == nil else {
fatalError("Failed Request")
}
// 식별자의 이름(꽃 이름)을 확인하기 위해 VNClassificationObservation로 변환해준다.
guard let classification = request.results as? [VNClassificationObservation] else {
fatalError("Faild convert VNClassificationObservation")
}
// 머신러닝을 통한 결과값 프린트
print(classification)
}
// 이미지를 받아와서 perform을 요청하여 분석한다. (Vision 프레임워크)
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
} catch {
print(error)
}
}
}
4. UIImagePickerControllerDelegate를 통해 훈련된 모델과 이미지랑 비교를 합니다.
- 위에서 만들어둔 메서드로 CIImage를 분석을 한다.
extension ViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
// 사진을 찍은 후 이미지를 갖고 할 일들을 정의
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
// info의 키 값으로 수정한 사진 이미지 받아온다.
guard let userPickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
fatalError("Failed Original Image pick")
}
// 위에서 받은 이미지를 이미지 뷰에 저장
imageView.image = userPickedImage
// Core모델 이미지로 사용하기 위해 CIImage로 변환
guard let coreImage = CIImage(image: userPickedImage) else {
fatalError("Faild convert CIImage")
}
// 변환 된 CIImage를 갖고 이미지를 처리하는 메서드 호출
detect(image: coreImage)
}
}
여기까지 과정을 마치고 사진을 찍어서 확인해 보면 데이터들이 정신없이 만들어져 있는 걸 볼 수 있습니다.
우리는 여기서 VNClassificationObservation
의 정확도(confidence)
와 이름(identifier)
만 유심히 보면 됩니다.
여기를 보시면
- confidence = 0.9945, identifier = "무궁화"
- confidence = 0.0035, identifier = "나팔꽃"...
백분율로 나타낸다면 "무궁화" 99.45% , "나팔꽃" 0.3% 이런 순으로 학습된 데이터들이 이미지와 비교하여 값이 나오게 됩니다.
우리는 사진과 가장 정확한 꽃의 이름만 알고 싶으니,
VNClassificationObservation
배열에서 정확도가 가장 높은 값, 즉 첫 번째 값만 알면 됩니다.
타이틀 값을 변경해 주기 위해서, CoreML 이미지 처리를 해준 3번으로 메서드로 돌아가봅시다.
print
값 대신에 VNClassificationObservation
배열의 첫 번째로 접근해서 타이틀을 identifier
로 설정해 줍시다.
// MARK: - CoreML 이미지 분류
extension ViewController {
func detect(image: CIImage) {
guard let coreMLModel = try? FlowerClassifier(configuration: MLModelConfiguration()),
let visionModel = try? VNCoreMLModel(for: coreMLModel.model) else {
fatalError("Loading CoreML Model Failed")
}
let request = VNCoreMLRequest(model: visionModel) { request, error in
guard error == nil else {
fatalError("Failed Request")
}
guard let classification = request.results as? [VNClassificationObservation] else {
fatalError("Faild convert VNClassificationObservation")
}
// 👉 타이틀을 가장 정확도 높은 이름으로 설정
if let fitstItem = classification.first {
self.navigationItem.title = fitstItem.identifier.capitalized
}
}
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
} catch {
print(error)
}
}
}
자! 테스트를 해봅시다.
테스트 결과
모델을 만들 때 학습 이미지의 개수를 15개씩 밖에 넣지 않았는데도 생각보다 높은 정확도를 갖고 있었습니다.
다만 범위를 너무 넓게 찍거나 꽃이 여러 개 있을 땐 정확도가 떨어지네요.
이상 CoreML
로 이미지 다루기였습니다. 전체 코드는 여기 서 확인하세요
참고
'Xcode > Framework' 카테고리의 다른 글
[iOS/Swift] SceneKit의 사용법 (2) - 주사위 만들기 (0) | 2023.01.08 |
---|---|
[iOS/Swift] SceneKit의 사용법 (1) - 정육면체와 달을 만들어 보자 (0) | 2023.01.07 |
[iOS/Swift] ARKit의 종류 (0) | 2023.01.07 |
[iOS/Swift] CoreML (1) - Create ML으로 Model 만들기 (0) | 2023.01.03 |
[iOS/Swift] WeatherKit 사용법 (0) | 2022.12.24 |