【ゴール】
Alamofireを用いてGoogle Cloud Vision APIに画像をPOSTし、画像から検出されて返される文字列を取得すること。
ただし、画像はiOSアプリから起動したiPhoneカメラで撮ったものを、base64でSrting型に変換したものを渡すこととする。
【できたこと①】
・以下のように"source"に画像URLを渡すと、APIリクエストが成功し、画像に含まれる文字列を認識してちゃんと返してくれました。
Swift
1let parameters: Parameters = [ 2 "requests": [ 3 "image": [ 4 "source": ["https://1.bp.blogspot.com/-DS_mPoCrYrQ/XVDZ7TPubmI/AAAAAAAASyI/Z7Dl29IkmQwtoiQc5g8a_eqILvpihY9RQCLcBGAs/s1600/fullsizeoutput_5bf.jpeg" 5 ] 6 ], 7 "features": [ 8 "type": "TEXT_DETECTION", 9 "maxResults": 1 10 ] 11 ] 12 ] 13
【できたこと②】
・iPhoneカメラで撮った画像をbase64でString型に変換することも、できていました。
Swift
1// 画像をbae64でエンコードする 2 private func base64EncodeImage(_ image: UIImage) -> String? { 3 return image.pngData()?.base64EncodedString(options: .endLineWithCarriageReturn) 4 }
Swift
1// 画像に含まれるテキストを検出する 2func detect(from image: UIImage, completion: @escaping (OCRResult?) -> Void) { 3 4 guard let base64Image = base64EncodeImage(image) else { 5 completion(nil) 6 return 7 } 8 9// Google Vision APIに、base64でエンコード済みのデータを渡す 10 callGoogleVisionAPI(with: base64Image, completion: completion) 11 12 print ("The type of base64Image is (type(of: base64Image))") 13 14 } 15
↓コンソール
The type of base64Image is String // 画像がString型になっている
【できなかったこと】
iOSアプリから起動したiPhoneカメラで撮ったものを、base64でSrting型に変換したものをAlamofireを使ってAPIリクエストした。
実行前・実行中(runtime)エラーのいずれもなく(エラーが何も出てこない)、Build Succeedとなり、正常にアプリが起動する。
しかし全くの無反応で、403や404などのエラーも返ってきません。
Swift
1let parameters: Parameters = [ 2 "requests": [ 3 "image": ["content": base64EncodedImage], 4 "features": [ 5 "type": "TEXT_DETECTION", 6 "maxResults": 1] 7 ] 8 ]
Google Cloud Platformコンソール画面に行ってAPIリクエストが届いているか確認しても、APIリクエストの数が増えていないので、リクエスト自体が、届いていないと思われます。
【その他のコード】
カメラを起動し、写真を撮るコード
Swift
1// 2// 3// CameraViewController.swift 4// 5// 6 7// MARK: AVCapturePhotoCaptureDelegateデリゲートメソッド 8extension CameraViewController: AVCapturePhotoCaptureDelegate{ 9 // 撮影した画像データが生成されたときに呼び出されるデリゲートメソッド 10 func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 11 if let imageData = photo.fileDataRepresentation() { 12 // Data型をUIImageオブジェクトに変換 13 let uiImage = UIImage(data: imageData) 14 // 写真ライブラリに画像を保存 15 UIImageWriteToSavedPhotosAlbum(uiImage!, nil,nil,nil) // 正常にライブラリに保存されることを確認済みです 16 17 // こっから下はGoogle Cloud Vision APIのdetectBoundingBoxes()を呼び出している 18 GoogleCloudOCR().detect(from: uiImage!) { ocrResult in 19 20 // self.activityIndicator.stopAnimating() //読み込み中画面を使う場合はコメントアウトを消す 21 guard let ocrResult = ocrResult else { 22 fatalError("Did not recognize any text in this image") 23 } 24 print(ocrResult) 25 } 26 } 27 } 28} 29
【Google CloudにAPIリクエストするコード】
Swift
1// 2// GoogleCloudOCR.swift 3// 4// 5 6import Foundation 7import Alamofire 8import UIKit 9 10class GoogleCloudOCR { 11 12 // Google Cloud Vision API 13 var apiKey = "<My API Key>" 14 var apiURL: URL { 15 return URL(string: "https://vision.googleapis.com/v1/images:annotate?key=(apiKey)")! 16 } 17 18 func detect(from image: UIImage, completion: @escaping (OCRResult?) -> Void) { 19 20 guard let base64Image = base64EncodeImage(image) else { 21 completion(nil) 22 return 23 } 24 callGoogleVisionAPI(with: base64Image, completion: completion) 25 26 print ("The type of base64Image is (type(of: base64Image))") 27 print ("callGoogleVisionAPI(with: base64Image, completion: completion) has been called") 28 } 29 30 private func callGoogleVisionAPI( 31 with base64EncodedImage: String, completion: @escaping (OCRResult?) -> Void) { 32 print ("func callGoogleVisionAPI() has been called") 33 34// APIリクエストが送れなかったparameters(【できなかったこと】) 35 /* 36 let parameters: Parameters = [ 37 "requests": [ 38 "image": ["content": base64EncodedImage], 39 "features": [ 40 "type": "TEXT_DETECTION", 41 "maxResults": 1] 42 ] 43 ] 44 */ 45 46// 以下のparametersならAPIリクエストが成功し、画像に含まれる文字列が返された(【できたこと①】) 47 let parameters: Parameters = [ 48 "requests": [ 49 "image": [ 50 "source": ["imageUri": "https://1.bp.blogspot.com/-DS_mPoCrYrQ/XVDZ7TPubmI/AAAAAAAASyI/Z7Dl29IkmQwtoiQc5g8a_eqILvpihY9RQCLcBGAs/s1600/fullsizeoutput_5bf.jpeg" 51 ] 52 ], 53 "features": [ 54 "type": "TEXT_DETECTION", 55 "maxResults": 1 56 ] 57 ] 58 ] 59 60 let headers: HTTPHeaders = [ 61 "Content-Type": "application/json", 62 "X-Ios-Bundle-Identifier": Bundle.main.bundleIdentifier ?? ""] 63 64 Alamofire.request( 65 apiURL, 66 method: .post, 67 parameters: parameters, 68 encoding: JSONEncoding.default, 69 headers: headers) 70 .responseJSON { response in 71 if response.result.isFailure { 72 completion(nil) 73 return 74 } 75 print(response.result.debugDescription) 76 debugPrint(response) 77 } 78 } 79 80 private func base64EncodeImage(_ image: UIImage) -> String? { 81 return image.pngData()?.base64EncodedString(options: .endLineWithCarriageReturn) 82 } 83 84 struct Vertex: Codable { 85 let x: Int? 86 let y: Int? 87 enum CodingKeys: String, CodingKey { 88 case x = "x", y = "y" 89 } 90 init(from decoder: Decoder) throws { 91 let container = try decoder.container(keyedBy: CodingKeys.self) 92 x = try container.decodeIfPresent(Int.self, forKey: .x) 93 y = try container.decodeIfPresent(Int.self, forKey: .y) 94 } 95 96 func toCGPoint() -> CGPoint { 97 return CGPoint(x: x ?? 0, y: y ?? 0) 98 } 99 } 100 101 struct BoundingBox: Codable { 102 let vertices: [Vertex] 103 enum CodingKeys: String, CodingKey { 104 case vertices = "vertices" 105 } 106 init(from decoder: Decoder) throws { 107 let container = try decoder.container(keyedBy: CodingKeys.self) 108 vertices = try container.decode([Vertex].self, forKey: .vertices) 109 } 110 } 111 112 struct Annotation: Codable { 113 let text: String 114 let boundingBox: BoundingBox 115 enum CodingKeys: String, CodingKey { 116 case text = "description" 117 case boundingBox = "boundingPoly" 118 } 119 init(from decoder: Decoder) throws { 120 let container = try decoder.container(keyedBy: CodingKeys.self) 121 text = try container.decode(String.self, forKey: .text) 122 boundingBox = try container.decode(BoundingBox.self, forKey: .boundingBox) 123 } 124 } 125 126 struct OCRResult: Codable { 127 let annotations: [Annotation] 128 enum CodingKeys: String, CodingKey { 129 case annotations = "textAnnotations" 130 } 131 init(from decoder: Decoder) throws { 132 let container = try decoder.container(keyedBy: CodingKeys.self) 133 annotations = try container.decode([Annotation].self, forKey: .annotations) 134 } 135 } 136 137 struct GoogleCloudOCRResponse: Codable { 138 let responses: [OCRResult] 139 enum CodingKeys: String, CodingKey { 140 case responses = "responses" 141 } 142 init(from decoder: Decoder) throws { 143 let container = try decoder.container(keyedBy: CodingKeys.self) 144 responses = try container.decode([OCRResult].self, forKey: .responses) 145 } 146 } 147} 148
回答1件
あなたの回答
tips
プレビュー