Skip to content

Commit cd4ab1b

Browse files
committed
Add JPEG and Simple WebP compression algorithms
1 parent 7a8f92b commit cd4ab1b

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from algorithm import Algorithm
2+
import numpy as np
3+
import cv2
4+
import matplotlib.pyplot as plt
5+
6+
class JPEGCompression(Algorithm):
7+
Q_BASE = np.array([
8+
[16, 11, 10, 16, 24, 40, 51, 61],
9+
[12, 12, 14, 19, 26, 58, 60, 55],
10+
[14, 13, 16, 24, 40, 57, 69, 56],
11+
[14, 17, 22, 29, 51, 87, 80, 62],
12+
[18, 22, 37, 56, 68, 109, 103, 77],
13+
[24, 35, 55, 64, 81, 104, 113, 92],
14+
[49, 64, 78, 87, 103, 121, 120, 101],
15+
[72, 92, 95, 98, 112, 100, 103, 99]
16+
], dtype=np.float32)
17+
18+
@staticmethod
19+
def get_params() -> dict:
20+
return {"quality": 85, "compression_level": 1.0}
21+
22+
@staticmethod
23+
def process_block(block, quantization_table):
24+
block = block.astype(np.float32) - 128 # Konwersja na float32 przed DCT
25+
dct_block = cv2.dct(block)
26+
quantized = np.round(dct_block / quantization_table)
27+
dequantized = quantized * quantization_table
28+
reconstructed = cv2.idct(dequantized) + 128
29+
return np.clip(reconstructed, 0, 255).astype(np.uint8) # Konwersja z powrotem do uint8
30+
31+
32+
@staticmethod
33+
def compress(image: np.ndarray, params: dict) -> np.ndarray:
34+
compression_level = params.get("compression_level", 1.0)
35+
36+
if len(image.shape) == 2:
37+
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
38+
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
39+
Q_Y = np.clip(JPEGCompression.Q_BASE * compression_level, 1, 255)
40+
Q_C = np.clip(JPEGCompression.Q_BASE * 1.2 * compression_level, 1, 255)
41+
42+
image_ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
43+
h, w, _ = image_ycrcb.shape
44+
compressed_image = np.zeros_like(image_ycrcb, dtype=np.uint8)
45+
46+
for channel in range(3):
47+
channel_data = image_ycrcb[:, :, channel]
48+
49+
h_pad = (8 - (h % 8)) % 8
50+
w_pad = (8 - (w % 8)) % 8
51+
channel_padded = np.pad(channel_data, ((0, h_pad), (0, w_pad)), mode='constant', constant_values=128)
52+
53+
h_new, w_new = channel_padded.shape
54+
compressed_channel = np.zeros((h_new, w_new), dtype=np.float32)
55+
56+
Q = Q_Y if channel == 0 else Q_C
57+
58+
for i in range(0, h_new, 8):
59+
for j in range(0, w_new, 8):
60+
block = channel_padded[i:i+8, j:j+8]
61+
processed_block = JPEGCompression.process_block(block, Q)
62+
compressed_channel[i:i+8, j:j+8] = processed_block
63+
64+
compressed_image[:h, :w, channel] = np.clip(compressed_channel[:h, :w], 0, 255).astype(np.uint8)
65+
66+
compressed_rgb = cv2.cvtColor(compressed_image, cv2.COLOR_YCrCb2RGB)
67+
return compressed_rgb
68+
69+
@staticmethod
70+
def decompress(image: np.ndarray, params: dict) -> np.ndarray:
71+
return image

src/compression/webp_compression.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from algorithm import Algorithm
2+
import numpy as np
3+
import zlib
4+
5+
class SimpleWebPCompression(Algorithm):
6+
"""
7+
Simple WebP-like compression algorithm.
8+
"""
9+
10+
@staticmethod
11+
def get_params() -> dict:
12+
return {"quality": "16"}
13+
14+
@staticmethod
15+
def compress(data: np.ndarray, params: dict[str, str]) -> np.ndarray:
16+
quality = int(params.get("quality", 16))
17+
quantized_array = (data // (256 // quality)) * (256 // quality)
18+
compressed_data = zlib.compress(quantized_array.tobytes(), level=9)
19+
return np.frombuffer(compressed_data, dtype=np.uint8)
20+
21+
@staticmethod
22+
def decompress(data: np.ndarray, params: dict[str, str], image_size: tuple) -> np.ndarray:
23+
quality = int(params.get("quality", 16))
24+
decompressed_data = zlib.decompress(data)
25+
img_array = np.frombuffer(decompressed_data, dtype=np.uint8).reshape(image_size)
26+
return (img_array // (256 // quality)) * (256 // quality)

0 commit comments

Comments
 (0)