2015-12-17 3 views
0

Я пытаюсь JPEG сжать изображение в оттенках серого в Python с помощью Numpy. Я пробовал два разных метода квантования: применение маски и деление на предопределенные веса, но в обоих случаях значения сжатого изображения слишком высоки. This is how it looks with a mask quantisation. Looks similar with weights.JPEG сжатие в Python становится отрицательным

Распечатка в питона IDE исходного изображения и обработанного изображения дает следующее:

Uncompressed: 
[[23 25 26 ..., 17 18 19] 
[23 25 26 ..., 16 17 18] 
[24 25 27 ..., 15 16 16] 
..., 
[68 52 45 ..., 20 18 17] 
[66 27 14 ..., 18 17 15] 
[68 29 14 ..., 17 15 14]] 

Compressed: 
[[ 278.70719913 280.56095939 281.89426619 ..., 273.41847541 
    274.41642174 275.11264205] 
[ 279.49137088 281.20996776 282.42671682 ..., 272.37174176 
    273.05506856 273.59872544] 
[ 280.26810477 281.7369523 282.73833074 ..., 271.18033959 
    271.45606872 271.81185441] 
..., 
[ 346.60801656 332.97428913 311.95287258 ..., 275.36547554 
    273.90408787 273.14715488] 
[ 326.40626296 308.74082394 285.71491905 ..., 274.10082953 
    272.12056066 271.00663571] 
[ 303.05777135 281.42687625 254.22921445 ..., 273.12188339 
    270.79982443 269.46372928]] 

Очевидно, что это приводит к областям изображения, которое должно быть темно становится ярким и наоборот. Я подозреваю, что ошибка заключается в вычислении матрицы преобразования DCT.

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.image as mpimg 
import matplotlib.cm as cm 

def dct_basis(): 
    """ Calculates matrix with dtc basis vectors. """ 
    rows = np.arange(1,16,2) 
    cols = np.arange(8) 
    rows.shape = (1,8) 
    cols.shape = (8,1) 
    coeffs = np.dot(cols,rows) # param in cos() in dct matrix, without pi/16 
    coeffs = coeffs.T 
    radians = (np.pi/16) * coeffs # now make the numbers radians 
    dct = np.cos(radians) 
    dct = np.sqrt(2./8)*dct 
    col0 = np.ones(8)*(1/np.sqrt(8)) 
    col0.shape = (8,1) 
    dct[:,0:1] = col0 # first column filled by sqrt(2/width) 
    dct = np.matrix(dct) 
    return dct 

def get_weights(): # commmented out is for quantising w/ weights 
## with open('weights.txt','r') as f: 
##  W = f.read() 
## W = weights.split() 
## W = map(float,weights) 
## W = np.asarray(weights) 
## W = np.reshape(weights, (8,8)) 
## W = np.matrix(weights) 
    a = np.triu([1,1,1,1,1]) # this is for quantising w/ mask 
    W = np.zeros((8,8)) 
    W[:5,3:] = a 
    W = np.fliplr(W) 
    return W  

def jpeg_encode(): 
    I = np.matrix(mpimg.imread('uggla2.tif')) 
    print "Pre: ",I 
    # More effective coding if values are centered around zero. 
    # This assumes a resolution of 256 colours. 
    I = I - 128 
    T = dct_basis() 
    W = get_weights() 
    blocksize = 8 
    size = I.shape 
    bx = size[0]/8 
    by = size[1]/8 
    C = np.matrix(np.zeros(size)) 
    for x in range(bx): 
     for y in range(by): 
      tmp = T.T * I[x*blocksize : x*blocksize + blocksize, 
          y*blocksize : y*blocksize + blocksize] * T 
      C[x*blocksize : x*blocksize + blocksize, 
       y*blocksize : y*blocksize + blocksize] = \ 
              np.around(np.multiply(tmp,W)) 
    return C 

def jpeg_decode(): 
    C = jpeg_encode() 
    T = dct_basis() 
    W = get_weights() 
    blocksize = 8 
    size = C.shape 
    bx = size[0]/8 
    by = size[1]/8 
    I = np.matrix(np.zeros(size)) 
    for x in range(bx): 
     for y in range(by): 
      tmp = C[x*blocksize : x*blocksize + blocksize, 
        y*blocksize : y*blocksize + blocksize] 
      #tmp = np.multiply(tmp,W) 
      I[x*blocksize : x*blocksize + blocksize, 
       y*blocksize : y*blocksize + blocksize] = \ 
              T * tmp * T.T 
    I = I + 128 
    print "Post: ",I 
    return I 

# Running the module from terminal 
if __name__ == '__main__': 
    fig = plt.figure() 
    a=fig.add_subplot(1,2,1) 
    img1 = mpimg.imread('uggla2.tif') 
    imgplot = plt.imshow(img1, cmap = cm.Greys_r) 
    a.set_title('Uncompressed') 
    img2 = jpeg_decode() 
    a=fig.add_subplot(1,2,2) 
    imgplot = plt.imshow(img2, cmap = cm.Greys_r) 
    a.set_title('Compressed') 
    plt.show() 
+0

Я глубоко подозрительно отношусь к «I = I - 128». Что такое dtype 'I'? 'plt.imread' обычно возвращает массив uint16, который выглядит в соответствии с отображением, которое вы указали в своем вопросе. Поскольку это тип без знака, любые значения, меньшие 128, будут переполняться. Попробуйте сначала направить его на тип с плавающей точкой, например. 'I = np.matrix (mpimg.imread ('uggla2.tif'), dtype = np.float64)'. –

+0

Будучи в стороне, я [настоятельно рекомендую] (https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html#array-or-matrix-which-should- i-use) вы должны использовать 'np.ndarray', а не' np.matrix' –

ответ

0

Большое спасибо Ali M. Тип данных uint16 был ошибкой! Так оно выглядит с использованием маски и веса соответственно для квантования: enter image description here

Смежные вопросы