1 
2 module dct;
3 
4 import std.math;
5 import std.algorithm;
6 import math;
7 import des.ts;
8 
9 ref const(T[N][N]) DCT_MATRIX(T, uint N)()
10 {
11 	static T[N][N] instance;
12 	static bool initialized = false;
13 
14 	auto C(uint k){ return (k == 0) ? 1.0/SQRT2: 1;}
15 
16 	if(!initialized)
17 	{
18 		foreach(x; 0..N)
19 		{
20 			foreach(k; 0..N)
21 			{
22 				instance[x][k] = C(k) * cos((x + 0.5) / N * k * PI);
23 			}
24 		}
25 
26 		initialized = true;
27 	}
28 
29 	return instance;
30 }
31 
32 void idct_1d(uint N,I,O)(I[] block, O[] rec, uint stride)
33 {
34 	const N2 = 2 * N;
35 
36 	for(uint i=0; i<N; ++i)
37 	{
38 		O sum = 0;
39 
40 		for(uint k=0; k<N; ++k)
41 		{
42 			sum += block[k * stride]
43 				//* C(k) * mycos((i + 0.5) / N * k * PI);
44 				 * DCT_MATRIX!(O,N)()[i][k];
45 		}
46 
47 		rec[i * stride] = sum * sqrt(2.0 / N);
48 	}
49 }
50 
51 void idct_2d(uint N)(ref short[N*N] block)
52 {
53 	real[N*N] rec;
54 	real[N*N] rec2;
55 
56 	// rows
57 	for(uint i=0; i<N; ++i)
58 	{
59 		idct_1d!N(block[i*N ..(i+1)*N], rec[i*N ..(i+1)*N], 1);
60 	}
61 
62 	// columns
63 	for(uint j=0; j<N; ++j)
64 	{
65 		idct_1d!N(rec[j..$], rec2[j..$], N);
66 	}
67 
68 	for(uint i=0; i<N*N; ++i)
69 	{
70 		block[i] = cast(short) round(rec2[i]);
71 	}
72 }
73 
74 void idct_2da(uint N, T = float)(ref short[N*N] block)
75 {
76 	T[N*N] rec;
77 
78 	// rows
79 	for(uint i=0; i<N; ++i)
80 	{
81 		for(uint x=0; x<N; ++x)
82 		{
83 			T sum = 0;
84 
85 			for(uint k=0; k<N; ++k)
86 			{
87 				sum += block[i*N + k]
88 					 * DCT_MATRIX!(T,N)()[x][k];
89 			}
90 
91 			rec[i * N + x] = sum;
92 		}
93 	}
94 
95 	// columns
96 	for(uint j=0; j<N; ++j)
97 	{
98 		for(uint x=0; x<N; ++x)
99 		{
100 			T sum = 0;
101 
102 			for(uint k=0; k<N; ++k)
103 			{
104 				sum += rec[k*N + j]
105 					 * DCT_MATRIX!(T,N)()[x][k];
106 			}
107 
108 			block[x * N + j] = cast(short) round(sum * 2.0 / N);
109 		}
110 	}
111 }
112 
113 void idct_annexA(ref short[64] block)
114 {
115 	idct_2da!8(block);
116 	foreach(i, v; block)
117 	{
118 		block[i] = saturate!(short,-256,255)(v);
119 	}
120 }
121 
122 unittest // check DC
123 {
124 	short[8] block;
125 	real[8] rec;
126 	auto reference = new real[8];
127 
128 	block[0] = 8;
129 	fill(reference, 8.0/sqrt(8.0));
130 
131 	idct_1d!8(block, rec, 1);
132 
133 	auto err = norm(rec, reference);
134 	assertEqApprox(err, 0, 10e-5);
135 }
136 
137 unittest // check Parseval's identity
138 {
139 	import std.random;
140 
141 	const N = 8;
142 
143 	foreach(i; 0..100)
144 	{
145 		auto block = uniformDistribution(N);
146 		real[N] rec;
147 
148 		idct_1d!N(block, rec, 1);
149 
150 		assertEqApprox(norm(block), norm(rec), 10e-5);
151 	}
152 }
153 
154 unittest // check DC 2D
155 {
156 	const N2 = 64;
157 	short[N2] block;
158 	auto reference = new real[N2];
159 
160 	block[0] = 64;
161 	fill(reference, 8.0);
162 	auto orig = block;
163 
164 	idct_2d!8(block);
165 
166 	auto err = norm(block, reference);
167 	assertEqApprox(err, 0, 10e-5);
168 }
169 
170 unittest // check idct2da
171 {
172 	const N2 = 64;
173 	short[N2] block;
174 	auto reference = new real[N2];
175 
176 	block[0] = 64;
177 	fill(reference, 8.0);
178 	auto orig = block;
179 	auto block2 = block;
180 
181 	idct_2d!8(block);
182 	idct_2da!8(block2);
183 
184 	assertEq(block, block2);
185 }