• ベストアンサー

濃淡画像の縦方向のゆがみを求めたいのですが・・

縦横256*256サイズの縦方向のゆがみをプログラムを用いて求めたいのですが 計算結果が思わしくなく アルゴリズムに問題があるのかうまくいきません。 画像の読み込み自体は問題ないので ゆがみを計算している部分に問題があると思うのですが どこが間違っているかわからないのでお暇な方は助言をお願いします。 手順としては 縦の重心pm、 縦の標準偏差qmを求め 最後に縦のゆがみsm求めています。 ゆがみを求める画像をimege(m,n)として mが縦方向nが横方向の座標ををあらわしています。 縦重心pmは ΣΣ(m=0~255、n=0~255)m*imege(m,n) を全画素数(256*256)で割ったもので 縦の標準偏差qmは ΣΣ(m=0~255、n=0~255) m*(m-pm)^2*imege(m,n) を全画素数で割って求めます。。 またゆがみsmは ΣΣ(m=0~255、n=0~255) (m-qm)^3*image(m,n) を重心pmの三乗と全画素数で割ったものです。 以下が私の書いたゆがみsmを求めるプログラム部分です。 //*********重心 pm ********// double pm,sum1; pm = sum1 = 0.0; for( m = 0; m < 256; m++) for( n = 0; n < 256; n++) { sum1= sum1 + m*image[m][n]; } pm = sum1/(256 * 256);//縦重心 //************標準偏差 qm***********// double qm; qm=sum1=0.0; for( m = 0; m < 256; m++) for( n = 0; n < 256; n++){ sum1 = sum1 + (m-pm) * (m-pm) * imege(m,n); } qm = sum1/(256*256);//縦の分散 qm = Math.sqrt(qm);//縦の標準偏差 //***********ゆがみ s *********// double sm; sum1 = sm =0.0; for( m = 0; m < 256; m++) for( n = 0; n < 256; n++) { sum1 = sum1 + (m-pm)*(m-pm)*(m-pm)*imege(m,n); } sm = sum1 /(qm*qm*qm*256*256) ;//縦のゆがみ 以上です。 式の説明等が分かりにくいかもしれませんが よろしくお願いします。

  • Java
  • 回答数3
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

> 「全画素の合計値 > ΣΣ(0~255)(0~255)image(m,n)で割る」 > ですね。 あ,そうだ.私もうっかり見落としてました.orz > これが私には分からないのですがどういうことでしょうか? 例えば座標系が下図のような方向になっていて, 点 P(x, y) の位置の輝度が image[y][x] であるのなら, 御質問のプログラムにより pm=重心のY座標,qm=Y方向の標準偏差, sm=Y方向の歪度が求まるはずです. ┌─────────→ X │ │ │   ・P(x, y) │ │ ↓ Y しかしもし,点 P(x, y) の位置の輝度が image[x][y] であるのなら, 御質問のプログラムが求めているのは pm=重心のX座標, qm=X方向の標準偏差,sm=X方向の歪度になります. ┌統計学だと1次元の重心の定義式しか出ていないことが多いので, │一般のN次元で使える重心の定義式を紹介しておきます. │(というか,こっちの方が元祖.) ↓ 重心を求める [物理のかぎしっぽ] http://www12.plala.or.jp/ksp/mechanics/CG/ 導出シリーズ 第23回「重心の公式を導く その1」 http://tachiro.client.jp/theorem/theorem-023-centroid-1.pdf ・2次元の重心の定義  位置ベクトル:r=(x, y)  重心位置ベクトル:rg=(xg, yg)  位置 (x, y) の密度:ρ(x, y)  とすると,2次元の重心位置は   rg = ∫∫r * ρ(x, y) dx dy / ∫∫ρ(x, y) dx dy  画像の場合は,位置 (x, y) の微小質量 ρ(x, y) dx dy の代わりに  位置 (x, y) の輝度 image(x, y) を使うと,   rg = Σ{x} Σ{y} r * image(x, y) / Σ{x} Σ{y} image(x, y) あ,それから, > また、下3分の1が黒(輝度が255)であれば > 負の値をとるはずです。 普通,輝度は数字が大きいほど明るくなります. 8ビットグレースケールの場合,黒=輝度0,白=輝度255です.

yamada-ke
質問者

お礼

度々ご意見ありがとうございます。 大変参考になりました。 >また、下3分の1が黒(輝度が255)であれば うわ・・・すいません。 これも私の書き間違いです。 おっしゃるとおり黒ならば輝度は0ですね。

その他の回答 (2)

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.2

プログラムは間違ってないと思いますよ. (image → imege のミスタイプと,効率が良くない点は別として.(笑)) ただし歪度の定義の説明に少し間違いがあります. > またゆがみsmは > ΣΣ(m=0~255、n=0~255) > (m-qm)^3*image(m,n) > を重心pmの三乗と全画素数で割ったものです。 重心の三乗ではなく,標準偏差の三乗ですね.(プログラムの方は合っています.) 「縦の~」と書いてある以上,image の添字の順序は image[y][x] のはずですよね? ひょっとして image[x][y] と勘違いしていませんか? 歪度と尖度 http://markun.cs.shinshu-u.ac.jp/learn/probability/i_05-05-02.html 要約統計量 (Wikipedia) http://ja.wikipedia.org/wiki/%E8%A6%81%E7%B4%84%E7%B5%B1%E8%A8%88%E9%87%8F 歪度 (Wikipedia) http://ja.wikipedia.org/wiki/%E6%AD%AA%E5%BA%A6 「"歪度" "3次モーメント"」で検索 http://www.google.co.jp/search?q=%22%E6%AD%AA%E5%BA%A6%22+%22%EF%BC%93%E6%AC%A1%E3%83%A2%E3%83%BC%E3%83%A1%E3%83%B3%E3%83%88%22&hl=ja&rlz=1B3GGGL_jaJP230JP230&pwst=1&start=0&sa=N

yamada-ke
質問者

お礼

ご意見、参考リンク等ありがとうございます。 ご指摘の通りゆがみsmを重心の3乗で 割ると書いたのはミスです。すいません。 また、 pm、qm、smを求める際に「全画素数で割る(256*256)」 というのは間違いでしたOrz 正確には 「全画素の合計値 ΣΣ(0~255)(0~255)image(m,n)で割る」 ですね。 画素の数でわったら重心の座標がでませんもんね・・・ >>「縦の~」と書いてある以上,image の添字の順序は image[y][x] のはずですよね? ひょっとして image[x][y] と勘違いしていませんか? これが私には分からないのですがどういうことでしょうか? 折り返しの質問すいません。

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.1

素人です。 統計(?)にまったく詳しくないので、 以後はもう、僕からは回答はつけられないと思いますが、 思ったことを書きます。 --- 定義がまちがってるのか、 はたまた「定義からソースコードへの変換」が間違っているのか。 その切り分けを最初にしましょう。 まず、 "縦の重心" "縦の標準偏差" "縦のゆがみ" などと呼ばれるモノの"用語"の定義が(質問者さんの書いた式で)正しいのかどうかを その"用語"を使ってる先生(※課題を出した人)に確認するべし。 定義を他人に聞いてもしょうがないので。 >アルゴリズムに問題があるのか ようするに「(教えてもらった)定義が間違ってるのかも」という疑念が ぬぐえないわけですよね? --- また、どういう「結果」ならば「正しい」のか、 第三者が検証できる具体的な材料を掲示しとくといいと思います。 例えば 縦90ピクセル、横30ピクセルの画像があり、 画像の下3分の1がすべて黒、残りがすべて白、 そして黒の画素値を1.0、白の画素値を0.0とした場合、 pm,qm,smはそれぞれ、どのような値になるべきなのか、とか。

yamada-ke
質問者

お礼

ご意見ありがとうございます。 式は間違ってはいないと思います。 問題を提示した先生や、その研究室の方の論文で何度か 使われていたものなので・・・。 論文によっては縦の重心は縦方向の平均値と書かれています。 >> また、どういう「結果」ならば「正しい」のか、 第三者が検証できる具体的な材料を掲示しとくといいと思います。 たしかにそうですね・・。 例えば上下が全く対称な画像でしたら 縦のゆがみは0になるはずです。 また、下3分の1が黒(輝度が255)であれば 負の値をとるはずです。 なぜ縦の重心(平均値)がこのような式になるのか いまいち私には理解できないので直接先生に 質問してみたいと思います。

関連するQ&A

  • バブルソートの組み込み方について

    情報の授業で10人分の点数を打ち込み、その平均点と標準偏差を出し、点数の高い順に並べるプログラムをC言語で作れという課題が出されました。 以下のソースのように平均点と標準偏差を出すところまではいったんですが、バブルソートをどう組み込めばいいのかわかりません。 どなたか教えてくれませんか? #include <stdio.h> #include <math.h> main() { float data[ 10 ], sum = 0, ave, s; int i, n = 10; for( i = 0; i < n; i++ ) { printf( "%d人目の点数 = ", i+1); scanf( "%f", &data[ i ] ); sum += data[ i ]; } ave = sum / n; for( i = 0; i < n; i++ ) { s += ( data[ i ] - ave ) * ( data[ i ] - ave ); } s = sqrt( s / ( n - 1 ) ); printf( "平均値・・ %f\n", ave ); printf( "標準偏差・・ %f\n", s ); return 0; }

  • ファイルのデータがうまく読み込まれません

    こんにちは。ファイルからデータを読み込んで、平均値と標準偏差を求めるプログラムを書いているんですが、計算結果がなぜか違う値になってしまいます。書いているプログラムは、 #include<stdio.h> #include<math.h> #define MAX 200 /* ファイル"sample.txt"から複数の値を入力し、それらの  平均値、標準偏差を出力する.  */ void main(void) { FILE *fp; char text[256],l[256]; int i, n; float a[MAX], sum,sum2,mean,sdev; fp = fopen("sample.dat","r"); /* sample.txt を開く */ if(fp == NULL){ printf("Error!\n");exit(0);}/* sample.txtがなければ停止 */ for(i = 1; i <= 3; i++) fscanf(fp, "%s\n",text); for(i = 0; i < MAX; i++) { if(fscanf(fp, "%s %f\n",l, a[i]) == EOF ) ; } n = i; sum = a[0]; sum2 = a[0]*a[0]; for(i = 0; i < n; i++) { sum += a [i]; sum2 += a[i]*a[i]; } mean = sum/n; /* 平均値の計算 */ sdev = sqrt(sum2/n - mean*mean); /* 標準偏差の計算 */ printf(" mean : %6.2f\n", mean); printf("standard dev.: %6.2f\n",sdev); } で、読み込むファイルは 平均値と標準偏差の計算 クラスA組み 氏名 身長(cm) 鈴木 175.54 佐藤 170.34 清水 165.29 徳田 185.23 赤木 178.61 と、長くなってしまいましたが、if文の中のfscanfの部分が違うんでしょうか?初心者でどこが違うのか分かりません。教えていただけないでしょうか?

  • 簡単なΣの問題

    分かっている方にとっては、簡単なことだと思うのですが... ΣΣの意味を教えてください (本来解きたい式はもっと複雑なので、ここでは簡単に表現します) ∞ ∞ Σ Σ mn(m+n) m=1 n=1 の式があるとすると、 1×1(1+1) + 2×2(2+2) + 3×3(3+3)・・・・・ m×n(m+n) と言うことでいいのしょうか? それとも、解釈が間違っています?

  • 桁落ちの誤差について

    #include <stdio.h> const double PI=3.141592653589793; double sum(long m) { double n,term,sum; n=1; sum=0; term= 1.0/ (n*n);/*初項*/ while( n<=m ){ sum+=term; n++; term= 1.0/ (n*n);/*次項の計算*/ } return sum; } /*この計算の答えはπ*/ int main(void) { double s; long m; int i; m=1; for(i=0;i<9;i++){ s=sum(m); printf("%2d m=%10ld sum= %22.16e err= %22.16e \n",i,m,s,s-PI*PI/6); m*=10;/*次は10倍にする*/ } return 0; のプログラムで誤差が生じる理由ってなんなんでしょうか?

  • c言語

    n人の名前、と国数英の点数を読み込み各人の平均点、標準偏差を求め見やすく出力するぷろぐらむです osはlinuxでコンパイラはgccです。 変数が多くなってしまいよくわかりません。 もっと簡単になりますか? #include<stdio.h> #include<math.h> #define N 50 main() { int eng[N], jap[N], math[N], n=0, i=0; char name[N][12]; double sum[N], SUM, sum1, sum2, sum3, ave1, ave2, ave3, vari, s_devi; printf("名前 合計点"); while(scanf("%s %d %d %d",&name[n],&eng[n],&jap[n],&math[n]) != EOF) { sum[i] = eng[n]+jap[n]+math[n]; sum1 += eng[n]; sum2 += jap[n]; sum3 += math[n]; printf("%-12s%4d",name[n], sum[i]); n++; i++; } ave1 = sum1/n; ave2 = sum2/n; ave3 = sum3/n; for(i=0; i<n; i++) { SUM += (eng[i]-ave1)*(eng[i]-ave1); } vari = SUM/n; s_devi = sqrt(vari); printf("English\n average = %f\nstandard deviation = %f\n\n",ave1,s_devi); for(i=0; i<n; i++) { SUM += (jap[i]-ave2)*(jap[i]-ave2); } vari = SUM/n; s_devi = sqrt(vari); printf("japanese\n average = %f\nstandard deviation = %f\n\n",ave2,s_devi); for(i=0; i<n; i++) { SUM += (math[i]-ave3)*(math[i]-ave3); } vari = SUM/n; s_devi = sqrt(vari); printf("math\n average = %f\n standard deviation = %f\n\n",ave3,s_devi); }

  • 桁落ちのプログラムで真の値と計算結果

    #include <stdio.h> const double PI=3.141592653589793; double sum(long m) { double n,term,sum; n=1; sum=0; term= 1.0/ (n*n);/*初項*/ while( n<=m ){ sum+=term; n++; term= 1.0/ (n*n);/*次項の計算*/ } return sum; } /*この計算の答えはπ*/ int main(void) { double s; long m; int i; m=1; for(i=0;i<9;i++){ s=sum(m); printf("%2d m=%10ld sum= %22.16e err= %22.16e \n",i,m,s,s-PI*PI/6); m*=10;/*次は10倍にする*/ } return 0; で真の値と計算結果を調べるにはどうしたらいいのでしょうか?

  • 数列の証明問題です

    等差数列An=a+d(n-1)について、第n項までの和をSn、m項までの和をSmとすると、m≠nのときSm=SnならばSm+n=0を証明せよ。という問題です。 次の証明は証明になっていますか? Sn=n{2a+d(n-1)}/2、Sm=m{2a+d(m-1)}/2と、Sm+n=(m+n){2a+d(m+n-1)}/2とおける Sm=Snより2am^2+dm^2-dm=2an+dn^2-dn dm^2+(2a-d)m-dn^2-(2a-d)n=0 m≠n、a、dは実数だからa=d=0 このとき Sm+n=(m+n){2・0+0・(m+n-1)}/2 =0 なにかがおかしい気がするんですが、どうでしょうか ちなみに模範解答は Sm-Snを変形してSm-Sn=Sm+n=0を導いています…

  • 等差数列の証明

    初項a, 公差d である等差数列の初項から第n項までの和をSn とする。m≠nであって Sm=Sn ならば Sm+n=0 であることを証明せよ。【4STEP 数Bの173】 という問題が分かりません。解答は、 Sn=1/2n{2a+(n-1)d} Sm=1/2m{2a+(m-1)d} Sm=Sn のとき Sm-Sn=0 だから 1/2m{2a+(m-1)d} - 1/2n{2a+(n-1)d} = 0 よって 1/2(m-n){2a+(m+n-1)d} = 0 m≠n だから 2a+(m+1)d} = 0 ----------(1) また Sm+n = 1/2(m+n){2a+(m+1)d} 従って(1)からSm+n=0 ということですが、なぜ 「よって 1/2(m-n){2a+(m+n-1)d} = 0」 となるのか分かりません。 その前に Sn=1/2n{2a+(n-1)d}はいいとして なぜ Sm=1/2m{2a+(m-1)d} なのか?です。 また、この問題のような数列って具体的には どんな数字の列があるのかなぁと思います。

  • ビルドが失敗してしまいます

    最近C言語を勉強を始めまして、参考書に載っていた以下のソースプログラムをvisualC++2010に打ち込んだのですがビルドが成功しません #include <stdio.h> #include <math.h> int main(void) { int d[33]; double m,v,s; int n=33; int i; double sum; printf("データを%d個入力してください\n",n); for(i=0;i<n;i++) { printf("date %d=",i+1); scanf_s("%d",&d[i]); } for(sum=0.0,i=0;i<n;i++) { sum+=d[i]; } m=sum/n; for(sum=0.0,i=0;i<n;i++) { sum+=(d[i]-m)*(d[i]-m); } v=sum/n; s=sqrt(v); printf("平均=%10.3f\n",m); printf("分数=%10.3f\n",v); printf("標準偏差=%10.3f\n",s); return 0; } エラーメッセージは ・'scanf' の宣言を確認してください。 ・(11): warning C4566: ユニバーサル文字名 '\u00A5' によって表示されている文字は、現在のコード ページ (932) で表示できません ・(14): warning C4566: ユニバーサル文字名 '\u00A5' によって表示されている文字は、現在のコード ページ (932) で表示できません ・(14): error C2065: 'i1' : 定義されていない識別子です。 と出るのですがさっぱりわかりません。どなたか教えてください。

  • C言語でmからnまでの合計を求めるプログラム

    これで動かないのですが、何が違っているのか、教えていただけますか。 #include <stdio.h> int main(void) { int m, n, sum, i, w ; printf("mからnまでの合計を求めます\n\n"); printf("m >> "); scanf(" %d", &m); printf("n >> "); scanf(" %d", &n); sum=0; if(m>n){ w=m; m=n; n=w; } sum=0; i=m; while(i<=n){ sum=sum+i; i=i+1; } printf("%d から %d の合計 = %d\n",m,n,sum); return 0; }

専門家に質問してみよう