アプリ版:「スタンプのみでお礼する」機能のリリースについて

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 ;


}

A 回答 (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行の修正で、質問者さんが挙げたリンク先の実行例と同じ結果になることは確認済です。
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/08/07 08:18

浮動小数点数を整数化するときの問題じゃないですかね。


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] << ",";

のようにするべきでしょう。
    • good
    • 0

浮動小数点数を整数化するときの問題じゃないですかね。


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] << ",";

のようにするべきでしょう。
    • good
    • 0
この回答へのお礼

doubleの切捨てに問題があるということですね?
私もそこは気になっていました。

その観点でもう少しプログラムいじってみます。

ご解答ありがとうございました。

お礼日時:2010/08/06 21:22

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!