ラベル CPP の投稿を表示しています。 すべての投稿を表示
ラベル CPP の投稿を表示しています。 すべての投稿を表示

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

C++・de・json


int leng = Z["doc"]["info"]["inputWizard"]["subjects"].length();
これでもC++である。^^V
こーゆークラスを書いたりすると、小躍りせざるを得ない^^;^^;

2013年3月22日金曜日

C++でJSONを扱う件(3)

C++でJSONを扱う件(3)
JSONファイルそのものをどうやって読めばいいのかって点ですが。。。
ところで話は変わって、【オブジェクト指向】ってあるじゃないですか。
よく、直感的に、思考に近い形でとか言いますよね。
CODINGは、要するに、object指向かどうかが問題なのではなくて、
頭でわかりやすいかどうかです。
単純なものほどわかりやすいのは至極当然。
よって、TREE構造のものを読み込むことを考えたときに、、
全て展開したTREEを、上から1行ずつ読み込んでいくような、そんな感じで読み込みましょう。

ポイントは、いくつかの文字の判定とその分岐です。
考えるのは、、
【"】【:】【{】【}】【[】【]】【,】
の7つだけです。
といったところで、こんな感じでつくってみました。

//wpは文字列の配列
for(int w=0;wp[w]!=0;w++){
 if(ダブルクォーテーション){
  //-----------------------------
  if(bIn){
   // ここで文字列が終わるので、文字列の特定
  }
  //-----------------------------
  else{
   // 文字列の始まりを憶えて置く
  }
  //-----------------------------
  bIn = ! bIn;
 }
 if(bIn) continue;//次へ
 else if(コロン){     // 【:】
  // キーを確定させる
  // 値の開始位置を覚える
 }
 else if(中カッコ開始){    // 【{】
  // 現在のobjectをPUSHする
  // 現在のobjectの下にobjectを生成してそれを現在のobjectにする
 }
 else if(中カッコ終了){    // 【}】
  //キーと値を調べて、少なくとも値があったら現在のobjectに登録
  //キーは無い場合もある
  //現在のobjectをひとつPOPする
 }
 else if(大カッコ開始){    // 【[】
  // 現在のobjectをPUSHする
  // 現在のobjectの下にobjectを生成してそれを現在のobjectにする
 }
 else if(大カッコ終了){    // 【]】
  //キーと値を調べて、少なくとも値があったら現在のobjectに登録
  //キーは無い場合もある
  //現在のobjectをひとつPOPする
 }
 else if(カンマ){     // 【,】
  //キーと値を調べて、少なくとも値があったら現在のobjectに登録
  //キーは無い場合もある
 }
 //-----------------------------
}
/*
 ポイント
 文字列を判断すること
 キーと値を判断すること
*/
まぁ、昔ながらのよくある方法ですが、文字列の始まりの【"】のところを憶えておき、終わりの【"】の部分に\0を突っ込んで、char*(wchar_t*)で読むっていう算段です。
値については、【"】ではじまるかどうかで、文字列かどうかを判定するわけですね。
もちろん、このLOOPに入る前に、\\と\"をなんらかの方法で退避させ、値をobjectに登録するときに戻してやりますよ。。

たぶん、つづく。。。

2013年3月21日木曜日

C++でJSONを扱う件(2)

C++でJSONを扱う件(2)

STEP2
で、object型ですが、ここでは簡略化して、以下のように考えます。


struct objson{
    objson* parent; //    親
    objson* child;  //    子
    objson* prev;   //    兄
    objson* next;   //    弟
    char*   value;  //    データ部
    char    dat[4]; //    key部
    //その他いろいろあるけど省略
    objson& operator[](const char* c);   //["abc"]とかのため
    operator char*();                    //キャストするため
    void operator=(char* cp);            //代入するため
};

これは、objectのデータ長さが一定ではないためです。
もちろん、構造体のメンバの中に、VARIANT的な値をもつという方法もありますが、ここでは面倒になるのでやりません。
よって、bool/int/doulbeとかであれば、まぁあっても8バイトなわけなので、最初から確保するという荒業もありますが、文字列だとそうはいきません。
よって、こんな風に生成してみます。
int size = sizeof(objson) + strlen(moji) + strlen(key);
char* p = new char[size];
memset(p,0,size);
objson* o = (objson*)p;


keyを設定するには、datへcopy、値を設定するには、valueのポインタを設定してからstrcpyします。
strcpy(o->dat,key);
o->value = &o->dat[strlen(key)+1];
strcpy(o->value,value);

長さを算定してメモリを確保し、それにobjson*でキャストしています。

例えば、メモリ管理を自分で書けば、メモリを連続させたりすることもできるし、不要なnew-deleteを考えなくてもすみます。

ここでは、keyになる文字列と値になる文字列の分を足して、メモリを確保しています。


生成したあとは、parent/child/prev/nextを設定して階層をつくってやれば、
o->child->child->child
なんて指定も可能になります。

つづく。。

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とかは授業でしかやったことないんで^^;使ったことないっすー。。。