Rubyで多項分布からのサンプリング

多項分布を扱うことがあったので、Rubyでサクッと多項分布からのサンプリングを書いてみた。ただし、何も見ずにカンで書いたので合ってるかどうかはまったく保証しません。

#!/usr/bin/ruby

# 多項分布からのサンプリングを行う関数
# probは、各項の確率(総和は1とする)
def samplingFromMultinomialDistribution(prob)
# 累積確率にする
prev=0.0
accprob=prob.map{|x| prev=prev+x }

# 一様乱数生成
r=rand()

# 要素を選択する
return accprob.index{|v| v > r}
end

# 適当な多項分布
p prob=[0.6,0.2,0.1,0.05,0.04,0.01]

# サンプリングして
index=samplingFromMultinomialDistribution(prob)

# その項を出力する
p index

何回か実行してみたけど、それっぽい結果が出ているのでよしとするか…。今回は厳密さとか全くいらないので。

厳密さが要求されるシーンで多項分布を扱っている方々はどんなふうにサンプリングしているのだろう?

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

gccでは通らないけどVisualStudio2008では通るコード

先生がはまってたので簡単に書いてみた.これなんでダメになるのかな?ちなみにNGな方のエラーメッセージはこちら.

test.cpp: In function ‘int main()’:
test.cpp:19: error: no match for ‘operator=’ in ‘t1 = Test()’
test.cpp:9: note: candidates are: Test& Test::operator=(Test&)

コンストラクタを直接呼んでそれをoperator=に突っ込むときはconstが必要らしい?まぁ常にconst付けてれば問題ないんですが.

OKなコード

#include <iostream>

class Test{
	public:
		Test(){}
		Test(const Test& other){}
		~Test(){}

		const Test& operator=(const Test& other){
			return *this;
		}
};

int main(){
	Test t1;

	Test t2(t1);

	t1=Test();

	return 0;
}

NGなコード

#include <iostream>

class Test{
	public:
		Test(){}
		Test(Test& other){}
		~Test(){}

		Test& operator=(Test& other){
			return *this;
		}
};

int main(){
	Test t1;

	Test t2(t1);

	t1=Test();

	return 0;
}
ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

Matlabを使った画像処理(物体領域抽出編)

最も簡単な背景差分法による物体領域抽出

今まで画像処理はOpenCVでやっていたが,機械学習とかにはMatlabの方がいろいろよさそうなのでMatlabの勉強を兼ねていろいろプログラムを書いていくシリーズ第1弾.

背景差分による物体領域抽出は,物体を含む画像と物体を含まない画像を比較して,その差がしきい値より大きい場所を物体領域として抽出する.

Matlabを使った方法

画像の読み込み

画像の読み込みにはimread関数を使う.img_f=imread('input.jpg');により,物体領域を含む画像を読み込む.また,img_b=imread('back.jpg');により,物体領域を含まない画像を読み込む.

画像の差を求める

単純に引き算( diff = img_f - img_b; )をすることで,画像の差を求めることができる.

しきい値を決める

用いる画像がカラー画像の場合,まずグレースケール化する必要がある.diff_gray=rgb2gray(diff); により,グレースケールの画像を得る.

次に,しきい値を決める.適当な値を自分で決めてもよいが,ここでは大津のしきい値判定法を使って決定する.大津のしきい値判定法はクラス内分散最小化を用いるもので,しきい値は thresh = graythresh( diff_gray );によって求めることができる.

しきい値よりも差が大きい部分を求める

次に,しきい値よりも大きい部分を物体領域(白),それ以外を背景領域(黒)とした2値画像を作る.これは,上で求めたしきい値を使って,diff_bw = im2bw( diff_gray, thresh );で求まる.

物体領域を求める

最後に,上で求めた2値画像と,物体を含む画像との積を求めることで,物体領域以外は黒にした画像を得ることができる.

for i=1:3
color=a(:,:,i);
color(bw ~= 1)=0;
result(:,:,i)=color;
end

こんな感じ.

まとめ

背景差分は画像処理の基本なので最初に押さえた.コードをまとめると以下のようになる.

img_f=imread( 'input.jpg' );
img_b=imread( 'back.jpg' );

diff = img_f - img_b;
diff_gray = rgb2gray( diff );

thresh = graythresh( diff_gray );
diff_bw = im2bw( diff_gray, thresh );

result = repmat(uint8(0), [size(img_f)] );
for i=1:3
    c=img_f(:,:,i);
    c(diff_bw ~= 1)=0;
    result(:,:,i)=c;
end

【追記】もっと賢いやり方を教えてもらったのでメモ

img_f=imread( 'input.jpg' );
img_b=imread( 'back.jpg' );

diff = img_f - img_b;
diff_gray = rgb2gray( diff );

thresh = graythresh( diff_gray );
diff_bw = im2bw( diff_gray, thresh );

result = img_f .* uint8(repmat( diff_bw, [1 1 3] ));
ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

std::arrayとstd::iota

std::array

std::array<T,n>は,T型のn個の固定長配列を表す型らしい.std::vector<T>と違い,固定長なので,push_back()などの操作はできない…と思う.これは,#include <array>すると使えるようになる.

std::iota

std::iota(a.begin(), a.end(), i)は,vectorとかlistとかarrayなどのコレクションのbegin()からend()までを,iから始まる値で埋めていく関数…だと思う.順に,i, i+1, i+2, …と値が入る.これは#include <numeric>をいれると使えるようになる.

使用例

コードは以下のとおり.GCCでコンパイルする場合は,オプションで,-std=c++0xが必要.

#include
#include
#include
#include 

void disp(int x){
	std::cout << x << std::endl;
}

int main(){
	std::array<int,5> a={1,1,1,1,1};
	std::for_each(a.begin(),a.end(),disp);

	std::iota(a.begin(),a.end(),10);
	std::for_each(a.begin(),a.end(),disp);
	return 0;
}

std::array<int, 5>型の変数aの各要素をstd::for_each(これは#include <algorithm>で使える)を使ってvoid disp(int x)という関数に渡して順に表示している.そのあと,std::iotaを使って値を10,11,…に変更.最後にその結果を表示している.この出力結果は

1
1
1
1
1
10
11
12
13
14

のようになる.

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

Visual Studio 2008 でコンパイルできたすごいコード

関数戻り値部分でのクラス定義

C++では,関数の戻り値の型を関数宣言/定義時に指定する.

Hoge func(){
    Hoge x;
    return x;
}

こんな感じに指定すると,先頭部分で関数の戻り値がHoge型だということがわかる.

クラスの定義は,

class Hoge{
    public:
        Hoge(){}
        void hello(){ std::cout << "Hello" << std::endl; }
};

という感じで行う.今回,これをくっつけてみたら,コンパイルが通った.

class Hoge{
    public:
        Hoge(){}
        void hello(){ std::cout << "Hello" << std::endl; }
} func(){
    Hoge x;
    return x;
}

int main(){
    Hoge a = func();
    a.hello(); // Helloが出力される
}

Visual Studio 2008では,コンパイルが通ったけど,gcc 4.4.5ではコンパイル通らなかった.gccでは,「class宣言の後ろにセミコロン抜けてるよ」というエラーが出力された.

文法的にはどっちが正しいのだろう?

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

Ruby 1.9 mswin64で エラー 0xc0150002

Ruby1.9のmswin64版をいれたときに起きた問題のメモ.実行したときに,

アプリケーションを正しく初期化できませんでした (0xc0150002)。[OK] をクリックし
てアプリケーションを終了してください。

というエラーが出た.これは,Visual C++の再頒布可能パッケージがないことによるエラー.なので,ここから該当する再頒布可能パッケージをダウンロードしてインストールすればOK♪

と思ってインストールしたんだけど相変わらず同じエラーが出る….何が原因だろう?再起動すればいいのかな?

ちなみにOSはWindows Server 2008の64bit版です.

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

Crocsを履くときの静電気対策

crocs

crocsは人気の靴メーカーとその製品で,たくさんカラーバリエーションがあったり,いろんなデザインの商品が出ている.基本的に合成樹脂で出来ているので,柔らかくて履きやすい.

Crocsの問題点

合成樹脂でできているため,電気を通さない.これのせいで,セーター等を着る冬場には大変なことになる.

なにが大変かというと,静電気が体にどんどん溜まってしまい,金属などに触れるとバチっと放電して痛い目に合う.自分が痛い目にあうし,たまに他の人にもダメージを与えてしまう.

対策

アイデア

アースを付けましょう.常に接地して電気的に地面と同じにしておけば,モノに触れてもバチっとこないはず!

やってみた

とりあえず導線を靴の内側に突き刺し,靴の履き口をまわして靴の外側へ出し,靴底に貼りつけた.

結果

しばらくこれで生活してみて,バチっと来なくなっていれば成功していると考えられる.

結果は後ほど.

ツイートツイート
カテゴリー: 未分類 | タグ: , , | 1件のコメント

OpenCVで主成分分析をしてみた

主成分分析とは

主成分分析:PCA (Principal Component Analysis)は,多次元データの解析法の一種で,多次元空間中のデータ分布のうち,最も分散の大きくなる方向から順に基底を取っていく手法です.これをすることにより,データにおける主な変化の傾向を知ることができます.具体的にはいろんなところ(朱鷺の杜Wiki , タコでもわかる主成分分析 , etc.)で紹介されているので,ここでは割愛します.

主成分分析をやるには

大量の高次元ベクトルに対して上記のように分散を計算していくのは手計算では無理です.普通はmatlabやRを使いますが,画像処理屋はOpenCVを使って解析をします.(僕は主に,自前で実装したIncremental PCAを使っているので,以下のコードを実際には使っていません.あと,ちゃんとしたデータに対して動作確認もしてないので,以下のコードを使うのは自己責任でお願いします.)

このコードは,C++とOpenCVを使って,200次元のデータ1000個に対して主成分分析を行う例です.この例では,主成分分析後,上位3次元の基底に着目し,200次元のデータを3次元の空間へ投影した時の座標を出力します.また,各基底がどのくらい強くその分布を表しているかを意味する,累積寄与率も計算して出力しています.入力データは,スペースで区切られた200次元,1000個のベクトルです.

#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <fstream>
#include <iomanip>
int main(){
	const int DIM=200; // 200次元
	const int SAMPLES=1000; // 1000サンプル
	const int RDIM=3; // 圧縮後3次元
	cv::Mat src(SAMPLES,DIM,CV_32FC1);
	cv::Mat result(DIM,DIM,CV_32FC1); // DIMとSAMPLESのうち小さい方
	double val;

	std::ifstream ifs("data.txt");

	for(int j=0;j<SAMPLES;j++){
		for(int i=0;i<DIM;i++){
			ifs >> val;
			((float*)src.data)[j*src.cols+i]=val;
		}
	}

	cv::PCA pca(src,cv::Mat(),CV_PCA_DATA_AS_ROW,0);

	result=pca.project(src);

	for(int j=0;j<SAMPLES;j++){
		for(int i=0;i<RDIM;i++){ // 上位RDIM次元だけを表示
			std::cout << std::dec << ((float*)result.data)[j*result.cols+i] << ",";
		}
		std::cout << std::endl;
	}

	cv::Mat evalues=pca.eigenvalues;
	float sum=0.0f;
	for(int i=0;i<pca.eigenvalues.rows;i++){
		sum+=((float*)evalues.data)[i];
	}

	float contribution=0.0f;
	for(int i=0;i<RDIM;i++){// 上位RDIM次元の寄与率を計算
		contribution+=((float*)evalues.data)[i] / sum;
		std::cout << i+1 << "次元の累積寄与率:" << contribution << std::endl;
	}

	return 0;
}

このように,C++/OpenCVで簡単に主成分分析をすることができます.

ツイートツイート
カテゴリー: 未分類 | タグ: , , | コメントをどうぞ

MacBookでネットワークをブリッジ(その2)

EMobileのPocketWifiは無線LAN接続が5台までしかできない.そこで,無線LANアクセスポイントを追加してもっとたくさんのPCを接続できるようにしたい.

今回の目的,環境.

今回使うのは,PocketWifi,MacBook,とBuffalo製のこのタイプの無線LANルータ.これで,PocketWifi-MacBook間のネットワークと,MacBook-無線ルータ間のネットワークをブリッジすることで,無線LAN経由でインターネットへつなげるようにする.

今回,PocketWifi-MacBook間は無線LANでつなぐとする.MacBookと無線ルータは有線のLANケーブルで接続する.

設定

今回の設定画面はこちら.

共有する接続経路にEthernetを,そして,相手のコンピュータが使用するポートにAirMacを指定する.これにより,無線ルータ側から有線LANを経由してMacBookに来たものが,そこでブリッジされてAirMacを通してPocketWifiへと接続される.

ただし,このときMacBookがDHCPサーバとして働くので,無線ルータは,裏面のスイッチでルータ機能をOFFにしておき,無線ルータとMacBookの接続は,インターネット接続端子ではなく,LAN接続端子を使って接続すること.

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ

MacBookでネットワークをブリッジ(その1)

自分のMacBookに挿しているEMobileなんかを他のPCからも利用したいというシチュエーション(ネット環境がそのEMobileしかない時など)があります.こういうとき,ネットワークをブリッジ接続すると良い.

ネットワークのブリッジ接続って?

ブリッジ接続というのは,簡単にいうと二つの異なるネットワークをくっつけること.くっつけたネットワークは,一つのネットワークみたいに利用出来る.上のEMobileの例だと,EMobile-MacBookのネットワークとMacBook-他のPCのネットワークをくっつけて,他のPCからEMobileを利用できるようになる.

どうやるの?

Macでは,「システム環境設定」→「共有」で設定をする.共有の画面

この画面で,共有する接続経路にEMobileのモデム(図ではHUAWEI Mobile Connect)を選択し,相手のコンピュータが使用するポートに,AirMacを選択する.最後に,左のインターネト共有の前のチェックボックスにチェックを入れると設定完了.AirMacを介して他のノートPCがMacBookに接続でき,EMobileのモデムを利用することができるようになる.

ツイートツイート
カテゴリー: 未分類 | コメントをどうぞ