LoginSignup
4
0

More than 3 years have passed since last update.

星を使った(使ってない)AR

Last updated at Posted at 2019-12-07

きっかけ

レジャー好きな人の支援

AR_FukuokaでLTした。やったことは星を利用したAR(*1)。この年になって星を使う事になるとは思わなかったが、やってよかったと思ってる。

ペルセウス.png

星座を利用するって壮大

*1: 星は利用してない

やること

Androidのカメラで星とかを映すと何の星座か教えてくれるクリスマスにぴったりなアプリ。

image.png

それっぽい画像も透過的に表示してすごいクリスマス感が出るはず。
動きはこんな感じ。

  • カメラを有効化
  • ボタンを押して「何の星座か教えて」の音声を認識する
  • カメラ画像に近似した星座を特定する
  • 星座の方向や位置に合わせて星座のイメージを透過的に表示
  • 音声で「これは○○座です」って発話

時間もないので下記点は妥協する。

  • 「何の星座か教えて」以外の音声も認識する
  • 星座の位置や方向に合わせない
  • 何が映っても全部ペルセウス
  • 音声は「これはペルセウスです」固定

何でもペルセウス。ペルセウス最高。

準備

OpenCVを使う。

Androidで OpenCV 4を使う方法とカメラライブビューの表示という素晴らしすぎる記事があるので同じところまでやる。この記事すごい。すごく助かる。

で 、  色  々  や  り  ま  し  た  !  !

が、2019.12.06時点のAndroidStudioだと動かないことが判明したのでOpenCVのカメラライブビューをあきらめることにした。参照は残したまま別の方法を探る。

尚、できなかった理由は下記の通り。

  • OnUnhandledKeyEventListenerがないとか言われてCameraViewが生成できない
    • compileSdkVersionを27以下にすればOK☆
      • AAPTでリソースのマージエラー。compileSdkVersionが28以上じゃないと使えないものが混ざる
      • compileSdkVersionを28以上にすればOK☆
        • OnUnhandle(ry

多分すごい人が何とかすんじゃなかろうか。

改めて準備

Android SDKのCamera2を使う。

Android, Kotlin + Camera API v2 でカメラ機能を実装するという素晴らしすぎる記事があるので同じところまでやる。この記事すごい。すごく助かる。

image.png

ここまでできれば問題ないはず

SurfaceView + Camera2で実装した。コードは後でアップするのでそっちを見てほしい。
一つだけ注意点を上げるとすれば、AndroidのCamera2はややこしいの一言に尽きる。

星座を教えてほしい的な音声を認識させる

コード書くのが面倒なので、怒りを爆発させて地球人を少しだけ超えるを流用する。
画面タップしたらインテント投げる感じにする。

SurfaceViewでイベント取って

surfaceView.setOnClickListener(object: View.OnClickListener{
    override fun onClick(view: View?) {
    DetectHoshiMitai()
    }
})

星座を認識したら(してないけど)message投げて

fun DetectHoshiMitai(){
    val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
    intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
    intent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true)
    intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName)
    val recognizer = SpeechRecognizer.createSpeechRecognizer(applicationContext)
    recognizer.setRecognitionListener(object: RecognitionListener {
        override fun onReadyForSpeech(p0: Bundle?) { }
        override fun onRmsChanged(p0: Float) { }
        override fun onBufferReceived(p0: ByteArray?) { }
        override fun onPartialResults(p0: Bundle?) { }
        override fun onEvent(p0: Int, p1: Bundle?) { }
        override fun onBeginningOfSpeech() { }
        override fun onEndOfSpeech() { }
        override fun onError(p0: Int) {

        }
        override fun onResults(results: Bundle?) {
            if (results == null) {
                return
            }
            val texts = results!!.getStringArrayList(android.speech.SpeechRecognizer.RESULTS_RECOGNITION)!!
            var detectKeyword = false
            for (text in texts) {
                if (text.indexOf("星座") >= 0  ||
                    text.indexOf("精度") >= 0  ||
                    text.indexOf("制度") >= 0  ||
                    text.indexOf("正座") >= 0  ) {

                    detectKeyword = true
                }
            }
            if (!detectKeyword){
                val message = Message.obtain()
                message.what = DETECTED_NEED_SEIZA
                handler.sendMessage(message)

            }
        }
    })
    recognizer.startListening(intent)
}

handlerで受ける

handler = object:Handler(){
    override fun handleMessage(msg: Message) {
        when(msg.what){
            WAIT_CREATE_CAMERA ->{
                if(state == StateInit){
                    state.enter()
                }
            }
            DETECTED_NEED_SEIZA->{

            }
        }
        super.handleMessage(msg)
    }
}

星座を認識して星座を出しつつ教える(星座の認識はしない、出すのも教えるのもペルセウスのみ)

「この星座はペルセウスです」って音声出す。

Handlerで受け付ける

handler = object:Handler(){
    override fun handleMessage(msg: Message) {
        when(msg.what){
            WAIT_CREATE_CAMERA ->{
                if(state == StateInit){
                    state.enter()
                }
            }
            DETECTED_NEED_SEIZA->{
                TeachPeruseusu()
                WritePeruseusu()
            }
            PERUSEUS_HIDING->{
                peruseusuImageView.alpha = peruseusuImageView.alpha * 0.9f
                if(peruseusuImageView.alpha <= 0.1){
                    peruseusuImageView.visibility = View.INVISIBLE
                } else{
                    handler.sendEmptyMessageDelayed(PERUSEUS_HIDING, 100)
                }
            }
        }
        super.handleMessage(msg)
    }
}

ペルセウス言う

fun TeachPeruseusu(){
    if(tts.isSpeaking){
        tts.stop()
    }
    tts.setPitch(0.1f)
    var map = HashMap<String,String>()
    map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "PERUSEUS")
    tts.speak("この星座はペルセウスです", TextToSpeech.QUEUE_FLUSH, map)
}

ペルセウス出す。

ペルセウスのImageViewを用意して

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        tools:layout_editor_absoluteX="0dp"
        tools:layout_editor_absoluteY="0dp"/>

    <ImageView
        android:id="@+id/peruseusuImageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        android:src="@drawable/perseus"
        tools:layout_editor_absoluteX="0dp"
        tools:layout_editor_absoluteY="0dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

透過的に出す

fun WritePeruseusu(){
    peruseusuImageView.alpha = 0.5f
    peruseusuImageView.visibility = View.VISIBLE
    handler.sendEmptyMessageDelayed(PERUSEUS_HIDING, 100)
}

ふりかえり

猫とかティッシュとかでやるととてつもなくくだらなくて楽しい

image.png

この星座もペルセウス

4
0
2

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