DCT3回目 開始!まずは、公式から

wikipedia等によると、公式はいくつかあるようなのですが、私は下記の公式を使う事にしました。
これから、以下の公式通りにプログラムを組んでみて、変換⇒逆変換と動かしてみて、
この公式が本当に正しいのかどうかを確かめてみようと思います。

===== 公式 =========================================================

N:変換する対象の要素数を表します。
π:円周率のパイです(3.1415926535・・・・)
S(x):DCT変換する前の値です。要素数N個の1次元の配列です。
S(u):DCT変換後の値です。要素数N個の1次元の配列です。
この値はDCT係数と呼ばれ、各々の波が、どの程度含まれているのか?という事を示しているそうです。

///// 変換 /////////////////////////////////////////////////////////

                        N-1                            
S(u) = √2/√N * C(u) * Σ  S(x) * cos( (2x+1)u*π/2N)  
                        x=0                            
但し、C(u)は、
    u=0  の時、1/√2
    u≠0 の時、1

///// 逆変換 ///////////////////////////////////////////////////////

                 N-1                                  
S(x) = √2/√N * Σ  C(u) * S(u) * cos( (2x+1)u*π/2N) 
                 u=0                                  
但し、C(u)は、
    u=0  の時、1/√2
    u≠0 の時、1     です。

====================================================================

↑が公式です。

今回は、要素の数を8個として実験します。
つまり、高さ1、幅8 の画像を1次元DCTするというイメージで行きたいと思います。

@ 0 1 2 3 4 5 6 7
10 20 30 40 50 60 70 80


次に、要素数を8としたときの公式と、そのプログラムを書きます。
上の公式の N が 8 になっただけです。

 /*
======変換=========================================
                     7
S(u) = 1/2 * C(u) * Σ  * S(x) * cos( (2x+1)uπ/16 )
                    x=0
但し、C(u)は、
    u=0  の時、1/√2
    u≠0 の時、1     です。
===================================================
*/
 double Cu = 0.0;
 double sigma = 0.0;
 double sigmain = 0.0;

 double cos=0.0;
 double cosin = 0.0;
 sb->AppendFormat("-----変換-----\r\n");

 for(u=0; u<8; u++){
 sigma = 0;
	 for(x=0; x<8; x++){
		 cosin = (2*x+1)*u*Math::PI/16;
		 cos = Math::Cos( cosin );
		 sigmain = Sx[x] * cos;
		 sigma += sigmain;
		 sb->AppendFormat("Sx[{4}]={5,4}, cos({0,8:F4})={1,8:f4},\tsigmain={2,10:f4},\tsigma={3,10:f4}\r\n"
			,cosin,cos,sigmain,sigma,x,Sx[x]);
	 }
	 if(u==0){
		 Cu = Math::Sqrt(1.0/2.0);
	 }else{
		 Cu = 1.0;
	 }
	 Su[u] = (int)(sigma/2.0*Cu);
	 sb->AppendFormat("Su[{0}]={1}\r\n",u,Su[u]);
 }

/*
=====逆変換========================================
              7
S(x) = 1/2 * Σ  * C(u) * S(u) * cos( (2x+1)uπ/16)
             u=0
但し、C(u)は、
	u=0  の時、1/√2
	u≠0 の時、1     です。
===================================================
*/
 sb->AppendFormat("-----逆変換-----\r\n");

 for(x=0; x<8; x++){
	 sigma = 0;

	 for(u=0; u<8; u++){
		 if(u==0){
			 Cu = Math::Sqrt(1.0/2.0);
		 }else{
			 Cu = 1.0;
		 }
		 cosin = (2*x+1)*u*Math::PI/16;
		 cos = Math::Cos(cosin);
		 sigmain = Su[u]*Cu*cos;
		 sigma += sigmain;
		 sb->AppendFormat("Su[{4}]={5,4}, cos({0,8:F4})={1,8:f4},\tsigmain={2,10:f4},\tsigma={3,10:f4}\r\n"
			,cosin,cos,sigmain,sigma,u,Su[u]);
	 }
	 Sx2[x] = (int)sigma/2;	 
	 sb->AppendFormat("Sx2[{0}]={1}\r\n",x,Sx2[x]);
 }
			 
 textBox3->Text = sb->ToString();


※計算途中の値を出力したいので、計算は、数回に分けてあります。

これを実行すると、以下のように出力され、この公式が、おそらく正しいであろうと思われるところまで来ました。

※double型からint型にキャスト(小数点切捨て)している為に、誤差が出ています。
また、DCT⇒逆DCTのみなら、プログラム上の丸め処理を考慮に入れなければ、可逆変換(完全に元に戻せる)です。

入力値 1 10 100 200 300 900 10 1
DCT後 538 -231 -417 420 -183 -119 357 -283
逆DCT後 1 10 100 199 299 899 10 0
入力値 100 100 100 100 100 100 100 100
DCT後 282 0 0 0 0 0 0 0
逆DCT後 99 99 99 99 99 99 99 99