Я пытаюсь JPEG сжать изображение в оттенках серого в Python с помощью Numpy. Я пробовал два разных метода квантования: применение маски и деление на предопределенные веса, но в обоих случаях значения сжатого изображения слишком высоки. 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()
Я глубоко подозрительно отношусь к «I = I - 128». Что такое dtype 'I'? 'plt.imread' обычно возвращает массив uint16, который выглядит в соответствии с отображением, которое вы указали в своем вопросе. Поскольку это тип без знака, любые значения, меньшие 128, будут переполняться. Попробуйте сначала направить его на тип с плавающей точкой, например. 'I = np.matrix (mpimg.imread ('uggla2.tif'), dtype = np.float64)'. –
Будучи в стороне, я [настоятельно рекомендую] (https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html#array-or-matrix-which-should- i-use) вы должны использовать 'np.ndarray', а не' np.matrix' –