앱에서 Google Cloud API를 호출하려면 승인을 처리하고 API 키와 같은 보안 비밀 값을 보호하는 중간 REST API를 만들어야 합니다. 그런 다음 모바일 앱에서 코드를 작성하여 이 중간 서비스에 인증하고 통신해야 합니다.
이 REST API를 만드는 한 가지 방법은 Firebase 인증 및 Firebase Functions를 사용하는 것입니다. 이 방법을 사용하면 인증을 처리하고 사전 빌드된 SDK를 사용하여 모바일 앱에서 호출할 수 있는 Google Cloud API에 대한 관리형 서버리스 게이트웨이가 제공됩니다.
이 가이드에서는 이 기법을 사용하여 앱에서 Cloud Vision API를 호출하는 방법을 설명합니다. 이 방법을 사용하면 인증된 모든 사용자가 Cloud 프로젝트를 통해 Cloud Vision 청구 서비스에 액세스할 수 있으므로 계속하기 전에 이 인증 메커니즘이 현재 사용 사례에 충분한지 고려해야 합니다.
시작하기 전에
프로젝트 구성
앱에 Firebase를 아직 추가하지 않았다면 시작 가이드의 단계에 따라 추가합니다.Swift Package Manager를 사용해 Firebase 종속 항목을 설치하고 관리하세요.
- 앱 프로젝트를 연 상태로 Xcode에서 File(파일) > Add Packages(패키지 추가)로 이동합니다.
- 메시지가 표시되면 Firebase Apple 플랫폼 SDK 저장소를 추가합니다.
- Firebase ML 라이브러리를 선택합니다.
- 완료되면 Xcode가 백그라운드에서 자동으로 종속 항목을 확인하고 다운로드하기 시작합니다.
https://github.com/firebase/firebase-ios-sdk
그런 다음 몇 가지 인앱 설정을 수행합니다.
- 앱에서 Firebase를 가져옵니다.
Swift
import FirebaseMLModelDownloader
Objective-C
@import FirebaseMLModelDownloader;
이제 몇 가지 추가 구성 단계를 거치면 시작할 준비를 마치게 됩니다.
-
프로젝트에 클라우드 기반 API를 아직 사용 설정하지 않았으면 지금 설정하세요.
- Firebase Console의 Firebase ML API 페이지를 엽니다.
-
프로젝트를 Blaze 요금제로 아직 업그레이드하지 않은 경우 업그레이드를 클릭하여 업그레이드하세요. 프로젝트가 Blaze 요금제가 아닌 경우에만 업그레이드하라는 메시지가 표시됩니다.
Blaze 수준 프로젝트만 클라우드 기반 API를 사용할 수 있습니다.
- 클라우드 기반 API가 아직 사용 설정되지 않은 경우 클라우드 기반 API 사용 설정을 클릭합니다.
- Cloud Vision API에 대한 액세스를 허용하지 않도록 기존 Firebase API 키를 구성합니다.
- Cloud 콘솔의 사용자 인증 정보 페이지를 엽니다.
- 목록에 있는 API 키마다 편집 화면을 열고 키 제한 섹션에서 Cloud Vision API를 제외한 모든 사용 가능한 API를 목록에 추가합니다.
호출 가능 함수 배포
다음으로 앱과 Cloud Vision API를 연결하는 데 사용할 Cloud 함수를 배포합니다. functions-samples
저장소에는 사용할 수 있는 예시가 포함되어 있습니다.
기본적으로 이 함수를 통해 Cloud Vision API에 액세스하면 앱의 인증된 사용자만 Cloud Vision API에 액세스할 수 있습니다. 다양한 요구사항에 맞게 함수를 수정할 수 있습니다.
함수 배포 단계는 다음과 같습니다.
- functions-samples repo를 클론하거나 다운로드하고
vision-annotate-image
디렉터리로 변경합니다.git clone https://github.com/firebase/functions-samples
cd vision-annotate-image
- 종속 항목을 설치합니다.
cd functions
npm install
cd ..
- Firebase CLI가 없으면 설치합니다.
vision-annotate-image
디렉터리에서 Firebase 프로젝트를 초기화합니다. 메시지가 표시되면 목록에서 프로젝트를 선택합니다.firebase init
- 함수를 배포합니다.
firebase deploy --only functions:annotateImage
앱에 Firebase 인증 추가
위에서 배포한 호출 가능 함수는 인증되지 않은 앱 사용자의 모든 요청을 거부합니다. 아직 추가하지 않았다면 Firebase 인증을 앱에 추가해야 합니다.
앱에 필요한 종속 항목 추가
Swift Package Manager를 사용해 Firebase용 Cloud Functions 라이브러리를 설치합니다.
이제 이미지 속 텍스트 인식을 시작할 수 있습니다.
1. 입력 이미지 준비
Cloud Vision을 호출하려면 이미지의 형식을 base64로 인코딩된 문자열로 지정해야 합니다.UIImage
를 처리하려면 다음 안내를 따르세요.
Swift
guard let imageData = uiImage.jpegData(compressionQuality: 1.0f) else { return } let base64encodedImage = imageData.base64EncodedString()
Objective-C
NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f); NSString *base64encodedImage = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
2. 호출 가능 함수를 호출하여 텍스트 인식
이미지 속 랜드마크를 인식하려면 JSON Cloud Vision 요청을 전달하는 호출 가능 함수를 호출합니다.먼저 Cloud Functions의 인스턴스를 초기화합니다.
Swift
lazy var functions = Functions.functions()
Objective-C
@property(strong, nonatomic) FIRFunctions *functions;
요청을 만듭니다. Cloud Vision API는
TEXT_DETECTION
및DOCUMENT_TEXT_DETECTION
의 두 가지 유형의 텍스트 감지를 지원합니다. 두 사용 사례 간의 차이점은 Cloud Vision OCR 문서를 참조하세요.Swift
let requestData = [ "image": ["content": base64encodedImage], "features": ["type": "TEXT_DETECTION"], "imageContext": ["languageHints": ["en"]] ]
Objective-C
NSDictionary *requestData = @{ @"image": @{@"content": base64encodedImage}, @"features": @{@"type": @"TEXT_DETECTION"}, @"imageContext": @{@"languageHints": @[@"en"]} };
마지막으로 함수를 호출합니다.
Swift
functions.httpsCallable("annotateImage").call(requestData) { (result, error) in if let error = error as NSError? { if error.domain == FunctionsErrorDomain { let code = FunctionsErrorCode(rawValue: error.code) let message = error.localizedDescription let details = error.userInfo[FunctionsErrorDetailsKey] } // ... } // Function completed successfully }
Objective-C
[[_functions HTTPSCallableWithName:@"annotateImage"] callWithObject:requestData completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) { if (error) { if (error.domain == FIRFunctionsErrorDomain) { FIRFunctionsErrorCode code = error.code; NSString *message = error.localizedDescription; NSObject *details = error.userInfo[FIRFunctionsErrorDetailsKey]; } // ... } // Function completed succesfully // Get information about labeled objects }];
3. 인식된 텍스트 블록에서 텍스트 추출
텍스트 인식 작업이 성공하면 BatchAnnotateImagesResponse의 JSON 응답이 작업 결과에 반환됩니다. 텍스트 주석은 fullTextAnnotation
객체에서 찾을 수 있습니다.
인식된 텍스트를 text
필드에서 문자열로 가져올 수 있습니다. 예를 들면 다음과 같습니다.
Swift
guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any] else { return }
print("%nComplete annotation:")
let text = annotation["text"] as? String ?? ""
print("%n\(text)")
Objective-C
NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);
이미지 영역과 관련된 정보를 가져올 수도 있습니다. 각 block
, paragraph
, word
, symbol
에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다. 예를 들면 다음과 같습니다.
Swift
guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
var pageText = ""
guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
for block in blocks {
var blockText = ""
guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
for paragraph in paragraphs {
var paragraphText = ""
guard let words = paragraph["words"] as? [[String: Any]] else { continue }
for word in words {
var wordText = ""
guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
for symbol in symbols {
let text = symbol["text"] as? String ?? ""
let confidence = symbol["confidence"] as? Float ?? 0.0
wordText += text
print("Symbol text: \(text) (confidence: \(confidence)%n")
}
let confidence = word["confidence"] as? Float ?? 0.0
print("Word text: \(wordText) (confidence: \(confidence)%n%n")
let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
print("Word bounding box: \(boundingBox.description)%n")
paragraphText += wordText
}
print("%nParagraph: %n\(paragraphText)%n")
let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
print("Paragraph bounding box: \(boundingBox)%n")
let confidence = paragraph["confidence"] as? Float ?? 0.0
print("Paragraph Confidence: \(confidence)%n")
blockText += paragraphText
}
pageText += blockText
}
Objective-C
for (NSDictionary *page in annotation[@"pages"]) {
NSMutableString *pageText = [NSMutableString new];
for (NSDictionary *block in page[@"blocks"]) {
NSMutableString *blockText = [NSMutableString new];
for (NSDictionary *paragraph in block[@"paragraphs"]) {
NSMutableString *paragraphText = [NSMutableString new];
for (NSDictionary *word in paragraph[@"words"]) {
NSMutableString *wordText = [NSMutableString new];
for (NSDictionary *symbol in word[@"symbols"]) {
NSString *text = symbol[@"text"];
[wordText appendString:text];
NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
}
NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
[paragraphText appendString:wordText];
}
NSLog(@"\nParagraph: \n%@\n", paragraphText);
NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
[blockText appendString:paragraphText];
}
[pageText appendString:blockText];
}
}