- 投稿日:2019-06-25T13:48:49+09:00
音楽ど素人が機械学習で楽譜認識するAndroidアプリを作る話 スマホで音符の検出編
はじめに
中学から吹奏楽部に入った息子が楽譜に音名を書くのがだるいと言いだしたんで、そんなもん今どきスマホとパシャッとすりゃAIでぱっと出てくるアプリがあるだろ?って言ったら意外となかったんで自分で作った
五線譜の検出編
https://qiita.com/Anadreline/items/4cf6e88c743a65b7da2c
音符検出モデルの作成編
https://qiita.com/Anadreline/items/f6c81774e241a33dd0d8
につづく第3弾、完結編です作成アプリ
Music Score Reader
https://play.google.com/store/apps/details?id=msreader.android.anadreline.com.musicscorereader
ちなみにiOS用だといくつかあります
スマホ用の楽譜認識アプリをまとめてみた
http://anadreline.blogspot.com/2019/06/wo.html開発者の初期スペック
- 五線譜のどこがドなのかがわからない
- ♯と♭って結局どっちかだけでよくない!?と思っている
- 息子にトランペットのドはドじゃないからねって言われてファッ!?ってなる
- 12音に五線譜表記って仕様がおかしくねって思っている
検証環境
この記事の内容は、以下の環境で検証しました。
- Android Studio 3.2.1
- CompileSdkVersion:27
- MinSdkVersion:21
- TargetSdkVersion:27
- OpenCV for Android 3.2.3
- TensorFlow Mobile
音符の検出プロセス
スマホ用のTensorFlow Mobileを利用して検出を行いました
ベースとなるところは公式のサンプルにすべて詰まってます
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android
ただし、今やるならTensorFlow Liteを使うのがベストだと思います画像取得
まずは認識するための楽譜画像の取得
MainActivity.javaUri m_uri; Bitmap m_image; //カメラIntent呼出 String photoName = System.currentTimeMillis() + ".jpg"; ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.Images.Media.TITLE, photoName); contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*"); m_uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, m_uri); startActivityForResult(intentCamera, REQUEST_CAMERA); //撮影画像取得 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { m_image = Utl.decodeUri(this, m_uri); } }よくあるカメラIntentからの取得、アプリではギャラリーからの取得も実装
認識画像の切り出し
楽譜の全体画像で認識をかけても大きすぎて認識できないんで
五線譜の検出編
https://qiita.com/Anadreline/items/4cf6e88c743a65b7da2c
で検出した五線譜の部分から切り出して認識用画像としました認識に必要なもの
公式のサンプルでは画像分類や物体の検出をカメラのリアルタイムプレビューで行うサンプルのため、結構なボリュームのプロジェクトになってます
今回のアプリではリアルタイムプレビューでの認識ではなく、1枚の画像から認識できればいいので、必要なものはこれだけです
公式のサンプルからClassifier.javaとTensorFlowObjectDetectionAPIModel.java
それにassetsに前回の音符検出モデルの作成編で作成したモデルファイル(frozen_inference_graph.pb)とラベルファイル(label_map.txt)の4つだけ音符の認識
TensorFlowObjectDetectionAPIModel.createで認識モデルを生成して、Classifier.recognizeImage()に認識させたい画像を放り込むと、リスト形式で認識結果が取得できる
Recognition.javaprivate static final int TF_OD_API_INPUT_SIZE = 300; private static final String TF_OD_API_MODEL_FILE = "file:///android_asset/frozen_inference_graph.pb"; Classifier detector = TensorFlowObjectDetectionAPIModel.create(getAssets(), TF_OD_API_MODEL_FILE, TF_OD_API_LABELS_FILE, TF_OD_API_INPUT_SIZE); final List<Classifier.Recognition> results = detector.recognizeImage(crop); for (final Classifier.Recognition result : results) { RectF location = result.getLocation(); //検出位置 Float conf = result.getConfidence(); //確度 String title = result.getTitle(); //ラベル名 }あとは確度の値をみて一定値以上なら採用という具合で取得
このアプリでは0.5にしてます、すこしゆるめの判断でとにかく認識率を上げようという作戦
でもまあ未検出はあるものの、誤認識はほとんどなかった