jpegのDCT変換がうまくいかない理由とは?

このQ&Aのポイント
  • jpegのDCT変換について質問があります。DCT変換を使用してjpegを作成する際、プログラムを作成しましたが、変換結果が期待通りになりませんでした。
  • DCT変換の式やプログラムは正しく実装されているはずですが、変換結果が異なる理由が分かりません。
  • 参考にしたサイトのDCT変換の例と同じ値になるはずなのに、異なる結果になってしまいます。どのような原因が考えられるでしょうか?
回答を見る
  • ベストアンサー

jpeg の DCT 変換がうまくいきません。

jpeg の DCT 変換がうまくいきません。 jpegを作りたいのですが、DCT変換で詰まってしまいました。 よろしければ、ご教授いただけませんでしょうか? http://www.ann.hi-ho.ne.jp/jiro/assyuku2.htm のDCT変換の例を見て、プログラムを作ってみましたが、 変換例と同じ値に変換されませんでした。 作ってみたプログラムです。 #include <iostream> #include <stdio.h> #define _USE_MATH_DEFINES #include <math.h> using namespace std; void main(int argc, char** argv) {   double cu = 1.0;   double cv = 1.0;     double long sum = 0.0;      int before[8][8] ={     {57,49,44,39,33,28,23,22},     {55,45,39,33,28,21,21,19},     {55,44,37,31,20,17,17,16},     {58,44,37,29,17,15,16,14},     {66,46,31,22,16,14,12,10},     {71,49,32,24,14,12,21,19},     {69,50,30,22,12,4,-1,-2},     {62,42,25,17,7,1,-16,-16}      };   int after[8][8];   ZeroMemory(after,sizeof(int)*64);   for(int v =0; v < 8; v++)   {     if(v) cv =1.0;     if(!v) cv = 1 / sqrt(2.0);     for(int u = 0; u < 8; u++)     {       if(u) cu =1.0;       if(!u) cu = 1 / sqrt(2.0);       sum = 0.0;       for(int y = 0; y < 8; y++)       {         for(int x = 0; x < 8; x++)         {           double long a = cos((2 * x + 1)*u*M_PI/16) * cos(( 2 * y + 1)*v*M_PI/16);           double long d = before[x][y];           sum += d * a;         }       }       after[u][v] = int(cu*cv*sum/4);     }   }   for(int j = 0; j < 8; j++)   {     for(int i = 0; i < 8; i++)     {       cout << after[i][j] << ",";     }     cout << endl;   }   int b;   cin >> b ; }

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

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.3

ちょっとだけ補足しておきます。 > int(floor(cu*cv*sum/4+0.5)); floor は「引数値を超えない最大の整数」を返す関数であり、 それに0.5足した値を入れることで、四捨五入になります。 修正前> double long d = before[x][y]; 修正後> double long d = before[y][x]; 修正前> after[u][v] = int(cu*cv*sum/4); 修正後> after[v][u] = int(floor(cu*cv*sum/4+0.5)); 修正前> cout << after[i][j] << ","; 修正後> cout << after[j][i] << ","; この3行の修正で、質問者さんが挙げたリンク先の実行例と同じ結果になることは確認済です。

suisuisui9
質問者

お礼

やっとできました。 正解まで載せていただいて、ありがとうございました。

その他の回答 (2)

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.1

浮動小数点数を整数化するときの問題じゃないですかね。 int にキャストすると切り捨てになってしまいいますので、 > floor(cu*cv*sum/4+0.5) としましょう。 それと、 before の初期化値の57,49,44,39,…が、y=0で、x=0,1,2,3…に対応するのなら、 配列アクセスは before[y][x] になります。 (このように、C言語で二次元配列を使うときは、yの方を最初の添え字に使う場合が多いです。) それにあわせて、配列アクセスは全て > double long d = before[y][x]; > after[v][u] = int(floor(cu*cv*sum/4+0.5)); > cout << after[j][i] << ","; のようにするべきでしょう。

suisuisui9
質問者

お礼

doubleの切捨てに問題があるということですね? 私もそこは気になっていました。 その観点でもう少しプログラムいじってみます。 ご解答ありがとうございました。

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.2

浮動小数点数を整数化するときの問題じゃないですかね。 int にキャストすると切り捨てになってしまいいますので、 > floor(cu*cv*sum/4+0.5) としましょう。 それと、 before の初期化値の57,49,44,39,…が、y=0で、x=0,1,2,3…に対応するのなら、 配列アクセスは before[y][x] になります。 (このように、C言語で二次元配列を使うときは、yの方を最初の添え字に使う場合が多いです。) それにあわせて、配列アクセスは全て > double long d = before[y][x]; > after[v][u] = int(floor(cu*cv*sum/4+0.5)); > cout << after[j][i] << ","; のようにするべきでしょう。

関連するQ&A

  • C言語でテーブル引きしたら速度が遅くなった

    プログラムに悩んでいるものです. とある画像処理のプログラムを組んでいるのですが,処理が遅くテーブル引きを組んでいます. この前もこの場を借りて質問しsqrt()のテーブル引きは実現したのですが,処理速度が遅くなってしまい原因が分からないので質問させていただきました. 前の質問URL:http://okwave.jp/qa/q7103550.html 前回から修正した現在のプログラムの一部を示します. ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー void filter(unsigned char* d, short *dx, short *dy, int w, int h) { ///// テーブル生成 ///// static int c_size = 0; // static 値を保持 static double c_sqrt[1020][1020]; if(c_size != 1020){ // 初回呼び出しのみ実行 c_size = 1020; for(int i=0; i<c_size; i++){ // 有りえるすべての値を生成 for(int j=0; j<c_size; j++){ c_sqrt[i][j] = sqrt( (double)(i*i + j*j) ); } } } ///// d = sqrt(dx^2 + dy^2) ///// for(int y = 1; y < h-1; ++y){ for(int x = 1; x < w-1; ++x){ double u = (double)dx[y*w+x]; double v = (double)dy[y*w+x]; if(u<0) u=-u; if(v<0) v=-v; int val = (int)c_sqrt[(int)u][(int)v] /4; if(val>255) val=255; d[y*w+x] = val; } } } ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー テーブル引きをしない場合(プログラム省略)はこの関数の処理時間が約9[ms]だったのに対し,上記のプログラムは約15[ms]となってしまいました. どういう風に修正すれば,テーブル引きの効果が出せるでしょうか? 長い文章を最後までお読みいただきありがとうございます. ご回答,よろしくお願い致します.

  • 変数変換について

    大学の講義で変数変換(v,u)|→(x(u,v),y(u,v))は dxdy=|J|dudv (Jはヤコビアン) となると習いました。 では、この変換を(x(u,v),y(u,v))|→(x(u,v),v)と(x(u,v),v)|→(x(u,v),y(u,v))の合成と見なしたとき、どのような計算をすれば dxdy=|J|dudv となるのでしょうか。 dxdv=(∂x/∂u)dudvとdxdy=(∂y/∂v)dxdv を使えば良いことは分かるのですが、どうしても答えが一致しません。 よろしくお願いします。

  • C言語でsqrt(a^2+b^2)のテーブル引き

    プログラムに悩んでいるものです. とある画像処理のプログラムを組んでいるのですが,処理が遅くテーブル引きを組んでいます. 三角関数などはすんなりできたのですが,質題にもある通りsqrt(a^2+b^2)が実現できず,この場を借りて質問させていただきました. 以下にプログラムの一部を示します. ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー void filter(unsigned char* d, short *dx, short *dy, int w, int h) { ///// テーブル生成 ///// static int c_size = 0; // static 次の呼び出しでも値保持 static double *c_sqrt = NULL; // c_size = 255;              // u,v:0~255 c_sqrt = (double *)malloc(sizeof(double)*c_size*c_size); // 領域確保 for(int i=0; i<c_size; ++i){     // 有りえるすべての値を生成 for(int j=0; j<c_size; ++i){ c_sqrt[i*j] = sqrt( (double)(i*i + j*j) ); } } ///// d = sqrt(dx^2 + dy^2) ///// for(int y = 1; y < h-1; ++y){ for(int x = 1; x < w-1; ++x){ double u = (double)dx[y*w+x]; double v = (double)dy[y*w+x]; int val = (int)c_sqrt[ (int)(u*v) ] /4; if (val>255) val=255; d[y*w+x] = val; } } } ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 見てご察し頂ける(?)と思いますが,この関数は何回も呼び出すので,上のほうででテーブル引きしようとしてます. ただ明らかなプログラム経験不足のためかうまくいってません. 個人的にはc_sqrtを別途関数c_sqrt(u,v)にしたほうがよいのかと思ってます. どういうプログラム記述をすれば,このテーブル引きが実現できるでしょうか? ご回答,お力添え,よろしくお願い致します.

  • プログラムのスレッド化について。

    以下の処理をスレッド化しようとしています。 public class FCP{ int N=10 long LOOP_MAX=100 double x[][] = new double[N][4] int g[][] = new int[N][4] boolean y[][] = new boolean[N][4]//出力 boolean A[][] = new boolean[N][10] double T=0.5 Set_Adjacent_Matrix() //A配列にtrueとfalseを代入 Set_initial_value() //y配列に初期値を代入(Math.random()>0.5) g1(int i, int j) //k<4 sum=1 if( y[i][k] == true ) --sum return(double)sum g2(int i, int j) //k<N sum=0 if( y[i][j] == true ) if( y[k][j] == true && A[i][k] == true ) --sum return(double)sum Display_output() //結果表示 if( y[i][j] ) System.out.print("0") else System.out.print(".") public static void main(String args[]) { long loop; int i, j, k; Set_Adjacent_Matrix(); Set_initial_value(); for( loop=0; loop<LOOP_MAX; loop++ ){ for( i=0; i<N; i++ ){ for( j=0; j<4; j++ ){ x[i][j] = g1( i, j ) + g2( i, j ); if( y[i][j] ){ x[i][j] += T; }else{ x[i][j] -= T; } if( x[i][j] > 0.0){ y[i][j] = true; }else{ y[i][j] = false; } } } Display_output(); } } 今回Threadクラスの継承を使ってスレッド化しようと考えました。runメソッドには上のプログラムのmain部分の処理をさせようと思っています。そしてstartメソッドで必要な数(Nの値=10コ)のスレッドを生成しrunメソッドを実行する。 と、ここまではわかったのですが、「生成された各スレッドの番号を保持し、そのスレッドに担当させる処理を決める」という部分をどうすればいいのかわかりません。 「i(1~10)番目のスレッドはN(1~10)列目の処理を担当している」という風にするにはどうしたらいいのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • C++でオセロのCPUの処理を考えたのですが、40手目あたりからうまく

    C++でオセロのCPUの処理を考えたのですが、40手目あたりからうまくいきません。ReverseOthello関数の石を探して裏返す処理がおかしいと思われます。一番裏返せる石が多い位置を裏返すという処理をしています。プログラミング経験が豊富な方よろしくお願いします。 #include "stdafx.h" bool Othello(int (*pBoard)[8] ){ int i; int j; int ans; int k = 0; int num[3] = {0,0,0}; int sum[28][3]; i = 0; while(i < 28){ j = 0; while(j < 3){ sum[i][j] = 0; j++; } i++; } i = 0; while(i < 8){ j= 0; while(j < 8){ if(pBoard[i][j] == 0){ ans = SeachStone(i,j,pBoard); if(ans != 0){ sum[k][0] = i; sum[k][1] = j; sum[k][2] = ans; k++; } } j++; } i++; } i = 0; while(i < 28){ if(num[2] < sum[i][2]){ num[0] = sum[i][0]; num[1] = sum[i][1]; num[2] = sum[i][2]; } i++; } if(num[2] == 0){ return false; } ReverseStone(num[0],num[1],pBoard); return true; } void ReverseStone(int y1,int x1,int (*pBoard)[8]){ int cnt = 0; int y2; int x2; int i; int j; int k; if(y1 == 0){ i = 0; } else { i = y1-1; } while(i < y1 + 2){ if(x1 == 0){ j = 0; } else { j = x1-1; } while(j < x1 + 2){ y2 = i; x2 = j; cnt = 0; while(pBoard[y2][x2] == -1){ y2 = y2 + (i - y1); x2 = x2 + (j - x1); cnt++; } if(pBoard[y2][x2] == 1&& cnt != 0){ k = 0; while(k < cnt + 1){ y2 = y2 + (y1 - i); x2 = x2 + (x1 - j); pBoard[y2][x2] = 1; printf("%d\n",pBoard[y2][x2]); k++; } } j++; } i++; } } int SeachStone(int y1,int x1,int (*pBoard)[8]){ int cnt = 0; int sumCnt = 0; int y2; int x2; int i; int j; if(y1 == 0){ i = 0; } else { i = y1-1; } while(i < y1 + 2){ if(x1 == 0){ j = 0; } else { j = x1-1; } while(j < x1 + 2){ y2 = i; x2 = j; cnt = 0; while(pBoard[y2][x2] == -1){ y2 = y2 + (i - y1); x2 = x2 + (j - x1); cnt++; } if(pBoard[y2][x2] == 1&& cnt != 0){ sumCnt = sumCnt + cnt; } j++; } i++; } return sumCnt; }

  • 偏微分方程式、差分法

    Fitzhugh-Nagumo方程式 dU/dt = d/dx(dU/dx) + (a-U)(U-1)U-V (d/dx(dU/dx)はUのxに対する二回微分) dV/dt =e(bU-gV) a=0.1, b=0.5, g=1.0, e=0.01 初期条件 (U,V)=(1,0) if x=0 (U,V)=(0,0) if x>0 境界条件 dU/dx=0 at x=0 dV/dx=0 at x=0 を差分して陽解法で解くと添付の答えになるらしいのですが、自分で解いたところ添付の結果のようになりました。答えと一致しないため、プログラム上で何を間違えているのかご指摘頂けると助かります。 #include <stdio.h> #include <stdlib.h> //exsit()で必要 #include <math.h> int main(){ double a,b,g,e; double dt,dx; int x,t; double **u,**v; int i,j,k; a=0.1;b=0.5;g=1.0;e=0.01; x=100;t=5000.; dt=0.001;dx=0.1; FILE *fp; if((fp = fopen("ResultNagumo.txt","w"))==NULL){ printf("Can't open file\n"); exit(2); } u = (double**)malloc(sizeof(double*)*t); v = (double**)malloc(sizeof(double*)*t); for(i=0;i<t;i++){ u[i]=(double*)malloc(sizeof(double)*x); v[i]=(double*)malloc(sizeof(double)*x); } //初期値 u[0][0]=1.0; v[0][0]=0.0; for(i=1;i<x;i++){ u[0][i]=0.0; v[0][i]=0.0; }    //差分計算 for(i=0;i<t-1;i++){ for(j=1;j<x-1;j++){ u[i+1][j] = u[i][j] + dt*((u[i][j+1]-2*u[i][j]+u[i][j-1])/pow(dx,2)+(a-u[i][j])*(u[i][j]-1)*u[i][j]-v[i][j]); v[i+1][j] = v[i][j] + dt*(e*(b*u[i][j]-g*v[i][j])); } //境界条件 u[i+1][0]=u[i+1][1]; v[i+1][0]=v[i+1][1]; u[i+1][x-1]=u[i+1][x-2]; v[i+1][x-1]=v[i+1][x-2]; }   //結果の出力 for(i=0;i<t;i++){ if((i%100)==0){ fprintf(fp,"%d\n",i); for(j=0;j<x;j++){ fprintf(fp,"%2.4e,",u[i][j]); } } } for(i=0;i<t;i++){ free(u[i]); free(v[i]); } free(u);free(v); fclose(fp); getchar(); return 0; }

  • 困ってます。巡回セールスマン問題

    ネットを参考にしてゼミの課題のプログラムを書いてみたのですが、動きません。prevがあいまいです。と出ます。どうやれば動きますか?教えてください。 #include <iostream> #include <cmath> using namespace std; const int MAX_N = 20; int n; double dist[MAX_N][MAX_N]; int prev[MAX_N]; double optval = 99999.99999; int optsol[MAX_N]; void solve(int u = 0) { bool end = true; for (int v = 0; v < n; ++v) { if (prev[v] == -1) { end = false; prev[v] = u; solve(v); prev[v] = -1; } } if (end) { double length = dist[u][0]; for (int v = u; v != 0; v = prev[v]) length += dist[prev[v]][v]; if (length < optval) { optval = length; for (int i = 0; i < n; ++i) optsol[i] = prev[i]; optsol[0] = u; } } } int main() { // get input cin >> n; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cin >> dist[i][j]; for (int i = 0; i < n; ++i) prev[i] = -1; prev[0] = 0; solve(); for (int u = optsol[0]; u != 0; u = optsol[u]) cout << u+1 << " <- "; cout << 1 << " : " << optval << endl; }

  • 下記プログラミングについて

    下のプログラミングの解説ができる方がいましたら教えてください! どう頑張っても理解できなくて困っています;; もしかしたら間違っているところがあるかもしれませんが、よろしくお願いします。 ---------------------------------------------------------------- #include<stdio.h> #include<math.h> main() { int A,B,C,t,h,i,j,k; int sum_column,sum_row,diagonal1,diagonal2; int conf,diag,seed,max; int U[101][101],V[101][101]; int rand(); A=1,B=1,C=1; printf("Please define the pueen problem size(5-100).\n"); scanf("%d", &max); printf("Please input a seed(0-999).\n"); scanf("%d", &seed); for(i=1; i<=seed; i++){ U[1][1]=rand(); }; for(i=1; i<=max; i++){ for(j=1; j<=max; j++){ U[i][j] = -(abs(rand() % 8)); V[i][j]=0; }; };   /* Main program */ t=0; diag=1; while((diag>0)&&(t<500)){ diag=0; for(i=1; i<=max; i++){ for(j=1; j<=max; j++){ sum_column=0; sum_row=0; for(k=1; k<=max; k++){ sum_row=sum_row+V[i][k]; sum_column=sum_column+V[k][j]; } diagonal1=0; k=1; while(((j+k)<=max)&&((i-k)>=1)){ diagonal1=diagonal1+V[i-k][j+k]; k++; } k=1; while(((j-k)>=1)&&((i+k)<=max)){ diagonal1=diagonal1+V[i+k][j-k]; k++; } k=1; while(((j+k)<=max)&&((i+k)<=max)){ diagonal2=diagonal2+V[i+k][j+k]; k++; } k=1; while(((j-k)>=1)&&((i-k)>=1)){ diagonal2=diagonal2+V[i-k][j-k]; k++; } k=1; h=0; conf=1; if(sum_column == 0) h=1; if(sum_row == 0) h++; if((sum_column+sum_row==2) && (diagonal1<2) && (diagonal2<2)) conf=0; U[i][j]=U[i][j]-A*(sum_row+sum_column-2)-B*(diagonal1+diagonal2)+C*h; if(U[i][j]>8) U[i][j]=8; if(U[i][j]<-8) U[i][j]=-8; if(U[i][j]>0) V[i][j]=1; else V[i][j]=0; diag=diag+conf; }; }; t++; printf("t=%d\n", t); if((t % 15) < 5) C=4; else C=1; }; printf("the number of iteretion steps=%d\n", t); printf("\n"); for(i=1; i<=max; i++){ for(j=1; j<=max; j++){ if(j==max){ if(V[i][j]==1) printf("*\n"); else printf("-\n"); } else{ if(V[i][j]==1) printf("* "); else printf("- "); } } } }

  • C言語。どうしてコンパイルできません^^;

    最近プログラミングの勉強をはじめました。 C言語を勉強しています。 /*入力した値の、平均値・最大値・最小値・を出す。*/ #include <stdio.h> int main(void) { int x[5],i,j,w,x,y,z,sum; printf("5つの実数の平均、最大値、最小値を求めます\n"); sum = 0; for(i=0; i<5; i++){ printf("値%d:",i+1); scanf("%d",&x[i]); sum += x[i]; } for(y=0; y<5; y++){ for(j=0; j<4; j++){ w=j+1; if(x[j] < x[w]){ z = x[i]; x[i] = x[w]; x[w] = z; } } } printf("平均値:%f\n最大値:%d\n最小値:%d\n", (double)sum/5, x[0], x[4]); return 0; } Microsoft Visual C++ 2008 Express Edition でコンパイルをしようとしたのですが、 「error C2040: 'x' : 'int' は 'int [5]' と間接操作のレベルが異なります。」 と出てできませんでした^^; 何度も見直したのですが、どうしても間違っている場所がわかりません^^; どこがいけないのでしょうか^^;

  • c言語

    #include<stdio.h> main(void) { int x; double y,sum; void p(double *); for(sum=0.0,x=1;x<10;x++){ sum+=1.0/p(&x); ここでエラーがでます。 } printf("%d\n",sum); } void p(double *y) { *y*=*y; } どうしてエラーがでるかわかりません。教えてください!

専門家に質問してみよう