ラベル グラフィックス の投稿を表示しています。 すべての投稿を表示
ラベル グラフィックス の投稿を表示しています。 すべての投稿を表示

2015年6月24日水曜日

ハフ変換(3)-ソースコードを見てみると。。。

それではググって、サンプルのソ-スでも見てみましょう。
とりあえず、ここあたりがソースとしてはわかりやすいです。
以下、抜粋です。
※<が漢字になってます。注意。
   //直線の場合 -------------------------------------------------
      int theta,rho;
      //直線検出用頻度カウンタ
      short[][] counter=new short[THETA_MAX][2*RHO_MAX];

      for(y=0;y<YMAX;y++)
         for(x=0;x<XMAX;x++)
            if(data[y][x]==1){
               for(theta=0;theta<THETA_MAX;theta++){
                  rho=(int)(x*cs[theta]+y*sn[theta]+0.5);
                  counter[theta][rho+RHO_MAX]++;
               }
            }

まぁ、中カッコ{}の有無が気に入りませんが、
まず、XとYの2重LOOPを回しています。
これは、『画像の全ての点』を対象にしているという意味ですね。

そして、その場所に該当データがあるかどうか、実際には点があるかどうかを判定し、
 点があった場合には、1024回のLOOPを回しています。
※THETA_MAXが1024 cs,snはsin,cosを再計算させるのを防止するため(CPU負荷がかかるから)、あらかじめテーブルにいれてあります。

同じ直線上の点であれば、 counter[角度][距離]が同じなので、
++でインクリメントしていきます。 まぁここまでは、だれが書いても似たようなコードになるでしょうかあr、特に問題はありませんですね。(o^^o) 

考えるとすれば、THETA_MAXが1024となっていますが、
この適切な値はどうやって決めるかという問題になりますね。

これには、ターゲットとする画像によって違うわけです。
ここでは、800*1200くらいに考えてみると、、、
ヨコ線が左右の端部で1ピクセル上下にズレた直線と仮定すると、
atan(1/800)→0.072度
180/0.072→2500分割くらい必要になります。

よって、上記のサンプルのTHETA_MAXはdefineされていますが、
本来はここは動的にするべきものとなりますね。 

さて、上記のrhoは、原点と直線の距離になるわけですが、
どのような値をとりえるかというと、実はマイナス値もとることがわけです。
はやい話、、こういう場合です。
 
では実際に、どのような値になるかを、
プログラムで確認してみましょう。

 つづく

2015年6月22日月曜日

ハフ変換(2)-そもそもハフ変換とは何か

よっぽど完成されたライブラリを使う以外は、 自分で理解できないソースコードは書くべきでないことは言うまでもありませんが、 そもそもハフ変換による直線の抽出はどうゆう理屈かという話の第一ステップを考えてみます。(o^^o)

では、点が4つあったと考えましょう。
これです。

さて点を1点以上通る直線は、無限です。
早い話、点Aを通る直線は、点Aを中心に0~180度
の分だけ、無限に引けるわけです。

点を2点以上通る直線が何本ひけるかというと、
4本です。


  
ここでどういう考え方をするかというと、
【点Aは直線1を通る点である】ということです。

また同様に、
【点Dは直線1を通る点である】ということです。

そうすると逆に、
【直線1を通る点は、A,Dの2点ある】ということです。

また、



【直線5を通る点は、Aの1点ある】ということです。
まぁAを通る直線は無限にあるわけですが、例として書きました。

これらを集計して、
【2点以上通る線のみ有効なものとする】
と判定できれば、直線1~4の4つが集計できるという、こういうわけです。

しかしながら、そもそも【直線1】をどう定義して、
【どのように判定したら点Aを通るとわかるのか?】という話が、本題となります。

ここで、以下の図のような考え方をするわけです。
 
●直線1とは、
・水平とのなす角度が『角度1』
・原点Oとの距離が『L1』
と定義できるのですね。

そうすると、例えば、、100ピクセル×100ピクセルの画像を考えると、
●角度は0~180度まで考えられる
●直線と原点との距離は、最大でも141ピクセルである
ということがわかります。
そうすると、とたえ1度刻みにしたとしても、
141×180=25,380コのデータが必要になります。
0.1度刻みにすれば、253,800コのデータが必要になります。
ようするに、、
data[141][180]
のデータを持って、それぞれいくつの点を通るかを判定するという、
ものすっごくベタなことをする、
それをするのがハフ変換なのです。

つづく




2015年6月20日土曜日

ハフ変換(1)-画像の角度を判定する

久々にまともな技術系な話です。
題名はハフ変換ですが、要するにこういうことです。
スキャナでスキャンした画像とかありますよね。
それを角度がついてるときに、戻したいって話です。
つまりこういうことです。
(1)スキャンした画像

(2)なんとなく角度を算定するために直線部分を検出する

(3)検出した角度から、正しい角度を予測して回転させる

まぁこんなことやりたいわけです。

まぁ、【ハフ変換】とかぐぐれば、なんとなくヒントがみつかるわけですが、
そして、サンプルのソースとかのってたりするわけですが、
はたまたOpenCVあたりのサンプルでも似たようなものがあったりするわけですが、
やってみればわかります。
そんな簡単にはいかないと。
では、どうしましょう。
まぁ元々技術的に無理がある話でもないので、ひとつずつ解決していきましょう。

ってことで、つづく(o^^o)


2014年6月26日木曜日

画像を縮小する(平均化)する件。

アルファチャンネルにアルファチャンネルを重ねる件とも似通った話ですが、画像を縮小化する場合の処理を考えてみます。
簡単に考えるために、2ピクセルを1ピクセルにすることを考えます。
もちろん、□と■を平均化すれば、中間のグレイになるだろうことはだれでも予想がつきます。
では、R1G1B1A1とR2G2B2A2を平均するにはどうすればよいか。

正しい方法ではないですが、特殊解から一般解を導くとたいてい合っている!
という方法があります。
そうすると、
0x00FFFFFF と 0xFFFFFFFF を混合すれば、、
0x80FFFFFF と なりそうなことは容易に想像できます。
※または、0x7FFFFFFF
ということは、、アルファの値は単純に平均をとるだけでいいような気がするので、
いいということにしましょう。

問題は、RGB部分のFFFFFFというところです。
これだけみると間違った方法をとってしまいそうなので、
別の特殊解を考えて見ます。そう、
0x00FF0000 と 0xFFFFFFFF を混合しても、、
0x80FFFFFF と、同じ結果となります。
当然と言えば当然で、アルファが0であれば、RGBが何であっても
表示上は何も無いので同じわけです。

さぁ、ここで、これらを黒地に置いた場合を考えると、
0x00FF0000 → 0xFF000000
0xFFFFFFFF → 0xFFFFFFFF

そうすると、前回と同じように、V1、α1、V2、α2とすると、
V1=100、α1=0
V2=100、α2=1.0
結果→α3=0.5、V3=100
とすると、どうやら、(V1α1+V2α2)/2 が、黒地に置いたときの実際の値と思われるので、
V3=((V1α1+V2α2)/2)/α3
  =((0*100)/2)/0.5=50/0.5=100 という感じと予測できます。
V1=100、α1=0.5とすれば、
V3=(150/2)/0.75=75/0.75=100 となり、V3=100、α3=0.75となるので、
これでもあってるっぽいですね。

で、結論としては、
●αは単純に平均化するのみ
●RGBはそれぞれの要素に関して、αをかけたR´G´B´を足し合わせて平均化し、
平均化されたαで割り返す
となります。












2014年6月25日水曜日

アルファチャンネルにアルファチャンネルにを重ねる件(3)

で、前回、こんなことを書いたわけです。

--------------------------------------------------
●元ピクセル
値V1、α:alp1
●のせる方のピクセル
値V2、α:alp2
としたとき合成したピクセルの値(B)は、
A = (0xff * (1-alp1) + V1 * alp1) * (1-alp2) + V2 * alp2
alp3 = alp2 + alp1*(1-alp2)
B = (A - 0xff*(1-alp3))/alp3
--------------------------------------------------
しかし、ハタと気づくわけです。
または感じるわけです。
何かが美しくないと。(o^^o)

そうです。白(0xff)の上に画像を置いた揚句、
あとからその部分を取り除くような考え方をしているわけです。
じゃぁ、黒の上に置いたらどうなるか。
そうすると、0xFFの部分が0になるわけなので、
A = (V1 * alp1) * (1-alp2) + V2 * alp2
= V1 * alp1 + V2 * alp2 - V1 * alp1 * alp2(式1)
alp3 = alp1 + alp2 - alp1*alp2(式2)
B = A /alp3
と、こうなるわけですね。
式がそれっぽくなりました。

で、検算してみると、うん。正しいようです。


ここで、式を見てみます。
式2を見ると、最終的なアルファの値は重ねる順序に関係な無いことがわかります。
式1を見ると、最終的なピクセルの値は、順序と関係する事がわかります。
そりゃあそうです。
白100%の上に赤100%を乗せれば赤になるし、逆なら白になるに決まってますよね。

2014年6月24日火曜日

アルファチャンネルにアルファチャンネルにを重ねる件(2)

で、色が違うときの話です。
まず、サンプル。

では、重なり部分のR成分の計算。
0xff * 0.5 + 0xff * 0.5 = 0xff
0x80*0.3 + 0xff * 0.7 = 0xD9
では、重なり部分は、
(0xff * 0.5 + 0xff * 0.5) * (1-0.3) + 0x80 * 0.3=0xD9
うんうん。ここまではあってますね。

では、前回と同じように合成後のアルファを考えると、
0.3 + 0.5 * (1-0.3)→0.65となる。
0.5 + 0.3 * (1-0.5)→0.65.もちろん同じ。

0xff * 0.35 + A * 0.65 = 0xD9
よって、
0xD9-0xff*(1-0.65)→0xC5
これをRGB要素全てに適用すればできる。。ハズ。

また重なってない部分を考えると、
0.3 + 0 * (1-0.3) →0.3
0xff*0.7 + A * 0.3 = 0xD9
A=0xff、アルファ:0.3
うん。できてるな。(o^^o)

ということで、
●元ピクセル
値V1、α:alp1
●のせる方のピクセル
値V2、α:alp2
としたとき合成したピクセルの値(B)は、

A = (0xff * (1-alp1) + V1 * alp1) * (1-alp2) + V2 * alp2
alp3 = alp2 + alp1*(1-alp2)
B = (A - 0xff*(1-alp3))/alp3

となります。
地道に展開したらもしかして簡単になるのでしょうか。。。
やってみますわー。

っといましたが、かここであることに気付くわけです。
で、それは次回で(o^^o)

アルファチャンネルにアルファチャンネルを重ねる件。

アルファチャンネル付き画像に、
アルファチャンネル付き画像を乗せたときの結果が、
思わしくない状況に遭遇することがあります。
では、何が正しいのかをちゃんと考えてみます。
PHP画像合成のバグもこの範疇に入ると思われます。
ということで、計算しやすくするため、以下の画像を考えます。
これは、イラレで矩形を透過属性付きで作成したもので、
黒白はα=1、
右の赤の矩形はα=80%
左と中央の赤の矩形はα=40%
としました。
そして画面キャプチャをとって、ピクセルの値を調べた値を#テキスト表示しています。


■白の上に赤40%→#FF9999。
R要素→ FF*60%+FF*40% → 0xff
GB要素→ FF*60%+00*40% → 153 → 0x99
よって、FF9999

■黒の上に赤40%→#660000。
R要素→ 00*60%+FF*40% → 0x66
GB要素→ 00*60%+00*40% → 0x00
よって、660000

■白の上に赤40%、さらに赤40%→#FF5C5C
さてここの考え方が、全てのポイントである。
GB要素→ FF*A%+00*40% → 92 → 0x5C
よって、Aは36%である。
ということは、明らかに、60%*60%である。

ようするに、アルファ:40%の画像の上に、アルファ30%の画像を載せたときの
アルファは、
30% + 40% * (100-30)% → 30+28 → 58% となる。
逆にすると、
40% + 30% * (100-40)% → 40+18 → 58% となり、やっぱり同じである。

シンプルな話なんですけどね。。。。。。(o^^o)
ただし、サンプルは同じ色のアルファだけ変えたサンプルなので、
色が違うときは、、、次回で。(-_-;)

2014年6月16日月曜日

PHPの画像合成のバグ

PHPで画像の合成なのですが、、 もちろん、
imagesavealphaと
imageAlphaBlendingを設定して、
imagecopyしたものを、
imagepng したわけですが、
こんな結果です。
●1

●2

●3


全て、中央の画像に右の画像を合成したものが左の画像なので、
本来は全て同じハズです。
違いは、中央の画像のα=0のピクセルのRGBの値が3つとも違い、
上から、0x000000(黒) 0xff0000(赤) 0xffffff(白)です。
要するにBLENDするときに、α=0の部分ももってきてしまって、
BLENDした挙句、αの値の平均でもとっているのでしょうかね。
どっちにしても、ダメっすねー。
まぁきちんと解明してみますです。(o^^o)
とりあえず、こういうバグがあるということでした。

追記
本来はこうあるべきというの作成。

上段がイラレで作成、
下段が自前のプログラムで作成。
残念ながら、僅かな誤差がありましたが(3Fと40とか^^;)、
基本的にはあっています。



2013年12月19日木曜日

大人の水彩画塗り絵のように加工する件。

前回のつづきとして、
水彩塗り絵っぽくする画像処理を考えます。
水彩塗り絵っぽくとは具体的に言うと、
・縁取りがしてある
・色が全体的に薄い
・色数が少ない
だいたい、こんなとこでしょう。
ただし、『水彩独特の筆のタッチ』とかは考慮しません。
それは、GUIアプリならば考慮できますが、自動ではなかな難しそうです。
機会があったらやってみますが。。。

ということで、縁取りは前回もやったので、
今回は、
(1)色を薄くする
(2)色数を少なくする
ということをしてみます。

具体的には、どうすればいいんでしょうね。。
ちなみに、何も参考にせずにこれを書いてるわけですが、
色は、とりあえずRGBで考えるとすると、
FF0000なんていうのは、真っ赤になっちゃいますから、
これを、FF8080あたりになるようなロジックです。
じゃぁどうするかというと、とりあえず、RGBそれぞれの成分に関して、、

0x20~0x50程度を足す。
1.2倍~2倍程度の倍率をかける。
0xffを超えるものは、0xffで頭打ちにする。

っとまぁ、この程度のことしてみた結果が以下です。
でも、まぁ、この程度でも結構いけます。
問題は、その
パラメータをヒストグラムあたりみて、自動的に設定する
ロジックですねーー。

【元画像】


【変換画像】



【SRC。こんな程度。】
RR = ((RR + 0x30) * 4)/3; if(RR > 0xff) RR = 0xff;
GG = ((GG + 0x30) * 4)/3; if(GG > 0xff) GG = 0xff;
BB = ((BB + 0x30) * 4)/3; if(BB > 0xff) BB = 0xff;
RR = ((int)(RR / 32))*32+31;
GG = ((int)(GG / 32))*32+31;
BB = ((int)(BB / 32))*32+31;



2013年12月9日月曜日

ベクトル図形のANDをとってみる件。(2)

つづきです。
では、順を追ってみましょう。
まず最初に、直線を登録(setLine)しているので、
こっから、頂点と交点、即ち、直線の始点/終点/直線同士の交点を求めます。
交点の求め方とかは、ここらへんを参考にどうぞ。
そして、今度はそのY座標だけをArrayに入れて、SORTしてみます。
そうすると、こういう結果になります。
# 0 : 20.0000 - 10.0000  
# 1 : 40.0000 - 10.0000  
# 2 : 60.0000 - 20.0000  
# 3 : 36.3636 - 20.9091  
# 4 : 50.0000 - 30.0000  
# 5 : 10.0000 - 40.0000  
# 6 : 30.0000 - 40.0000  
# 7 : 60.0000 - 40.0000  
# 8 : 45.0000 - 40.0000  
# 9 : 40.0000 - 50.0000 
# 0 : 10.0000
# 1 : 20.0000
# 2 : 20.9091
# 3 : 30.0000
# 4 : 40.0000
# 5 : 50.0000

図で言えば、こういうことです。
ここで、Y座標は6コあることがわかります。
このY座標で水平な線を引き、
全ての登録した直線に対して、その直線で分割してしまいます。
ただし、水平な線は含みません。
ようするに、こういうことです。
データにすると、こういうふうになっています。
ここで、いくつかの値を一緒に登録しています。
(1)【tag】。分断する前の直線を一意に識別するための番号。
(2)【bup】。直線が、上を向いているか(終点のY座標>始点のY場表)どうか。
(3)【hnum】。その直線が、どの段(直線の中点がどのY座標の間にあるか)にあるか。
※全て、あとで使います。

# 0  tag:1  bup:1  bHz:0 hnum:1 x1:20.0 y1:10.0 x2:16.7 y2:20.0 x:18.3 y:15.0
# 1  tag:4  bup:0  bHz:0 hnum:1 x1:35.0 y1:20.0 x2:20.0 y2:10.0 x:27.5 y:15.0
# 2  tag:5  bup:1  bHz:0 hnum:1 x1:40.0 y1:10.0 x2:36.7 y2:20.0 x:38.3 y:15.0
# 3  tag:8  bup:0  bHz:0 hnum:1 x1:60.0 y1:20.0 x2:40.0 y2:10.0 x:50.0 y:15.0
# 4  tag:1  bup:1  bHz:0 hnum:2 x1:16.7 y1:20.0 x2:16.4 y2:20.9 x:16.5 y:20.5
# 5  tag:4  bup:0  bHz:0 hnum:2 x1:36.4 y1:20.9 x2:35.0 y2:20.0 x:35.7 y:20.5
# 6  tag:5  bup:1  bHz:0 hnum:2 x1:36.7 y1:20.0 x2:36.4 y2:20.9 x:36.5 y:20.5
# 7  tag:7  bup:0  bHz:0 hnum:2 x1:60.0 y1:20.9 x2:60.0 y2:20.0 x:60.0 y:20.5
# 8  tag:1  bup:1  bHz:0 hnum:3 x1:16.4 y1:20.9 x2:13.3 y2:30.0 x:14.8 y:25.5
# 9  tag:5  bup:1  bHz:0 hnum:3 x1:36.4 y1:20.9 x2:33.3 y2:30.0 x:34.8 y:25.5
# 10  tag:4  bup:0  bHz:0 hnum:3 x1:50.0 y1:30.0 x2:36.4 y2:20.9 x:43.2 y:25.5
# 11  tag:7  bup:0  bHz:0 hnum:3 x1:60.0 y1:30.0 x2:60.0 y2:20.9 x:60.0 y:25.5
# 12  tag:1  bup:1  bHz:0 hnum:4 x1:13.3 y1:30.0 x2:10.0 y2:40.0 x:11.7 y:35.0
# 13  tag:5  bup:1  bHz:0 hnum:4 x1:33.3 y1:30.0 x2:30.0 y2:40.0 x:31.7 y:35.0
# 14  tag:3  bup:0  bHz:0 hnum:4 x1:45.0 y1:40.0 x2:50.0 y2:30.0 x:47.5 y:35.0
# 15  tag:7  bup:0  bHz:0 hnum:4 x1:60.0 y1:40.0 x2:60.0 y2:30.0 x:60.0 y:35.0
# 16  tag:2  bup:1  bHz:0 hnum:5 x1:10.0 y1:40.0 x2:40.0 y2:50.0 x:25.0 y:45.0
# 17  tag:3  bup:0  bHz:0 hnum:5 x1:40.0 y1:50.0 x2:45.0 y2:40.0 x:42.5 y:45.0

これで、準備が整いました。
これから、ANDとかORの演算をすることになります。

次回につづきますが、きっと、ちょっとわかる人は、この図を見ればわかります。


つづく。



2013年12月8日日曜日

ベクトル図形のANDをとってみる件。

●図形を演算する話。
ベクタ画像を合成(演算)する件。のつづきです。
簡単に実装してみますです。
こぅいぅときゎ、まず、どう使いたいかをcodingしてみます。
とりあえず、こうしました。
aPolies A;
//1つめ
A.setLine(20,10,10,40);
A.setLine(10,40,40,50);
A.setLine(40,50,50,30);
A.setLine(50,30,20,10);
//2つめ
A.setLine(40,10,30,40);
A.setLine(30,40,60,40);
A.setLine(60,40,60,20);
A.setLine(60,20,40,10);
A.execute();
A.test();
で、test()の結果が以下です。
# moveTo [5] 36.36 20.91
# lineTo [5] 30.00 40.00
# lineTo [0] 45.00 40.00
# lineTo [3] 50.00 30.00
# lineTo [4] 36.36 20.91
それぞれのデータをグラフにすると、以下です。



実際には、7つのステップを踏んで、この座標を割り出しています。 それが、以下ですね。
# 0 : 20.0000 - 10.0000
# 1 : 40.0000 - 10.0000
# 2 : 60.0000 - 20.0000
# 3 : 36.3636 - 20.9091
# 4 : 50.0000 - 30.0000
# 5 : 10.0000 - 40.0000
# 6 : 30.0000 - 40.0000
# 7 : 60.0000 - 40.0000
# 8 : 45.0000 - 40.0000
# 9 : 40.0000 - 50.0000
------------------------
# 0 : 10.0000
# 1 : 20.0000
# 2 : 20.9091
# 3 : 30.0000
# 4 : 40.0000
# 5 : 50.0000
------------------------
# 0  tag:1  bup:1  bHorizon:0  x1:20.0 y1:10.0 x2:10.0 y2:40.0 x:15.0 y:25.0
# 1  tag:2  bup:1  bHorizon:0  x1:10.0 y1:40.0 x2:40.0 y2:50.0 x:25.0 y:45.0
# 2  tag:3  bup:0  bHorizon:0  x1:40.0 y1:50.0 x2:50.0 y2:30.0 x:45.0 y:40.0
# 3  tag:4  bup:0  bHorizon:0  x1:50.0 y1:30.0 x2:20.0 y2:10.0 x:35.0 y:20.0
# 4  tag:5  bup:1  bHorizon:0  x1:40.0 y1:10.0 x2:30.0 y2:40.0 x:35.0 y:25.0
# 5  tag:6  bup:1  bHorizon:1  x1:30.0 y1:40.0 x2:60.0 y2:40.0 x:45.0 y:40.0
# 6  tag:7  bup:0  bHorizon:0  x1:60.0 y1:40.0 x2:60.0 y2:20.0 x:60.0 y:30.0
# 7  tag:8  bup:0  bHorizon:0  x1:60.0 y1:20.0 x2:40.0 y2:10.0 x:50.0 y:15.0
------------------------
# 0  tag:1  bup:1  bHz:0 hnum:1 x1:20.0 y1:10.0 x2:16.7 y2:20.0 x:18.3 y:15.0
# 1  tag:4  bup:0  bHz:0 hnum:1 x1:35.0 y1:20.0 x2:20.0 y2:10.0 x:27.5 y:15.0
# 2  tag:5  bup:1  bHz:0 hnum:1 x1:40.0 y1:10.0 x2:36.7 y2:20.0 x:38.3 y:15.0
# 3  tag:8  bup:0  bHz:0 hnum:1 x1:60.0 y1:20.0 x2:40.0 y2:10.0 x:50.0 y:15.0
# 4  tag:1  bup:1  bHz:0 hnum:2 x1:16.7 y1:20.0 x2:16.4 y2:20.9 x:16.5 y:20.5
# 5  tag:4  bup:0  bHz:0 hnum:2 x1:36.4 y1:20.9 x2:35.0 y2:20.0 x:35.7 y:20.5
# 6  tag:5  bup:1  bHz:0 hnum:2 x1:36.7 y1:20.0 x2:36.4 y2:20.9 x:36.5 y:20.5
# 7  tag:7  bup:0  bHz:0 hnum:2 x1:60.0 y1:20.9 x2:60.0 y2:20.0 x:60.0 y:20.5
# 8  tag:1  bup:1  bHz:0 hnum:3 x1:16.4 y1:20.9 x2:13.3 y2:30.0 x:14.8 y:25.5
# 9  tag:5  bup:1  bHz:0 hnum:3 x1:36.4 y1:20.9 x2:33.3 y2:30.0 x:34.8 y:25.5
# 10  tag:4  bup:0  bHz:0 hnum:3 x1:50.0 y1:30.0 x2:36.4 y2:20.9 x:43.2 y:25.5
# 11  tag:7  bup:0  bHz:0 hnum:3 x1:60.0 y1:30.0 x2:60.0 y2:20.9 x:60.0 y:25.5
# 12  tag:1  bup:1  bHz:0 hnum:4 x1:13.3 y1:30.0 x2:10.0 y2:40.0 x:11.7 y:35.0
# 13  tag:5  bup:1  bHz:0 hnum:4 x1:33.3 y1:30.0 x2:30.0 y2:40.0 x:31.7 y:35.0
# 14  tag:3  bup:0  bHz:0 hnum:4 x1:45.0 y1:40.0 x2:50.0 y2:30.0 x:47.5 y:35.0
# 15  tag:7  bup:0  bHz:0 hnum:4 x1:60.0 y1:40.0 x2:60.0 y2:30.0 x:60.0 y:35.0
# 16  tag:2  bup:1  bHz:0 hnum:5 x1:10.0 y1:40.0 x2:40.0 y2:50.0 x:25.0 y:45.0
# 17  tag:3  bup:0  bHz:0 hnum:5 x1:40.0 y1:50.0 x2:45.0 y2:40.0 x:42.5 y:45.0
------------------------
# 0  tag:5  bup:1  bHz:0 hnum:3 x1:36.4 y1:20.9 x2:33.3 y2:30.0 check:1
# 1  tag:4  bup:0  bHz:0 hnum:3 x1:50.0 y1:30.0 x2:36.4 y2:20.9 check:1
# 2  tag:0  bup:0  bHz:1 hnum:3 x1:33.3 y1:30.0 x2:50.0 y2:30.0 check:0
# 3  tag:5  bup:1  bHz:0 hnum:4 x1:33.3 y1:30.0 x2:30.0 y2:40.0 check:1
# 4  tag:3  bup:0  bHz:0 hnum:4 x1:45.0 y1:40.0 x2:50.0 y2:30.0 check:1
# 5  tag:0  bup:0  bHz:1 hnum:4 x1:30.0 y1:40.0 x2:45.0 y2:40.0 check:1
# 6  tag:0  bup:0  bHz:1 hnum:3 x1:50.0 y1:30.0 x2:33.3 y2:30.0 check:0
------------------------
# 0  tag:5  bup:1  bHz:0 hnum:3 x1:36.4 y1:20.9 x2:33.3 y2:30.0 check:1
# 1  tag:5  bup:1  bHz:0 hnum:4 x1:33.3 y1:30.0 x2:30.0 y2:40.0 check:1
# 2  tag:0  bup:0  bHz:1 hnum:4 x1:30.0 y1:40.0 x2:45.0 y2:40.0 check:1
# 3  tag:3  bup:0  bHz:0 hnum:4 x1:45.0 y1:40.0 x2:50.0 y2:30.0 check:1
# 4  tag:4  bup:0  bHz:0 hnum:3 x1:50.0 y1:30.0 x2:36.4 y2:20.9 check:1
------------------------
# moveTo [5] 36.36 20.91
# lineTo [5] 30.00 40.00
# lineTo [0] 45.00 40.00
# lineTo [3] 50.00 30.00
# lineTo [4] 36.36 20.91
つづく。

2013年9月27日金曜日

ベクタ画像を合成(演算)する件。

なぜかはよくわからないけど、図形を演算するロジック、
そう、イラストレータで言えば、『パスファインダ』、
これ↓である。
この機能を作りたかったのだが、どうにもこうにもそれらしい情報が、
ネットを見てもほとんどないのである。
で、かろうじて合ったのはここ。
http://www7b.biglobe.ne.jp/~garaku/Boolean.html
途中まではわかりやすいのだが、途中以降はよくわからないので、自分流にやってみた。
でも、そもそもなんでこんな基本的なことが出てないんだろうと言う疑問はさておき、
とりあえず、題材を元にロジックをかいてみよう。

【1】題材はこれ。
ピンクの図形と、薄緑の図形。

【2】ベクトル方向
もちろん、緑図形が抜けているのはベクトルの廻りが逆だから。
今回は、右回りを基本とする。
基本というか、最外郭が右回りという前提である。
【3】Y座標の算定
全てのベクトルを見たとき、次の点のY座標を抽出する。
図では横線として表示。
●ベクトルの始点
●ベクトルの終点
●ベクトル同士の交点
-----------------
そして、各ベクトルを横線で分割する。
【4】ベクトルに値を設定
上向きを+1、下向きを-1とする。
--------------------
次に、横線の間の各段(横線の数-1)ごとに、
左側から、値を集計し、記入す。
最後は0になるはず。
0にならなかったら、図形が閉じていないのだ。


【5】今回は、図形をORしてみる。

次に、横線の間の各段(横線の数-1)ごとに、
左側からベクトルをみて、+1(↑)と0(↓)を抽出し、それらのベクトルが離れている場合は右回りになるように、三角形または四角形を作成する。

【6】図形を分割したんだよ。
上記の【5】の作業で作成された、三角形と四角形は、←の図のようになる。
ここからいらないと思われる水平のベクトルを削除していくのだ。
【7】ちょっと説明が難しいので、簡単な例を。
←の図は四角形が3つだが、上の四角形の底辺(=下の四角形の上辺)の位置の水平のベクトルを考えてみる。
【8】左回り図形になってしまったが、、、
頂点を左から番号をふると、6コある。

【9】頂点が6コということは、間は5コということである。
これの、偶数番目の間にあるベクトルを削除するのである。
上の四角形の底辺のベクトルは、4と3と2なので、2を削除する。
左下の四角形の上面のベクトルは、1と2なので、2を削除する。
右下の四角形の上面のベクトルは、4と5なので、4を削除する。
【10】ちなみに、頂点がダブったときも、頂点は2コあるということにする。
【11】残ったベクトルをつなぎ合わせると、左図のような図形ができあがる。
【12】【6】に戻って、同様の処理を行う。
【13】水平のベクトルはこのようになる。
【14】右上部分を拡大すると、こんな感じ。
よって、上部の三角形の底辺は、
1-2-3-4-5-6-7-8なので、2-3,4-5,6-7のベクトルは削除される。
また、1と2、3と4、5と6、7と8は同じ点なので、最終的にはこの三角形の底辺の部分の水平のベクトルは全て削除される。
【15】残ったベクトルをつなぎ合わせると、このようになる。
※点線部はないよ。

あとは、冗長点の削除をすればよいですね。
つづく。

2013年1月18日金曜日

ghostScriptのラスタライズが正しく透過されない件。

何の話かというと、。。。。

ghostScriptでPDFをPNG出力させてみても、バックが正しく透明にならない。
-sDEVICE=pngalpha を指定しても、『中途半端に透過』しているだけなのだ。
図形があると、そのboundingboxの背景が白くなり、早い話使い物にならない。

ということで、これを正しく透過させるべく、いろいろやってみた。
もちろん、ghostScriptのソースに手をいれればいいのだが、再配布のときにめんどいので、ここではghostScriptには手を入れずにやってみる。

しかしながら、普通に考えたら無理なのである。
透過して白なのか、白い矩形があって白なのかは、ラスタライズされた画像をみても区別がつかないのである。
で、ここでは、どうやってそうするかは別にして、PDFの中のエンティティの色を全て黒くすればそれらしくできるのである。

もちろんPDFの中身のエンティティの色を全て黒にするとなると、それはそれで面倒な話ではあるが、ここではそれには触れない。

ということで、今回やりたかったことは、
↓この画像

を使って、
↓この画像

を生成することである。
そのためには、結論から言えば
↓こういう画像

が必要になるのである。


理論的には、。。。。

透過属性をもつPNG画像を、何かの画像の上に置くならば、その1ピクセルに着目すると、
PIXELの色は、
元々のPIXELの色*(1-PNGの当該PIXELのアルファ値)+PNGの当該PIXELの色*PNGの当該PIXELのアルファ値
である。<br/>
よってこれを逆算すればいいのだ。

以下は実際のコードのLOOPの中で、1ピクセルに対しての処理を行っている部分である。
unsigned int alp = bvalue ^ 0xff;

unsigned char* bp = (unsigned char*)pN;
unsigned int BB = bp[0];
unsigned int GG = bp[1];
unsigned int RR = bp[2];

int vBB = (0xff * (BB - 0xff + alp)) / alp;
int vGG = (0xff * (GG - 0xff + alp)) / alp;
int vRR = (0xff * (RR - 0xff + alp)) / alp;

if(vBB < 0)  vBB = 0; if(vBB > 255) vBB = 255;//いらない気が^^;
if(vGG < 0)  vGG = 0; if(vGG > 255) vGG = 255;//いらない気が^^;
if(vRR < 0)  vRR = 0; if(vRR > 255) vRR = 255;//いらない気が^^;

unsigned int vv = (alp << 24) | (vRR << 16) | (vGG << 8) | vBB;


2013年1月15日火曜日

プロットされた点を曲線で結ぶ件。

久々の更新。 どーもFBには書くけど、BLOGの更新をしないようになってしまった。
今年はもうちょっと書こう。
 ってことで、ありがちだけど、プロットされた点を結んで曲線補完。  
今回の条件は、
【XによってYが一意に決まること。】
よって、曲線としては滑らかであっても、XによってYが2つ3つ値をとるようでは困るので、
 制御点の取り方を工夫。 

また、最初と最後(点A-B間、D-E間)に関しては、 制御点を2つ取れないので、
この部分は2次Bスプラインで考える。
1つの点を共用して3次(ベジェ)で考えてもいいのだが、
やってみたらあまり滑らかな線にならなかったので、2次とした。

 流れ。
A,B,C,D,Eが与えられる。
B,C,D(最初と最後を除いた点)については、その左右に制御点をとる。
制御点の取り方だが、Bを例にして考えるならば、B1-B-B2は一直線となり、
直線A-Cと平行になるような点をとる。
あとは、B1-B、B-B2の長さだが、B1-B2が直線A-Cの長さの固定倍とし、
Bが内分する点となるようにするのだが、 今回はX座標の比率(X(B-A):X(C-B)の比率となるように、 B1,B2をとってみた。 

まぁ所詮、曲線補完なので、何が正しいってわけじゃないので、
今回の要件はこの程度で。。

 2次のBスプラインの説明は、
http://opentype.jp/fontguide_doc2.htm
ベジェの説明は、
http://opentype.jp/fontguide_doc3.htm

がわかりやすい。と思う。思うだけかも。。

2012年11月26日月曜日

千社札再び。

ということで、ひさびさの更新になってしまいまして(-_-;)

こんなのをつくってみました。


GUIで文字は入力しづらいので(マスクやらなにやらあるから。。)一括入力します。



分解するとこうなってます。


図形(ポリライン)部分


文字部分


マスク部分


全体のObjectTree


家紋の画像は、都度つくるのはめんどいので、
【グレイスケールPNGで作成して、階調をアルファチャンネルに変換して、RGBで色をのせる】
ということをやってます。


2012年7月1日日曜日

せっかくなのでステッカーにする。




私のノートPCに貼ってあるステッカーをどうやってつくるのか、数人に聞かれたので、
ちょっと書いてみます。

ポイントは、
・紙をケチらない
・フィルム系にプリントする
・UVカットシールを貼る
・丸い刃のカッターを使う
です。

1:原稿をつくる


2:印刷する。フィルム系の耐水系の白い系で。


3:おおざっぱに切る。


4:UVカットシールを用意


5:UVカットシールを切ってから、一枚ずつ貼る。
このとき、切らずに一枚ものとして貼ると、たいがい空気が入って失敗する。


6:貼った状態


7:まわりをカットする。カッターやはさみだと、フチがあまりキレイにならない。
よって、写真のようなカッター(押して切る丸いやつ。@ダイソー)で切ったほうがよい。


8:できあがり。