Реализация DCT дискретного косинусного преобразования C
Im пытается реализовать прямое и обратное дискретное косинусное преобразование (DCT) в C. код должен трансормировать один входной блок пикселей в матрицу преобразования через функцию dct (), а затем вернуться к исходным значениям пикселей через функцию idct (). См. прилагаемый код. Моя выходная форма idct-это последовательные значения 244, 116, 244, 116 и т. д. Судя по значениям idct, похоже, что моя программа не работает.. Может кто-нибудь помочь мне и дать мне идею каких результатов следует ожидать после каждой функции? Очевидно, после idct я должен быть близок к исходной входной Матрице.
спасибо
# include <stdio.h>
# define PI 3.14
void dct(float [][]); // Function prototypes
void idct(float [][]); // Function prototypes
void dct(float inMatrix[8][8]){
double dct,
Cu,
sum,
Cv;
int i,
j,
u,
h = 0,
v;
FILE * fp = fopen("mydata.csv", "w");
float dctMatrix[8][8],
greyLevel;
for (u = 0; u < 8; ++u) {
for (v = 0; v < 8; ++v) {
if (u == 0) {
Cu = 1.0 / sqrt(2.0);
} else {
Cu = 1.0;
}
if (v == 0) {
Cv = 1.0 / sqrt(2.0);
} else {
Cu = (1.0);
}
sum = 0.0;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
// Level around 0
greyLevel = inMatrix[i][j];
dct = greyLevel * cos((2 * i + 1) * u * PI / 16.0) *
cos((2 * j + 1) * v * PI / 16.0);
sum += dct;
}
}
dctMatrix[u][v] = 0.25 * Cu * Cv * sum;
fprintf(fp, "n %f", dctMatrix[u][v]);
}
fprintf(fp, "n");
}
idct(dctMatrix);
}
void idct(float dctMatrix[8][8]){
double idct,
Cu,
sum,
Cv;
int i,
j,
u,
v;
float idctMatrix[8][8],
greyLevel;
FILE * fp = fopen("mydata.csv", "a");
fprintf(fp, "n Inverse DCT");
for (i = 0; i < 8; ++i) {
for (j = 0; j < 8; ++j) {
sum = 0.0;
for (u = 0; u < 8; u++) {
for (v = 0; v < 8; v++) {
if (u == 0) {
Cu = 1.0 / sqrt(2.0);
} else {
Cu = 1.0;
}
if (v == 0) {
Cv = 1.0 / sqrt(2.0);
} else {
Cu = (1.0);
}
// Level around 0
greyLevel = dctMatrix[u][v];
idct = (greyLevel * cos((2 * i + 1) * u * PI / 16.0) *
cos((2 * j + 1) * v * PI / 16.0));
sum += idct;
}
}
idctMatrix[i][j] = 0.25 * Cu * Cv * sum;
fprintf(fp, "n %f", idctMatrix[i][j]);
}
fprintf(fp, "n");
}
}
int main() {
float
testBlockA[8][8] = { {255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255} },
testBlockB[8][8] = {{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255} };
dct(testBlockB);
}
3 ответов
в задании константы Cv в операторах if есть как минимум две опечатки:
if (v == 0) {
Cv = 1.0 / sqrt(2.0);
} else {
Cu = (1.0); // << this should be Cv = 1.0
}
не проверял слишком правильно. С помощью немецкой Википедии о косинусном преобразовании, следующий код работает... Я не хотел тратить время на выяснение того, как вы определяете константу преобразования. Я думаю, вам нужно убедиться, что вы используете правильные константы и обратные функции:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void dct(float **DCTMatrix, float **Matrix, int N, int M);
void write_mat(FILE *fp, float **testRes, int N, int M);
void idct(float **Matrix, float **DCTMatrix, int N, int M);
float **calloc_mat(int dimX, int dimY);
void free_mat(float **p);
float **calloc_mat(int dimX, int dimY){
float **m = calloc(dimX, sizeof(float*));
float *p = calloc(dimX*dimY, sizeof(float));
int i;
for(i=0; i <dimX;i++){
m[i] = &p[i*dimY];
}
return m;
}
void free_mat(float **m){
free(m[0]);
free(m);
}
void write_mat(FILE *fp, float **m, int N, int M){
int i, j;
for(i =0; i< N; i++){
fprintf(fp, "%f", m[i][0]);
for(j = 1; j < M; j++){
fprintf(fp, "\t%f", m[i][j]);
}
fprintf(fp, "\n");
}
fprintf(fp, "\n");
}
void dct(float **DCTMatrix, float **Matrix, int N, int M){
int i, j, u, v;
for (u = 0; u < N; ++u) {
for (v = 0; v < M; ++v) {
DCTMatrix[u][v] = 0;
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++) {
DCTMatrix[u][v] += Matrix[i][j] * cos(M_PI/((float)N)*(i+1./2.)*u)*cos(M_PI/((float)M)*(j+1./2.)*v);
}
}
}
}
}
void idct(float **Matrix, float **DCTMatrix, int N, int M){
int i, j, u, v;
for (u = 0; u < N; ++u) {
for (v = 0; v < M; ++v) {
Matrix[u][v] = 1/4.*DCTMatrix[0][0];
for(i = 1; i < N; i++){
Matrix[u][v] += 1/2.*DCTMatrix[i][0];
}
for(j = 1; j < M; j++){
Matrix[u][v] += 1/2.*DCTMatrix[0][j];
}
for (i = 1; i < N; i++) {
for (j = 1; j < M; j++) {
Matrix[u][v] += DCTMatrix[i][j] * cos(M_PI/((float)N)*(u+1./2.)*i)*cos(M_PI/((float)M)*(v+1./2.)*j);
}
}
Matrix[u][v] *= 2./((float)N)*2./((float)M);
}
}
}
int main() {
float
testBlockA[8][8] = { {255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255},
{255, 255, 255, 255, 255, 255, 255, 255} },
testBlockB[8][8] = {{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255},
{255, 0, 255, 0, 255, 0, 255, 0},
{0, 255, 0, 255, 0, 255, 0, 255} };
FILE * fp = fopen("mydata.csv", "w");
int dimX = 8, dimY = 8;
int i, j;
float **testBlock = calloc_mat(dimX, dimY);
float **testDCT = calloc_mat(dimX, dimY);
float **testiDCT = calloc_mat(dimX, dimY);
for(i = 0; i<dimX; i++){
for(j = 0; j<dimY; j++){
testBlock[i][j] = testBlockB[i][j];
}
}
dct(testDCT, testBlock, dimX, dimY);
write_mat(fp, testDCT, dimX, dimY);
idct(testiDCT, testDCT, dimX, dimY);
write_mat(fp, testiDCT, dimX, dimY);
fclose(fp);
free_mat(testBlock);
free_mat(testDCT);
free_mat(testiDCT);
return 0;
}
редактировать dct основан на crossproduct формулы ДКП-II в вики. idct основан на перекрестном произведении формулы DCT-III с коэффициентом нормализации 2/N на измерение (поскольку это обратный DCT-II, как указано в тексте). редактировать Я уверен, что коэффициент в обратном dct должен быть sqrt(2), а не 1/sqrt(2) в вашей версии.
не
#include <math.h>
это может означать, что компилятор предполагает вещи о математических функциях, которые не являются истинными, например, что все они возвращаютint
. Обратите внимание, что все функции, которые вы вызываете, должны быть объявлены где-то, C не имеет "встроенного" sin()
больше, чем у него есть встроенный printf()
(для последнего вы правильно включаете stdin.h
, конечно).
кроме того, вы можете использовать M_PI
как только вы включили <math.h>
.
в дополнение к предыдущему ответу о опечатках в константе Cv (как в DCT (), так и в функциях idct ()) вы использовали обратная формула DCT (2nd) неправильно. Вы должны были умножать на Cv и Cu каждый раз в цикле. Итак, правильный код idct () должен быть:
void idct(float dctMatrix[8][8]){
double idct,
Cu,
sum,
Cv;
int i,
j,
u,
v;
float idctMatrix[8][8],
greyLevel;
FILE * fp = fopen("mydata.csv", "a");
fprintf(fp, "\n Inverse DCT");
for (i = 0; i < 8; ++i) {
for (j = 0; j < 8; ++j) {
sum = 0.0;
for (u = 0; u < 8; u++) {
for (v = 0; v < 8; v++) {
if (u == 0) {
Cu = 1.0 / sqrt(2.0);
} else {
Cu = 1.0;
}
if (v == 0) {
Cv = 1.0 / sqrt(2.0);
} else {
Cv = (1.0); //mistake was here - the same is in dct()
}
greyLevel = dctMatrix[u][v];
// Multiply by Cv and Cu here!
idct = (greyLevel * Cu * Cv *
cos((2 * i + 1) * u * PI / 16.0) *
cos((2 * j + 1) * v * PI / 16.0));
sum += idct;
}
}
// not "* Cv * Cu" here!
idctMatrix[i][j] = 0.25 * sum;
fprintf(fp, "\n %f", idctMatrix[i][j]);
}
fprintf(fp, "\n");
}
}
в этом случае выходные значения близко к 255, 0, 255, 0, и т. д.