相関法の計算の仕方

[戻る]
寝れない日々 2002/01/11(金) 06:50:54
画像処理としてパターンマッチングのプログラムを作らなければならないのですが
なにぶんプログラムにうといものでどうしてよいやらわからなくて困ってます。
相関法の計算式までは調べたのですがそれをどうプログラムしてよいか
見当もつかないのが現状です。
本を調べても基本的な総和は載っていてもちょっと厄介な計算に関しては
載っていなくてまいっています。
もしよろしければどなたか教えてください。
よろしくおねがいします。

CdS 2002/01/11(金) 18:23:27
画像処理の専門でない人は「パターンマッチング」だとか「相関法」という言葉は知らないはずです。
少なくとも私は全く分かりません。
その上「厄介な計算」と言われてもどうしたらいいのか分かりません。

プログラミングに関してならアドバイスできるかと思いますが、それらが一体どういうものかを簡単に
でも説明してもらわなければ回答はまず得られないと思います。
かといって延々と説明されても困りますが。

そういう訳で回答がないのだと思いますよ。

寝れない 2002/01/13(日) 23:27:32
そうですね。すいませんでした。
大体説明するととりあえず狽フ計算をしなければなりません。
ただ範囲が決まってないところが困ってるところです。
1からNまでという不規則なところがよくわからないのです。
それに加えてそこに使う変数に別のファイルにあるデータを
読み込みたいのですがそこでもかなり困ってます。

CdS 2002/01/15(火) 09:56:59
>大体説明するととりあえず狽フ計算をしなければなりません。
>ただ範囲が決まってないところが困ってるところです。
>1からNまでという不規則なところがよくわからないのです。

と言われてもこちらとしてはどうすることもできないので、計算の部分はご自分で行ってください。
あくまでもプログラミングのことしかアドバイスできません。


>それに加えてそこに使う変数に別のファイルにあるデータを
>読み込みたいのですがそこでもかなり困ってます。

MFCを使っているのならCFile、使っていないのならCreateFile, ReadFile等を調べてください。
どう分からないかを書いてもらわないと、こういう回答しかできません。

#最初の投稿でもそうですが、「寝れない(日々)」さんが今どう困っているかなんてこっちは分からない訳ですよ...。

寝れない日々 2002/01/21(月) 03:33:04
すいませんでした。
一応自分なりにプログラムは組んでみたのですが
EXEファイルを実行しようとすると動かなくなるので
どうしたらよいかアドバイスしていただければ幸いです。

#include <stdio.h>
#include <math.h>
#include <process.h>
#define n 1000000        /*データの数*/
#define N 1600            /*N pixel*/

void read(float x1[],float x2[],float y1[],float y2[],float I[],float M[]);
float calculate(float I[],float M[]);

main()
{
    float x1[n],x2[n],y1[n],y2[n];
    float I[n],M[n];
    float r;
    read(x1,x2,y1,y2,I,M);
    r=calculate(I,M);
    printf("r=%f\n",r);            /*相関係数*/
    printf("↑相関係数\n");
}

/*メインプログラムはここまで*/

/*こっからはサブルーチン*/

/*ファイルの読み込み*/

void read(float x1[],float x2[],float y1[],float y2[],float I[],float M[])

{    
    int i;
    FILE *input1,*input2;

    input1 = fopen("data1.txt","r");
    input2 = fopen("data2.txt","r");
    
    if (input1 == NULL){
        printf("ファイルが存在しません!\n");
        exit(-1);
    }
    if (input2 == NULL){
        printf("ファイルが存在しません!\n");
        exit(-1);
    }


    while(
        (fscanf(input1,"%d\t%d\t%f\n",&x1[i],&x2[i],&I[i]) !=EOF)
        /*一つ目のファイルから読み込み*/
            &&
        (fscanf(input2,"%d\t%d\t%f\n",&x2[i],&x2[i],&I[i]) !=EOF)
        /*二つ目のファイルから読み込み*/
            &&
        (i<n)
    )

    fclose(input1);
    fclose(input2);
}

/*相関係数の計算*/

float calculate(float I[],float M[])
{
    int i;
    float r;
    float ans1,ans2,ans3;
    float sum1=0,sum2=0,sum3=0,sum4=0,sum5=0;

    for(i=0;i<=n;i++){
        sum1+=I[i];
        sum2+=M[i];
        sum3+=I[i]*M[i];
        sum4+=I[i]*I[i];
        sum5+=M[i]*M[i];
    }

    ans1=N*sum3-sum1*sum2;
    ans2=N*sum4-sum1*sum1;
    ans3=N*sum5-sum2*sum2;
    r=ans1/sqrt(ans2*ans3);
    return r;
}

これがソースなんですがファイルの読み込みの部分があまり自信ないです。
よろしくお願いします。

TAKA 2002/01/21(月) 10:49:54
わかっているだけでも
readのなかがだめですね

>    while(
>        (fscanf(input1,"%d\t%d\t%f\n",&x1[i],&x2[i],&I[i]) !=EOF)
>        /*一つ目のファイルから読み込み*/
>            &&
>        (fscanf(input2,"%d\t%d\t%f\n",&x2[i],&x2[i],&I[i]) !=EOF)
>        /*二つ目のファイルから読み込み*/
>            &&
>        (i<n)
>   )
iの初期化がない
ファイル1のよみこみと2の読み込みにおなじ変数を定義してる
x1を一回x2を3回Iを2回
デバッグをしやすいように一文に書くのではなく
分けて書いて少しづつデバッグできるようにしないと何もできませんね。
またx1等がfloatなのに%dをつかってますね

>これがソースなんですがファイルの読み込みの部分があまり自信ないです
わかっているなら調べやすいようにソースを整理してデバッグしましょう。

例
while(i<n){
if (fscanf(input1,"%f",x1[i]) == EOF) {
break;
}
if (fscanf(input1,"%f",x2[i]) == EOF) {
break;
}
・
・
・
i++;
}

寝れない日々 2002/01/22(火) 03:47:48
すばやいレスでのアドバイスありがとうございます。

うち間違ったところを修正してみました。
この場合本来ならまったく同じデータを使わない限り
r=1.000000とはならないはずなのですが
どんなデータを使ってもr=1.000000 or r=-1.000000の両端の値しか
返してくれません。これはどこに原因があるのでしょう?
(-1.000000<=r<=1.000000がrのとりうる範囲です)
それとn,Nの値は本当ならnが6000000くらい、Nは10000くらいで
処理をしたいのですがそれだとエラーになってしまいます。
これはどのようにすればよいですか?

#include <stdio.h>
#include <math.h>
#include <process.h>
#define n 3            /*データの数*/
#define N 10            /*N pixel*/

void read(float x1[],float x2[],float y1[],float y2[],float I[],float M[]);
float calculate(float I[],float M[]);

main()
{
    float x1[n],x2[n],y1[n],y2[n];
    float I[n],M[n];
    float r;
    read(x1,x2,y1,y2,I,M);
    r=calculate(I,M);
    printf("r=%f\n",r);            /*相関係数*/
    printf("↑相関係数\n");
}

/*メインプログラムはここまで*/

/*こっからはサブルーチン*/

/*ファイルの読み込み*/

void read(float x1[],float x2[],float y1[],float y2[],float I[],float M[])

{    
    int i=0;
    FILE *input1,*input2;

    input1 = fopen("data1.txt","r");
    input2 = fopen("data2.txt","r");
    
    if (input1 == NULL){
        printf("ファイルが存在しません!\n");
        exit(-1);
    }
    if (input2 == NULL){
        printf("ファイルが存在しません!\n");
        exit(-1);
    }


    while(
        (fscanf(input1,"%f\t%f\t%f\n",&x1[i],&y1[i],&I[i]) !=EOF)
        /*一つ目のファイルから読み込み*/
            &&
        (fscanf(input2,"%f\t%f\t%f\n",&x2[i],&y2[i],&M[i]) !=EOF)
        /*二つ目のファイルから読み込み*/
            &&
        (i<n)
    )

    fclose(input1);
    fclose(input2);
}

/*相関係数の計算*/

float calculate(float I[],float M[])
{
    int i;
    float r;
    float ans1,ans2,ans3;
    float sum1=0,sum2=0,sum3=0,sum4=0,sum5=0;

    for(i=0;i<=n;i++){
        sum1+=I[i];
        sum2+=M[i];
        sum3+=I[i]*M[i];
        sum4+=I[i]*I[i];
        sum5+=M[i]*M[i];
    }

    ans1=N*sum3-sum1*sum2;
    ans2=N*sum4-sum1*sum1;
    ans3=N*sum5-sum2*sum2;
    r=ans1/sqrt(ans2*ans3);
    return r;
}

非常に面倒な質問でしょうがよろしくおねがいします。

TAKA 2002/01/22(火) 09:28:15
前回にも書きましたが
>    while(
>        (fscanf(input1,"%f\t%f\t%f\n",&x1[i],&y1[i],&I[i]) !=EOF)
>        /*一つ目のファイルから読み込み*/
>            &&
>        (fscanf(input2,"%f\t%f\t%f\n",&x2[i],&y2[i],&M[i]) !=EOF)
>        /*二つ目のファイルから読み込み*/
>            &&
>        (i<n)
>    )
わけてデバッグしましょう。
これはiの値が更新されないため、x1[0]以外は未定義のデータです。
最後までi=0のため
i++ がないでしょう?
後はどこまで動いてるかデバッグすればいいはずです。
ステップ実行すれば後はできるはずです。
I・Mにきちんとデータがはいっているか確認すれば分かったはずです。
人にたよるまえに、そのくらいはしましょうね。

NGA 2002/01/22(火) 09:45:52
>それとn,Nの値は本当ならnが6000000くらい、Nは10000くらいで
>処理をしたいのですがそれだとエラーになってしまいます。
>これはどのようにすればよいですか?

ざっと計算してみると、90MBを超えているようですね。
それではスタックオーバーフローも当然です。
動的に確保するなり、もっと小さいサイズでも動くように変更するなりしないといけませんね。

寝れない日々 2002/01/22(火) 23:59:42
すいませんでした。
もう一度やりなおしてみます。

寝れない日々 2002/01/22(火) 23:59:44
すいませんでした。
もう一度やりなおしてみます。

寝れない日々 2002/01/23(水) 04:11:23
読み込みに関する部分ではうまくいきました。
オーバーフローしないようにreadの中で相関係数の計算を
してしまいたいのですがそのときwhileの中でsum1〜sum5を
計算するにはどうしたらよいのですか?
今はwhileが二つになってしまったのでsum3の処理がわからないです。

TAKA 2002/01/23(水) 09:20:23
参考までに今のプログラムをみるだけではこんな感じにします。
readの中ですが。
また、後で使わないならI・Mは配列にしません。
説明に必要ない部分は省いてます。あしからず・・・

    float I, M;
    float sum1=0.0f,sum2=0.0f,sum3=0.0f,sum4=0.0f,sum5=0.0f;

    for (i = 0; i <= n; i++) {
        /*一つ目のファイルから読み込み*/
        if (fscanf(input1,"%f\t%f\t%f\n",&x1[i],&y1[i],&I) == EOF) {
            // エラーである又は終了を明記
            break;
        }
        /*二つ目のファイルから読み込み*/
        if (fscanf(input2,"%f\t%f\t%f\n",&x2[i],&y2[i],&M) == EOF) {
            // エラーである又は終了を明記
            break;
        }
        sum1 += I;
        sum2 += M;
        sum3 += I * M;
        sum4 += I * I;
        sum5 += M * M;
    }
    if (エラーでないなら) {
        // 以下計算
    }

ねれない日々 2002/01/23(水) 16:41:25
TAKAさん毎回アドバイスありがとうございます。
自分なりにがんばってみたのですが、
データの数がファイル1とファイル2でちがうとき
sum3の値がおかしくなります。
これをなおすにはどのようにすればよいのですか?


#include <stdio.h>
#include <math.h>
#include <process.h>
#define n 1000        /*データの数*/
#define N 1000            /*N pixel*/

float read(float x1[],float x2[],float y1[],float y2[],float I[],float M[]);

main()
{
    float x1[n],x2[n],y1[n],y2[n];
    float I[n],M[n];
    double r;
    read(x1,x2,y1,y2,I,M);
    
}

/*メインプログラムはここまで*/

/*こっからはサブルーチン*/

/*ファイルの読み込み*/

float read(float x1[],float x2[],float y1[],float y2[],float I[],float M[])

{    
    int i=0;
    int j=0;
    float sum1=0.0f,sum2=0.0f,sum3=0.0f,sum4=0.0f,sum5=0.0f;
    float ans1,ans2,ans3;
    float r;
    FILE *input1,*input2;
    
    char filename1[30];
    char filename2[30];

    printf("入力ファイル1=");
    gets(filename1);
    printf("入力ファイル2=");
    gets(filename2);

    input1 = fopen(filename1,"r");
    input2 = fopen(filename2,"r");
    
    if (input1 == NULL){
        printf("ファイル1が存在しません!\n");
        exit(-1);
    }
    if (input2 == NULL){
        printf("ファイル2が存在しません!\n");
        exit(-1);
    }


    while((fscanf(input1,"%f\t%f\t%f\n",&x1[i],&y1[i],&I[i]) !=EOF)){
        /*一つ目のファイルから読み込み*/
            printf("%d %f %f %f\n",i,x1[i],y1[i],I[i]);
            sum1+=I[i];
            sum4+=I[i]*I[i];
            i++;
    }
    i=0;
    j=0;
    while((fscanf(input2,"%f\t%f\t%f\n",&x2[j],&y2[j],&M[j]) !=EOF)){
        /*二つ目のファイルから読み込み*/
            printf("%d %f %f %f\n",j,x2[j],y2[j],M[j]);
            sum2+=M[j];
            sum5+=M[j]*M[j];
            sum3+=I[j]*M[j];
            j++;
    }
    
    printf("sum1r=%f\n",sum1);
    printf("sum2r=%f\n",sum2);
    printf("sum3r=%f\n",sum3);
    printf("sum4r=%f\n",sum4);
    printf("sum5r=%f\n",sum5);

    ans1=N*sum3-sum1*sum2;
    ans2=N*sum4-sum1*sum1;
    ans3=N*sum5-sum2*sum2;
    r=ans1/sqrt(ans2*ans3);
    

    printf("ans1r=%f\n",ans1);
    printf("ans2r=%f\n",ans2);
    printf("ans3r=%f\n",ans3);
    printf("r=%f\n",r);
    printf("↑相関係数\n");
    return r;

    fclose(input1);
    fclose(input2);
}

TAKA 2002/01/24(木) 09:54:41
データに対してどんな結果が正かわからないため判断しがたいですね・・・。
とりあえず、こんなとこが考えられますが・・・。

1.ファイル内のデータの少ない方までを計算する。(前回の参照)
2.ファイル内のデータの少ない方のデータのI・Mの初期値を1.0fとする。

こんなんでどうでしょう?

    bool bFile1end, bFile2end;
    bFile1end = bFile2end = false;

    for (i = 0; i <= n; i++) {
        /*一つ目のファイルから読み込み*/
        if (bFile1end == false) {
            if (fscanf(input1,"%f\t%f\t%f\n",&x1[i],&y1[i],&I) == EOF) {
                bFile1end = true;
                I = 1.0f;   // 以降1.0fとする 1.ならここでbreak;
            }
        }
        /*二つ目のファイルから読み込み*/
        if (bFile2end == false) {
            if (fscanf(input2,"%f\t%f\t%f\n",&x2[i],&y2[i],&M) == EOF) {
                bFile2end = true;
                M = 1.0f;   // 以降1.0fとする 1.ならここでbreak;
            }
        }
        if (bFile1end && bFile2end) {    // 両方EOFなら終了
            break;
        }
        sum1 += I;
        sum2 += M;
        sum3 += I * M;
        sum4 += I * I;
        sum5 += M * M;
    }

寝れない日々 2002/01/25(金) 05:11:13
TAKAさん、何とか計算はうまくいくようになりました。
ありがとうございます。
もうひとつ質問なのですが、
ファイルを読み込ませるときに任意の場所から読み込ませることはできるでしょうか?
たとえば

1.23 2.34 3.45
4.56 5.67 6.78
7.89 8.90 9.01
0.12 1.11 1.22
1.33 1.44 1.55

というファイルがある時に

4.56 5.67 6.78
0.12 1.11 1.22

だけを読ませるという風にです。
ファイルがとても大きいため
途中で区切ってそこから読ませる必要があり
知っているやり方だと
つねにファイルの最初から読んでしまうことになってしまうので・・・。

TAKA 2002/01/25(金) 09:36:01
やりたいことによって変わってくると思いますが、

一度読み込んだファイルの続きだとすると
ftell と fseek をつかってやればいいでしょう。

1ラインのながさが決まっているなら
行きたい行数*ラインの文字数(改行含む)
で fseek してあげればいいでしょう。

>ファイルがとても大きいため
>途中で区切ってそこから読ませる必要があり

どうしてこう思うかについてはわかりませんが、
new や malloc を使ってやれば出来るのでは?

寝れない日々 2002/01/25(金) 12:39:18
すいません。まだまだかじりたてなので
mallocやnewとかぜんぜんわからないのです。
これからすこしづつ勉強してみます。

古いスレッドには追加発言できません。