ラベル アルゴリズム の投稿を表示しています。 すべての投稿を表示
ラベル アルゴリズム の投稿を表示しています。 すべての投稿を表示

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年7月5日土曜日

新しいことを始めるときは。

新しいことを始めるとき。
今回は、AppMethodに挑戦なのですが、
プログラミングに限らず、新しいことを始めるときは、
大きく2つの方法があると思ってます。
(1)基礎から徹底的に学ぶ
(2)何かの目標をつくって、その最短距離を学ぶ。

もちろん、子供が勉強するかのごとく、(1)は良い方法というか、王道です。
しかし、大人がピアノを習うときは、(1)だと絶対めげちゃうんですよ。
だから、(2)なのです。
ハノンもやらず、『ピアノのテクニック』もやらず、
【弾きたい曲をなんとか仕上げる】
という方法をとるべきです。

ということで、【つくってみたいアプリをとにかく完成させる】ことを目標とし、
(2)の方法でAppMethodを学びます。
そして、都度、必要に迫られたときに、基本的なことを学びます。

ツール類は、最低条件として、ひととおりつかえることが大前提なので、

●STEP1
Wizardにでてくるものは、ひととおり、何もせずに(追加をね)、BUILDして実行してみる。
これです↓↓


●STEP2
『サンプル』として提供されてるものから、明らかに興味を引かないもの以外を、
BUILDして実行してみる、
これです↓↓


そこらへんを前準備としてやった後に、作りたいものを開始です。

私の場合は、最初に設計することをしません。
最後まで見通せるほど、普通の人間は、頭がよくないからです。

よく、SIerさんで、【要件定義】-【設計】-【詳細設計】-【実装】-
なんていうSTEPを、全て違う責任者がいたりして、
文書を書いてハンコをもらわないと進めなかったりして、
挙句の果てに、設計ミスがあっても戻れずに、
結果、ぐでぐでになるなんていうのは、
大きな企業ほどありがちです。
っていうか、あります。
っていうか、ありすぎます。

技術も流行りもめまぐるしくかわってる時代に、
いい年のおっちゃんがハンコを押したって、何もなりません。

まぁ結論から言えば、
設計書というのは、アプリが出来上がってから書くものなのです。

っと、話はそれましたが、
若い人には、
『常に美しい方法を選択し、感性でプログラムを書きながら、全体像を設計』
してほしいと思いますですね。
これでいいのです。
絵にすれば、こうです。(o^^o)










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年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年3月19日火曜日

mのn乗回LOOPをまわす方法。

mのn乗回LOOPをまわす方法な件なんですけどねー。
いやいや、
v = m * n;
for(int w=0;w<v;w++){
なんて、そんな話じゃないですよ。
だって、longとかlong longに収まる範囲でしかできない方法じゃダメなんですよ。
だからっていって、下手に再帰させるのもダメですよ。stackOverFlowもあるしね。
って、どんだけ大きな数を扱おうとしてるかって話でもなく、
ここでは、再帰よりも『美しく』codingしましょう。

ということで、やりかたはわからなかったのですが、
なんとなくcodingしてたら、案の定できました。
基本的には、タイガー計算機の如く、1ケタづつLOOPする変数を準備すればいいだけです。
まぁ制限としては、nもmもintの範囲っていうくらいの制限はありますが。^^;

で、できたのがこれ。
これなら、1000の1000乗のLOOPでもまわせます。そんなことしたら、おわりませんけど。
loopFuncが関数、countUpがサブの関数、theFuncsがテストなCallBack関数。
typedef int (*func1)(int*,int);

int countUp(int* dat,int mmm,int nnn){
    for(int w=0;w<nnn;w++){
        dat[w]++;
        if(dat[w] < mmm){
            return true;
        }
        dat[w] = 0;
    }
    return false;
}
int theFuncs(int* ip,int n){
    static int counter = 0;
    printf("<%d> ",counter++);
    for(int w=n-1;w>=0;w--){
        printf("[%d]",ip[w]);
    }
    printf("\n");
    return 0;
}
void loppFunc(int mmm,int nnn,func1 f){
    int* dat = new int[nnn];
    memset(dat,0,sizeof(int)*nnn);
    do{
        f(dat,nnn);
    }while( countUp(dat,mmm,nnn) );
    delete[] dat;
}
loppFunc(10,3,theFuncs);//呼び出し方

ケタの数だけ、配列して、関数に渡します。←日本語おかしいな^^;^^;
まぁどんな言語でもいけるっちゃいけますけど、かなり用途は狭いでしょうし、、ホントに巨大な数だけLOOPするようなものを、C(C++)以外でつくることも、そうそうないでしょうし。
あ、すんません。Fortranとかは授業でしかやったことないんで^^;使ったことないっすー。。。