SotaでQRコードを読み取る

今回はSotaにQRコードを読み込ませてみる。
Sotaに何かしら入力をしたい場合に、QRコードを使うというのは結構あるので、実装の仕方が分かると便利だと思う。

[公式のGithub](https://github.com/vstoneofficial/SotaSample)の[QRCodeTestクラス](https://github.com/vstoneofficial/SotaSample/blob/master/src/jp/vstone/sotatest/QRCodeTest.java)もあるが、たぶんこれだとうまく動かせないと思うので、改良してみた。
(そのうち修正するんじゃないかな)

環境はいつも通り。

|対象|OS、バージョン|
|:--|:--|
|PC|Windows10 x64|
|Sota|1.4.0|
|VstoneMagic|1.0.6047.29447(VstoneMagic_update20160803)|
|VstoneMagicのSotaライブラリ|1.4.0|

VstoneMagicの操作方法等については、[SotaでHelloWorld](http://qiita.com/satoshi_noda/items/4cec6b8c80e44aa0f4ce)を参照。
今回のソースは[ここ](https://github.com/scarviz/SotaQRCodeReader)。

# QRコード読み込みクラスを作成する
[QRcodeReaderクラス](https://github.com/scarviz/SotaQRCodeReader/blob/master/src/jp/co/mysota/QRcodeReader.java)を作成する。
このクラスはテキストエディタで作成している。
QRコードはZXingを利用してデコードしている。

## カメラオープン処理
まずは、QRコードを読み込ませるため、カメラをオープンする。
CameraCaptureクラスのインスタンスを生成し、openDeviceで「/dev/video0」(通常はこれがカメラデバイス)を指定する。

```java:QRcodeReader.java
// VGAサイズのグレースケールでキャプチャするように設定
CameraCapture cap = new CameraCapture(CameraCapture.CAP_IMAGE_SIZE_VGA, CameraCapture.CAP_FORMAT_BYTE_GRAY);
// カメラデバイスをオープン
cap.openDevice("/dev/video0");
```

## スナップ処理
snapメソッドでスナップし、RawtoBufferedImageでイメージデータを取得する。

```java:QRcodeReader.java
cap.snap();
BufferedImage image = cap.RawtoBufferedImage();
```

## デコード処理
イメージデータからBinaryBitmapを生成し、decodeメソッドでデコードした結果を取得する。
読み取ったコンテンツはgetTextメソッドで取得する。

```java:QRcodeReader.java
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
// デコード
Reader reader = new MultiFormatReader();
Result result = reader.decode(bitmap);

// コンテンツ読み取り結果
content = result.getText();
```

QRコードが読み込めなかった場合にリトライをしたいので、スナップ処理とデコード処理をリトライできるようにしておく。

## クローズ処理
最後にカメラデバイスをクローズする。

```java:QRcodeReader.java
cap.close();
```

# VstoneMagicでの実装
## QRコード読み込みクラスをインポートする
VstoneMagicで新規ワークスペースを作成し、エクスプローラのjp.co.mysotaパッケージ以下に、QRコード読み込みクラスをインポートする。
`右クリックメニュー > 追加 > クラスのインポート`
で、さっき作成したQRcodeReader.javaを指定する。
![001.png](https://qiita-image-store.s3.amazonaws.com/0/141310/457592ef-c8cd-8689-35d6-003564e0f94a.png)

## リトライ回数用の変数宣言ブロックを用意
リトライ回数を設定する変数を用意する。
`ツールボックス > プリミティブ > 変数宣言`
をコンストラクタの中に入れる。
![002.png](https://qiita-image-store.s3.amazonaws.com/0/141310/f500f23a-d89b-ff28-60f4-66eb4a5db94d.png)

追加した変数宣言ブロックをダブルクリックし、ダイアログを表示する。
名前を「qrReadRetryCnt」とし、
`initParamの値をダブルクリック > 定数入力:intの値に30`
として、OKボタンをそれぞれ押してダイアログを閉じる。
OKボタンを押さないと反映されないので、気を付けること。
![003.png](https://qiita-image-store.s3.amazonaws.com/0/141310/e388857f-50b1-9baa-5227-f2845e1a566c.png)

## readQRCodeメソッドブロックの実装
メソッドブロックを追加する。
`ツールボックス > プリミティブ > メソッドブロック`

追加したメソッドブロックをダブルクリックし、methodNameを「readQRCode」とし、typeを「String」に設定する。このtypeは戻り値の値になるので、最終的にQRコード読み取り結果を返すように実装する。
![004.png](https://qiita-image-store.s3.amazonaws.com/0/141310/1e52ae03-3411-d0f7-f5d3-604f4fe4bd3c.png)

readQRCodeメソッドブロックに、変数宣言ブロックを追加し、名前を「content」、typeを「String」、initParamをnullとする。
![005.png](https://qiita-image-store.s3.amazonaws.com/0/141310/bfa8926c-27d7-565c-7c28-895bea9ca829.png)

returnブロックを追加する。
`ツールボックス > プリミティブ > return`
追加したreturnブロックをダブルクリックし、ダイアログを表示する。
returnValueの値をダブルクリックし、変数選択から「content」(さっき追加した変数)を選択する。
OKボタンをそれぞれ押して、ダイアログを閉じる。
![006.png](https://qiita-image-store.s3.amazonaws.com/0/141310/5fd47f36-4670-7e81-6850-5fc4c66d6949.png)

自由記述処理ブロックを追加する
`ツールボックス > RobotLib > 自由記述処理`

自由記述処理ブロックは、その名の通り、自由にコードを記述することが出来る。
ただのテキストボックスなので、スペルミスに気付かなかったり、どこに何が実装されているか分からなくなるので、あまり多用しないようにする方が良いと思う。
今回は、QRcodeReaderクラスのインスタンスを生成し、readメソッドを呼び出す処理を記述する。

追加した自由記述処理ブロックをダブルクリックし、textsの値をダブルクリックする。
![007.png](https://qiita-image-store.s3.amazonaws.com/0/141310/cf4b4a04-5351-015b-9561-d7ca3c3efabf.png)

下記を記述する。

```java
QRcodeReader reader = new QRcodeReader();
content = reader.read(qrReadRetryCnt);
```
![008.png](https://qiita-image-store.s3.amazonaws.com/0/141310/8c4619cb-2627-f6bb-7e93-b9a34c67ca82.png)

## メインメソッドの実装
mainメソッドブロックに、QRコード読み込み前に発話(ここでは「20センチくらい離した位置で、QRコードを見せてね」としている)ブロックを追加し、QRコード読み込み結果のコンテンツを受け取る変数宣言ブロック(content)を追加する。

readQRCodeメソッドブロックを追加する。
`エクスプローラ > mymainクラス > readQRCodeメソッド`
![009.png](https://qiita-image-store.s3.amazonaws.com/0/141310/08bf9667-3f6b-5108-0b27-6f69c775ecc9.png)

追加したreadQRCodeメソッドブロックを選択し(ダブルクリックではダイアログは表示されない)、プロパティのenableGetReturnの値を「True」(デフォルトではfalseになっている)に変更し、recvVariableの値に「content」(さっき追加した変数)を選択する。
![010.png](https://qiita-image-store.s3.amazonaws.com/0/141310/8f52700f-d8ff-84db-dee6-34620d9b6732.png)

QRコード読み取り結果のコンテンツをとりあえず発話させてみる。
発話ブロックを追加し、発話内容をcontentに設定する。
![011.png](https://qiita-image-store.s3.amazonaws.com/0/141310/c6e8dcd2-4cd7-e086-994f-953528cb1d94.png)

実行すると、発話 > QRコード読み取り > 結果を発話　という流れになる。
QRコード読み取り結果のコンテンツがnullだと、QRコード読み取りに失敗した扱いなので、分岐させて処理すると良いと思う。