Проблема с реализацией 2D дискретного косинусного преобразования в Python

Я пытаюсь переписать метод стеганографии Чжао Коха из Matlab в Python, и я застрял в самом начале.

Первые две процедуры в матлабе:

Шаг 1:

A = imread(casepath); # Reading stegonography case image and aquiring it's RGB values. In my case it's a 400x400 PNG image, so it gives a 400x400x3 array.

Шаг 2:

D = dct2(A(:,:,3)); # Applying 2D DCT to blue values of the image

Аналог кода Python:

from scipy import misc
from numpy import empty,arange,exp,real,imag,pi
from numpy.fft import rfft,irfft

arr = misc.imread('casepath')# 400x480x3 array (Step 1)
arr[20, 30, 2] # Getting blue pixel value

def dct(y): #Basic DCT build from numpy
    N = len(y)
    y2 = empty(2*N,float)
    y2[:N] = y[:]
    y2[N:] = y[::-1]

    c = rfft(y2)
    phi = exp(-1j*pi*arange(N)/(2*N))
    return real(phi*c[:N])


def dct2(y): #2D DCT bulid from numpy and using prvious DCT function
    M = y.shape[0]
    N = y.shape[1]
    a = empty([M,N],float)
    b = empty([M,N],float)

    for i in range(M):
        a[i,:] = dct(y[i,:])
    for j in range(N):
        b[:,j] = dct(a[:,j])

    return b

 D = dct2(arr) # step 2 anlogue

Однако, когда я пытаюсь выполнить код, я получаю следующую ошибку:

Traceback (most recent call last):
File "path to .py file", line 31, in <module>
D = dct2(arr)
File "path to .py file", line 25, in dct2
a[i,:] = dct(y[i,:])
File "path to .py file", line 10, in dct
y2[:N] = y[:]
ValueError: could not broadcast input array from shape (400,3) into shape (400)

Может быть, кто-то может любезно объяснить мне, что я делаю неправильно?

Дополнительная информация: ОС: Windows 10 Pro 64 бит Python: 2.7.12 scipy:0.18.1 numpy:1.11.2 подушка: 3.4.1


person Caiphas Kain    schedule 18.10.2016    source источник
comment
Из numpy и scipy у вас есть прямой доступ к dct(). Вместо этого вы заинтересованы в том, чтобы использовать свой собственный, медленный подход?   -  person Reti43    schedule 18.10.2016
comment
Спасибо, не знала о нем, только что попробовала. Кажется, это работает просто отлично.   -  person Caiphas Kain    schedule 18.10.2016


Ответы (1)


Ваш код работает нормально, но он рассчитан только на двумерный массив, как dct2() в Матлабе. Поскольку ваш arr представляет собой трехмерный массив, вы хотите сделать

D = dct2(arr[...,2])

Как упоминалось в моем комментарии, вместо этого или заново изобретая колесо, используйте (быстрый) встроенный dct() из пакета scipy.

Код из ссылки в моем комментарии эффективно предоставляет вам это:

import numpy as np
from scipy.fftpack import dct, idct

def dct2(block):
    return dct(dct(block.T, norm='ortho').T, norm='ortho')

def idct2(block):
    return idct(idct(block.T, norm='ortho').T, norm='ortho')

Но опять же, я должен подчеркнуть, что вы должны вызывать эту функцию для каждой цветовой плоскости отдельно. dct() Scipy с радостью примет любой N-мерный массив и применит преобразование к последней оси. Поскольку это ваши цветовые плоскости, а не ваши строки и столбцы ваших пикселей, вы получите неправильный результат. Да, есть способ решить эту проблему с помощью входного параметра axis, но я не буду излишне усложнять этот ответ.


Что касается различных реализаций DCT, задействованных здесь, ваша версия и реализация scipy дают один и тот же результат, если вы опустите параметр norm='ortho' из приведенного выше фрагмента. Но с включенным этим параметром преобразование scipy будет соответствовать преобразованию Matlab.

person Reti43    schedule 18.10.2016