1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GoogleのML Kitを使って、オフラインで日本語テキスト認識するカメラメモアプリを作る(その1:画面の説明とSDKの導入)

Last updated at Posted at 2021-09-03

iOS 15ではOCR機能がOSに標準搭載されます(Live Text)。これはオフラインの機械学習モデルを使っているので、ネットワークに画像データが乗ったり、プライバシーの心配なく使えるのが魅力です。しかし、リリース時点では日本語に対応していません。

そこで使ってみたのがGoogleのML Kitになります。まだベータ版なのですが、バージョン2から日本語にも対応しています。また、ML Kitはオフライン動作も可能で、Google Cloudへの登録なども不要です。これを使えばLive Text的なことはできそうです。

今回はこのML Kitを使って、以前作成したNCMBのSwift SDKを用いたカメラメモアプリのメモを自動入力する機能を追加してみます。写真の中にあるテキスト情報をメモに使えば、後で検索したりコピーしたりするのに便利そうです。

コード

今回のデモアプリのコードはNCMBMania/Swift_CameraMemo_MLKit: Swift SDKによるカメラメモアプリにML Kitを追加した版ですにアップロードしてあります。

利用したライブラリ・SDK

今回は以下のライブラリ・SDKを利用しています。

言語はSwiftです。

カメラメモアプリの機能について

カメラメモアプリは、写真を撮影して、その写真データをファイルストアにアップロードします。そして、写真の中にあるテキスト情報をML Kitを使って抽出し、メモとして写真に紐付けて保存します。

利用する機能について

カメラメモアプリで利用するNCMBの機能は次の通りです。以前あった認証機能は省いています。

  • データストア
    • ファイルストアと紐付けたメモを保存
    • 保存しているメモを取得
  • ファイルストア
    • ファイルアップロード
    • ファイルダウンロード

画面について

カメラメモアプリでは次の画面(View)を用意しています。

  • ContentView
    タブバーで2つの画面を読み込んでいます。1つは写真撮影とアップロードする画面(InputView)、もう1つは写真一覧画面(ImageView)です。
  • Imagepicker
    写真の撮影またはフォトライブラリから写真を選択します。
  • InputView
    タブバーから読み込まれます。写真の撮影とテキスト抽出、アップロードを行います。
  • ImageView
    NCMBへアップロードした写真を一覧表示します。
  • ModalView
    写真一覧をタップした際にモーダル表示します。
  • GridImageView
    写真一覧のグリッド表示用ビューです。

ContentView

タブバーで2つの画面を読み込んでいます。

struct ContentView: View {
    var body: some View {
        TabView {
            InputView()
                .tabItem {
                    VStack {
                        Image(systemName: "photo")
                        Text("Photo")
                    }
            }.tag(1)
            ImageView()
                .tabItem {
                    VStack {
                        Image(systemName: "rectangle.grid.2x2")
                        Text("Photos")
                    }
            }.tag(2)
        }
    }
}

Imagepicker

写真の撮影またはフォトライブラリから写真を選択します。コードは【SwiftUI】カメラ機能の実装方法【撮影画像とライブラリー画像の利用】から拝借しています。ありがとうございます。

InputView

IMG_2431.PNG

写真の選択やML Kitによる日本語抽出、NCMBへの保存処理を行います。

struct InputView: View {
    // イメージピッカーの表示用フラグ
    @State var showingPicker = false
    // 選択した写真が入る
    @State var image: UIImage?
    // 認識したテキストが入る
    @State var recognizeText: String?
    // ML Kitのテキスト認識用オブジェクト
    @State var textRecognizer = TextRecognizer.textRecognizer(options: JapaneseTextRecognizerOptions())
    // アラートのタイトル
    @State var title: String?
    // アラートのメッセージ
    @State var message: String?
    // アラートの表示用フラグ
    @State private var showingAlert = false
        
    var body: some View {
        VStack {
            HStack {
                Button("写真を撮る", action: {
                    showingPicker = true
                })
                Spacer()
                Button("保存する", action: {
                    savePhoto()
                })
                .disabled(image == nil)
            }
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                Text(recognizeText ?? "")
            }
        }
        .sheet(isPresented: $showingPicker) {
            ImagePickerView(image: $image, sourceType: .library)
        }
        .onChange(of: image, perform: { value in
            getText()
        })
        .alert(isPresented: $showingAlert) {
            Alert(title: Text(title!), message: Text(message!))
        }
    }

    // テキスト抽出を行います
    func getText() -> Void {
      // 後述
    }
    
    // NCMBへ写真とテキストを保存します
    func savePhoto() -> Void {
      // 後述
    }    
}

ImageView

ファイルストアから画像を取得します。

struct ImageView: View {
    @State var memos: [NCMBObject] = []
    
    var columns: [GridItem] = Array(repeating: .init(.fixed(200)), count: 2)
    
    var body: some View {
        ScrollView(.vertical) {
            LazyVGrid(columns: columns, alignment: .center, spacing: 200) {
                ForEach (memos, id: \.objectId) { memo in
                    GridImageView(memo: memo)
                }
            }
            .onAppear() {
                getAllPhotos()
            }
        }
    }
    func getAllPhotos() {
      // 写真をファイルストアから取得(後述)
    }
}

ModalView

IMG_2433.PNG

写真をタップした際にモーダル表示します。

struct ModalView: View {
    @Binding var isActive: Bool
    @State var memo: NCMBObject
    @State var imageData: Data
    
    var body: some View {
        HStack {
            Spacer()
            VStack {
                Spacer()
                GeometryReader { geometry in
                    Image(uiImage: UIImage(data: imageData)!)
                        .resizable()
                        .scaledToFill()
                        .frame(width: geometry.size.width, height: geometry.size.height)
                        .clipped()
                }
                if let text: String = memo["text"] {
                    Text(text).padding()
                }
                Button("閉じる") {
                    isActive = false
                }
                Spacer()
            }
            Spacer()
        }
        .padding()
        .background(Color(.black))
    }
}

GridImageView

IMG_2434.PNG

写真一覧のグリッド表示用です。

struct GridImageView: View {
    @State private var fileName: String = ""
    @State private var imageData: Data? = .init(capacity:0)
    @State var memo: NCMBObject? = nil
    @State private var isShowing = false
    
    var body: some View {
        GeometryReader { geometry in
            if imageData?.count ?? 0 > 0 {
                Image(uiImage: UIImage(data: imageData!)!)
                    .resizable()
                    .scaledToFill()
                    .frame(width: geometry.size.width, height: geometry.size.width)
                    .clipped()
            } else {
                Rectangle().fill(Color.clear)
            }
        }.onAppear() {
            loadImage()
        }.onTapGesture {
            isShowing = true
        }.fullScreenCover(isPresented: $isShowing) {
            ModalView(isActive: $isShowing, memo: memo!, imageData: imageData!)
        }
        
    }

    func loadImage() {
      // 写真データを読み込みます(後述)
    }
}

SDKの導入法

NCMBのSwift SDKはCocoaPods向けに提供しています。Swift Packagesでもインストールできますが、ML KitがCocoaPods向けだったので、一緒にインストールします。Xcodeで新しいiOSプロジェクトを作ったら、Podfileを用意します。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'TextRecognition' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for TextRecognition
  pod 'GoogleMLKit/TextRecognitionJapanese', '2.3.0'
  pod 'NCMB', :git => 'https://github.com/NIFCLOUD-mbaas/ncmb_swift.git'
end

そして pod install でSwift SDKとML Kitをインストールします。

Swift SDKの初期化について

現在、新規でiOSアプリを作成すると、InterfaceがSwiftUI、Life CycleがSwiftUI Appとなっています。この状態で作ると AppDelegate.swift はなく、 (アプリ名)App.swift というファイルが作られます。

この場合、まずSwift SDKを読み込みます。

import SwiftUI
import NCMB   // 追加

そして var body の上に @Environment を追加します。

@Environment(\.scenePhase) private var scenePhase // 追加
var body: some Scene {

最後に WindowGrouponChange を追加します。このonChangeの中で初期化処理を行います。

WindowGroup {
    ContentView()
}
.onChange(of: scenePhase) { scene in
    switch scene {
    case .active:
        NCMB.initialize(applicationKey: "YOUR_APPLICATION_KEY", clientKey: "YOUR_CLIENT_KEY")
    case .background: break;
    case .inactive: break;
    @unknown default: break;
    }
}

これで利用可能になります。

まとめ

今回は必要な画面の内容と、NCMBのSwift SDK導入までを紹介しました。次回はML Kitによるテキスト抽出と写真アップロードを解説します。

イントロダクション (Swift) : クイックスタート | ニフクラ mobile backend

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?