A bitmap or BMP is composed of a series of two-dimensional arrays that contain the values corresponding to the amount (a number between 0 and 255) of red (R), green (G) y blue (B) color that make up each pixel of an image.
The idea is as follows: if we have a bitmap of n pixels in width and m in height, through a discrete transform we can decompose the image as the sum of nxm frequencies. If we can reduce the number of frequencies using some criterion, we will obtain an image that approximates the original but is described with less information.
In broad terms, the JPG format uses the Discrete Cosine Transform (DCT) to decompose the image into frequencies.
Implementation: a simplified version of JPG compression would be as follows: We read an image, convert it to grayscale, and obtain the contributing frequencies. Then, we eliminate frequencies and reconstruct the image.
Let's see how this would look in Python:
import matplotlib.pyplot as plt #paquete para graficar
import numpy as np #paquete de operaciones matemáticas
from scipy.fftpack import dct, idct #paquete para transformadas
# leemos la imagen
im = plt.imread('perro.tif')
#fórmula para convertir a escala de grises
R, G, B = im[:,:,0], im[:,:,1], im[:,:,2]
imGrises = 0.2989 * R + 0.5870 * G + 0.1140 * B
# transformada de coseno discreta
def dct2(a):
return dct(dct(a.T, norm='ortho').T, norm='ortho')
# antitransformada de coseno discreta
def idct2(a):
return idct(idct(a.T, norm='ortho').T, norm='ortho')
# frecuencias de la imagen
imF = dct2(imGrises)
# frecuencias no nulas
print(np.not_equal(imF,0).sum())
# eliminamos las frecuencias cuyo valor absoluto sean menor que 100
Q=100
imF[abs(imF)<Q]=0.0
# frecuencias no nulas luego
print(np.not_equal(imF,0).sum())
# reconstruimos la imagen con menos frecuencias
im2=idct2(imF)
# nos quedamos con "cuanto" de las frecuencias (1=100%)
cuanto = 0.5
cuantasFrecuencias = int(len(X)*cuanto)
cuantaEnergia = np.linalg.norm( X[ indices[range(0,cuantasFrecuencias)] ] )/np.linalg.norm(X)
# al resto de las frecuencias las ponemos en 0
X[ indices[range(cuantasFrecuencias+1, len(X))] ] =0
# reconstruimos el sonido con las nuevas frecuencias
xx= idct(X, norm="ortho")
# mostramos la imagen
plt.imshow(im2, cmap='gray')
plt.show()
Python code
Color image without compression (RGB).
Image with Q=0 and 100% of the frequency coefficients
Q=20, we keep 9% of the frequency coefficients
Q=60, we keep 2% of the frequency coefficients
Q=100, we keep 0.65% of the frequency coefficients
Q=200, we keep 0.25% of the frequency coefficients
Q=400, we keep 0.097% of the frequency coefficients
Q=1000, we keep 0.025% of the frequency coefficients