Image Processing on FPGA

GitHub Repo View the code on GitHub


This design shows how we can read an image from BRAM, apply visual effects in real time, and drive a display over HDMI using an FPGA.
For this project, I chose to use a photo of myself (from when I was young and beautiful, hahaha), because there’s something special about seeing your own face transformed by hardware you programmed. After converting the image into a .mif file (my_picture_RGB8.mif) and loading it into the FPGA’s Block RAM, I built a series of VHDL modules to apply various visual effects.
It would’ve been easy to use a phone app for similar edits, but creating these effects in VHDL and watching them run on real hardware is a completely different experience. I did really LOVE it. =)))

Watch my video on youtube (click on the picture below):

Video

Note!
The demonstration images in this README were captured from the simulator using the full RGB24 color format. Because the Cyclone V GX FPGA has limited Block RAM (BRAM) capacity, I configured the hardware implementation to use a compressed 8-bit (RGB332) format for image storage within the ROM. Although the system expands this 8-bit data back to 24-bit (RGB888) before displaying it on the HDMI monitor, the simulation images maintain higher visual quality because they were processed without any initial color reduction. As a result, while the system functions perfectly in real-time, the colors on the physical monitor may appear slightly less vibrant than those seen in the high-fidelity simulation results.


Project Overview

This project is a hardware image-processing pipeline built in VHDL. It stores a static image in BRAM, reads pixels in sync with display timing, converts the stored compact color format into a full-color representation, and applies one of many visual effects before sending the result to a monitor.
The image is first converted by Python into a small 8-bit RGB332 format and stored as a .mif file. In the FPGA, each pixel is read in real time and expanded into a 24-bit RGB888 color value so the effect modules can process it with greater precision.
The system can display the original image, mirrored image, pixelized image, or many color and stylized filter effects. It also supports simulation for verification before deploying to the hardware.

Block Diagram


Effect Module Details

In this digital image processing system, each visual effect is implemented using specific mathematical logic or bit manipulation. The system processes 24-bit RGB data (8 bits each for Red, Green, and Blue) to generate the output for each module.
Below are the formulas and logic used for each effect:


Intensity and Contrast Effects

Channel_out = Channel_in + g-BRIGHT
Channel_out = Channel_in - g-DARK
Channel_out = 128 + (Channel_in - 128) * g-CONTRAST 
Channel_out = (Channel_in  AND  11100000)   

Intensity and Contrast Effects


Black-white and Grayscale Effects

Gray = (Red + Green + Blue) / 3
Output of all channels = ( Gray )
If  (R+G+B) > g-THRESHOLD  then 
    Output <= White 
else 
    Output <= Black

Black-white and Grayscale Effects


Posterize and Tint Effects

Posterize and Tint Effects


Stylistic and Color Conversion Effects

If  (R+G+B) > g-THRESHOLD  then 
    Output <= (255-R, 255-G, 255-B) 
else 
    Output <= original
Channel_out =  NOT Channel_in  

Stylistic and Color Conversion Effects


Coordinate and Dynamic Effects

if (X(4) XOR  Y(4)) = '1' then
    Output = Image
else 
    Black
If Y(0) = '1' then 
    Channel_out = Channel_in / 2
else
    Channel_out = Channel_in
Red-Noise = LFSR / 4 
Green-Noise = LFSR / 2
Blue-Noise = LFSR
Channel_out = Channel_in + Noise

Coordinate and Dynamic Effects-1
Coordinate and Dynamic Effects-2


Address Manipulation and Expansion Effects

Address = (639 - X) + (Y \times 640)
Address = ( Y(MSB downto 2) & "00" )  *  c-IMG-WIDTH + ( Y(MSB  downto  2)$ & "00" ) 

Expansion Effects


Setup Guide

1) Prepare the Image

2) Compile the code and configure the FPGA

3) Select Effects