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 }