2011年5月20日金曜日

2次元グラフィックライブラリを作る的なはなし(3)

単純に横方向へスキャンするときの欠点。

横方向へスキャンをして、面積比でアルファチャンネルを決定するだけでも、
垂直に近い辺に関しては、結構キレイに表示できます。
↓

元の線は、こんな感じですかねー。

しかしこのやりかただけでは、大きな欠点がありますね。
それは、水平に近いせんの場合です。

こんな場合ですね。
↓


□の部分が、ガタガタです。ね 


本当はこうしたいところなのです
↓

単純なスキャンだけではすまなそうですね。
はい、ダメですね。
じゃぁ、どうしましょうねー。
どこに書いてあったってわけじゃぁないんですけど、私はこう考えました。

ずいぶん前に紹介した絶版の本、
によると、1ピクセルを、さらに細かくスキャンする方法、
例としては、4回スキャンして足し合わせるようなことが紹介されていました。
しかしそれでは、グラデっぽく表示されるピクセルが4ドットを超える場合に、
やっぱり、多少ガタガタしてきますね。
だからといって、数十回やればいいかっていう、交点を求めるコストを考えると、
それはやりすぎです。

ということで、1ピクセルの中で交点を、2点求め、直線補完をします。

今度はピクセルの中間ではなく、1ピクセルのはじまり近くと終わり近くの
2つの位置でスキャンし、交点を2つ求めます。
それが、A,Bですね。

そうしたら、下図のように色わけした部分(青・黄)部分の面積比(↓図のCに対する面積比)で、
アルファチャンネルを決定します。


こんな程度でも、結構、イイ感じになります。

まぁ、これはこれで問題があるにはあるんですけどね。^^;^^;




2011年5月18日水曜日

2次元グラフィックライブラリを作る的なはなし(2)

前回は矩形だから簡単だった。
でも三角形とかだったらどうなる。。?
↓

こういうのを考えると、ピクセルを考えなければ
↓ 

でも実際は1ピクセル以下は無理だから、
↓ 

でもアンチエイリアスというのをかけて
↓ 

これも実は、前回と同じように、スキャンするのです。
↓

でも前回と違って、スキャンの交点に、小数点が入ってしまいますね。

交点に小数点以下がなければ、
って感じですが、ある場合はこうします。
↓ 

即ち、交点を求め(A)、そこにタテ線を入れて(B)
その、色を塗る面積の比率で、色の濃さを決定します。
実際には、上図では、白と紫の中間の色のようになりますが、
実際はアルファチャンネルにするべきです。
そうでないと、キャンバス色が白でないと、おかしな話になります。

つづく。。。

2011年5月17日火曜日

2次元グラフィックライブラリを作る的なはなし。(1)

2次元グラフィックライブラリを作る的なはなし。(1)
最初は、矩形を描く話でしょう。やっぱり。
矩形といっても、輪郭ではなく、塗りつぶしです。
輪郭の方が、難しいからです^^;ね。

あ、図の網目はピクセルですが、XYは、座標なので、
小数点があるくらいに思っときましょう。

こんな↓矩形を塗りつぶすと、

こんな↓風になりますよ。


ここではこれを、(3,3)-(7,3)-(7,8)-(3,8)の矩形、POLYLINEと呼んで見ます。
早い話、この矩形の中に位置するピクセルだけに色を塗るわけです。

これを、ヨコ方向に考え、↓の絵のごとくSCANしていきます。
要するに、水平方向のスキャンラインと矩形の交点を算定し、
交点と交点の間を塗りつぶします。


ということで、ロジックですが、、、
(3,3)-(7,3)-(7,8)-(3,8)
の、Y方向の最大最小値を調べると、
MIN:3 MAX:8とわかります。
よって、スキャンするライン(ヨコ線)としては、
y=3.5~7.5まで、1.0ずつ増分させていけばそれらしくなります。
なぜ、0.5を足すかというと、なんとなく中間だからなんですけどね。
要するに、左上のピクセルを塗ることは、
(0,0)-(1,0)-(1,1)-(0,1)の矩形を塗りつぶすという意味だと考えれば、
ピクセルの中心座標は、0,0ではなく、0.5,0.5となります。

これが正しいという話ではなく、考え方としてなんとなくそんな感じという風に思えばいいです。

つづく



2011年4月30日土曜日

画像をぼかす。。とは?3

ということで、【キレイにボカす】ということで、ガウス消去ガウスぼかしをいってみましょう。
まず、これ↓がガウス分布というやつです。
どうやってつくったかっていうと、

double ar = 1.0; // 1.0  2.0  2.8
for(int a = 0;a<100;a++){
    double aa = (double)a / 10.0;
    double gausu = exp( - (double)aa * aa / (2.0 * ar * ar ) );
    printf("gausu:%.6f\n",gausu);
}
こんなことを書いて、テキストファイルにリダイレクトして、openOfficeの表計算に貼って、
グラフ化して、でもこれだとグラフは右半分だけだから、
グラフィック系S/Wで対象な図形にしたわけです。

これがどう関係するかということですが、
前回は、上下左右のピクセルの色をとってきて、それを平均化することで、
ぼかしてたわけです。
これを、上下左右を**ピクセルづつとってきたときに、
遠い方のピクセルの影響度を少なくしようという方法です。
上の分布のように、中心を100%として、中心のピクセルの影響度を100%としたときの、
周囲のピクセルの影響度を減らしていくのです。

この場合も、前回と同様に、X方向にガウスぼかしをしたあと、
Y方向にガウスぼかしをすることによって、
上下左右を一度にぼかした結果と等価になるのです。
なぜかはここでは問題ではないのです。

ということで、やってみると、、、





やっぱりキレイにボケてます。
ちなみに前回のガウスぼかしじゃないやつ↓


ただし、欠点もないわけではなく、同じようなボケ精度(どのくらい判別できないか)
という点で考えると、ガウスぼかしの方が範囲を広くとらないと、
シャープになってしまいます。
よって範囲を広く取ると計算量が増えるわけですね。
もちろん、部分的に使うという使い方もできるので、
そうすれば計算量はたいして増えませんよね。

まぁでも、用途によってそこらへんは使い分ければいいわけなので、
この話はこのくらいで。

ちなみに、逆ガウスぼかしをしてみたところ、、
(※離れるほど重みを増やす)
そもそも何をやってるかわからなっちゃいましたね
↓↓↓↓↓






2011年4月29日金曜日

画像をぼかす。。とは?2


前回はモノクロだったので、カラーに適用するとこうなりますよ、、的な話。
もちろん、平均はR,G,Bと別々に平均をとりますよ。
αチャンネルはどうしましょうかね。まぁとりあえずは元のままでいいでしょう。
(平均を取らずにもとのピクセルのα値をそのまま使用する)
但し、正しくはというか、画像の合成という話題になったりすると、
αチャンネルをもつ画像同士の合成なんかを考えなきゃならないので、
そのとき考えましょう。
このへんのことは、正しく処理されていないS/Wをときどき見かけますんで、
っていうか、自分でも何度もバグを出しましたけどね^^;^^;^^^;

ってことで、あとはサンプルの画像のみで。







↑これがガウスぼかし(半径15)
カラーですると、単純に前後左右で矩形で平均をとったものと
歴然の差がでますね。^^;^^;^^;
なんか、、【キレイにボケてる】感があります。

うん。しょうがない。次回はガウスぼかしだな^^;^^;


画像をぼかす。。とは?

画像をぼかす。。って、ちょこちょこ書いてたわけですが、
技術的には、非常に簡単な考え方です。

下図の黒い部分がドット(ピクセル)だとすると、
その周辺を含めた平均を出し、その値に変換してしまうのです。
要するに、赤いピクセルに着目し(下図の■)、
その周辺、たとえば前後左右を1ピクセルずつ考慮すると、
9ピクセルの矩形が考えられます(下図の□)。
これの平均を出して、変換後のピクセルの色にしてしまうだけです。
この画像を前後左右1ピクセルを考慮すると、
↓
こうなります。


どうようにして、こんな画像を用意して、
影響範囲を前後左右1ピクセルの3*3=9ドットの平均すると
↓ 
影響範囲を前後左右2ピクセルの5*5=25ドットの平均すると
↓  

影響範囲を前後左右3ピクセルの7*7=49ドットの平均すると
↓  
影響範囲を前後左右4ピクセルの9*9=81ドットの平均すると
↓   


影響範囲を前後左右7ピクセルの15*15=225ドットの平均すると
↓    

影響範囲を前後左右15ピクセルの31*31=961ドットの平均すると
↓   


っとこれでわかるように、演算量は、2乗に比例するような気もするのですが、
実は、タテと横を別々に行っており、最初にヨコでぼかした画像を生成し、
それをさらにタテにぼかして画像を生成します。
よって、計算量は、2乗ではなく、2Nですかね。。

間単に、【平均】なんて書いてしまいましたけど、平均のとりかたに、
重みをつけたりすると、微妙に結果がかわります。

そこらへんは、、、まぁ、いろいろ調べてみましょう^^;^^;
その中のひとつに、【ガウスぼかし】なるものがあります。
まぁたいしたものでもないのですが、たまにはSRCを乗せると。。
二重のLOOPを2回まわしてるだけですね。^^;
int minusv = (haba - 1) / 2;
    for(int yy = 0;yy<hh;yy++){
        for(int xx = 0;xx<ww;xx++){
            for(int z=0;z<haba;z++){
                int idxx = xx + z - minusv;
                int idxy = yy;// + z - 2;
                if(getPixelIndex(G,idxx,idxy)){
                    uc[z] = G.GetPixelsDirect3(idxx,idxy);
                }
            }
            unsigned int ucc = getBock5(uc,haba);
            GO.SetPixels32(xx,yy,ucc);
        }
    }
    for(int yy = 0;yy<hh;yy++){
        for(int xx = 0;xx<ww;xx++){
            for(int z=0;z<haba;z++){
                int idxx = xx;// + z - 2;
                int idxy = yy + z - minusv;
                if(getPixelIndex(GO,idxx,idxy)){
                    uc[z] = GO.GetPixelsDirect3(idxx,idxy);
                }
            }
            unsigned int ucc = getBock5(uc,haba);
            G.SetPixels32(xx,yy,ucc);
        }
    }

2011年4月23日土曜日

【αちゃんねる】な件。3

さて今回は前回のつづきで、グレースケール画像のふちどりです。
これは、こういうことをしたいからですね。
(※画像がちょっとキタナイのは圧縮の高いJPEGだから^^;)
↓

これも、もと画像から作成することができます。
元画像
↓
まず、元画像をボカします。
ここでは、ガウスぼかしをしました。
それがこれ
↓
そうしたらこの画像の中の白でない部分を黒に変換します。
拡大してみると(下図)、入り組んだところは、こういう風になってるので、
この白に近いグレーも黒にします。



おどろくなかれ、白でない部分ってこんなにあるんですね。
↓
しかし、白でない部分を黒にしたってことは、白と黒の2値、
即ち、#000000と#ffffffの2つだけなので、ギザギザになってしまいますね。
よってこれをさらにガウスぼかしします
↓
そうこれを前回やった、グレースケールをαチャンネルに置き換え、
さらに白に乗せ、それを黒い画像に置くと、こうなります。
↓

最後に、赤を乗せた葵の御紋をのせれば、
完成ですね。
↓

で、千社札っぽくしてみます。
そんでもって、前回のと比べてみましょう。。
ぜんぜんイイっすね。ふちどりした方が。。^^;

ということで、、
【結論。】
【モノクロのグレースケール画像さえ準備すれば、
それに色をつけたり、ふちどりしたりしたパーツとして、
貼りこむことが可能である】

でもどうやって?という話はまた今度。