2013年12月10日火曜日

OpenEarsを使ってみた



AppCon2013で作ったBlack Rabbit
怪しさをお楽しみください。
http://fandroid-ej.org/appcon_2013/

作った物はこちら
http://www.youtube.com/watch?v=eAA2ktd_cCw
自分でもなんなんだかよくわからないけど、音声認識に対応したカメラです。w
機能は写真撮影、動画撮影、ズーム、ライトです。
UIImagePickerControllerとかも初めて使ったので苦戦しました。





前々から興味のあった音声認識のアプリを作ってみました。
使ったのはオープンライブラリーのOpenEarsというもの。

OpenEarsのサイトはこちら。
http://www.politepix.com/openears/

なにが出来るかっていうと、音声合成と音声認識。
英語とスペイン語の辞書が入ってるようで、それらを喋らせることが出来ます。

今回は元々OpenEarsで提供してるサンプルアプリを題材に、機能の分かった部分と使い方を書いていきます。
先述した公式ファイルからライブラリーをDLします。その中にサンプルアプリのファイルがあるので、それです。
ダウンロードはサイトの右側にあるここから。




使い方を学ぶ際、こちらなどを参考にさせていただきました。
http://qiita.com/shu223/items/eda02dc7d334c339ff64
http://www.politepix.com/openears/tutorial/


サンプルアプリの仕組み

1.機能


これがサンプルアプリの画面です。
Status:Pocketsphinx is now listening.となっている状態で
GO, TURN, LEFT, RIGHT, FORWARD, BACKWARD, CHANGE, MODEL
のいずれかの単語を発話すると、マイクで聞き取って合成音声が喋ってくれます。

CHANGE MODELと言うと辞書が切り替わって
MONDAY, TUESDAY, ..., SUNDAY
の曜日の単語を認識するようになります。

もう一度CHANGE MODELと言うと元のGOとかの辞書に戻る。

あとは
Input level = 聞き取り度
Output level = 合成音声の音量
Stop Listening = 聞き取り終了
Suspend Recognition = 認識を一時停止

2.FrameworkファイルとVocablaryFiles

プロジェクトファイルを開くとFrameworkとVocablaryFilesというフォルが入っています。
















Frameworkは文字通りOpenEarsを使う時に必要なフレームワークです。

問題はVocablaryFilesの方で、事前に登録してある単語の辞書だと思われます。
イマイチ中に入っているファイルの内容はわかりませんが、おそらく辞書です。
写経してる時、このファイルを追加するのを見落として時間がかかりました。要注意。

3.クラス紹介

OpenEarsを使うのに必要なクラスは3つ。
FliteControllerクラスとSltクラスとPocketsphinxControllerクラスの3つ。

・FliteControllerクラス
合成音声を受け持つクラス。
- (void) say:(NSString *)statement withVoice:(FliteVoice *)voiceToUse;
メソッドで音声を再生させたり、プロパティで音声の高低や再生速度を変えたり出来ます。

・Sltクラス
合成音声そのもののクラス。

・PocketsphinxController
音声認識を受け持つクラス。



4.ざっくりした解説

最初に単語の辞書を登録する必要があります。






認識させたい単語を入れてやればOKです。


あとは基本的にデリゲートをセットして
- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID;
メソッドの中に単語が発話された時の処理を書くっていうので使えます。

















サンプルコードだと↑の部分。
hypothesisというのは認識された単語を持つ変数。

if([hypothesis isEqualToString:@"HOGE"])
{
処理
}
ってやれば認識した単語に応じた処理をさせてやることができます。



ざっくりと一通りコード読んで大体使えるようになったけど、まだ理解が足りてないので中途半端です。
サンプルで大体必要な機能が載ってるので、それを元に書いたり読んだりしていけば良いと思います。

2013年2月23日土曜日

h_Mission1

現在プログラマーのHさんにiOS開発を教えていただいていまして、課題をだしていただいています。
その課題の復習も兼ねてブログにまとめようと、と、と


課題1:UITableViewで1〜100までをリスト表示する画面を作ってください。ただし、素数の場合は文字色を赤とすること。通常は黒。



プロジェクト名:h_Mission1



StoryBoardにはTableViewを貼っただけ。































ViewController.h



説明
コメントの通り。


ViewController.m


説明
viewDidLoad内では1〜100の数字の配列を用意する。
ViewController.hで宣言したarrayのcapacityを100用意する。100個数字入れるから。
for文で100回数字を足す式をループさせる。

[array addObject:[NSNumber numberWithInteger:i]];

ではint iで用意した数字をarrayに入れる。
intはプリミティブ型という単純な数字しか扱えないもので、NSArrayはオブジェクト型しか扱えないのでint iをオブジェクト型のNSNumberに変換してから入れてやる。



TableViewに表示できる行の数は端末の画面の関係上限られてくる。
なので計算して用意した値には待機していてもらわなきゃいけない。
そこで用意するのがこれ。

cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

これは画面をスクロールしていった時に画面にデータを表示してくれる一文。
キュー=先に入力したデータが先に出力されるという特徴をもつ、データ構造体の一種。
とのこと。


コメントアウトしてある文に

cell.textLabel.text = [array objectAtIndex:indexPath.row];

があるけれど、これだとうまくarrayが入力されない。
というのも、textで出力するには数字では駄目で、Stringにしてやらないといけないから。

cell.textLabel.text = [NSString stringWithFormat:@"%d", ((NSNumber*)[array objectAtIndex:indexPath.row]).integerValue];

だとうまくいく。
[NSString stringWithFormat: でNSNumberをNSString型に変換して入力する。
ポインタとは、他の変数やメモリ領域のアドレスを示す変数のことで、間接的にデータにアクセスするもの。
integerValueは整数値を返り値にしているということ。

cell.textLabel.textColor = [UIColor redColor];
これは色を赤色に変えているだけ。



結果






























うまくいきましたー。
でも素数がまだできていません。
次の木曜までに素数の部分は仕上げます。



始めたばかりで説明の仕方とか、プログラミングの用語の使い方とか、つたないところが多々ありますが、ツッコミいただければありがたいです!




2012年10月30日火曜日

実績、その他バイト探しに向けて


この度バイトを探す事になったので自分に関する詳細をこちらに載せます。

スマートフォン等のアプリの開発をするような仕事をしたいと思っていますが、まだまだ勉強が足りていないというのと、まずはお金を稼ぐというノルマがあるので自分が長く使い、親しんできたパソコンを使ったバイトをしたいと考えています。

・最近の活動
・これからの抱負
・これまでの実績

を以下に書いていきます。



○最近の活動

最近はAndroidとiOSのプログラミングを初心者向けの本とWebを使って写経したりしていますが、まだ自分でコーディングするレベルには達していません。iOSは本を2冊、Androidは本ブログで取り扱っているようなものを写経しています。特に興味があってこれからやっていきたいのはiOSで、ゲームが好きなのでそういう開発もしていきたいです。IT関係のイベント・勉強会にも参加して勉強させていただいています。

ほかにはTOEICに向けた英語の勉強、学校のドイツ語の勉強に熱中しています。

太極拳・長拳(カンフー)においては次の12月の県大会に向けて週3回練習をしています。



○今後の抱負

・今年6月にAppleのデベロッパー登録をしたので、来年期限が切れるまでに最低一本は iOSアプリをリリースする。

・来年1月のTOEICまで勉強して、挑戦して腕試しし、その後も受け続ける。大学卒業までにはTOEICのスピーキングのテストにも手を出してみたい。

・長拳では新しく槍をひたすらに練習する。神槍・李書文を目指して。




○実績

・第14回宮城県児童生徒コンピュータ・ソフトウェア作品展(2003年)
 銅賞「1年生用計算プログラム・3.4年生用漢字」
 VB.netを使って夏休みに勉強し、開発しました。


・第14回JOCジュニアオリンピック武術太極拳大会(2006年)
 男子 ジュニア太極拳1 第3位

・第18回宮城県武術太極拳選手権大会(2010年)
 男子 長拳A 第1位

・第18回宮城県武術太極拳選手権大会(2010年)
 男子 太極剣・刀 第3位
                    

 上の動画は3位を取った時の剣の表演です。

2012年9月13日木曜日

iOS6

iOS6を家にあるiPad2にいれてみた。






siriちゃんが動くと期待して!!






siriちゃんが動くと期待して!!!!














動きませんでした(^q^)




公式ページを見ると、iPhone 5、iPhone 4S、iPad(第3世代)、iPod touch(第5世代)でのみ動くとのこと。

残念...orz

mapも特に新しくはなっていないようだった。

とりあえず新しいiPadがあるので、そっちに入れてしばらく遊んでみようかと。



siriちゃん楽しみ!!



2012年6月25日月曜日

誕生日プレゼント



この本を勝ってもらいました。

http://www.amazon.co.jp/dp/4839941734/ref=cm_sw_r_tw_asp_ER4uD.13VD6ST

次はこの本をやっていきます。
載せていくかはわかりませんが...←

とりあえずこの本の前に一冊入門書を終わらせたので、iOSを少しずつやっていくつもりです。
Developper IDも取るので、年内に2本くらいはアプリをリリースしてみたいなぁ...とか。

2012年4月3日火曜日

3月中の成果

Javaでパズルアプリを本を見て写経しました。
長いのでコピペします。
なのでインデントはめちゃくちゃですが...
そしてまだ途中なのであしからず...



Project Name:ImagePuzzle

ImagePuzzleActivity.java



package jp.rutles.puzzle;

import android.app.Activity;
import android.os.Bundle;
import android.view.*;

public class ImagePuzzleActivity extends Activity {
public float disp_w,disp_h;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    Window window = getWindow();
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    WindowManager manager = window.getWindowManager();
    Display disp = manager.getDefaultDisplay();
    disp_w = disp.getWidth();
    disp_h = disp.getHeight();
    setContentView(R.layout.main);
    }
}



PuzzleBoard.java




package jp.rutles.puzzle;

import java.util.*;

import android.graphics.*;

public class PuzzleBoard {
public static final int CENTER = 0;
public static final int NORTH = 1;
public static final int SOUTH = 2;
public static final int EAST = 3;
public static final int WEST = 4;
private Bitmap image;
private float x,y;
private int[] data;
public int place;
private static final int row = 6;
private static final int col = 4;
private float pW = 100f;
private float pH = 100f;
public int count = 0;

public PuzzleBoard(float x, float y, float dw, float dh, Bitmap image) {
super();
this.x = x;
this.y = y;
pW *= dw;
pH *= dh;

this.image = image;
data = new int[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1};
place = 23;
}

public void init() {
for (int i = 0;i < 200;i++){
Random r = new Random(new Date().getTime());
int a = r.nextInt(data.length);
int b = r.nextInt(data.length);
int val = data[a];
data[a] = data[b];
data[b] = val;
}
for (int i = 0;i < data.length;i++)
if (data[i] == -1) place = i;
count = 0;
}

public void draw(Canvas canvas){
int n = 0;
for (int i = 0;i < row;i++){
for (int j = 0;j <col;j++){
int c = data[n] % col;
int r = (int)(data[n] / col);
if (data[n] != -1){
canvas.drawBitmap(image,
new Rect(x + c * pW , y + r * pH, x + c * pW +pW, y + r * pH + pH),
new Rect(x + j * pW, y + i * pH, x + j * pW + pW,y + i * pH + pH),
new Paint());
}
n++;
}
}
}

public void move(int move){
int c =place % col;
int r = (int)(place / col);
int c2 = c;
int r2 = r;
switch(move){
case NORTH:
if (r2 < row - 1) r2++;
break;
case SOUTH:
if (r2 > 0) r2--;
break;
case WEST:
if (c2 < col - 1) c2++;
break;
case EAST:
if (c2 > 0) c2--;
break;
}
int n = data[r * col + c];
data[r * col + c] = data[r2 *col + c2];
data[r2 * col + c2] = n;
for (int i = 0;i <data.length;i++)
if (data[i] == -1) place = i;
count++;
}

public boolean checkFinish(){
boolean flg = true;
for (int i = 0;i < data.length - 1;i++)
if (data[i] != i) flg = false;
return flg;
}
}






PuzzleView.java



package jp.rutles.puzzle;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.*;
import android.widget.Toast;

public class PuzzleView extends View {
private static final int btn_x = 50; // ボタンの横位置
private static final int btn_y = 768; // ボタンの縦位置
private static final int btn_w = 390; // ボタンの横幅
private static final int btn_h = 40; // ボタンの縦幅
private static final int board_x = 40; // ゲーム版の横位置
private static final int board_y = 126; // ゲーム版の縦位置
private static final int score_x = 60; // テキストの表示横位置
private static final int score_y = 73; // テキストの表示縦位置
private ImagePuzzleActivity puzzle; // Puzzleクラス
private PuzzleBoard board; // PuzzleBoardクラス
private Drawable back,btn1,btn2; // 使用するイメージ
private booleanbtn_down,isPlaying; // ボタンの状態、プレイ中の状態
private int pressX,pressY,upX,upY; // ボタンを押した時、話した時の位置
public PuzzleView(Context context) {
super(context);
init(context);
}
public PuzzleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
puzzle = (ImagePuzzleActivity)context;
Resources resources = context.getResources();
back = resources.getDrawable(R.drawable.back);
btn1 = resources.getDrawable(R.drawable.start);
btn1.setBounds(btn_x, btn_y, btn_x + btn_w, btn_y + btn_h);
btn2 = resources.getDrawable(R.drawable.start2);
btn2.setBounds(btn_x, btn_y, btn_x + btn_w, btn_y + btn_h);
Bitmap img = BitmapFactory.decodeResource(resources, R.drawable.image1);
board = new PuzzleBoard(board_x, board_y, img);
btn_down = false;
isPlaying = false;
}
@Override
protected void onDraw(Canvas c) {
c.drawColor(Color.BLACK);
int w = this.getWidth();
int h = this.getHeight();
back.setBounds(0, 0, w, h);
back.draw(c);
board.draw(c);
if (btn_down){
btn2.draw(c);
} else {
btn1.draw(c);
}
Paint p = new Paint();
p.setTextSize(30f);
c.drawText("count: " + board.count, score_x, score_y, p);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int x = (int)event.getX();
int y = (int)event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
pressX = x;
pressY = y;
if (isIn(x,y,btn1.getBounds())){
btn_down = true;
isPlaying = true;
board.init();
Toast toast = Toast.makeText(puzzle, "スタート!", Toast.LENGTH_LONG);
toast.show();
}
break;
case MotionEvent.ACTION_UP:
btn_down = false;
upX = x;
upY = y;
if (isPlaying) checkMove();
break;
}
invalidate();
return true;
}
public boolean isIn(int x, int y,Rect rect){
return x > rect.left && x < rect.right && y > rect.top && y <rect.bottom;
}
public void checkMove(){
int dx = upX - pressX;
int dy = upY - pressY;
if (dx < -100) board.move(PuzzleBoard.WEST);
if (dx > 100) board.move(PuzzleBoard.EAST);
if (dy < -100) board.move(PuzzleBoard.NORTH);
if (dy > 100) board.move(PuzzleBoard.SOUTH);
isPlaying = false;
Toast toast = Toast.makeText(puzzle, "おめでとう!", Toast.LENGTH_LONG);
toast.show();
}
}


main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.donroid.com/apk/res/jp.rutles.puzzle"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
  <jp.rutles.puzzle.PuzzleView
      android:id="@+id/PuzzleView01"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      />

</FrameLayout>



うん、全然理解はしてません...;
まだ写経も全部終わってません!;




2012年3月11日日曜日

Android Education Program:Lesson3 ver1.1

ギブアップ...。
なんか全然出来ぬ...。



Mission3Activity.java



package jp.sendai.tanaka.mission3;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class Mission3Activity extends Activity {
    //TextViewをtxtとして置く
    public TextView txt;
    //int型のcountメソッドを使用
    int count;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button btn1 =(Button)this.findViewById(R.id.button1);
        txt = (TextView)findViewById(R.id.textview1);
        
        //ボタンの反応
        btn1.setOnClickListener(new View.OnClickListener(){
             //ボタンを押した時の反応
            public void onClick(View v) {
                count++;
                String c = String.valueOf(count);
                if(c = 3)
                    txt.setText("さん");
                else if(c = 6)
                    txt.setText("ろく");
                else if(c = 9)
                    txt.setText("きゅう");
                else if(c = 12)
                    txt.setText("じゅうに");
                else
                    txt.setText(c);
            }
        });
    }
}



if(c = 3)、else if(c = 6,9)の中でエラーが起きている。
型の不一致だと言われた。
キャストしてあげればいいのかな...?
しかしどうやって...。