2016年11月02日

RANSACのテスト その2

前回は2次曲線で近似しましたが、今回はPCLに付属のサンプル点群をオーソドックスな平面で近似してみました。PCLで使用されているPCDデータですが、ファイルフォーマット的には簡単なのですが、binary_compressedデータは圧縮が入ってきて面倒だったので、結局PCLを使うことにしました。表示は自前でOpenGL使ってやっています。

PCLは以前all-in-one-installerを使用してインストールしていたのですが、すっかり忘れていてソースからCMake使ってコンパイルしました。FLANNとかBoostとか必要で結構面倒でした。

平面近似についてはこちらも前回同様特異値分解を用いてパラメータ推定をしました。平面の方程式は以前の記事でまとめていましたので、そこを参考にしました。

実行結果

PCL付属のfive_people.pcdを読み込んで表示した結果です。PCDファイルとはY軸が反転しているのか、上下が逆さまになっていましたが、気にしないことにしました。

pcl_test_001.png

以前の記事でOctreeを使った近傍探索も試していましたので、おまけでマウスでクリックしたところに赤い球を表示して、そこの座標を表示するようにしてみました。

続いて、平面近似した結果です。未知数4個なので、4点使って点と平面の距離が0.1以下の点群の数を、10000パターン試して最も一致数が多いものをRANSACで選んでいます。こちらもおまけで平面の領域+閾値の幅を適当に区切った直方体と、範囲内の点群を緑色で表示しています。

pcl_test_002.png

前回も書きましたが、この辺は自分で実装しなくてもPCLでできるのでほぼ確認の意味ですが、RANSACは大体使えるようになったので何か機会があれば使ってみたいと思います。
web拍手 by FC2
posted by シンドラー at 19:03 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2016年10月15日

RANSACのテスト

論文などでよく見るRANSACですが、試してなかったので試してみました。RANSACについては[1]を参考にさせていただきました。アルゴリズム的には簡単ですね。モデルも自由に変更できますし。今回は2次曲線の方程式を使ってみます。

equation_001.png

テスト画像は下記のものです。ペイントで適当に書きました。楕円で近似できればいいなといった図形です。

circle_test.png

白画素を点群として、2次曲線で近似します。未知数が6個ですので、6点以上使って特異値分解します。この辺のやり方は過去記事を参考にしました。全ての点群を使って特異値分解した場合には、左上の円に引っ張られて誤差の大きな近似曲線になります。

use_all_points.png

今回はRANSACで6点使って特異値分解で近似して、点群との距離?が閾値以下の点の数が最も多いパラメータを選んでみました。本当は点と曲線の距離を計算しないといけないのですが、近似したパラメータに点の座標を代入して、0に近いかどうかで判定したので正確ではありません。

実行結果

use_ransac_001.png

赤が全画素に対して行った閾値以下の点の領域で、緑が点群の中で閾値以下のものです。適当に描いた絵なのできれいにとはいきませんが、2次曲線で大きい方の楕円が近似できています。切り出しを行いたい場合は、範囲内の点で再度パラメータを計算して、閾値以下の点を取り除いて、残った点でまたRANSACということを行えば、2つの2次曲線を取り出せるみたいですが、今回はそこまでは試していません。

本当は3次元でKinectなどで取得した点群から球や平面を抽出したりといったことをしようと思っていたのですが、その辺はまた今度試してみたいと思います。まぁPCLなどで実装されているので、自分でやる意味はあまりないのですが。

[1] 【お勉強してみた】RANSACのおはなし - Qiita
web拍手 by FC2
posted by シンドラー at 18:18 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2016年07月22日

ビットマップフォントに関するメモ

ここのところ月1回しか更新してないですね…。困ったものです。

今日はビットマップフォントに関するメモです。画面や画像に文字を表示する方法は、OpenGLやOpenCVなどにも用意されているので、それを使えば問題ないかと思います。今回のメモはライブラリ等を使わずに無理矢理表示するためのものです。

フォントについては、大きく分けてビットマップフォントとアウトラインフォントがあります。綺麗な文字を描きたいのであればアウトラインフォントだと思いますが、今回は簡単のためビットマップフォントを使用します。

フォントに関しては、ライセンスに気を付ける必要があります。今回は[1]のm+ fontsを使用させていただくことにしました。

こちらのフォントですが、BDFというファイルフォーマットのフォントデータがあります。BDFはBitmap Distribution Formatの略のようで、UNIXで標準的に使用されていたフォーマットのようです。

テキストベースのファイルフォーマットですが、自分で読み込むのも面倒ですので、[2]のbdf2bmpというソフトウェアを使用させていただき、bdfファイルをbmpファイルに変換しました。

後は文字ごとに切り出して拡大/縮小し、白:背景、黒:文字として元の画像にmixしてあげれば画像上に文字を描くことができます。

実行結果

Lenna画像上にHello worldを表示してみました。

chartest.png

[1] m+ fonts
[2] bdf2bmp
web拍手 by FC2
posted by シンドラー at 19:00 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2015年12月21日

色の類似度を用いたグレースケール化

いつの間にかあと2週間で今年も終わりとは困ったものです。

OpenCVを使用していると、たまに入力がグレースケール指定のものがあります。単純にグレースケール化しても良いのですが、例えば赤っぽさで明暗にしたグレースケール画像を入力した方が都合が良い場合もあるかと思います。

というわけで、色々な誤差(類似度)[1]を使ってカラー画像をグレースケール化してみました。HSVに関しては、参考サイトの式ではなく、色相は1周するのでその辺を考慮した[2]のと、Hの類似度(0〜1)×彩度(0〜1)という彩度が低いと類似度が低いという適当な式で計算したものです。

実行結果

rainbow.png
                原画像
Paintて適当に作った画像です。

赤との類似画像

red_SSD.png red_ZNCC.png red_HSV1.png
        SSD               ZNCC                HSV

青との類似画像

blue_SSD.png blue_ZNCC.png blue_HSV1.png
        SSD               ZNCC                HSV

緑との類似画像

green_SSD.png green_ZNCC.png green_HSV1.png
        SSD               ZNCC                HSV

HSVやZNCCを使う場合は分母が0に近づく時が困りますね。

[1] 色の類似度
[2] hue値を使った色類似度計算についての試行

web拍手 by FC2
posted by シンドラー at 16:59 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2015年10月30日

位相限定相関法(POC)のテスト

以前ちょっと試してそのまま放置していたので何となく整理しました。参考サイトもたくさんありますし、OpenCVでも実装されているようです[1]〜[4]。

2枚の画像のマッチングを行うときに、フーリエ変換して位相情報のみの相関をとって逆変換すると、平行移動量の所にピークが出るみたいです。

で、ピークの様子を確認するのにgnuplot等で表示すればいいのだと思いますが、画像サイズと等しいXY平面ポリゴンを作成して、値を高さZにするディスプレイスメントマッピングみたいなものを作ってみました。

POC_002.png

POC_003.png

上記の計算をしてPLYで出力するサンプルプログラムです。法線計算とか除いています。今回は表示をMeshLab上でやっていますが、法線計算もMeshLabでやればいいかと思います。
plytest.cpp

実行結果
poc_001.png

ついでにLenna画像で試してみました。高さはグレースケール化した時の輝度値です。

POC_006.png
横から見た結果
POC_008.png POC_007.png
       光源なし              光源あり

後は高さマップや法線マップを読み込んでポリゴンで出力するバージョンも作ってみました。画像から読み込んで出力する値を変更しただけですが。
POC_005.png
[5]の画像を使用させていただいております。

話が逸れましたが、まずは平行移動させた画像です。同一画像の場合、ピークが画像の中心に来ますので、平行移動量は画像の中心からどれだけずれているか、になるのではないかと思います。

POC_010.png POC_011.png
原画像

POC_004.png
ピーク画像

結果としては完全に一致していたと思います。ペイントで適当に移動させただけですので、サブピクセル単位のずれはありません。

次に、回転角の計算です。こちらはRIPOCというもので、2枚の画像をフーリエ変換して得られたスペクトル画像をLogPolar変換した画像からPOCで平行移動量を求める、という方法のようです。おそらく。

POC_010.png POC_012.png
原画像

POC_013.png
LogPolar変換した2枚の画像
(平坦な部分に見える線が横(画面奥方向)に平行移動している。今回は横方向がθ)

POC_009.png
ピーク画像

LogPolar変換で、今回は横軸にθ(-PI〜PI)をとっていますので、画像の幅が512ピクセルであれば、512ピクセルで2PIラジアンのずれ、ということになります。端の方が大きい値をとっていますので、変換バグがあるかもしれません。

計算した結果、横方向に48ピクセルずれたところにピークがありましたので、2PI*48/512ラジアン≒33.75度となりました。確かGIMPで33.4度回転させた気がしますので、大体あってそうです。もっと精度がほしい場合はピーク位置をsinc関数か何かで出す必要があるみたいです。

[1] http://d.hatena.ne.jp/suzume_r/20100515
[2] http://authorunknown408.blog.fc2.com/blog-category-1.html#39
[3] http://www.soaristo.jpn.org/blog/archives/2015/02/150214.php
[4] http://cvl-robot.hateblo.jp/entry/2014/02/06/171541
[5] http://www.bencloward.com/shaders_offset.shtml

web拍手 by FC2
posted by シンドラー at 18:28 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2015年05月25日

PCL 1.7.2のOctreeのテスト

Voxelで何かしようかなと思っているのですが、高速化のためにはOctreeなどデータ構造が大事かと思いますので、Point Cloud LibraryのOctreeを使用することにしました。本当はSparse Voxel Octreeのライブラリなどを使用した方がいいのだとは思いますので、機会があれば試してみたいと思います。

PCL 1.7.2の導入
公式は1.6.0のall-in-one-installersしかなかったですが、[1]で1.7.2のものを公開していただいていましたので、そちらを使用させていただきました。octreeのtutorialsは[2]にあります。今回必要なのはoctreeだけなので、includeやlibも最低限必要なものだけにしておきます。

インクルードのパス
$(PCL_ROOT)\include\pcl-1.7;
$(PCL_ROOT)\3rdParty\Eigen\Eigen3;
$(PCL_ROOT)\3rdParty\Boost\include\boost-1_57;

ライブラリのパス
$(PCL_ROOT)\lib;

ライブラリ(リリース)
pcl_octree_release.lib;

実行時に必要なライブラリ
$(PCL_ROOT)\bin\pcl_octree_release.dll

[3]を参考に、MagicaVoxelのVoxデータを読み込んでRaycastingで表示してみました。

ソースの一部(画像処理・レイの計算部分は省略)
#include <pcl/point_cloud.h>
#include <pcl/octree/octree.h>

int rayCastTest(const int width, const int height)
{
    int hit = 0;

    MV_Model mv;
    mv.LoadModel("voxel/doom.vox");

    // ポイントクラウドの作成(色情報のためのラベルのためPointXYZLを使用)
    pcl::PointCloud<pcl::PointXYZL>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZL>);

    // 画像とレイキャスティングの準備は省略

    // voxデータからポイントクラウドを生成
    cloud->width = mv.voxels.size();
    cloud->height = 1;
    cloud->points.resize (cloud->width * cloud->height);

    for (size_t i = 0; i < cloud->points.size (); ++i)
    {
        cloud->points[i].x = mv.voxels[i].x;
        cloud->points[i].y = mv.voxels[i].y;
        cloud->points[i].z = mv.voxels[i].z;
        cloud->points[i].label = mv.voxels[i].colorIndex;
    }

    // octreeの生成、解像度はoctreeのボクセルのサイズ?
    float resolution = 1.0f;
    pcl::octree::OctreePointCloudSearch<pcl::PointXYZL> octree (resolution);

    octree.setInputCloud (cloud);
    octree.addPointsFromInputCloud ();

    // レイとボクセルの衝突判定
    std::vector<int> k_indices;

    Eigen::Vector3f org, target, dir;
    for (int y=0; y<height; y++)
    {
        for (int x=0; x<width; x++)
        {
            // 画素からレイの到達先を計算
            // 視点位置と到達先からレイの方向を計算

            // octreeとvoxelの衝突判定(1回)
            int ret = octree.getIntersectedVoxelIndices(org, dir, k_indices, 1);
            if (ret > 0)
            {
                // 今回は1個目のindex固定(解像度によってはk_indicesが複数Indexを含む)
                int label = cloud->points[k_indices[0]].label;
                // パレットから色を取得して画像に設定
                color.r = mv.palette[label].r;
                color.g = mv.palette[label].g;
                color.b = mv.palette[label].b;
                hit++;
            }
        }
    }
    // 画像の保存
    return hit;
}
実行結果(MagicaVoxel付属のサンプルdoom.vox使用)
pcl_test_001.png
ボクセル数2万弱、1024x1024の画像で、レイキャスティングの時間だけで400msぐらいでした。どちらかというと、全部のレイと衝突判定するのではなく、全部のボクセルを枝刈りしながらレイに当たるか判定する陰面消去的な探索がしたいのですが、どうやるんですかね。

[1] http://unanancyowen.com/?p=712
[2] http://pointclouds.org/documentation/tutorials/#octree-tutorial
[3] http://voxel.codeplex.com/wikipage?title=Sample%20Codes
web拍手 by FC2
posted by シンドラー at 00:56 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2015年03月27日

OpenEXRのコンパイル方法についてのメモ

Appleseedでは、HDR画像のファイルフォーマットが.exrだけになっているようでしたが、.hdrも有名どころですので、.hdrを.exrに変換するプログラムでも作ることにしました。既存のコンバータがいくらでもあると思いますが。

.hdrは、[1][2]などを参考に以前読み込めるようにしていたので、OpenEXR形式の読書きができれば変換できます。そのものずばりなOpenEXR[3]というC++のライブラリがあるようですので、それを使ってみることにしました。



というわけで、一応変換できたのですが、以前から使っているDevILでOpenEXRの読書きもできたみたいなので、やらなくて良かったかなという感じです。まぁCMake-guiでAdvancedにチェックを入れると細かい設定ができることがわかったのは今後の役には立ちそうです。

[1] http://www.graphics.cornell.edu/~bjw/rgbe.html
[2] http://t-pot.com/program/102_HDRI/index.html
[3] http://www.openexr.com/

web拍手 by FC2
posted by シンドラー at 18:46 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年12月26日

画像の極座標変換について その2

今頃気づきましたが、画像の極座標変換のところにコメントをいただいていました。手法など全然説明していないので自分で読んでもどうやっていたのか良くわからないですね。というわけで一応解説とOpenCV使ったサンプルソースコードを作ってみました。

polar_image_001.png

[1]を上の式で変換した結果(polarTest)
polar_image_dst.png

polar_image_002.png


[2]"Photo by DAVID ILIFF. License: CC-BY-SA 3.0"を上の式で変換した結果(polarTest2)
polar_image_dst2.png

ソースコード
opencv_polar.cpp
(2015.10.29追記:atan2(dx, dy)はatan2(dy, dx)の間違いです)

[1] http://www.mvision.co.jp/WebHelpIM/_RESOURCE/Filter_Mvc_Polar.html
[2] Helvellyn Striding Edge 360 Panorama, Lake District
web拍手 by FC2
posted by シンドラー at 17:49 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年07月23日

非等方ボロノイ分割のテスト

前々回の参考文献[1]適応的非等方ボロノイ分割によるステンドグラス風画像の作成にあった非等方ボロノイ分割を試してみることにしました。ボロノイ分割に距離以外に色を加えたものですので、特に難しいことはないかと思います。

入力画像

sphinx.png

原画像が分からなかったので(ちゃんと探していませんが)、[1]のPDFの縮小画像をコピーして拡大して大体同じ大きさにしたものを使用させていただいております。著作権とかで問題がありましたら削除しますのでお知らせください。

実行結果

ランダムに配置した128個のセルを使用していますので、適応的ではないただの非等方ボロノイ分割です。画素数(面積)が1000未満のセルは削除して他のセルに分配しました。

αを変化させたときの結果の違い

avt_alpha0.1_001.png
α=0.1(ほぼ座標)

avt_alpha0.5_002.png
α=0.5 (まだ座標)

avt_alpha1_001.png
α=1.0(ちょうど良い?)

avt_alpha2.5_001.png
α=2.5(色優先?)

avt_alpha5_001.png
α=5.0(色優先)

色がおかしいのはLab変換が間違っているんだと思います。kd-treeとか使って近傍探索しないとボロノイ分割にしても時間かかりすぎですね。
web拍手 by FC2
posted by シンドラー at 23:16 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年07月21日

ステンドグラス風画像の作成について その2

前々回のノイズから作った凹凸を加えるところまでやってみました。
あぴミクさんを使用させていただいております。

原画像にガウスフィルタ

stained_020.png

Lab画像

stained_019.png

領域分割+エッジ画像

stained_018.png

ノイズ+光源などの計算

stained_017.png

最終結果

stained_016.png

C-Means法の領域分割に時間かかりすぎですね。非等方ボロノイ分割で高速にできるようにした方が良さそうでしょうか。
web拍手 by FC2
posted by シンドラー at 00:12 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年07月18日

ステンドグラス風画像の作成について その1

ランダムなステンドグラス風画像もいいですが、モチーフというか既存の画像をステンドグラス風にできた方がいいかなと思いました。ステンドグラスとボロノイで検索してみると、非等方ボロノイ分割というものがあるようです[1]。

バイラテラル距離というもので、距離だけではなく、色のCIELAB距離も使って非等方ボロノイ分割をするという方法のようです。

それはそれとして、昔C-Means法で領域分割していた気がしたので、それを使ってステンドグラス風画像を作ってみることにしました。

1. 原画像の読込みとぼかし

とりあえずLenna画像を読み込んで、3x3のガウスフィルタを2回かけました。

stained_009.png

2.CIELABに変換

[2]を参考に変換しましたが、結構大きい値になってしまっているので、計算間違いしているかもしれません。

stained_010.png

3. C-Means法で領域分割

多めですが、1024クラスに分割しました。距離の計算にはx, y座標とL, a, b座標の5次元ベクトルを使用しました。

stained_011.png stained_012.png

4. 色付け

各クラスの平均値で領域を塗りつぶします。

stained_013.png

5.エッジ付け

ID画像のソーベルエッジを作って、前回のセレクタで合成します。

stained_014.png

後は高さマップとノイズと法線マップと光源計算をすれば前回のようになるはずですがとりあえずこの辺で。

[1] 適応的非等方ボロノイ分割によるステンドグラス風画像の作成(PDF直リン注意)
[2] 色空間の変換(3)
web拍手 by FC2
posted by シンドラー at 00:35 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年07月13日

libnoiseの使い方について その7

今度こそステンドグラス風です。ステンドグラス風の画像を作る方法として、[1]を参考にさせていただきました。

まずはガラスの質感のノイズです。ノイズを50%生成して、ぼかしフィルタを2回かけるということで、このノイズをPhotoshopと同じような感じにすることにしました。

フィルター→ノイズ→ノイズを加えるのパラメータについて

量:○%
分布方法:1. 均等に分布、2. ガウス分布

量って書かれているので、ノイズが載る確率なのかな、と思ったら違うみたいですね[2]。ノイズが載る確率は100%で、載る量の範囲を%で指定するということのようです。25%の場合、255の25%で、元の画素値に±64の範囲で乱数が加算されるようです。ですので、元の画素値を255にしておいて、50%のノイズを加えた場合、乱数は±127の間の数値をとりますが、+の場合は全て255を超えるので255にクリッピングされるため、ノイズが載る確率が50%という風な見た目にすることができるようです。

実行結果

白色背景に50%のノイズを加えたあと2回3x3のガウスフィルタを掛けました。

stained_001.png

エンボスフィルタについて

パラメータの強さなどが良くわからなかったので、適当に一般的なエンボスフィルタを実装しました。f1-f2+0.5で、f2の場所をパラメータとして設定できるようにした感じです。

実行結果

100度の方向に3ピクセルで離れたところに1.5倍の強さのエンボスフィルタを掛けた結果です。

stained_002.png

libnoiseのselectorのようなもの

libnoiseには、selector moduleというものがあります[3]。これは、2つのノイズを、selectorで指定したノイズの割合でブレンドしているのだと思います。多分。

同じような機能を作って、まずは、前々回作ったボロノイエッジと、ボロノイIDから適当に7色付けた画像をボロノイエッジの明るさの割合でブレンドします。ボロノイエッジがあるところはボロノイエッジのまま、それ以外のところはボロノイIDから適当につけた色が現れることになります。

実行結果

これだけでもステンドグラス風といえばステンドグラス風ですね。

stained_003.png

続いて、高さマップもボロノイエッジと、ガラスの質感のレイヤとを、ボロノイエッジをセレクタとしてブレンドします。

実行結果

エッジの部分にガラスっぽい質感を出さないためにセレクタを使っています。立体感がないですね。

stained_004.png

高さマップから法線ベクトルの生成

前回はnoiseutilsを使いましたが、今回は自前のものです。5x5のソーベルフィルタを使っているぐらいで、他は同じだと思います。

実行結果

stained_005.png

AOの計算

続いて、高さマップと法線マップから、適当に環境遮蔽を計算します。結構前に作ったものなのでパラメータ設定がわからなくて微妙です。

実行結果

stained_006.png

Blinn-Phongの計算

続いて、高さマップと法線ベクトルを使って光の反射を計算します。Blinn-Phongモデルを使っています。メロンのテクスチャを思い出します…。

実行結果

stained_007.png

最終結果

後はこれらの結果を足したり掛けたり色々しました。もっとぱっと一つの処理でできるようにならないと、MMEとかに適用しにくいですね。

stained_008.png

[1] http://azp2.sakuraweb.com/illust/stainedglass/index.html
[2] http://www.hirax.net/keywords/log/%E4%B9%B1%E6%95%B0/latest
[3] http://libnoise.sourceforge.net/glossary/index.html#selectormodule
web拍手 by FC2
posted by シンドラー at 22:40 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年06月06日

ホワイトノイズに関するメモ

画像によくホワイトノイズが入った劣化画像・・・とでてくるので、どういうものか確認してみます。ホワイトノイズはすべての周波数がほぼ同じ強度のパワースペクトルになるノイズらしいです[1]。ホワイトノイズはガウスノイズとしばしば誤解されるけれど概念は違うけれど似ているらしいです[1]。よくわからないので試してみることにしました。

何となくホワイトノイズというと一様乱数なノイズがのるような印象だったのですが、上の説明からすると正規分布に近いみたいですね。

とりあえず1次元で-0.5〜0.5までの一様乱数を生成してみます。

random_signal_001.png

ヒストグラムをとると、-0.5から0.5の間で大体同じ数がでているので一様乱数になっています(画像は-1.0〜1.0の範囲)。

random_histgram_001.png

この信号をフーリエ変換して振幅スペクトルを調べると、下図のようになりました(低周波部分の一部)。ブレはありますが割と一定な気がしないでもないですね。

random_spectral_001.png

このデータをホワイトノイズに変換してみます。やり方は1/fノイズの時と同じように、一定になるような倍率を計算して、実部・虚部それぞれに掛けてあげることにします。一定にする値は1〜dataNum/2までの振幅スペクトルの平均値にすることにします。

平均値を計算して振幅スペクトルがその値になるように実部・虚部をスケーリングした結果のスペクトルが下図のようになりました。当然ですが(直流成分を除く)すべての周波数の振幅スペクトルが等しくなります。(もしかすると直流成分も同じスペクトルするのが正しいホワイトノイズなのでしょうか)

white_spectral_001.png

これを逆フーリエ変換して実部のデータを見ると、下図のようになっていました。

white_signal_001.png

ヒストグラムを計算すると、下図のようになり、何となく正規分布っぽい気がします。

white_histgram_001.png

今度は逆に、正規分布に従って生成した信号はホワイトノイズに近いのか確認してみることにしました。平均0、標準偏差0.25の信号が下記のようになりました。

gauss_signal_001.png

これのヒストグラムは下図で、正規分布になっていることが確認できます。これを見るとホワイトノイズとは少し違うようですが、分散の違いかもしれません。

gauss_histgram_001.png

フーリエ変換して振幅スペクトルを図示してみると、一様乱数と大して変わらないレベルであまりホワイトノイズに近い気がしませんね。

gauss_spectral_001.png

ホワイトノイズ以外にも、カラードノイズ[2]というので色々なタイプがあるようですが、今回のように無理やり振幅スペクトルを加工してあげれば生成できそうです。

[1] ホワイトノイズ
[2] カラードノイズ

web拍手 by FC2
posted by シンドラー at 22:01 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年04月06日

色々なエッジのテスト

一言にエッジといっても色々なエッジが考えられますので、メモしておきます。

1. 色の違いによるエッジ
色が違っているところに線を引きます。微分フィルタを使うのが一般的かと思います。今回は色といってもグレースケール化して[7]の方法でエッジを計算してみました。

実行結果(元データ、エッジ画像、テクスチャに掛けた画像)

edge_color_001.png edge_color_002.png
edge_color_003.png

閾値処理などをすればノイズは減ると思います。色が変わるということは元々エッジが見えるということのような気もしますが。

2. 深度値の違いによるエッジ
奥行きが違っているところに線を引きます。こちらも微分フィルタで出せるかと思います。ここでいう深度値をどうするかという問題もありますので、深度値について復習しました。

depth_001.png
depth_002.png

実行結果
今回はZsで[7]の方法で深度値のエッジを計算してみました。

edge_depth_001.png edge_depth_002.png edge_depth_003.png

奥行に差があるところに線を引くというのはわかりやすいですが、内部の線がなかなか見えにくい気もしますね。こちらも閾値処理すれば良いのかもしれません。

3. 法線ベクトルの違いによるエッジ
ポリゴンとしては平面ですが、法線ベクトルを焼き込んで凹凸をつけていることなどがありますので、法線ベクトルを使ったエッジも大事になります。微分フィルタを使う方法や、内積を使う方法などがあるようです。今回は単純に法線ベクトルの差の合計の微分を使いました。

実行結果

edge_normal_001.png edge_normal_002.png edge_normal_003.png

閾値処理でノイズを減らせば割と自然なエッジの気もしますね。法線マップを使ったモデルなどに有効なのかもしれません。

4. マテリアルIDの違いによるエッジ
[1]に書かれていた方法です。PMD/PMXなどは材質ごとに番号が割り当てられていますので、材質が違うところには線を引けるでしょうということのようです。IDの値の差に意味はありませんので、近傍N画素中M個違っていればといった閾値処理になるかと思います。

実行結果

edge_material_001.png edge_material_002.png edge_material_003.png

はっきりとした線は引きやすいですね。材質番号が同じだと左足と右足の間にエッジが引かれないので、単体だと少し物足りない印象もあります。

というわけで、4つほどエッジを試してみました。それぞれ一長一短な気がしますので、用途や組合せで何とかする感じでしょうか。

[1] 深度法線エッジによる輪郭抽出
[2] 第5回 座標変換
[3] 第6回 視点の移動
[4] 第7回 カメラパラメータ
[5] リニアデプスシャドウマッピング
[6] OpenGLのデプスバッファ(pdf)
[7] T. Saito and T. Takahashi, "Comprehensible Rendering of 3-D Shapes", Computer Graphics, Vol. 24, 1990

web拍手 by FC2
posted by シンドラー at 19:33 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年04月02日

LIC(Linear Integral Convolution)のテスト その2

前回の続きです。[1]を参考にさせていただき、手書きっぽい効果を試してみます。今回もあぴミクさんを使用させていただいております。

1. 適当にベクトル場を生成
法線ベクトルと外積を使って上方向ベクトルを計算しました。この辺はもっと良さそうなベクトル場を考えた方が良いとは思います。
lic_007.png lic_008.png

2. グレースケール化とホワイトノイズの生成
あぴミクさんを普通にレンダリングして、グレースケール化します。それを輝度値として、[1]に書かれている方法を使ってホワイトノイズを生成します。追加として、材質が肌のところは輝度値に関係なく白色にしました。
lic_006.png lic_008.png

3. LIC法で線+エッジ+紙素材背景
LIC法で線を引いて、以前の方法で生成したエッジを掛けて、[2]のサイトの紙素材を掛けてみました。今回ただ掛けただけなのですが、参考文献ではエッジがボケたりしているので畳込み演算などが必要かもしれません。
lic_010.png

今回は画像処理として試しただけなので、次回はシェーダ辺りでできるようになるといいですね。

[1] "LIC法を利用した鉛筆画の自動生成法", 芸術科学会論文誌, Vol.1, No. 3, pp.147-159. (2002)
[2] フリーテクスチャ素材館
web拍手 by FC2
posted by シンドラー at 19:03 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年04月01日

LIC(Line Integral Convolution)のテスト

つい先日お正月だった気がするのですがもう4月なんですね。恐ろしいことです。

可視化の本を読んでいると、LICというものがありましたので、試してみることにしました。手書き風のエフェクトなどでも使われているようですので、やる気がでればGLSL等で実装してみたいと思います。参考サイトは[1][2]で、[1]にCのソースコード、[2]にC++のソースコードがありましたので、参考にすれば特に問題なく実装できるかと思います。

[1]の図がわかりやすいですが、ベクトルデータとホワイトノイズを用意して、各画素でベクトルに従って1ピクセルずつ移動して、その画素のホワイトノイズの値をボックスフィルタリングで畳込み演算すると線を引いたような絵ができる、という不思議な方法です。

実行結果

[1]のソースにあったサドル状のベクトルデータと、ベクトルを矢印で描いた図です。

lic_001.png lic_002.png

ホワイトノイズ(左)と、ある特定の画素に注目して、前後にピクセルを辿っていった線(右)です。

lic_003.png lic_004.png

線上のホワイトノイズの値に、ボックスフィルタの重みをかけたものを足して重みで割ると、その画素の色が決まります。それを全ての画素について実行した結果が下図のようになります。(ベクトルを掛けて適当に色付けしています)

lic_005.png

次回は手書き風シェーダっぽい絵ができるといいですね。

[1] Line Integral Convolution
[2] Using Line Integral Convolution to Render Effects on Images (PDF)

web拍手 by FC2
posted by シンドラー at 19:35 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2013年12月19日

特異値分解を用いた連立一次方程式の計算

連立一次方程式を解くとき、逆行列を計算するのではなく、特異値分解をする方が良い、というのをどこかで見た気がしますので、試してみることにします。

今回例題として、高さマップから局所的な2次曲面を計算してみます。
高さ情報をz座標と見立てて、3次元の座標F(x,y,z)=0となる等値面と考えると、
3変数の2次曲面の方程式は、以下のように表すことができます。

svd_007.png

これは2次形式で表現するのが普通なのだと思いますが、とりあえず連立方程式の
形にしてみます。
ある注目画素を中心とするMxMの近傍画素の座標を、 x,y,zそれぞれ-1〜1の範囲に
変換します。そうすると、N=MxM個の連立方程式を作ることができます。

svd_008.png

これを行列の形で表すと、Ax=0の形になります。

svd_009.png

今回は、それぞれの行をノルム1に正規化したものを行列Aとします。
(正規化したほうが近似精度が上がったため)

svd_011.png

この場合、前回のホモグラフィ行列のときにも用いましたが、特異値分解して
特異値が最も小さい特異ベクトルが誤差の二乗が最小になる解になるらしいです。

svd_010.png

Eigenを用いた場合、最小特異値を持つ特異ベクトルは、Vの一番右端に
来ているようですので、そのベクトルがa,b,…,jの値となります。

これで10個のパラメータが求まりましたので、画像上ではx,yを決めてzを求める方法、
3次元空間上では視点とレイを決めて、レイと2次曲面の衝突判定をすることで、
計算した2次曲面で近似した場合の結果を得ることができます。

後、たまに近傍と大きく異なる推定結果の点が出てきましたので、10個のパラメータを
画素ごとに求めて、5x5のガウスフィルタをかけてパラメータの平均化?をしました。

実行結果
各画素における2次曲面を、近傍5x5の高さ情報から計算する、ということをやっています。
画像の拡大とか勾配・法線ベクトルの計算などを試してみないとこの結果だけでは特に意味は無いと思います。
(特異値分解で連立一次方程式を解くテストという意味合いしかありません)

2次曲面の特性上、エッジがはっきりしているようなものは近似しにくいと思いましたので、
入力画像には5x5のガウスフィルタを1回掛けてあります。

1. 円内が1.0、それ以外が0.0の高さを持つマップを近似した結果は以下のようになりました。
近傍5x5の25x10の行列を作って、2次曲面の係数10個を計算しました。
パラメータのガウスフィルタ0回適用です。

svd_002.png svd_014.png
     原画像         近似画像

PSNRが66ぐらいで、エッジ周辺にノイズがみられます。

2. 高さマップを近似した結果は以下のようになりました。
近傍5x5、ガウスフィルタ2回適用です。

svd_004.png svd_013.png
     原画像         近似画像

PSNRが101ぐらいで、かなり再現できています。エッジが少ないからでしょうか。

3. おまけとして、Lenna画像をグレースケール化したものを試してみました。
こちらも近傍5x5で、ガウスフィルタ1回適用です。

svd_006.png svd_012.png
     原画像         近似画像

PSNRが84ぐらいで、まずまずですが、やはりエッジ付近にノイズがみられます。
ベジエ曲面やスプライン曲面ならうまくいくのでしょうか。

次はKinectで取得した点群データをこの2次曲面近似してみようかなと思います。
Kinect持ってないですが。
どこかにKinectで取得した点群データのデータベースとかないんでしょうかね。

web拍手 by FC2
posted by シンドラー at 22:44 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2013年12月11日

台形補正のテスト

いつのまにか年末とか信じられませんね。
今回は、[1]などを元に色々画像処理系のことを試してみて、最終的に台形補正をしてみました。

全体の流れは以下のような感じです。
1.歪んでいる画像と、歪んでいない画像を準備
2.Harrisのコーナー検出でコーナー点を検出
3.コーナー点の強度?の大きい順に、指定した範囲以上の間隔でサンプリング
4.ICP(Iterative Closest Point)アルゴリズムを用いて対応点とホモグラフィ行列を推定
(対応点の距離にはユークリッド距離と正規化相互相関(NCC)[1][4]を使用)
5.推定したホモグラフィ行列で台形補正

ひとつずつもう少し詳しく書いておきます。

1.歪んでいる画像と、歪んでいない画像を準備

GIMP2で歪んでいる画像を作りました。

trapezoid_000.png trapezoid_001.png

2.Harrisのコーナー検出でコーナー点を検出

[1]を参考に実装しました。エッジ検出フィルタを掛けて、勾配の共分散行列を計算してその固有値から判定する感じでしょうか。
エッジ検出に5x5のSobelフィルタ、勾配値の共分散行列の平均計算に5x5のガウスフィルタを使用しました。

trapezoid_002.png trapezoid_003.png

歪ませた方はジャギーが原因で等間隔にコーナー点が出てしまっていますね…。

3.コーナー点の強度?の大きい順に、指定した範囲以上の間隔でサンプリング

強度が0より大きい点は512x512の画像で約20万点ぐらいあり、今回は20ピクセル以上離れている点という条件で上位60個をサンプリングしました。
ちょっと見えづらいですが、赤い×印がサンプリングした点です。
微妙に違う点が選ばれてしまっていますね。

trapezoid_004.png trapezoid_005.png

4.ICP(Iterative Closest Point)アルゴリズムを用いて対応点とホモグラフィ行列を推定
(対応点の距離にはユークリッド距離と正規化相互相関(NCC)を使用)

ある点は、ある点に3x3のホモグラフィ行列Hが掛けられることで得られたと考えて、AH=0の行列を特異値分解で解いてホモグラフィ行列を計算することになります[1][2]。

ただ、対応点が分かっていればそれを並べて行列Aを作ることができるのですが、今回それぞれの画像で個別に特徴点を計算しているため、特徴点ごとの対応を決める必要があります。これは、特徴点同士の距離(誤差)を計算する必要があると思われますので、今回は単純なユークリッド距離と、点の近傍5x5の(1.0−NCC)を重みづけして足し合わせたものを特徴点間の距離と定義しました。

これで特徴点間の距離の計算はできるようになりましたが、どの対応点の組み合わせが最も良いのかはわかりませんので、ICPアルゴリズムを使用して対応点を決めることにしました[3]。ICPの使い方がこれで合っているのかどうかはちょっとよくわかりません。

4.1. 3.で選んだ60点を、ランダムに5点×12グループに分けて、グループ毎にホモグラフィ行列Hiを計算
(今回、特異値分解の計算には行列計算ライブラリEigenを使用しました。)
4.2. 各Hiで各特徴量の最近傍点のペアを作成し、総距離Eiを計算
4.3. Eiがこれまでの最小距離Eminより小さければ、そのグループのホモグラフィ行列HiをHminとして保持
4.4. 500回ぐらい4.1.〜4.3.を繰返す。すべての回数が終わった時のHminが台形補正のためのホモグラフィ行列になっているはず。

本当はRANSACというものを使ってはずれ点を除去していくべきらしいです。
後、Eigenで特異値分解をしたときの注意点として、8x9の行列を特異値分解した場合、ComputeThinVにしているとVは8x9の行列、ComputeFullVにしていると9x9の行列になって、特異値が最小の特異ベクトル?は9番目になるため、ComputeFullVで計算しないとホモグラフィ行列が出てこなくて困りました。

5.推定したホモグラフィ行列で台形補正

Hが求まれば、X'=HXで変換後の座標は計算できますので、それを使って補正します。

trapezoid_001.png → trapezoid_006.png

4隅を手動で指定して得られた正解のホモグラフィ行列が左で、今回の手法で得られた行列が右です。
4点マウスでクリックして1回ホモグラフィ行列を計算すれば終わるので、どう考えても手動でやった方が高速で高精度ですよね。

[ 1.312542 0.074179 -27.6734 ] [ 1.101552 -0.05357 8.442439 ]
[ 0.107716 1.354367 -48.4918 ] [ 0.062449 1.004017 -35.8303 ]
[ 0.000365 0.000347 1.000000 ] [ 0.000292 -0.00028 1.000000]

平行移動のところとか割と違ってる気がするんですが大丈夫なんでしょうかね。
まぁ自動(といって正解の歪んでいない画像を使っていますが)でもそれなりにうまくいっているのでしょうか。
ランダムに選ぶ5点によって毎回結果が変わるのでうまくいかない場合もあります。
Harrisの特徴点より、おそらくSIFT特徴量などを使った方が精度が上がるのではないかとは思います。

[1] Jan Erik Solem 著、相川 愛三 訳,「実践コンピュータビジョン」,オライリー・ジャパン
[2] ホモグラフィ行列を求める:http://www.kimura-lab.net/wikimura/index.php/%E3%83%9B%E3%83%A2%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E8%A1%8C%E5%88%97%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B
[3] http://www.mm.media.kyoto-u.ac.jp/research/thesis/2011/b/nakai/nakai.pdf
[4] http://navi.cs.kumamoto-u.ac.jp/~koutaki/pukiwiki/index.php?%C0%B5%B5%AC%B2%BD%C1%EA%B8%DF%C1%EA%B4%D8%A5%DE%A5%C3%A5%C1%A5%F3%A5%B0

web拍手 by FC2
posted by シンドラー at 00:29 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2013年10月17日

HDR画像ビューアの作成 その2

昨日の続きです。

やはり負の値も扱いたかったので、-1〜1の場合、保存時には0〜2にシフトして保存、読込時には-1〜1の範囲に戻すことにしました。
シフトする量はヘッダのコメントなどがあればそこに入れたかったのですが、無駄が無さそうでしたので別ファイルで読書きすることにしました。

実行結果

HDRViewer_001.png

オレオレ仕様になってしまいましたが、-1〜1の範囲のように一応負の値でも取り扱えるようになりました。
その他、大きい画像は適当に縮小したり、マウスの中ボタンを押すとそこの画素値を表示するようにしたり、キーボード入力で0〜1の範囲に設定したりと、とりあえず必要な機能は実装できたかなと思います。

web拍手 by FC2
posted by シンドラー at 00:35 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2013年10月16日

HDR画像ビューアの作成

Luminance HDRを使ったのでいいのですが、とりあえず線形変換だけでいいのですぐ開いて確認して閉じるための自分用ビューアを作ることにしました。
対応ファイルフォーマットはRGBEだけで、読込み/書込みも[1]のプログラムを使用させていただいております。

このプログラムを作成中に気付いたのですが、RGBEって負の値は扱えないんですね。浮動小数点=float型だから負の値でもなんでも扱えるだろうと思って負の値を出力してました…。球面調和関数とかもHDRで負の値出力していたような気がするので確認してみないと…。
(rgbe.txtにはちゃんと0からって書いてました。ファイルフォーマット理解せずに適当に使ってると駄目ですね…。)

実行結果

[2]のサイトの画像でテストさせていただいております。



通常0〜1の範囲ですが、0〜21.75の間のデータになっているので、最初は暗いですが、マウスドラッグで範囲を調整すれば線形変換で一応暗いところ、明るいところの確認だけはできるようなものです。

[1] http://www.graphics.cornell.edu/online/formats/rgbe/
[2] http://www.anyhere.com/gward/hdrenc/pages/originals.html

web拍手 by FC2
posted by シンドラー at 00:43 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする