mrubyでWebカメラを黒い画面にそのまま表示できるようにした
おはようございます。切り替えの遅かった長男が最近ではすっかり、お気に入りのYoutubeを見ていても、お風呂の号令でさっと、お風呂に来るようになりました。しかし、次男の悪さが今度は目立ってしまってます。まぁ、長男もそうだったから、まぁ、いいかぁ。っとこれだから次男は。。。@kjunichiです。
背景
長編まとめ・Sixel Graphics復活への動き(1) - Togetter
libsixelの使い方
// gcc `pkg-config libsixel --cflags --libs` main.c // ./a.out > test.sixel #include <stdio.h> #include <stdlib.h> #include <sixel.h> static int sixel_write(char *data, int size, void *priv) { return fwrite(data, 1, size, (FILE *)priv); } static SIXELSTATUS output_sixel(unsigned char *pixbuf, int width, int height, int ncolors, int pixelformat) { sixel_output_t *context; sixel_dither_t *dither; SIXELSTATUS status; context = sixel_output_create(sixel_write, stdout); dither = sixel_dither_create(ncolors); status = sixel_dither_initialize(dither, pixbuf, width, height, pixelformat, SIXEL_LARGE_AUTO, SIXEL_REP_AUTO, SIXEL_QUALITY_AUTO); if (SIXEL_FAILED(status)) return status; status = sixel_encode(pixbuf, width, height, pixelformat, dither, context); if (SIXEL_FAILED(status)) return status; sixel_output_unref(context); sixel_dither_unref(dither); return status; } int main(int argc,char **argv) { SIXELSTATUS status; int WIDTH = 128; int HEIGHT = 128; unsigned char *pixbuf; pixbuf = malloc(sizeof(char)*WIDTH*HEIGHT*3); for(int h=0; h < HEIGHT; h++) { for(int w=0; w<WIDTH;w++) { int index = 3*(h*WIDTH+w); int v = (w*h)%255; pixbuf[index] = 0; pixbuf[index+1]=v; pixbuf[index+2]=0; } } status = output_sixel(pixbuf, WIDTH,HEIGHT,256,SIXEL_PIXELFORMAT_RGB888); if (SIXEL_FAILED(status)) { fprintf(stderr, "%s\n%s\n", sixel_helper_format_error(status), sixel_helper_get_additional_message()); return status; } printf("test\n"); }
画像サイズと、RGBの順にunsigned charが並んだ配列を渡せば、良きに計らってくれることが分かった。
mruby-webcamの対応
JPEG出力一択だったところをWebcam#setFmtメソッドを新設して、 "jpg","ppm"等のファイル拡張子による指定を可能として、 libsixelで処理し易い、ppm形式での出力を実装した。
実装と言っても、
imencode(".jpg", mat, buff, param);
と固定だった拡張子の指定を以下の様に可変にしただけ。
imencode(type.c_str(), mat, buff, param);
mruby-webcamでカメラの映像をppm形式で出力する
cam = Webcam.new cam.setFmt "ppm" cam.capture {|img| # img : PPMのP6形式で渡される。 puts img.length } cam.start
mruby-sixelの作成
mrbgemの概要
libsixelにRubyのGemを参考に
encoder = SixelEncoder.new encoder.encode_from_ppm ppm_image_buf
動かす
必要な物
- sixelに対応したターミナルエミュレーター
OSX,Linuxではmltermを用意すれば、試せる。WindowsでもRLoginから試せる。
参考資料
と
- libsixel本体
スペースキーを押すと、端末に画像が表示される。
cam = Webcam.new encoder = SixelEncoder.new cam.setFmt("ppm") cam.capture {|img| puts "\ec" encoder.encode_from_ppm img } cam.start
成果物
macOSでやるには
Undefined symbols for architecture x86_64:
— kjunichi (@kjunichi) 2017年2月25日
"GENERATED_TMP_mrb_mruby_sixel_gem_init
"GENERATED_TMP_mrb_mruby_sixel_gem_final
macOSだとclangが内部的に使われているのと、Linuxだとgccだから?現時点ではさっぱり。
— kjunichi (@kjunichi) 2017年2月25日
まとめ
前々から、sixel表示を手元の環境で試したと思いながら数年経ってしまったが、 2017年にようやく実現でき、mruby-sixelなるmrbgemも作成することが出来た。
関連記事
mrubyつながり
黒い画面つながり
Webカメラつながり
- GoでFaceTime HDカメラやWebカメラを使う
- WindowsでmrubyからGoで作ったライブラリを呼び出して、Webカメラの画像をコマンドプロンプトに表示した
- RustでWebカメラの映像をコマンドプロンプトに出すコマンドを作った
9年前の記事
6年前の記事
3年前の記事
アメッシュでECONNRESETを食らっててslackbotが死んでた件
おはようございます。次男の保護者会に行けずに、個別に面談する予定でしたが、電車の人身事故で保育園のお迎え時間もぎりぎりになり面談はなくなり、資料をもらうだけになりました。まぁ次男はうまいことやってることが予想されるのであんまり気にしてません。@kjunichiです。
背景
気づいたら、botkitで作ってHerokuにあげていたslackbotが死んでました
調査
このbotは「雨どう」と尋ねると、東京アメッシュの画像を張り付ける機能があり、 ここでエラーが起き、node.jsが死んでました。
原因
エラーの原因は、アメッシュからJPEGファイルを取得する際なぜか、通信途中でECONNRESETがかかり、 JPEGファイルの一部が欠落した状態でした。
2017-02-09T22:20:00.602972+00:00 app[web.1]: http://tokyo-ame.jwa.or.jp/mesh/000/201702100715.gif 2017-02-09T22:20:01.290589+00:00 app[web.1]: { Error: read ECONNRESET 2017-02-09T22:20:01.290599+00:00 app[web.1]: at exports._errnoException (util.js:1026:11) 2017-02-09T22:20:01.290600+00:00 app[web.1]: at TCP.onread (net.js:569:26) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' } 2017-02-09T22:20:03.239987+00:00 app[web.1]: Premature end of JPEG file
対策
Node.jsでの定番のハンドリングできなかった例外をキャッチして続行することで、bot自体は 死なないようにできました。
process.on('uncaughtException', function(err) { console.log(err); });
ECONNRESETへの対応
これが謎。 公式のhttp.getの解説だと
getの外でerrorをとらえてはいるが、このやり方だと、今回設定したuncaughtExceptionまでいってしまった。
また、連続して画像を取得するのが悪いのかと思い、各レイヤーごとにウェイトを入れてアクセスしてみたが、 これもダメだった。
関連記事
- Node.jsでターミナル.appにアメッシュを表示させてみた
- アメッシュの画像を表示するslackのボットをbotkitを使ってDockerイメージにしてherokuで動かした
- herokuでbotkitを動かしGoogle Calendar APIを使う
- DockerのAlpine Linuxでタイムゾーンでハマった
- herokuにデプロイしてたSlackボット(Botkitベース)を治した
9年前の記事
6年前の記事
5年前の記事
Tensorflowのclassify_image.pyにElectronでGUIを被せてみた
こんにちは、最近次男は保育園の帰り道、自分で走って帰るといって聞かず、自宅までの走って帰る日々です。長男も同じような時期にそういうことがあったので、そういうもんなんだと諦めて、次男の走りに付き合ってます。@kjunichiです。
GPUを使えるTensorflowをWin,Macに入れたものの
tensorflowを入れたものの、動かし方が、実はよくわからず、Python APIのみの pipで入れても、実はサンプルコードがsite-lib配下にインストールされてることすら 最近まで知りませんでしたw。
classify_image.pyにElectronでGUIをつけてみた。
Linux,Windowsで画像ファイルをドロップすると、classify_image.pyで画像分類できるように してみた。
これで、子供たちと、簡単に画像ファイルを選んで、人工知能にどんな写真かを調べてもらうことが できました。
pipでいれたTensorflowのサンプルコードのありか
import site print(site.getsitepackages())
これで、pipでインストールされるインストール先のディレクトリ一覧が取得できる。 環境によって、複数のパスが返されるので、この中からtensorflowディレクトリを探す。
画像ファイルをドロップして読み込む
大昔、HTML5の修業であれこれ作った
から持ってきた。
iphoneの写真だとEXIFを考慮する必要ありだった
これまた大昔、
を作ったが、この知識が役に立った。
Exifでカメラの回転情報を保持しているので、 これ考慮してclassify_image.pyに渡さないと分類結果に影響が出た。
もっとも、オリジナルのJPEGファイルをそのまま、classify_image.pyに渡せばこの辺り、Tensorflow側で 処理してくれたのかもしれないが。。
成果物
Windowsの場合はCondaのPython3を優先して動かすようにしてます。 その他のプラットフォームではパスに登録されてるPython3を優先して、そこにtensorflowがあれば、 それを使う感じにしてます。
関連記事
- Windows(MSVC)でmrubyからGPU対応のTensorflowを動かせた
- 第3回:3月26日(日)Blender勉強会(UE4よちよち勉強会_スピンオフ)@HDE(渋谷)に行ってきた
- Tensorflowのclassify_image.pyをWebアプリ化した
- pytorchによるcycleGANの実装をWindowsで動かした
- Raspberry Pi3でTensorflowをビルドして動かした