LoginSignup
0
0

MLKitを使った簡易的な翻訳アプリ

Last updated at Posted at 2023-12-25

はじめに

こんにちは。watnowで主にiOSアプリをダラダラ作っているKUROです。
今回はFirebaseが提供しているMLKitという文字認識のAPIを使って文字を認識し、認識した文字を翻訳できるアプリを作りたいと思います。

今回作るもの

今回作るものは下記のようにカメラに映った文字認識して翻訳するアプリです。RPReplay_Final1703471238.gif

使用した技術

MLKit
CropViewController
UIKit
ひらがなAPI

実際に作る

下準備

ライブラリの導入

MLKitとCropViewControllerはCocoaPodsを使って導入しました。
CocoaPodsでのライブラリ導入方法はこちらの記事を参考にしました。

UIを作る

今回はカメラを起動し、その場で撮影した画像から翻訳範囲を切り取り、翻訳をするアプリを作成するので、シンプルなUIを目指しました。
パーツとしては撮影した画像を表示するUIImageViewと翻訳を実施するUIButton、カメラを起動するUIButton、翻訳結果を表示するUILabelの4つのパーツを配置します。
スクリーンショット 2023-12-25 9.17.16.png

ライブラリのインポート

UIKitはもちろん、今回使用するMLKit、日本語と文字を認識するためのMLKitTextRecognitionJapaneseMLKitTextRecognitionCommon、カメラを使用するためのAVFoundationそして撮影した画像を切り取るためのCropViewController

ViewController
import UIKit
import MLKit
import MLKitTextRecognitionJapanese
import MLKitTextRecognitionCommon
import AVFoundation
import CropViewController

ついに本題へ

下準備も終えたので、本題のコードを書いていきましょう。

コードを書いていく!

まずは変数を宣言。

ViewController
//カメラやCropViewControllerのDelegateを継承しておくのを忘れずに
class ViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate,CropViewControllerDelegate {
//パーツの宣言
@IBOutlet var imageView: UIImageView!
@IBOutlet var result: UILabel!

//翻訳結果を一時的に入れる変数
var kanziResult: String = ""
//日本語を認識するためのクラス
let japaneseOptions = JapaneseTextRecognizerOptions()
let japaneseTextRecognizer = TextRecognizer.textRecognizer(options:JapaneseTextRecognizerOptions())

次にカメラの起動処理の部分を書いていきます。
takePhoto関数でカメラを起動し、imagePuckerController関数でカメラを閉じた際にCropViewControllerを起動し、画像を切り取りできるようにしています。

ViewController
//カメラを起動するボタンのIBAction
@IBAction func takePhoto() {
    let picker = UIImagePickerController()
    picker.sourceType = .camera
    picker.delegate = self
    present(picker, animated: true, completion: nil)
}
//カメラを閉じた後の処理を記述
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true)
    guard let image = info[.originalImage] as? UIImage else{
    print("Image not found.")
    return
    }
    let cropController = CropViewController(croppingStyle: .default, image: image)
    cropController.delegate = self
    cropController.customAspectRatio = CGSize(width: 100, height: 100)
    
    //今回は使わないボタン等を非表示にする。
    cropController.aspectRatioPickerButtonHidden = true
    cropController.resetAspectRatioEnabled = true
    cropController.rotateButtonsHidden = true
    
    //cropBoxのサイズを固定する。
    cropController.cropView.cropBoxResizeEnabled = true
    //pickerを閉じたら、cropControllerを表示する。
    picker.dismiss(animated: true) {
        self.present(cropController, animated: true, completion: nil)
    }
}
//撮影した画像を切り取ったものに置き換える
func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
    updateImageViewWithImage(image, fromCropViewController: cropViewController)
}
//ImageViewに切り取った画像を表示させる
func updateImageViewWithImage(_ image: UIImage, fromCropViewController cropViewController: CropViewController) {
    imageView.image = image
    cropViewController.dismiss(animated: true, completion: nil)
}

カメラを起動して画像を撮影できたらいよいよ翻訳していきましょう。
今回は画像内の文字をひらがなに変えてくれる、ひらがなAPIを使用しました。基本的にはこちらの記事を参考にし、ひらがなに変える元の文字をMLKitで抽出しました。

ViewController
@IBAction func honyaku() {
    let image = VisionImage(image: imageView.image!)
    //ここで、画像からテキストを認識しています。
    japaneseTextRecognizer.process(image) { result, error in
        guard error == nil, let result = result else { return }
        self.kanziResult = result.text
        print("resultText: \(result.text)")
    }
    //ここからAPIにHTTPリクエストを送っていきます。
    var request = URLRequest(url: URL(string: "https://labs.goo.ne.jp/api/hiragana")!)
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    //POSTするデータをURLRequestに持たせる
    let postData = PostData(app_id: "6937c927439be919b9c5add398fcd7a18307788779ce23b4181eb3a9c5435b6f", request_id: "record003", sentence: kanziResult, output_type: "hiragana")
    guard let uploadData = try? JSONEncoder().encode(postData) else {
        print("json生成に失敗しました")
        return
    }
    request.httpBody = uploadData
    //APIへPOSTしてresponseを受け取る
    let task = URLSession.shared.uploadTask(with: request, from: uploadData) {
        data, response, error in
        if let error = error {
            print ("error: \(error)")
            return
        }
        guard let response = response as? HTTPURLResponse,
              (200...299).contains(response.statusCode) else {
            print ("server error")
            return
        }
        if response.statusCode == 200 {
            guard let data = data, let jsonData = try? JSONDecoder().decode(Hiragana.self, from: data) else {
                print("json変換に失敗しました")
                return
            }
            print(jsonData.converted)
            DispatchQueue.main.async {
                self.result.text = jsonData.converted
            }
        } else {
            print("サーバエラー ステータスコード: \(response.statusCode)\n")
        }
    }
    task.resume()
}
}
//APIから受け取る結果の構造体
struct Hiragana:Codable {
    var request_id: String
    var output_type: String
    var converted: String
}
//APIにPOSTする際の構造体
struct PostData: Codable {
    var app_id:String
    var request_id: String
    var sentence: String
    var output_type: String
}

ここまでできたら、一度実行してみてください。おそらく、もうすでに翻訳ができていると思います。
ただ、一つ気づくと思います。結果のLabelに収まらなくね?と。そうなった場合は以下のコードを追加してください。自動的に結果をLabelに収めてくれます。

ViewController
override func viewDidLoad() {
    result.adjustsFontSizeToFitWidth = true
    super.viewDidLoad()
}

完成!

スクリーンショット 2023-12-25 11.21.23.jpeg

終わりに

今回はMLKitを使った翻訳アプリを作ってみました。
僕が所属するwatnowではこのように簡単なモバイルアプリから、1万ユーザーを超えるバスアプリまで色々なアプリやサービスを作っています。
もし、少しでも興味がありましたら是非Twitter覗いてみてください。
ここまで読んでいただきありがとうございました。

0
0
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
0
0