最近では現場でタブレットを使う機会も増えてきた。タブレットにはカメラがついているから保守や修繕のときには証拠写真を撮っておきたいと思うのが人情だろう。その写真をDBに入れるためにクライアントアプリを入れるのは面倒なのでブラウザですませたい。そこでreact-webcamのサンプルをTypeScriptで書いてみる。
mozmorris/react-webcamを使ってブラウザからreactでカメラを利用する。
まずは環境を作る。
$ yarn create react-app webcam-sample --typescript $ cd webcam-sample/ $ yarn add react-webcam @types/react-webcam
スクリーンショットを撮るサンプルがGitHubにあるので、それを参考にしてTypeScriptで書いてみる。
スクリーンショットを撮ったらとりあえず、imgタグに突っ込んでおく。
仕事で使うならこれをサーバ側に保存したり、canvasに流して加工できるようにする必要があるだろう。
App.tsxを編集する。
import React from "react"; import Webcam from "react-webcam"; interface State { img_src: string; } export default class App extends React.Component<any, State> { constructor(props: any) { super(props); this.state = { img_src: "" }; } capture = () => { const imageSrc = (this.refs.webcam as Webcam).getScreenshot(); if (imageSrc) { this.setState({ img_src: imageSrc }); } }; render() { const videoConstraints = { width: 1280, height: 720, facingMode: "user" }; return ( <div> <div> <Webcam audio={false} height={350} ref={"webcam"} screenshotFormat="image/jpeg" width={350} videoConstraints={videoConstraints} onUserMediaError={() => window.alert('cant access your camera')} /> </div> <div> <button onClick={this.capture}>Capture photo</button> </div> <div> <img src={this.state.img_src} /> </div> </div> ); } }
これで起動すれば、ブラウザが立ち上がってカメラへのアクセスを許可するか聞いてくる。
$ yarn start
WindowsでGoを使って外部コマンドをCMDで実行するときに、「cd」でカレントディレクトリを移動してから実行したい。
GoというよりはCMDの使い方になるが、コマンドとコマンドの間を「&」でつなぐことで続けて実行できる。
package main import ( "fmt" "log" "os/exec" ) func main() { out, err := exec.Command("cmd", "/c", "cd", "C:\\go", "&", "dir").Output() if err != nil { log.Fatal(err) } fmt.Printf("%s\n", out) }
実行すると出力される結果が文字化けしているがそれは別の問題なのでここでは気にしない。
実際にこういう使い方をするとき実行したいのはbatファイルやVBScriptだろうし、出力が必要でも日本語でなければいいし。
Visual Studio Codeで「>Go:Install/Update Tools」したときに、「Installing github.com/sqs/goreturns FAILED」になったら
CMD> go get -v -u github.com/sqs/goreturns
コマンドラインでインストールしたら問題なく入った。
scikit-learnのテキトーに作ったモデルを読み込んで、Flaskを使ってWebでもアクセスできるようにしてみる。
前に作ったモデルを読み込んで使う。
バッチ処理だけではなんなので、Webアプリに組み込んでみた。
import json from flask import Flask from flask import request from flask import abort import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.externals import joblib scaler = joblib.load("foo.scaler") model = joblib.load("foo.learn") app = Flask(__name__) @app.route('/foo', methods=['POST']) def foo(): if not request.json: abort(400) data = pd.DataFrame(request.json) for col in data.loc[:, data.dtypes == 'int64']: data[col] = data[col].astype(float) X = data.loc[:, data.columns].as_matrix() X = scaler.transform(X) y_predict = model.predict(X) return json.dumps(str(y_predict[0])) if __name__ == "__main__": app.run(debug=True, port=5000)
こんなテキトーなものでも動いてるな。
$ curl http://localhost:5000/foo -s -X POST -H "Content-Type: application/json" -d '{"YYYY": ["2018"], "MM": ["08"], "DD": ["05"], "DY": ["0"]}'
試してないけど、jQueryだとこんな感じかな。
$('#btn').click(function() { var d = {"YYYY": ["2018"], "MM": ["08"], "DD": ["05"], "DY": ["0"]}; $.ajax({ url: 'http://localhost:5000/foo', type: 'POST', contentType: 'application/json', data: JSON.stringify(d), }).done(function (data) { console.log(JSON.parse(data)); }); });
バッチ処理だけでは利用用途が限られるのと、未来の予測に必要なデータを作り込むのが大変だけど、こうやってWebで使えるようになると、入力に反応してリアルタイムに使う道が増えるから一気に活用の場所が広がるな。
あと、初めてFlaskを使ったけど、小さいものを作る分にはものすごく楽。
scikit-learnのテキトーに作ったモデルを読み込んで使ってみる。
前に作ったモデルを読み込んで使ってみる。
まずは予測したい列を除いたCSVファイル(「target.csv」って名前にする)を用意する。 前に作った時には「target」カラムがあったけど、今回はそれを予測するためのデータなのでその行はない。
YYYY,MM,DD,DY 2018,1,9,火 2018,1,10,水 2018,1,11,木 2018,1,12,金 2018,1,13,土
作ったモデルを読み込んで、予測したあと、もう一度、CSVを読んで結果を追記して「result.csv」に出力する。
import pandas as pd from sklearn.preprocessing import LabelEncoder from sklearn.externals import joblib target_csv_file = "target.csv" data = pd.read_csv(target_csv_file, encoding="SHIFT-JIS", sep=",") le = LabelEncoder() for col in data.loc[:, data.dtypes == 'object']: data[col] = le.fit_transform(data[col]) for col in data.loc[:, data.dtypes == 'int32']: data[col] = data[col].astype(float) X = data.loc[:, data.columns].as_matrix() scaler = joblib.load("foo.scaler") X = scaler.transform(X) model = joblib.load("foo.learn") y_predict = model.predict(X) data = pd.read_csv(target_csv_file, encoding="SHIFT-JIS", sep=",") tmp = [] for i in range(len(y_predict)): tmp.append(y_predict[i]) data["result"] = tmp data.to_csv("result.csv", encoding="SHIFT-JIS", sep=",")
CSVで入出力してしまえば、どの程度のデータ量が必要かはおいといてDBから出して加工して入れるっていうこれまでよく作ってきたバッチ処理と同じだから実際のシステムに組み込む場合のイメージがつきやすいな。
テキトーなCSVファイルを用意してscikit-learnをテキトーに使ってみる
機械学習の本を読んでサンプルをいじっているだけでは、わかったつもりになるだけで実際に使えるようにはならないので、本当にテキトーなデータで機械学習してみる。
まず、テキトーなCSVデータ(「train.csv」って名前で保存)を用意する。下のは一部でこんな感じでたくさん用意する。
YYYY,MM,DD,DY,target 2018,1,20,土,2038 2018,1,21,日,2039 2018,1,22,月,2040 2018,1,23,火,2041 2018,1,24,水,2042 2018,1,25,木,2043
このCSVの「target」行を予測するモデルを作ってみる。
import pandas as pd from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsRegressor from sklearn.externals import joblib train_csv_file = "train.csv" target_column_name = "target" data = pd.read_csv(train_csv_file, encoding="SHIFT-JIS", sep=",") le = LabelEncoder() for col in data.loc[:, data.dtypes == 'object']: data[col] = le.fit_transform(data[col]) for col in data.loc[:, data.dtypes == 'int32']: data[col] = data[col].astype(float) X = data.loc[:, data.columns != target_column_name].as_matrix() y = data[target_column_name].as_matrix() scaler = StandardScaler() scaler.fit(X) X = scaler.transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y) model = KNeighborsRegressor(n_neighbors=5) model.fit(X_train, y_train) print("Train score: {:.2f}".format(model.score(X_train, y_train))) print("Test score: {:.2f}".format(model.score(X_test, y_test))) joblib.dump(scaler, "foo.scaler") joblib.dump(model, "foo.learn")
こんななんの役にも立たないモデルでも一応、動くものを作った方が勉強にはなるだろう。