Программа 2d DCT не работает

Я должен сделать это 2d DCT изображения для моего проекта. Я перевел формулу прямо в код. Логически все выглядит хорошо, но не дает нужного результата. Я сопоставил это с функцией Matlab, чтобы проверить результаты для матрицы 3x3, но они неверны.

Кроме того, то, что и как я закодировал, дает огромное количество циклов, так что фактическая операция с изображением выполняется часами.

Любое предложение по уменьшению количества циклов и указаний на программную ошибку было бы замечательным. Спасибо.

Это мой код.

    double alpha_p, alpha_q;
    double pi = Math.atan(1.0) * 4.0;
    //dct begins
    System.out.println("it begins");
    for (int p = 0; p < M; p++) {
        for (int q = 0; q < N; q++) {
            if (p == 0)
                alpha_p = 1 / sqrt(M);
            else
                alpha_p = sqrt(2 / M);
            if (q == 0)
                alpha_q = 1 / sqrt(N);
            else
                alpha_q = sqrt(2 / N);
            double toreturn = 0;
            for (int m = 0; m < M; m++) {
                for (int n = 0; n < N; n++) {
                    toreturn = toreturn + img[m][n]
                            * cos(((2 * m + 1) * p * pi) / 2 * M)
                            * cos(((2 * n + 1) * q * pi) / 2 * N);
                }
            }
            dctimg[p][q] = alpha_p * alpha_q * toreturn;
            System.out.println("euta");
        }
    }
    // dct over
    System.out.println("its over");

    //inverse dct begins
    for (int m = 0; m < M; m++) {
        for (int n = 0; n < N; n++) {
            double toreturn = 0;
            for (int p = 0; p < M; p++) {
                for (int q = 0; q < N; q++) {
                    if (p == 0)
                        alpha_p = 1 / sqrt(M);
                    else
                        alpha_p = sqrt(2 / M);
                    if (q == 0)
                        alpha_q = 1 / sqrt(N);
                    else
                        alpha_q = sqrt(2 / N);
                    toreturn = toreturn + alpha_p * alpha_q * dctimg[p][q]
                                          * cos(((2 * m + 1) * p * pi) / 2 * M)
                                          * cos(((2 * n + 1) * q * pi) / 2 * N);
                }
            }
            finalimg[m][n] = toreturn;
        }
    }
    //inverse dct over

person user8311562    schedule 15.07.2017    source источник
comment
double pi=Math.atan(1.0) * 4.0 .. или вы могли бы использовать Math.PI   -  person harold    schedule 15.07.2017
comment
Спасибо, что поделились знаниями. Math.PI Хммм.   -  person user8311562    schedule 15.07.2017
comment
см. вычисление DFCT с использованием DFFT и Как вычислить ДПФ/ДПФФ. Убедитесь, что вы используете совместимые DCT... Если мне не изменяет память, их 4...   -  person Spektre    schedule 16.07.2017


Ответы (1)


Прежде всего, в формуле DCT знаменатель cos равен 2 * M. Это типичная ошибка. 4 / 2 * 2 = 4 не 1

cos(((2 * m + 1) * p * pi) / 2 * M) должно быть cos(((2 * m + 1) * p * pi) / (2 * M))

Скобки необходимы во всех четырех случаях.


Еще один момент, который я хочу отметить, это sqrt(2 / M). Если M имеет целочисленный тип (по вашему коду это непонятно) и больше 2, то выражение 2 / M равно 0. Потому что оба операнда имеют целые типы, а / дает только целую часть. Чтобы исправить это, добавьте плавающую точку, например sqrt(2.0 / M).


Как вы уже заметили, циклов очень много, другими словами, сложность 2D DCT II составляет O(n^4).

В реальной жизни никто не применяет DCT ко всему реальному изображению. Изображение разбивается на блоки размером 8x8 и каждый блок обрабатывается DCT. Такой подход позволяет сохранить n на низком уровне, а сложность становится приемлемой.

Чтобы уменьшить алгоритмическую сложность, я хочу дать ссылку здесь, где методы использования 1D DCT и БПФ хорошо объяснены.

person Enegue    schedule 15.07.2017
comment
Спасибо, сэр Enege, за ваш хорошо объясненный ответ. Я понял ошибки. Я также попытаюсь уменьшить сложность, применяя к блокам 8x8. Хорошо то, что теперь я получаю исходные значения пикселей после последовательных DCT и IDCT. Но коэффициенты DCT не соответствуют результатам теста Matlab. Я попробовал матрицу 3x3 для этого теста. Придется с этим разобраться. Знаете ли вы, какой размер блока использует Matlab в качестве стандарта? - person user8311562; 15.07.2017
comment
@user8311562, я применил с нуля DST2, описанный здесь и проверил его на том же вводе с помощью MathLab online J = dct2([11 12 13; 14 15 16; 17 18 19]);. Результат тот же, возможно, мы пропускаем другую ошибку. Я не уверен, но я думаю, что функция dst2 не использует блоки, это чистое преобразование. Другой вопрос, почему так быстро? Ответ заключается в том, что MathLab сильно оптимизирован для матричных операций, и добиться такой производительности довольно сложно. - person Enegue; 16.07.2017
comment
Спасибо Энеге. Все улажено. - person user8311562; 16.07.2017