AutoML Vision Edge를 사용하여 자체 모델을 학습시키면 앱에서 모델을 사용하여 이미지에 라벨을 지정할 수 있습니다.
AutoML Vision Edge에서 학습된 모델을 통합하는 방법에는 두 가지가 있습니다. 모델의 파일을 Xcode 프로젝트로 복사하여 모델을 번들로 묶거나 Firebase에서 동적으로 다운로드할 수 있습니다.
모델 번들 옵션 | |
---|---|
앱에 번들로 제공 |
|
Firebase로 호스팅 |
|
시작하기 전에
Podfile에 ML Kit 라이브러리를 포함합니다.
모델을 앱과 함께 번들로 묶는 방법은 다음과 같습니다.
pod 'GoogleMLKit/ImageLabelingCustom'
Firebase에서 모델을 동적으로 다운로드하려면
LinkFirebase
종속 항목을 추가합니다.pod 'GoogleMLKit/ImageLabelingCustom' pod 'GoogleMLKit/LinkFirebase'
프로젝트의 pod를 설치하거나 업데이트한 후
.xcworkspace
를 사용하여 Xcode 프로젝트를 엽니다. ML Kit는 Xcode 12.2 이상 버전에서 지원됩니다.모델을 다운로드하려면 Android 프로젝트에 Firebase를 추가해야 합니다(아직 추가하지 않은 경우). 모델을 번들로 묶을 때는 이 작업이 필요하지 않습니다.
1. 모델 로드
로컬 모델 소스 구성
모델을 앱과 함께 번들로 묶는 방법은 다음과 같습니다.
Firebase Console에서 다운로드한 zip 파일에서 모델과 모델의 메타데이터를 폴더로 추출합니다.
your_model_directory |____dict.txt |____manifest.json |____model.tflite
세 파일이 모두 같은 폴더에 있어야 합니다. 다운로드한 파일을 수정하지 않고(파일 이름 등) 그대로 사용하는 것이 좋습니다.
폴더를 Xcode 프로젝트에 복사합니다. 이때 폴더 참조 만들기를 선택해야 합니다. 모델 파일과 메타데이터가 앱 번들에 포함되며 ML Kit에서 사용할 수 있습니다.
LocalModel
객체를 만들고 모델 매니페스트 파일의 경로를 지정합니다.Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return true } let localModel = LocalModel(manifestPath: manifestPath)
Objective-C
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:manifestPath];
Firebase 호스팅 모델 소스 구성
원격 호스팅 모델을 사용하려면 모델을 게시할 때 할당한 이름을 지정하여 CustomRemoteModel
객체를 만듭니다.
Swift
// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)
Objective-C
// Initialize the model source with the name you assigned in
// the Firebase console.
MLKFirebaseModelSource *firebaseModelSource =
[[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"];
MLKCustomRemoteModel *remoteModel =
[[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];
이제 다운로드를 허용할 조건을 지정하여 모델 다운로드 작업을 시작합니다. 모델이 기기에 없거나 최신 버전의 모델을 사용할 수 있으면 모델이 Firebase에서 비동기식으로 다운로드됩니다.
Swift
let downloadConditions = ModelDownloadConditions(
allowsCellularAccess: true,
allowsBackgroundDownloading: true
)
let downloadProgress = ModelManager.modelManager().download(
remoteModel,
conditions: downloadConditions
)
Objective-C
MLKModelDownloadConditions *downloadConditions =
[[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
allowsBackgroundDownloading:YES];
NSProgress *downloadProgress =
[[MLKModelManager modelManager] downloadRemoteModel:remoteModel
conditions:downloadConditions];
대부분의 앱은 초기화 코드로 다운로드 작업을 시작하지만 모델 사용이 필요한 시점 이전에는 언제든지 다운로드할 수 있습니다.
모델에서 이미지 레이블러 만들기
모델 소스를 구성한 후 모델 소스 중 하나에서 ImageLabeler
객체를 만듭니다.
로컬로 번들된 모델만 있다면 LocalModel
객체에서 라벨러를 만들고 필요한 신뢰도 점수 임곗값을 구성합니다(모델 평가 참조).
Swift
let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Cloud console
// to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options)
Objective-C
CustomImageLabelerOptions *options =
[[CustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0f); // Evaluate your model in the Cloud console
// to determine an appropriate value.
MLKImageLabeler *imageLabeler =
[MLKImageLabeler imageLabelerWithOptions:options];
원격 호스팅 모델이 있다면 실행 전에 모델이 다운로드되었는지 확인해야 합니다. 모델 관리자의 isModelDownloaded(remoteModel:)
메서드로 모델 다운로드 작업의 상태를 확인할 수 있습니다.
이 상태는 레이블러 실행 전에만 확인하면 되지만 원격 호스팅 모델과 로컬로 번들된 모델이 모두 있는 경우에는 ImageLabeler
를 인스턴스화할 때 이 확인 작업을 수행하는 것이 합리적일 수 있습니다. 원격 모델이 다운로드되었으면 원격 모델에서, 그렇지 않으면 로컬 모델에서 레이블러를 만듭니다.
Swift
var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
options = CustomImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0f); // Evaluate your model in the Firebase console
// to determine an appropriate value.
MLKImageLabeler *imageLabeler =
[MLKImageLabeler imageLabelerWithOptions:options];
원격 호스팅 모델만 있다면 모델 다운로드 여부가 확인될 때까지 모델 관련 기능 사용을 중지해야 합니다(예: UI 비활성화 또는 숨김).
기본 알림 센터에 관찰자를 연결하여 모델 다운로드 상태를 가져올 수 있습니다. 다운로드하는 데 시간이 걸릴 수 있고 다운로드가 완료되면 원래 객체가 해제될 수 있으므로 관찰자 블록의 self
에 약한 참조를 사용하세요. 예를 들면 다음과 같습니다.
Swift
NotificationCenter.default.addObserver(
forName: .mlkitMLModelDownloadDidSucceed,
object: nil,
queue: nil
) { [weak self] notification in
guard let strongSelf = self,
let userInfo = notification.userInfo,
let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
as? RemoteModel,
model.name == "your_remote_model"
else { return }
// The model was downloaded and is available on the device
}
NotificationCenter.default.addObserver(
forName: .mlkitMLModelDownloadDidFail,
object: nil,
queue: nil
) { [weak self] notification in
guard let strongSelf = self,
let userInfo = notification.userInfo,
let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
as? RemoteModel
else { return }
let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
// ...
}
Objective-C
__weak typeof(self) weakSelf = self;
[NSNotificationCenter.defaultCenter
addObserverForName:MLKModelDownloadDidSucceedNotification
object:nil
queue:nil
usingBlock:^(NSNotification *_Nonnull note) {
if (weakSelf == nil | note.userInfo == nil) {
return;
}
__strong typeof(self) strongSelf = weakSelf;
MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];
if ([model.name isEqualToString:@"your_remote_model"]) {
// The model was downloaded and is available on the device
}
}];
[NSNotificationCenter.defaultCenter
addObserverForName:MLKModelDownloadDidFailNotification
object:nil
queue:nil
usingBlock:^(NSNotification *_Nonnull note) {
if (weakSelf == nil | note.userInfo == nil) {
return;
}
__strong typeof(self) strongSelf = weakSelf;
NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError];
}];
2. 입력 이미지 준비
UIImage
또는 CMSampleBufferRef
를 사용하여 VisionImage
객체를 만듭니다.
UIImage
를 사용하는 경우 다음 단계를 따르세요.
UIImage
로VisionImage
객체를 만듭니다. 올바른.orientation
을 지정해야 합니다.Swift
let image = VisionImage(image: uiImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
CMSampleBufferRef
를 사용하는 경우 다음 단계를 따르세요.
-
CMSampleBufferRef
버퍼에 포함된 이미지 데이터의 방향을 지정합니다.이미지 방향을 가져오는 방법은 다음과 같습니다.
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
CMSampleBufferRef
객체와 방향을 사용하여VisionImage
객체를 만듭니다.Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. 이미지 레이블러 실행
비동기식으로:
Swift
imageLabeler.process(image) { labels, error in
guard error == nil, let labels = labels, !labels.isEmpty else {
// Handle the error.
return
}
// Show results.
}
Objective-C
[imageLabeler
processImage:image
completion:^(NSArray<MLKImageLabel *> *_Nullable labels,
NSError *_Nullable error) {
if (label.count == 0) {
// Handle the error.
return;
}
// Show results.
}];
동기식으로:
Swift
var labels: [ImageLabel]
do {
labels = try imageLabeler.results(in: image)
} catch let error {
// Handle the error.
return
}
// Show results.
Objective-C
NSError *error;
NSArray<MLKImageLabel *> *labels =
[imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.
4. 라벨이 지정된 객체 정보 가져오기
이미지 라벨 지정 작업이 성공하면 ImageLabel
의 배열이 반환됩니다. 각 ImageLabel
은 이미지에서 라벨이 지정된 항목을 나타냅니다. 각 라벨의 텍스트 설명(TensorFlow Lite 모델 파일의 메타데이터에 표시되는 경우), 신뢰도 점수, 색인을 가져올 수 있습니다.
예를 들면 다음과 같습니다.
Swift
for label in labels {
let labelText = label.text
let confidence = label.confidence
let index = label.index
}
Objective-C
for (MLKImageLabel *label in labels) {
NSString *labelText = label.text;
float confidence = label.confidence;
NSInteger index = label.index;
}
실시간 성능 향상을 위한 팁
실시간 애플리케이션에서 이미지 라벨을 지정하려는 경우 최상의 프레임 속도를 얻으려면 다음 안내를 따르세요.
- 인식기 호출을 제한합니다. 인식기가 실행 중일 때 새 동영상 프레임이 제공되는 경우 해당 프레임을 드롭합니다.
- 인식기 출력을 사용하여 입력 이미지에 그래픽을 오버레이하는 경우 먼저 인식 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 입력 프레임별로 한 번만 디스플레이 표면에 렌더링됩니다. 관련 예시는 쇼케이스 샘플 앱에서 previewOverlayView 및 FIRDetectionOverlayView 클래스를 참조하세요.