2016年1月28日木曜日

数式を表示できるようにしてみた。


MathJaxというJavaScriptを入れるとブログで数式が表示できるようになるらしいので入れてみました。
HTMLのヘッダー部分に以下のHTMLを入れるだけで数式が表示できるらしいです。

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]] } });
</script>
<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML">
</script>

テスト

\(e^{i\pi}=-1\)

簡単に数式が書けるんですね。

2016年1月27日水曜日

僕のコンピュータに猫を認識させてみた

厄年というのはとても恐ろしいです。
おじさん、厄年になってまだ一か月たっていないのにおたふく風邪にかかってしまいました。しかも子供のころに予防接種うったのに。年を取ると免疫の学習がダメになってくるようです。

顔が腫れて会社にいけないし、部屋からでれないので、今回はディープラーニングについて書きます。


何年か前に、Googleがディープラーニングでコンピュータに猫の顔をひたすら見せて認識させていました。

https://googleblog.blogspot.jp/2012/06/using-large-scale-brain-simulations-for.html

この論文が以下にあります。

http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/unsupervised_icml2012.pdf


どうやって顔の画像作っているのか、調べてみると、深層ボルツマンマシンで16000台のコンピュータで学習させたらしいです。

この猫の画像作りたいのに。こりゃーおじさんの安いメモリ4GバイトのペンティアムのPCだとおたふく風邪が治るまでに計算できないね。

しかもディープラーニングの論文ってみんな線形代数のベクトルの数式で書かれているので、W(i,j,k)とかもうどの記号が何を表しているかを追うのが大変。あれから間違えなくソースコードを起こすのってさらに大変。
この辺の勉強は、誰かの書いたコードをデバッグしながら動かして解析した方が、圧倒的にわかりやすいし早い気がします。数式がわかる力も当然いりますが、コードを読んで動かす力が必要な気が。

そこで、さらにいろいろ調べてみると、どうもRBM(制限ボルツマンマシン)で一枚くらい画像を学習させるくらいだとおじさんのおんぼろPCでも実験できそう。

世の中には本当に頭の良いすごい人がいてRBMをC++で実装した人がいるんですね。
原理とかもとてもわかりやすく解説されていて本当にすごいです。

http://kivantium.hateblo.jp/entry/2015/12/01/000207

ということで、このライブラリを利用して猫を認識させて、画像の再構築をしてみました。ソースコードはとても短いのに、おじさんのPCでは一枚の画像認識させるのに数分かかります。でもこれである程計算の順番とかを追うことができる!
オリジナル画像



オリジナル二値化画像

再構築画像




こりゃーインタープリタの言語でRBMの実験したり、本当に何百万枚も画像を学習して認識させるにはGPU付きPCが何万台もいるねぇ。

2016年1月20日水曜日

日本が夏の時、オーストラリアは?

うちの会社にはとても面白い若手社員がいまして、「日本が夏の時、オーストラリアは?」と聞くと自信満々に「夏」という社員がいます。
理由を聞くと、「日本が8月だとオーストラリアも8月だから」と言われました。

おじさん、最近の若者の考え方わからないあるよ。
おじさん、最近の若者の考え方本当にわからないあるよ。

やっぱりこの問題、難しいからなぁ。
なので、このとっても難しい問題をコンピュータで解くことにしました。
解く必要ないって?

いえいえ、こんな難しい問題はコンピュータでないと解けないんです。
この問題を自然言語処理で解こうというのが今回のブログなんです。
おじさん、集中力がないので画像処理のブログを書くのはあきてしまいました。


そこで今回はGoogleの超天才研究者が開発したWord2Vecというライブラリで単語の演算というのをやってみます。

単語の演算というのは

A->BならばC->?
というのを解く問題です。
A-B+C
などと書く場合もあります。記号だとよくわからないですね。
A、B、Cそれぞれに日本、東京、フランスという単語を当てはめて説明しますね。

日本と東京のような関係があるとき、フランスの対に当たる単語を見つける問題です。
日本と東京は国と首都という暗黙の関係で結ばれているので、フランスの場合はパリが答えです。

すごいですね。コンピュータのくせにクイズが解けちゃうんです。
このクイズを解いちゃうライブラリに(日本)-(夏)+(オーストラリア)を入れてみたいのです。

いままでブログで書いてきた画像処理のような、コンピュータでいろいろなものを認識することをやるときには必ずなんでもデータをベクトル化しないといけないのですが、自然言語処理にはいままで効率の良いベクトル化の方法がなかったのです。この研究者が画期的な方法で単語のベクトル化ができたんです。ほんとうにすごいです。

しかももっとすごいのはそのソースコード。
C言語のファイルが一つしかないんです。しかも答えを求める部分の全てのソースがたったの140行。
なので手軽に遊ぶことができます。

ソースコードはこちらです。
https://code.google.com/p/word2vec/

LinuxかMacOSXでしか動かないのですが、せっかくなのでWindows用に移植してみました。ファイル一つしかないので移植も超簡単です。


コンパイルもめんどくさいという人はここにサービスがあるので、簡単に実験することができます。

http://deeplearner.fz-qqq.net/ja.html

そして、ついに答えがでました。



日本が夏の時、オーストラリアは冬だそうです。
すげー。うちの会社の社員のレベルを超えている。
理由教えて欲しいんですが、コンピュータ理由はわからないみたいです。

物体認識してみた

前回はHaar-like特徴で顔認識をしました。おじさんのような年齢になると顔認識できてもプログラムのお仕事ってなかなかないんです。若い時にもっとプログラムと英語を勉強しておけばよかったです。そこで今回はいま一番お金になりそうなSIFT、SURFという特徴抽出をつかって物体認識をしたいと思います。

物体認識はロボット、自動運転、ジェスチャーゲーム、指紋認証などいろいろな分野で応用を研究されています。これができるといって職安に行けば、おじさんも時給700円でプログラムのお仕事が見つかるかもしれません。

いままでOpenCV3.0でプログラムをしていたのですが、SIFTやSURFは特許があるらしく、OpenCV3.0ではこれらのライブラリが別モジュールになっています。ソースコードは公開されているのですが、バイナリーが公開されていないのでビルドするのがめんどくさいです。やっぱり、金になりそうなところは特許でおさえられているのね。
さらに、この辺の分野はどんどん研究や新規開発が行われているので、ライブラリのバージョンごとにクラスの構成が大きく異なります。これでは手軽に勉強できないですね。

なので、今回はOpenCV2.4.10で実装をしてみたいと思います。


---------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include "mygetopt.h"

#ifdef _WIN32
#pragma comment(lib,"opencv_core2410")
#pragma comment(lib,"opencv_highgui2410")
#pragma comment(lib,"opencv_features2d2410")
#pragma comment(lib,"opencv_contrib2410")
#pragma comment(lib,"opencv_flann2410")
#pragma comment(lib,"opencv_imgproc2410")
#pragma comment(lib,"opencv_nonfree2410")
#pragma comment(lib,"opencv_ocl2410")
#pragma comment(lib,"IlmImf")
#pragma comment(lib,"zlib")
#pragma comment(lib,"libjasper")
#pragma comment(lib,"libpng")
#pragma comment(lib,"libjpeg")
#pragma comment(lib,"libtiff")

#pragma comment(lib,"comctl32")

#endif


int main(int argc, char *argv[])
{
int c;
std::string file_img1="kitkat1.jpg", file_img2="kitkat2.jpg";
cv::Mat colorImg1,colorImg2;
cv::Mat grayImg1, grayImg2;
std::vector<cv::KeyPoint> keypoints1,keypoints2;
std::vector<cv::DMatch> matches;
cv::BFMatcher matcher;
int N = 30;

while (1)
{
int this_option_optind = myoptind ? myoptind : 1;
c = mygetopt(argc, argv, "i:c:");
if (c == EOF)break;

switch (c){
case 'i':
file_img1 = myoptarg;
break;
case 'c':
file_img2 = myoptarg;
break;
}
}


colorImg1 = cv::imread(file_img1);
colorImg2 = cv::imread(file_img2);
if (colorImg1.empty() || colorImg2.empty()){
return 1;
}

cv::cvtColor(colorImg1, grayImg1, CV_BGR2GRAY);
cv::cvtColor(colorImg2, grayImg2, CV_BGR2GRAY);

//cv::SiftFeatureDetector detector;
//cv::SiftDescriptorExtractor extractor;  
cv::SurfFeatureDetector detector(1000);
cv::SurfDescriptorExtractor extractor;


detector.detect(grayImg1, keypoints1);
detector.detect(grayImg2, keypoints2);

cv::Mat descriptors1;
extractor.compute(grayImg1, keypoints1, descriptors1);
cv::Mat descriptors2;
extractor.compute(grayImg2, keypoints2, descriptors2);

matcher.match(descriptors1, descriptors2, matches);

nth_element(matches.begin(), matches.begin() + N - 1, matches.end());
matches.erase(matches.begin() + N, matches.end());

cv::Mat matchedImg;
cv::drawMatches(colorImg1, keypoints1, colorImg2, keypoints2, matches, matchedImg);

cv::imshow("image", matchedImg);
cv::waitKey(0);

return 0;
}


---------------------------------------------------------------

detector.detect()で特徴点を検出して、extractor.compute()で特徴ベクトルを計算して、matcher.match()で距離を計算してマッチングしてます。
プログラムはとっても簡単です。


みんなネットにはいい結果ばかり載せていますが、よく見るとけっこう特徴点が一致してない気が・・・・。だからみんなよいアルゴリズムを研究しているのね。








2016年1月19日火曜日

顔認識してみた

前回のブログでは一番簡単な画像認識のテンプレートマッチングについて書きました。
今回は少し難しくなってOpenCVで定番の顔認識をやってみたいと思います。

人間の顔認識、猫の顔認識、アニメのキャラクター認識、企業のロゴ認識なんてことをやるにはOpenCVでカスケード分類器というものを使います。

このカスケード分類器に人の顔のデータと人の顔でないデータを何千枚も見せて、機械学習させて、学習結果のデータを作ります。そして、その学習結果に識別させたい画像を入れて判別を行います。

カスケード分類器に機械学習をさせるためには顔と顔以外のデータを数千枚も用意しないといけないのです。とても大変な作業なのですが、OpenCVには顔を学習させた結果のデータファイルも入っているので、今回はこれを使うことにします。

OpenCVにはカスケード分類器に学習させるためのツールも入っているので、以下のページのようにすれば特定の人の顔を識別する学習データや、特定のロゴを識別する学習データも簡単につくることができます。

おじさんの時代はホームページ作れるだけでパソコンできるって言われてソニーとか松下電器に就職できたのに。
いまや小さな会社や学生が数時間で当たり前のように機械学習とかできるのね。
恐ろしい世の中です。Googleに入るためにはどんだけ勉強しないといけないんでしょ。

まぁそれは置いておいて、上記のページにはカスケード分類器を用いた顔認識の原理とかも書いてあるので、顔認識の原理を勉強するのにもとても参考になります。

コンピュータにいろいろなものを認識させたり学習させたりするときには、学習データと特徴ベクトルという画像の特徴を抽出するアルゴリズムが必要なのですが、顔認識ではだいたいHaar-Like特徴というアルゴリズムで特徴を抽出します。

いつものように、顔認識の原理を超省略して一行で簡単に説明すると、Haar-Like特徴によるカスケード分類器で機械学習させて、その学習結果で判別を行います。

まぁ機械学習には学習のさせ方の方法がたくさんある、判別させたいものの特徴を表す特徴ベクトルのアルゴリズムもたくさんある、学習結果のデータがいる程度のことを覚えておくといろいろな人に知ったかぶりできます。


ソースコードにするとこんな感じです。
-------------------------------
#include <stdio.h>
#include <opencv2/opencv.hpp>

#include "mygetopt.h"

#ifdef _WIN32
#pragma comment(lib,"opencv_core300")
#pragma comment(lib,"opencv_highgui300")
#pragma comment(lib,"opencv_hal300")
#pragma comment(lib,"opencv_world300")
//#pragma comment(lib,"opencv_ts300")
#pragma comment(lib,"ippicvmt")
#pragma comment(lib,"zlib")
#endif

int main(int argc,char* argv[])
{
int c;
cv::Mat image;
std::vector<cv::Rect> faces;
std::string img_file="lena.jpg";
std::string cascade_file="haarcascade_frontalface_default.xml";
cv::CascadeClassifier cascade;

while (1)
{
int this_option_optind = myoptind ? myoptind : 1;
c = mygetopt (argc, argv, "i:c:");
if (c == EOF)break;

switch (c){
case 'i':
img_file=myoptarg;
break;
case 'c':
cascade_file=myoptarg;
break;
}
}

image = cv::imread(img_file);
cascade.load(cascade_file);

cascade.detectMultiScale(image, faces, 1.1, 3, 0, cv::Size(20, 20));

for (int i = 0; i < faces.size(); i++){
rectangle(image, cv::Point(faces[i].x, faces[i].y), 
cv::Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), 
cv::Scalar(0, 200, 0), 3, CV_AA);
}


cv::imshow("detect face", image);
cv::waitKey(0);

return 0;
}
-------------------------------


OpenCVにデフォルトで入っているhaarcascade_frontalface_default.xmlという顔認識の学習結果データを読み込んで、detectMultiScaleを呼び出すだけです。
顔認識はcascade.detectMultiScaleという一行で終わってしまうんですね。
とっても簡単です。これで以下のように顔の部分がわかります。


この写真の人はレナさんという人らしいです。
顔認識はかならずレナさんでやるみたいです。


とりあえず顔認識できた。機械学習による顔認識ってとってもかんたん。数時間でできちゃいます。
次は物体認識にしようかパターン認識にしようか音声認識にしようか文字認識にしようか迷っています。ではまた。









テンプレートマッチングをしてみた

サーバ実装のブログはだいぶあきたので、今日からしばらくは画像処理、かっこよくいうとコンピュータビジョン系のことでも書こうと思います。

コンピュータが機械学習して、人の顔とか猫とかアニメのキャラクターとかを識別するあれです。
いきなり顔認識や機械学習のソースコードをのっけると、話が飛びすぎるので、まず今日は画像処理の基礎から。一番簡単な画像認識であるテンプレートマッチングをやることにします。

そもそもテンプレートマッチングとは何かというと、ある画像から画像の一部を切り出して、その切り出した画像が元の画像のどこにあるのかを判別することです。

テンプレートマッチングがどのようにして画像を判別しているのかについて、ちょー簡単かつ適当に説明すると、地図で例えるならば、画像のそれぞれの点で明るいところを山、画像の暗いところを谷にして立体地図のようなものを作り、立体地図の一部の破片がどこにはまるかを比べていくような感じですね。


歯医者でたとえると、でこぼこの歯形があったとして、医者がどこの歯に合うか突き止めるような感じ。

数学的にいうと面のそれぞれの点で距離を図って差の平均をとる、つまり面の明るさで距離を測る感じですか。
自分でいうのもなんですが、「面の明るさで距離を測る」ってわけのわからないこと書いているなぁと。


こんなわけのわからないこともOpenCVというライブラリを使えば簡単に行うことができます。
C++言語のソースコードで書くとここんな感じになります。

-----------------------------------------------------
#include <stdio.h>
#include <opencv2/opencv.hpp>

#include "mygetopt.h"

#ifdef _WIN32
#pragma comment(lib,"opencv_core300")
#pragma comment(lib,"opencv_highgui300")
#pragma comment(lib,"opencv_hal300")
#pragma comment(lib,"opencv_world300")
//#pragma comment(lib,"opencv_ts300")
#pragma comment(lib,"ippicvmt")
#pragma comment(lib,"zlib")
#endif

int main(int argc,char* argv[])
{
cv::Mat src_img,tmp_img,dst_img,gray_img;
cv::Point min_loc=0.0,max_loc=0.0;
double min_val,max_val;
int c;
char* src_file="chrome.png";
char* ptn_file="google.png";

while (1)
{
int this_option_optind = myoptind ? myoptind : 1;
c = mygetopt (argc, argv, "s:p:");
if (c == EOF)break;

switch (c){
case 's':
src_file=myoptarg;
break;
case 'p':
ptn_file=myoptarg;
break;
}
}



src_img=cv::imread(src_file);
if(src_img.empty()){
printf("Error:src_img.imread() error\n");
exit(1);
}

tmp_img=cv::imread(ptn_file,0);
if(tmp_img.empty()){
printf("Error:tmp_img.imread() error\n");
exit(1);
}

cv::cvtColor(src_img,gray_img,cv::COLOR_RGB2GRAY);
cv::matchTemplate(gray_img,tmp_img,dst_img,cv::TM_CCOEFF_NORMED);
cv::minMaxLoc(dst_img,&min_val,&max_val,&min_loc,&max_loc);


printf("%d,%d,%d,%d,%d\n",(int)(max_val*100),max_loc.x,max_loc.y,max_loc.x+tmp_img.cols,max_loc.y+tmp_img.rows);

#if 0
cv::rectangle(src_img,max_loc,cv::Point(max_loc.x+tmp_img.cols,max_loc.y+tmp_img.rows),CV_RGB(255,0,0),3);
cv::namedWindow("image1",1);
cv::imshow("image1",src_img);
cv::waitKey();
#endif

return 0;
}

-----------------------------------------------------

Chromeブラウザ画像のなかからGoogleロゴの画像の位置を突き止めるプログラムです。

画像はこのようなものを使っています。


↑試験画像
↑発見したいパターン


cv::matchTemplateというところの一行でテンプレートマッチングの計算をしています。
一行でできるんですね。
ほかの行は画像を読み込んだり、白黒に変換したりしているだけです。


このテンプレートマッチング、先ほど型の合う部分を探すといった通り、発見したいパターンの画像が拡大縮小回転されたりすると元の画像に型がどこにも合わなくなって判別できなくなるんです。

だから、アプリケーションのテストでボタンの位置を特定して自動でボタンを押す、というような用途にはとても役立つんですが、顔認識するとか、物体認識するということにはほとんど役に立ちません。無理やり顔認識させることもできなくもないのですが、かなり精度が悪いです。

じゃあどうやって顔とか猫とかを認識するのかというと、カスケード分類器というのを使って機械学習させます。正確には誰かが学習させた結果のデータをどこかから持って来れば認識はできるので、学習させる必要は必ずしもないのですが。これもプログラムは全然簡単なので、次回に書きたいと思います。

2016年1月18日月曜日

ビデオカメラの動画をネット配信する

防犯カメラとかUSBカメラの映像をネット配信するサーバをたまに見かけるんですが、どうやって作るのか調べてみました。

まず、動画をPCに取り込むキャプチャーデバイスが必要です。
高画質なHD画質で取り込みたい場合はAverMediaのAVT-C875などがよく使われてします。
SD画質で良い場合は、IO-DataのGV-USB2が値段も安くて手頃です。
これらのデバイスはWindowsのDirectShowに対応しているので、デバイスを買ってきてパソコンにデバイスドライバーを入れさえすれば、専用ソフトウェアだけでなく、さまざなまソフトウェアでキャプチャーを行うことができます。


続いて、ソフトウェアです。ffmepgというソフトウェアを使います。


このソフトウェアをパソコンに入れて、コマンドラインから次のように打つと、キャプチャーした動画のファイルが作られます。


ffmpeg -f dshow -i video="デバイス名" out.mp4


実際には録画時間や画面サイズ等を指定したいと思いますので、以下のようにします。




ffmpeg -f dshow -i video="デバイス名" -t 300 -s 1280x720 -r 30 out.mp4


また、デバイス名がわからない場合は以下のように打つと名前を取得することができます。



ffmpeg -list_devices true -f dshow -i dummy


たったこれだけ。
これでPC上にビデオカメラの映像を取り込むことができるんです。

昔はね、DirectX-SDK入れて、DirectShowのFilterGraphを作ってとっても難しいCOMの勉強をしないと動画キャプチャーのプログラムなんてできなかったんです。しかし、今ではコマンドを打つだけで色々なエンコード形式で動画をキャプチャーして保存できるんです。おじさん、最新のソフトウェア技術に全くついていけてませんでした。


コマンドを打つのを自動化し、キャプチャー動画をhttpdのディレクトリに保存すれば、動画配信サーバも簡単に作れちゃいます。

ネット対応の防犯カメラって意外と簡単に作れちゃうんです。


ffmpegは録画だけでなく、動画ファイルから静止画の切り出しとかも簡単にできるので、切り出した画像をOpenCVやTensorFlowで解析すれば、動画を使った顔認識とか今流行りの深層学習DeepLerningとかも簡単に行えます。問題は動画の画像の解析はとても時間がかかることです。静止画はそんなに時間がかからないのですが、動画はGPUがないとダメな気がします。



2016年1月8日金曜日

超軽量動画投稿サービスを作ってみた。

先日、このブログで、動画配信サービスの作り方を書いたのですが、本日はその逆の動画投稿サービスの作り方について。

正月にぼーっとしていてふと思ったのです。
世の中のスマホのアプリって、基本的に以下の三つのことしかしていないのではないか。

(1)サーバにデータを上げる
(2)サーバからデータのリストを取得する。
(3)サーバからデータをとってくる。

だから、この三つのことを簡単にできるようにすればどんなサービスでも作れるのではないかと。
ということで実験でハイビジョンとか4Kサイズの動画をスマホから投稿して、投稿した動画をみる超軽量動画投稿サービスを二日間で作ってみました。

なんでバイビジョン動画なのかというと、最近コーデック技術の発達で超高画質高圧縮のmp4ファイルがffmpegで簡単に作れてしまうんです。1分あたり30Mバイトくらいで高画質な動画が送れるんです。本当にびっくり。

作ったサイトはこれ。
http://219.0.242.21/test/test_postfile/

ソースコードはこちら
https://drive.google.com/file/d/0B5M9qMMg3tfQRG94T1NrbEFDdjQ/view?usp=sharing
見てもらえばわかりますが、ソースコードも超簡単。

(1)サーバにデータを上げる、postFile
(2)サーバからデータのリストを取得する、filelist_html
(3)サーバからデータをとってくる、nph-file-stream

gccでこれらのソースをコンパイルして、apacheとかanhttpdとかのhttpdのどっかのディレクトリに適当に置くだけで動画投稿サーバが完成です。


写真や動画の投稿サイトって投稿した動画のサムネイルや、フォーマット変換をしないといけないのですが、このような面倒なことは全部オープンソースのffmpegが全部やってくれます。

もうだれでも個人で簡単に動画投稿サービスを作れちゃうんですね。
これでもうyoutubeとか個人できる!。

実際に商用運用するには何万人もアクセスが集中したり、データが何万と多くなった時に処理を分散させないといけないのですが、それも大して難しくないので、また機会があれば書きたいと思います。

超軽量httpdであるmongooseとcivetwebをコンパイルして使ってみた

最近、Raspberry Piなどの小型マイコンボードで工作するのが流行っています。
このようなボードをスマホから遠隔操作するようなことをしたい時に必要になるのが、cgiを実行できるhttpdです。

Apacheでも良いんですが、もっと軽量でしかも簡単にソースコードを変更できて、簡単にコンパイルできてCGIが実行できるものでないと、サーバ側を作るのがめんどくさくて、ちょっとした遊び感覚でサーバを作れないです。

そこで、最近のオープンソースのhttpdを色々調べてみました。
そうしたところ、どうもmongooseというオープンソースのhttpdがかなり使えそうです。
https://code.google.com/p/mongoose/

このライブラリは、まだあまり日本語で記事になっていないので今回ブログを書くことにしたのですが、とても軽量です。

どのくらい軽量化というと、c言語で書かれていてメインの部分はたった一つのソースファイルでできています。しかも、linux,windows,macos,ios,androidなどあらゆるosで動きます。

コンパイルも超簡単。
gcc mongoose.c simplest_web_server.c
と打てばサーバが作れてしまいます。
もちろんWindowsのVisualStudioやMacOSXのXcodeでもコンパイルできます。
ライブラリにはhttpのクライアントもあるので、このライブラリだけでサーバとクライアントの両方を作ることができます。本当にすごいです。

唯一の不満はソースコードがGPLである点。ソースがGPLではスマホ用のhttpdが欲しい時に商用では使えないじゃん。

ところが、すごいことに、このmongooseから派生したcivetwebというhttpdがあるのです。
https://github.com/civetweb/civetweb

こちらはホームページがあまり親切ではありませんが、BSDライセンスなので自由に改変を行うことができます。mongooseから派生しているので、使い方もmongooseとほとんど同じでとても便利。

ということでとりあえず、mongooseとcivetwebでサーバを作ってみました。
何に使うかはまだ決まってません・・・・。