忍者ブログ
RoboCup Junior Japan Rescue Kanto OB

             2005~2013
本来ならPythonそのものの入門記事を予定していたのですが、

最近利用したライブラリがかな~り難解だったので、

再度使うときに忘れないようにするための備忘録を作っておくことにしました。



今回はJuliusというライブラリについてです。

これはいわゆる音声認識ライブラリでして、

某大学と某大学が研究で開発した基本無償提供のオープンソースライブラリです。

公式ページ

特徴としては、
・オースンソースであること
・マルチプラットフォームであること
・単語辞書を用いたシステムであること
・日本語のライブラリであること(英語版はあるけど公式は有償)改変した無償版を配布している方はおられました。
・認識におけるパラメータ調整が行えること(長くなるのでここではスルー
・なんかAPIがあるっぽい(試してないデス。

という具合。単語辞書ありきのシステムなので単語辞書を作らないと動いてくれません。

ネットの前評判では認識制度は上々、商用制限もないので使えると超便利という評価でした。



ただ、大学なので当然ですが、割とアカデミックな要素が強く、ぶっちゃけ使うだけでもとても難しいです。


正直ブログを調べてみると、使えた!という記事よりも使えなかった!という記事の方が目立つ程度には難しいです。

そのためネットでは情報が錯綜しています。

バージョンによっても挙動が違うとか違わないとかいう噂があるのでご注意を

また、Read meや、こちらから編集するファイルの文字コードが悉くshift-JISとなっているらしく、

Linuxユーザーの方がブチギレていました(笑)僕含め



とまぁ、前置きはこのぐらいにして本編をば。

今回は文法の解析をしてほしかったのでgrramar-kitを利用します。

まずは記事掲載時の最新版grammar-kit-4.3.1をDL、解凍します。.

起動についてはまぁ色々方法はありますが、とりあえず今回はbin/win32まで降りてみます。

cmdで
julius -C ../../testmic.jconf
と打つと起動します。エディタで開いてjconfはパス遡ればわかりますがただのconfigです。

ここで辞書ファイルの方を指定しています。初期状態ではfruitを参照しているのがわかると思います。

当該のフォルダを開いてみるとfruit.dfa fruit.term fruit.dict の3つのファイルがあると思います。

これがいわゆる辞書になります。ここに登録されている単語、文法で認識を行っています。


今micで起動していますので、マイク入力が使えるはずです。

"(りんご|蜜柑|ぶどう)([0-9]+個)? を? 下さい"  とマイクに向かってしゃべると

### Recognition: 2nd pass (RL heuristic best-first) STAT: 
00 _default: 20 generated, 20 pushed, 7 nodes popped in 190 
sentence1: <s> ぶどう を ください </s> 
wseq1: 7 0 3 4 8 
phseq1: silB | b u d o u | o | k u d a s a i | silE 
cmscore1: 1.000 0.362 0.999 0.654 1.000 
score1: -6065.491699
と、このような感じで認識してくれます。正規表現は果たしてこれであっているのか・・・?

と、まぁ動かすだけならここまでです。Win環境下だとここまでは順調でした。





ところが問題がここから。

このJuliusは辞書にある単語しか認識しないので辞書を自分で作らないと単語認識してくれません。

五十音全てを持つ辞書は標準で用意されていますが、それを使うと認識率は当然落ちるので、

ちゃんとした認識を行うのであれば、自分で辞書を生成できるようにしないといけません。


ですが、Juliusはこの辞書ファイルの生成が大変厄介です。

このあたりの内容はJuliusbook含め、公式情報だけだと解決が不可能になるので

Google先生のお力を借りることになりました。


まず辞書ファイルはfruit.dfa fruit.term fruit.dict の3つのファイルです。

これらはfuit.voca及びfruit.grammarより生成されています。

で、ここの生成に必要なファイルがmkdfa.plというファイルになります。



plです。perlです。perl環境がないと動かないんですこの子。

更にこのmkdfaを動かすにはmkfaとdfa_minimizeが必要になります。

これらは全てJuliusの実行ファイルと同じフォルダ内にあります。



で、perlということだったので、Windowsでの初手は当然cygwinです。ですが。。。

そのままではcygwinでは起動することができません。tmpフォルダの生成に失敗するので

手動でusrtmpdirを設定しないとなりません。

設定しても動かないという例は多々確認して、それに対する解決策も色々ネットにはありましたが、

正直原因となりうる項目が多すぎて自分がどのパターンなのか探すのも面倒になるのでお勧めできません。


じゃあLinuxはどうかというと、linuxではmkdfa内で呼び出されるmkfaが動きません。

自分は試していないのですが、

mkfaを動かすためのライブラリはいくつか標準でインストールされていないものがあるようなので

mkfaを単体起動して調べてみる必要があるそうです。


Windows内にPerlが入っていれば割と問題なく動くようです。が、自分の環境には入っておらず。
それでもなんか$thisdirの取得ができないらしいので、何か別の方法で実行ファイルの絶対パスを入れる必要があるっぽいです

と、いう訳で。もういろいろ難しくて面倒だったので

Pythonで書き直しました(´・ω・`)
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 1991-2011 Kawahara Lab., Kyoto University
# Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
# Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology
#
# Generated automatically from mkdfa.pl.in by configure. 
#
# Julius for python convert by radiumproduction
# Copyright (c) 2007-2017 RadiumProduction

import os
import sys
import re
import subprocess

## setup
# tmpdir
usrtmpdir = "";		# specify if any

args = sys.argv
argc = len(sys.argv)

# mkfa executable location
thisdir =  os.getcwd()
mkfabin = thisdir+"/mkfa.exe"

# dfa_minimize executable location
minimizebin = thisdir+"/dfa_minimize.exe";
# find tmpdir
tmpdirs = [usrtmpdir, os.environ.get('TMP'), os.environ.get('TEMP'), "/tmp", "/var/tmp", "/WINDOWS/Temp", "/WINNT/Temp"]

def usage():
    print "mkdfa.pl --- DFA compiler"+os.linesep
    print "usage: "+__file__+" [-n] prefix"+os.linesep
    print "\t-n ... keep current dict, not generate"+os.linesep
    exit()

tmpdir=""
for tmp in tmpdirs:
    t = tmpdirs.pop(0)
    if (t == ""):
        continue
    if (os.path.isdir(t) and os.access(t,os.W_OK)) :
        tmpdir = t
        break   

if (tmpdir == ""):
    sys.stderr.write("Please set working directory in \$usrtmpdir at "+__file__+os.linesep)
    exit(1)

#############################################################

if (argc < 2 or args[1] == "-h"):
    usage()

make_dict = 1;
make_term = 1;

CRLF = 0;

gramprefix = "";
for arg in args:
    if (arg == "-t"):
        make_term = 1
    elif (arg == "-n"):
        make_dict = 0
    else:
        gramprefix = arg
    

if (gramprefix == ""):
    usage()

gramfile = gramprefix+".grammar"
vocafile = gramprefix+".voca"
dfafile  = gramprefix+".dfa"
dictfile = gramprefix+".dict"
termfile = gramprefix+".term"
tmpprefix = tmpdir+"\g"+str(os.getpid())
tmpvocafile = tmpprefix+".voca"
rgramfile = tmpprefix+".grammar"

# generate reverse grammar file
try:
    gram=open(gramfile,'r')
    rgram=open(rgramfile,'wb')
    n=0
    for row in gram:
        row=row.rstrip('\r\n')
#       row=re.sub(r"\r+$","",row)
        row=re.sub("#.*","",row)
        if not(re.match("^[ \t]*$",row)==None):
            continue
        spdata=row.split(":")
        spword=spdata[1].split(" ")
        spword.reverse()
        rgram.write(spdata[0]+":"+" ".join(spword)+os.linesep)
        n+=1
    gram.close()
    rgram.close()
except:
    sys.stderr.write("cannot open "+gramfile+" or "+rgramfile+os.linesep)
    exit(1)

print gramfile+" has "+str(n)+" rules"+os.linesep

# make temporary voca for mkfa (include only category info)
if (not(os.access(vocafile,os.R_OK) )):
    sys.stderr.write("cannot open voca file "+vocafile)
    exit(1)

try:
    voca=open(vocafile,'r')
    tmpvoca=open(tmpvocafile,'w')
    if(make_term==1):
        gterm=open(termfile,'wb')
    n1=0
    n2=0
    termid=0
    for row in voca:
        row=row.rstrip('\r\n')
#       row=re.sub(r"\r+$","",row)
        row=re.sub("#.*","",row)
        if not(re.match("^[ \t]*$",row)==None):
            continue
        mt_data=re.match("^%[ \t]*([A-Za-z0-9_]*)",row)
        if not(mt_data==None):
            tmpvoca.write("#"+mt_data.group(1)+os.linesep)
            if make_term==1:
                gterm.write(str(termid)+"\t"+mt_data.group(1)+os.linesep)
                termid+=1
            n1+=1
        else:
            n2+=1
    voca.close()
    tmpvoca.close()
    if make_term==1:
        gterm.close()
    print vocafile+"    has "+str(n1)+" categories and "+str(n2)+" words"+os.linesep
except:
    sys.stderr.write("cannot open "+vocafile+" or "+tmpvocafile+os.linesep)
    exit(1)

print "---"+os.linesep

# call mkfa and make .dfa
status=0;
if not(os.access(minimizebin,os.X_OK)):
    # no minimization
    print "Warning: dfa_minimize not found in the same place as mkdfa.pl"+os.linesep
    print "Warning: no minimization performed"+os.linesep
    if tmpprefix.find("cygdrive")!=-1 :
        status = subprocess.check_call(mkfabin+" -e1 -fg `cygpath -w "+rgramfile+"` -fv `cygpath -w "+tmpvocafile+"` -fo `cygpath -w "+dfafile+"` -fh `cygpath -w "+tmpprefix+".h`",shell=True)
    else :
        status = subprocess.check_call(mkfabin+" -e1 -fg "+rgramfile+" -fv "+tmpvocafile+" -fo "+dfafile+" -fh "+tmpprefix+".h",shell=True) 
else :
    # minimize DFA after generation
    if tmpprefix.find("cygdrive")!=-1 :
       status = subprocess.check_call(mkfabin+" -e1 -fg `cygpath -w "+rgramfile+"` -fv `cygpath -w "+tmpvocafile+"` -fo `cygpath -w "+dfafile+".tmp` -fh `cygpath -w "+tmpprefix+".h`",shell=True)
    else :
       status = subprocess.check_call(mkfabin+" -e1 -fg "+rgramfile+" -fv "+tmpvocafile+" -fo "+dfafile+".tmp -fh "+tmpprefix+".h",shell=True)
    subprocess.check_call(minimizebin+" "+dfafile+".tmp -o "+dfafile,shell=True)
    os.remove(dfafile+".tmp")
os.remove(rgramfile)
os.remove(tmpvocafile)
os.remove(tmpprefix+".h")
print "---"+os.linesep
if (status != 0) :
    # error
    print "no .dfa or .dict file generated"+os.linesep
    exit()

# convert .voca -> .dict
# terminal number should be ordered by voca at mkfa output
if make_dict == 1 :
    nowid = -1
    try:
        voca=open(vocafile,'r')
        dictf=open(dictfile,'wb')
        for row in voca:
            row=row.rstrip('\r\n')
#            row=re.sub(r"\r+$","",row)
            row=re.sub("#.*","",row)
            if not(re.match("^[ \t]*$",row)==None):
                continue
            if not(re.match("^%",row)==None):
                nowid+=1
                continue
            else:
                a=row.split()
                name=a.pop(0)
                dictf.write(str(nowid)+"\t["+name+"]\t"+" ".join(a)+"\r\n")#+os.linesep)
        voca.close()
        dictf.close()
    except:
        sys.stderr.write("cannot open "+vocafile+"or"+dictfile+os.linesep)
        exit(1)

gene = dfafile
if make_term == 1:
    gene += termfile
if (make_dict == 1) :
    gene += dictfile
print "generated: "+gene+os.linesep

はい。解決です。訳あって、もともとここの変換プログラムはexe形式にしたかったんですよ。

ただ、なんかperlってexeに書き出すとアホみたいに重くなるって聞いたので、はい。
HelloWorldだけでで3M持ってかれるって聞いたんですけどマジです?




でもここで終わりではないんです。

mkdfaにおいて変換元となる、vocaファイルとgrammarファイルですが、

grammarファイルは文法ファイルということで、こちらで手書きで文法を定義していくものです。
○○をください、とか、○○教えて、とか認識するフレーズを定義します。


しかし、vocaファイルは単語とそれに対する読みを音素列で定義してあるファイルです。

Juliusにおける音素列はこちらのサイトにあるようなのですが、如何せんこれを見ながら打つのはアホらしい。。。



ということでJuliusにはyomi2voca.plというプログラムがありまして、

これを使って単語とそのひらがな読みの羅列でできたyomiファイルからvocaファイルを生成することができます。




でも、これもperlだったので

Pythonで書き(ry
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Julius for python convert by radiumproduction
# Copyright (c) 2007-2017 RadiumProduction

import sys
import os
import re

args = sys.argv


error=0
lineno=0


yomi = open(os.path.dirname(os.path.abspath(__file__))+"/"+args[1]+".yomi", 'r')
voca = open(os.path.dirname(os.path.abspath(__file__))+"/"+args[1]+".voca", 'w')

for line in yomi:
	if re.match(u"^%",line):
		voca.write(line)#+"\n")
		continue;
	
	word=line.split()
	word[1]=word[1].rstrip(os.linesep)

	word[1]=word[1].replace("う゛ぁ","b a ")



-------------------------------(省略)--------------------------------------


	word[1]=word[1].replace("を","o ")


	word[1]=re.sub(r"^ ","",word[1])
	word[1]=re.sub(r":+",":",word[1])
	word[1]=re.sub(r" :",":",word[1])

	lineno+=1
	if re.match(r"^[a-zA-Z:]+$",word[1]):
		if error==0:
			error=1
			print "Error: (they were also printed to stdout)"+"\n"
		print "line "+str(lineno)+":"+word[0]+"\t"+word[1]+"\n"
	voca.write(word[0]+"\t"+word[1]+"\n")
if len(args)==3:
	if args[2]=="-n":
		voca.write(r"% NOISE"+"\n")
		voca.write(r""+"\tsp"+"\n")
voca.write(r"% NS_B"+"\n")
voca.write(r"<s>"+"\tsilB"+"\n")
voca.write(r"% NS_E"+"\n")
voca.write(r"</s>"+"\tsilE"+"\n")

yomi.close()
voca.close()

こっちは単純にperlのs/gによる置換をreplaceで置換しただけです。perlの文字列処理パないわ
元ファイルからコピペ→置換でOKです

後はNS_BとNS_Eを自動で書きだす機能と-nのオプションでsp(休符)を書き出す機能を追加しました。
※NS_BとNS_Eはnoise_beginとnoise_endの略みたいです。文法の最初と最後にいるみたい。

spを入れる場合はgrammarの方でspを使わないとmkdfaでエラーを吐くのでご注意を。




という訳で作ったファイルで辞書を生成してみます。今回、prefixはtestで行います。

辞書ファイルは全て同じprefixじゃないと正しく認識されないのでご注意ください。

test.yomi
% NAME
ココア	 ここあ
チノ ちの
リゼ りぜ
千夜 ちや
シャロ しゃろ
% CHAN
ちゃん ちゃん
% CUTE
かわいい かわいい
もふもふ もふもふ

test.grammar
S       :  NS_B NAME_S CUTE NS_E
NAME_S 	:  NAME CHAN
NAME_S 	:  NAME

cmd入力
python yomi2voca test
python mkdfa test


これで最後に
generated: test.dfatest.termtest.dict
となっていれば成功です。因みに僕はpyinstallerを使っているのでexeにしてから実行しています。

文字コードは公式ではWinodowsはUTF-8、それ以外はEUCという風に指定されていますが、

先述したように、配布されているサンプルは何故か全てshift-jisです。

という訳で、どうやらshift-jisでも動くようです。

因みにwindowsのメモ帳はUTFで保存すると先頭に意味不明な文字が付加されるので、

辞書ファイルはメモ帳では作らないでください(´・ω・`)



3ファイルが生成されたらそれを、今回はとりあえずgrammar-kit直下に置きます。ちゃんとフォルダ作ろう?

生成されない場合は余分な改行とか、grammarファイルの文法ミスとかです。
入力仕様は本家様に合わせているので、変なもの入れると失敗するのはご愛敬です。


んでもって同一階層のtestmic.jconfを開いて
-gram test
-C hmm_ptm.jconf
-input mic -demo
と変更。

あとはさっきと同じようにJuliusを起動すれば・・・

pass1_best: <s> ココア かわいい </s>
pass1_best_wordseq: 3 0 2 4
pass1_best_phonemeseq: silB | k o k o a | k a w a i i | silE
pass1_best_score: -4262.506348
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 10 generated, 10 pushed, 5 nodes popped in 142
sentence1: <s> ココア かわいい </s>
wseq1: 3 0 2 4
phseq1: silB | k o k o a | k a w a i i | silE
cmscore1: 1.000 0.941 1.000 1.000
score1: -4261.156738

pass1_best: <s> チノ ちゃん もふもふ </s>
pass1_best_wordseq: 3 0 1 2 4
pass1_best_phonemeseq: silB | ch i n o | ch a N | m o f u m o f u | silE
pass1_best_score: -4179.256836
### Recognition: 2nd pass (RL heuristic best-first)
STAT: 00 _default: 15 generated, 15 pushed, 6 nodes popped in 139
sentence1: <s> チノ ちゃん もふもふ </s>
と、まぁこんな感じでリアルタイムでの音声認識が可能です。
文法はwordseqから判断できますね(´・ω・`)

Windowsで文字化けする場合は
chcp 65001
で文字コードをUTFに変えてしまいましょう。



で、記事の本題はここから。

まだpythonを使ってJuliusを動かしてないですからね。





プログラムに組み込む方法としては、JuliuslibとかいうAPIもあるようですが、

今回は簡潔に行きたかったのでsocketを用いた方法で行きます。あっちは情報が少なすぎる



まずはJuliusをモジュールモードで起動します。
julius -C ../../testmic.jconf -module
jconfで変更は可能ですが、Juliusは標準で10500番を使っているようなので、今回はそれで設定します。

クライアントのプログラムは此方。

標準出力してからファイルにも出力しています。贅沢ですね(´・ω・`)/
#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

port = 10500
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("localhost", port))

f=open("reading_data.txt",'wb')
while(1):
	data=client.recv(1024)
	print data 
	f.write(data)
これ以上記事を伸ばしたくないので、出力結果は割愛しますが

それぞれ別個で動かすと、なんかクライアントの方にリアルタイムでデータがぶっこまれます。

出力形式はxmlっぽいタグ付きの何かです。正規表現か何かで抜き出すといいんじゃないかな。これ正式名称あるのかな





というわけで今回の記事は5000兆年ぶりくらいに真面目なライブラリ備忘録でした。

やる気になったら1日かからずに全部終わったっていうか、この記事書く時間のほうが長かったくらいなので

plファイルで悩んでいる方はpythonやrubyで書き直すことをオススメします。


(^・ω・)ノ curonet at RadiumProduction
本日は電の就役日です。

予告通り本日からPythonについての記事を書いていこうと思います。今書いているのはphpだけどね!
今日は手持ちのプロジェクトを進めるために、形態素解析というものに手を出した時の話をしてみます。


そもそも形態素解析ってなんぞやという話ですが、
今までのブログの流れを完全に無視しています。ご了承ください。

昨日、唐突にOpenCVを使ったアプリケーションを作りました。

一体何がしたかったのかというと、

某ブラウザゲームの(ピーーーーー)がとてつもなく(ピーーーーーーー)ので

この際(ピーーー)を(ピーーーーーー)しようというのをふと思いつきまして、

手元にpythonがあったので、pythonを使ったOpenCVを使って実装できないかと思ってやってみました。


まず、OpenCVってなんじゃという人のための話ですが、

OpenCVとは簡単に言うと、コンピューター上で画像や動画の処置を行うためのライブラリです。

今回はこれのテンプレートマッチングを使って(ピーーー)を(ピーー)していきます。


まず最初にテンプレート画像となる(ピーーー)の画像をスクショします。

次にOpenCVに現在のPC画面のキャプチャをぶち込まないといけないのですが、

調べた限り、OpenCVには直接画面キャプチャをする方法はなかったので

今回はPILというライブラリをインストールします。今思えばOpenGL使えばよかったね!

ダウンロードはここから、Pillowを落としてきます。

今回はpython2.7を使用していくので Pillow‑2.7.0‑cp27‑none‑win32.whl をDLします。

whlファイルなので、インストールにはpipを使用しました。


pip install Pillow‑2.7.0‑cp27‑none‑win32.whl


pipがインストールされていればこんなかんじでインストールできますね。

今回はPILの中にあるImageGrabを使います。


次はOpenCVですが、これは公式サイトからDLします。

今回は、3.0はベータ版だったので2.4.10をDLしました。

これはexeファイルなので普通に起動してインストールします。特に環境変数の設定もせず入れるだけで使えました。

後はnumpyをインストールしました。これもここからDLします。

今回は面倒だったので最新版のexeファイルをDLしました。

以上で環境構築は終了です。ここからは簡単にプログラムについてです。


まずimportの部分です。


import cv2

import numpy as np

import time

import random

from PIL import ImageGrab

from ctypes import *



こんなかんじです。特記することもありませんね(´・ω・`)

次に画像キャプチャの部分です。

def ScreenCap(x1=0,y1=0,x2=0,y2=0):

       if x1==y1==x2==y2==0:

                img=ImageGrab.grab()

               img.save("cap.png")
        else:

               img=ImageGrab.grab((x1,y1,x2,y2))

               img.save("cap.png")


Javaのようにオーバーロードが使えればよかったのですが、残念ながらpythonにはないのでこうなっています。

呼び出すときに引数なしで画面全体を、引数ありで指定範囲[px]内の画像を取得してcap.pngに保存します。

次に保存した画像を呼び出します。ここではimreadメソッドを使っています。

temp = cv2.imread('img/temp.png',0)


今回はキャプチャ画像も一度保存してからimreadで再度呼び出しましたが、キャプチャした時点で保存せずに

def ScreenCap(x1=0,y1=0,x2=0,y2=0):
       
if x1==y1==x2==y2==0:

               img=ImageGrab.grab()

               cap = np.asarray(img) 

       else:

               img=ImageGrab.grab((x1,y1,x2,y2))

               cap = np.asarray(img) 
       return cap

       return cv2.cvtColor(cap, cv2.COLOR_BGR2GRAY)



とすることで、そのままOpenCVで使用することができるっぽいです。ぽいぽい言ってるのは試してないからですね。
2/25追記:グレースケールに変換する工程を忘れてました。てへぺろ
これで動作確認でました。一旦画像に保存して実行する場合とは類似度の結果が異なります。



次はテンプレートマッチングについてです。

テンプレートマッチングとは、簡単にいえば、

1つの大きな画像からある特定の箇所のある位置を検索するものです。

例えば与えられた画像がコレで
RCJ2013関東ブロックの被災者部屋です。 
探す対象であるテンプレート画像がコレであれば


このように探索画像のどの位置にテンプレート画像があるかを調べてくれます。



そしてテンプレートマッチングはプログラムにするとこんな感じになります。

def Temprate_matching(img,temp):
        res = cv2.matchTemplate(img,temp,cv2.TM_SQDIFF)
        w, h = temp.shape[::-1]
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        top_left = min_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)
        center=(top_left[0] + w/2,top_left[1] + h/2,min_val)
        return center


今回は輝度差の2乗誤差を使う方法でマッチングをしているので、

結果の最低値であるmin_valがマッチング結果となります。

今回はcenterというtupleを作って、マッチング中心点の座標及びmin_valの値をreturnするようにしています。

プログラムについては以上ですね。あとは魔法のクリック関数くらいでしょうか。

def click(posx,posy):
        windll.user32.SetCursorPos(random.randint(posx-5,posx+5),random.randint(posy-5,posy+5))
        time.sleep(random.uniform(0.05,0.1))
        windll.user32.mouse_event(0x2,0,0,0,0)
        time.sleep(random.uniform(0.1,0.2))
        windll.user32.mouse_event(0x4,0,0,0,0)


ノータイムで同じ場所に(ピーーーーーーーーー)と(ピーーーーーーーーーーーーー)ので

ここでその対策をしています。
以上OpenCVを用いた(ピーーーーーーーーーーー)の作成でした。徹頭徹尾アウトじゃねぇか(´・ω・`)

(^・ω・)ノ RadiumProduction at curonet
カレンダー
09 2017/10 11
S M T W T F S
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
最新CM
[09/25 ONE RoboCuper]
[11/19 big]
[11/11 お馬さん]
[08/08 うまごやぐらし!]
[04/20 匿名(にさせてw]
かうんた
らじぷろ目次
らじぷろ検索機
プロフィール
HN:
Luz
年齢:
23
性別:
男性
誕生日:
1994/02/15
職業:
大学生
趣味:
ラボ畜
自己紹介:
初めまして。Luzと申します。
某大学の情報学科に入りました。のんびりと生活を送るのが今年の夢です。
めーる
radiumproduction☆yahoo.co.jp
※☆を@に変更して下さい。
バーコード

PR

忍者ブログ 2007-2017,Powered by Radium-Luz-Lα+-Rescatar in RadiumProduction [PR]


Related Posts Plugin for WordPress, Blogger...