ECナビ+セブンネットショッピング=SD
この記事は、@kjunichiの2018年パーソナルアドベントカレンダーの21日目の記事です。
忘れた頃位に3000ポイントもらえる
ECナビでセブンネットショッピングのキャンペーンで書籍購入で3000ポイント貯まる。 今年は、これで結構SDの他に技術関連の書籍を購入した。
ECナビのポイントは6000ポイント毎にアマゾンの500円分のギフト券に交換してる。
- 作者: 中井悦司,橘慎太郎,石川聡彦,中西崇文,貞光九月,谷本心,櫻庭祐一,渡辺祐,あっきぃ,安藤幸央,結城浩,武内覚,宮原徹,平林純,くつなりょうすけ,職業「戸倉彩」,速水祐,高橋憲一,樽石将人,清水琢也,上田隆一,田代勝也,山田泰宏,中村壮一,eban,mattn,小飼弾,すずきひろのぶ,青田直大,小島啓史,あわしろいくや,中島雅弘,横田結菜,武貞真未,大塚和彦,後藤大地,杉山貴章,Software Design編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2018/12/18
- メディア: 雑誌
- この商品を含むブログを見る
今年ECナビ+セブンネットショッピングで買ったその他の書籍
- 作者: Katherine Cox-Buday,山口能迪
- 出版社/メーカー: オライリージャパン
- 発売日: 2018/10/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
実践 Deep Learning ―PythonとTensorFlowで学ぶ次世代の機械学習アルゴリズム (オライリー・ジャパン)
- 作者: Nikhil Buduma,太田満久,藤原秀平,牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2018/04/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
- 作者: 中西崇文,中川伸一,橘慎太郎,安部晃生,横山直敬,馬場真哉,藤原秀平,飯塚修平,足立昌彦,藤田稜,やまねひでき,安藤幸央,結城浩,武内覚,宮原徹,北村壮大,平林純,速水祐,樽石将人,清水琢也,山田泰宏,田代勝也,上田隆一,中村壮一,重村浩二,くつなりょうすけ,mattn,小飼弾,すずきひろのぶ,あわしろいくや,中島雅弘,榎真治,法林浩之,関治之,奥村和彦,後藤大地,Software Design編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2018/08/18
- メディア: 雑誌
- この商品を含むブログを見る
関連記事
12年前の記事
5年前の記事
- 2013年をはてブで振り返る11月
- 2013年をはてブで振り返る10月
- 2013年をはてブで振り返る9月
- 2013年をはてブで振り返る8月
- 2013年をはてブで振り返る7月
- 2013年をはてブで振り返る6月
- 2013年をはてブで振り返る5月
- 2013年をはてブで振り返る4月
- 2013年をはてブで振り返る3月
- 2013年をはてブで振り返る2月
- 2013年をはてブで振り返る1月
4年前の記事
3年前の記事
1年前の記事
Surface Goのカメラ映像をRustでコマンドプロンプトに表示した
この記事は、Rustその2 Advent Calendar 2018の20日目の記事と@kjunichiの2018年パーソナルアドベントカレンダーの20日目の記事を兼ねています。
背景
Surface Goをセットアップして開発環境を整備がほぼ終わり、 以前Rustで作成したWebカメラの映像をコマンドプロンプトに表示するコマンドを OpenCV 3.4.2を利用するように修正して試したら、
[ WARN:0] cvCreateFileCaptureWithPreference: backend MSMF doesn't support legacy API anymore. [ WARN:0] cvCreateFileCaptureWithPreference: backend DSHOW doesn't support legacy API anymore.
とエラー。
これはOpenCVのC APIのサポートがどうやらほんとうに切れて、C++のAPIを使わないとビデオキャプチャー が行えなくなってしまったということを訴えているエラーメッセージの模様。
RustからOpenCVを使うのに、C++のAPIを使わないとならない。
RustでOpenCVのC++ APIを使う
RustでCのAPIを扱うには、FFIが用意されているので、Rust側でCに対応する型を使って 呼び出したいAPIの関数を宣言する程度で容易に扱える。
しかし、C++にはマングリングの問題や、クラスを扱っているのでこれらに対応する必要があり、 Cと同様にFFIすることはかなり難しい。
RustでC++を扱うには
C++で対象のライブラリをラップしてCのAPIで叩ける口を用意し、これをRustからFFIで利用するというのが一般的な手法の模様。
まずは、RustでC++を扱うには、cc crateというcrateがあり、WindowsではC/C++コンパイラとしてcl.exeを利用している。 今回OpenCVのC++ APIをラップするC++のコードをこのcc crateを使うことでRustのプロジェクトの 一部としてシームレスに扱えるようになる。
これにより、cargo build
やcargo run
でC++のコードもビルド出来るようになる。
具体的にはcc crateを利用することでbuild.rsを以下のように直感的に記述できるようになる。
extern crate cc; fn main() { cc::Build::new() .cpp(true) .warnings(true) .file("src\\webcam\\cpp\\src\\webcam.cpp") .include("src\\webcam\\cpp\\include") .include("C:\\tools\\opencv\\build\\include") .compile("libwebcam.a"); }
libwebcam.aなる指定があるが、cl.exeな環境でもこれで動くし、 内部的にwebcam.libも作成してれる。
参考資料
OpenCVのC++ APIの雑なラップ
CではRustからFFIで直接アクセスできたので、 OpenCVで使われている一部の構造体はRustでもstructで 定義して内部構造にアクセスできるようにしていたが、 今回C++なので、Rust側ではすべて、Enum宣言することで 対応できた。
C++ APIの関数
以下のC++ APIで用意されている関数を適当にextern "C"
で包んで
RustのFFI経由で利用できるようにした。
- cv::imwrite
- cv::imshow
- cv::imencode
- cv::namedWindow
- cv::waitKey
- cv::destroyAllWindows
クラス/構造体へアクセス関数
Cの時はOpenCVのAPIで使われている型に対応する型をRust側に用意していたが、 今回はC++なので、そのまま対応する型をRustには用意できないので、Rust <-> C 間での やり取りする型を別に用意する必要がった。
cv::VideoCapture, cv::Matの扱い
以下ようなCvVideoCapture, Cv2Mat(CvMatはOpenCVのC APIで使用済み)なる構造体を用意して、 これらの構造体を介して、Rust<->C<->C++のやり取りを行った。
typedef struct CvVideoCapture_ { void *raw_ptr; } cvVideoCapture; CvVideoCapture *cv_video_capture(int camnum) { VideoCapture *cap; cap = new VideoCapture(); cap->open(camnum); CvVideoCapture *ccap; ccap = (CvVideoCapture*)malloc(sizeof(CvVideoCapture)); ccap->raw_ptr = cap; return ccap; } typedef struct Cv2Mat_ { void *raw_ptr; } Cv2Mat; Cv2Mat *cv_create_mat() { Cv2Mat *mat; mat = (Cv2Mat*)malloc(sizeof(Cv2Mat)); mat->raw_ptr = new Mat(); return mat; }
画像データの扱い
C++ならばcv::Mat型とvector型の配列で画像データを扱えるが、Cを使うので、 画像データを扱える独自の構造体を用意して対処した。
C++のvector型がCにあれば良いが、無いので、Webカメラからの画像を以下のようにC側で先頭アドレスとサイズを保持するメンバ をもつ構造体を宣言して、これを使うようにした。
typedef struct ImgBuffer_ { void *ptr; int size; void *raw; } ImgBuffer; ImgBuffer *cv_imencode(const char *ext, Cv2Mat *img, int *params) { vector<uchar> *buf; buf = new vector<uchar>; imencode(ext, *((Mat*)(img->raw_ptr)), *buf, vector<int>()); ImgBuffer *dst = new ImgBuffer(); dst->ptr = buf->data(); dst->size = buf->size(); dst->raw = buf; return dst; }
成果物
あとがき
Rustとタイトルにあるが、コマンドプロンプトへの画像データの表示はGoで別途自作したライブラリを使っていたりする。
画像をオンメモリーで扱う際にC++のVector型で取得できるが、これをRust側に渡して、Rust側で 不要になったら領域を解放したかったが、ストレートにこれを行う方法が分からなかったので、 一旦C++側でクラッシックな配列を確保して、これをRust側に戻し、この配列をRust側で不要になった タイミングで開放するように実装した。
Rustは当初はWindowsではMinGWがメインストリームだったが、MSVCに移り、今回使ったcc crateもcl.exeを シームレスに使えてWindowsプラットフォームでもC/C++との連携も問題なく扱えることが分かった。
マイクロソフト Surface Go (128GB/8GB) MCZ-00014
- 出版社/メーカー: マイクロソフト
- 発売日: 2018/08/28
- メディア: エレクトロニクス
- この商品を含むブログを見る
関連記事
- RustでWebカメラの映像をコマンドプロンプトに出すコマンドを作った
- Rustでコマンドラインアプリでキーが押されたかの判定しつつ、別の処理も進めるには
- Go言語でコマンドプロンプトに画像を表示するコマンドを作って、Vimの:terminalで表示させた
- RustでGoのライブラリを使うときのCargoのbuild.rsの書き方
- Surface Goが届いた
9年前の記事
4年前の記事
1年前の記事
mac mini(Late 2014)にSSDを増設したらUSBポートが足りなくなり、ハブを買った
この記事は@kjunichiのパーソナルアドベントカレンダーの19日目の記事です。
背景
の通り、amazonのサイバーマンデー でSSDを買ってmac miniを延命させることに。
USB 3.0のハブをタイムセールで購入
SSDがいざ届いて、mac miniにつなげようとしたら、本体のUSBポートが埋まってたw
たまたま、amazonのタイムセールのUSB3.0のハブの広告が表示され、ポチッとなw
USB3.0ハブ 4ポート USB3.0高速ハブ 5Gbps高速 USB HUB MicroUSB給電ボード付き セルフパワー/バスパワー対応 Windows/Mac ブラック
- 出版社/メーカー: ACASIS
- メディア: エレクトロニクス
- この商品を含むブログを見る