Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

JPEG Compression from Scratch πŸ–ΌοΈ

A complete implementation of the JPEG compression pipeline β€” encoding and decoding β€” built from scratch using NumPy and OpenCV.


πŸ“Œ Overview

This project implements the full JPEG compression and decompression pipeline without relying on any JPEG library. It demonstrates the mathematical foundations behind one of the world's most widely used image formats, achieving compression ratios of up to 10.3:1 on standard test images.

Pipeline

Original Image (RGB)
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Color Space          β”‚  RGB β†’ YCbCr (separates luma from chroma)
β”‚ Conversion           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Block Splitting      β”‚  Divide into 8Γ—8 macroblocks
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ DCT (2D)            β”‚  Spatial β†’ Frequency domain
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Quantization         β”‚  Lossy step β€” discard high-freq info
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Zig-Zag Scanning     β”‚  2D β†’ 1D, groups zeros together
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Run-Length Encoding  β”‚  Lossless compression of zero runs
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
    Compressed Bitstream

         β–Ό  (Decoding reverses all steps)

Reconstructed Image

By default it loads cameraman.bmp. To use a different image, edit the cv2.imread(...) call at the bottom of the script.


πŸ“ Algorithm Details

1. Color Space Conversion β€” BGR_to_YCbCr

Converts the BGR image (OpenCV default) to YCbCr, separating luminance (Y) from chrominance (Cb, Cr). The human visual system is less sensitive to color detail than brightness, so chroma channels can be compressed more aggressively.

Y  =  0.299Β·R + 0.587Β·G + 0.114Β·B
Cb = 128 βˆ’ 0.168736Β·R βˆ’ 0.331264Β·G + 0.5Β·B
Cr = 128 + 0.5Β·R βˆ’ 0.418688Β·G βˆ’ 0.081312Β·B

2. Macroblock Splitting β€” macroblock

Pads the image (if needed) to a multiple of 8, then slices each channel into non-overlapping 8Γ—8 blocks. Each block is processed independently.

3. 2D Discrete Cosine Transform β€” dct_2d

Applies the 1D DCT row-wise then column-wise. The DCT concentrates most image energy into a small number of low-frequency coefficients, making subsequent quantization effective.

Before DCT, each block is level-shifted by βˆ’128 (centering the range from [0, 255] to [βˆ’128, 127]).

4. Quantization

Each DCT coefficient is divided by a corresponding entry in the standard JPEG quantization table and rounded to the nearest integer. Higher-frequency entries in the table are larger, aggressively discarding perceptually unimportant data.

Table Used for
quantization_Y Luminance (Y channel)
quantization_C Chrominance (Cb, Cr channels)

5. Zig-Zag Scanning β€” zig_zag_scanning

Reorders the 8Γ—8 quantized block into a 1D array following a zig-zag path. This groups the typically-nonzero low-frequency coefficients at the start and the many zeros at the end β€” ideal for RLE.

6. Run-Length Encoding β€” run_length_encoding

Encodes runs of zeros between non-zero AC coefficients as (RUNLENGTH, SIZE, AMPLITUDE) triplets, where:

  • RUNLENGTH = number of preceding zeros
  • SIZE = bit-width of the amplitude
  • AMPLITUDE = the coefficient value

7. Compression Ratio

Compression Ratio = bits_original / bits_compressed

The original image requires H Γ— W Γ— 3 Γ— 8 bits. The compressed representation uses the total bits across RLE triplets for Y, Cb, and Cr.

8. Decoding (Decompression)

The decoding pipeline reverses every step:

Inverse Zig-Zag β†’ Dequantization β†’ Inverse DCT β†’ Level Shift (+128) β†’ Merge Blocks β†’ YCbCr β†’ BGR


πŸ“Š Results

Test images used: corn.bmp, pepper.bmp, cameraman.bmp

Image Original Size Compression Ratio
corn.bmp β€” 5.1 : 1
pepper.bmp β€” 8.1 : 1
cameraman.bmp β€” 10.3 : 1

The reconstructed image is visually close to the original with the standard quantization tables, consistent with real-world JPEG behavior (typically 10:1 with minimal perceptible loss).


πŸ”‘ Key Functions Reference

Function Description
BGR_to_YCbCr(img) Color space conversion
macroblock(img, channel) Split channel into 8Γ—8 blocks
dct_1d(x) 1D Discrete Cosine Transform
dct_2d(img) 2D DCT via separable 1D DCT
zig_zag_scanning(x) 2D block β†’ 1D zig-zag ordered array
run_length_encoding(x) RLE on zig-zag scanned coefficients
compression(image) Full encoding pipeline
inverse_zig_zag_scanning(x, n) Reverse zig-zag
inverse_dct_1d(x) Inverse 1D DCT
inverse_dct_2d(img) Inverse 2D DCT
decompression(e_Y, e_Cb, e_Cr, ...) Full decoding pipeline
YCbCr_to_BGR(ycbcr) Inverse color space conversion
max_bits(x) Estimate bits needed for RLE output

πŸ“š References


πŸ“„ License

This project is for academic purposes. Feel free to use, study, and extend it.

About

JPEG Compression from Scratch πŸ–ΌοΈ A complete implementation of the JPEG compression pipeline β€” encoding and decoding β€” built from scratch using NumPy and OpenCV

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages