openFrameworksを使ってopenCVを使おうと思ったら、意外と単純じゃなかったのでメモ。
学生の時にもっと画像処理系の研究しておくべきだった。
openFrameworksにはopenFrameworks用のopenCVライブラリofxopenCVが用意されているのだけど、openCVよりもできることが限られてる気がしました。
例えば、watershedアルゴリズムを使って領域分割しようとしてもofxopenCV用にはその関数が用意されていなかったり。直接openCVも使えるので多分そっち使ってってことだとは思うけど。
以下、openFrameworks内でwatershedアルゴリズムを実装した方法です。
1、ofxCvClolorImageのインスタンスに画像を読み込む
ofImage buf;
ofxCvColorImage ofxSrc;
buf.loadImage("munk.jpeg");
ofxSrc.setFromPixels(buf.getPixels(), buf.width, buf.height);
2、openCVの画像データ構造体IplImageの入力画像、マーカー画像、出力画像用インスタンスを生成する。
この時、marker用画像のdepthは IPL_DEPTH_32S、nchannelは1にしなければエラーになる。(ここに詰まった。)
IplImage *srcImg, *markers, *dstImg;
srcImg = ofxSrc.getCvImage();
markers = cvCreateImage(cvGetSize(srcImg), IPL_DEPTH_32S, 1); //depth, nchannelに注意
cvZero(markers);
dstImg = cvCloneImage(srcImg);
3、watershedアルゴリズム用のマーカーをランダムに分割数(この例では200個にした)作成する
int seed_rad = 20;
static int seed_num = 0;
for(int i=0;iwidth), ofRandom(srcImg->height));
cvCircle (markers, pt, seed_rad, cvScalarAll (seed_num), CV_FILLED, 8, 0);
}
4、watershedアルゴリズムを実行し、出力画像に結果を代入する。
cvWatershed(srcImg, markers);
// 実行結果の画像中のwatershed境界(ピクセル値=-1)を結果表示用画像上に表示する
int *idx;
for (int i = 0; i < markers->height; i++) {
for (int j = 0; j < markers->width; j++) {
idx = (int *) cvPtr2D (markers, i, j, NULL);
if (*idx == -1)
cvSet2D (dstImg, i, j, cvScalarAll (255));
}
}
5、最後に画面描画ができるように用にofxCvClolorImageに結果画像を代入する。
ofxCvColorImage ofxSrc,ofxDst;
ofxDst.allocate(dstImg->width, dstImg->height);
ofxDst = dstImg;
ムンクの画像を分割した結果がこれ。