# Spatial Image Enhancer Pro

Production-grade public SPA for spatial-domain image enhancement using Django REST Framework, OpenCV, NumPy, React, Tailwind CSS, Celery, Redis, PostgreSQL, Docker Compose, and Caddy.

![screenshot](./screenshot.png)

## Local Development

Backend:

```bash
cd backend
python -m venv .venv
.venv\Scripts\activate
copy .env.sample .env
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
```

Frontend:

```bash
cd frontend
copy .env.sample .env
npm install
npm run dev
```

Open `http://localhost:5173`. The frontend `.env` uses `VITE_API_BASE=http://localhost:8000`, and the backend `.env` allows that origin via CORS/CSRF settings.

## Docker

```bash
copy .env.example .env
copy backend\.env.sample backend\.env
docker compose up --build
```

Caddy serves the SPA and proxies `/api/*` and `/media/*`. Set `CADDY_DOMAIN`, `DJANGO_ALLOWED_HOSTS`, `DJANGO_CSRF_TRUSTED_ORIGINS`, `CORS_ALLOWED_ORIGINS`, and a strong `DJANGO_SECRET_KEY` before production deployment.

For production, use `.env.sample` as the root Compose template and `backend/.env.production.sample` as the backend-only template.

## Backend Structure

The Django app follows the HackSoftware Django Styleguide pattern:

- API views validate request input and return responses.
- `processing/services.py` contains business workflows and writes.
- `processing/selectors.py` contains database fetch helpers.
- Settings are environment-driven through `backend/.env`.

## Algorithms

The app is organized as a small MATLAB-like image workspace. Each operation creates a new image state, so you can compare results, keep useful steps, and delete unwanted states.

### Basic Workspace

- **Histogram view** shows how pixel values are distributed. For gray images it uses one intensity histogram; for RGB images it also shows R, G, and B channels. Formula: `p(r_k) = n_k / n`.
- **Histogram equalization** improves contrast by spreading gray levels using the cumulative histogram. Formula: `s_k = round(255 * CDF(r_k))`.
- **Add images** combines registered images by summing pixels and clipping to display range. Formula: `g = f1 + f2`.
- **Subtract images** highlights differences between registered images. Formula: `g = normalize(|f1 - f2|)`.
- **Dot product** multiplies registered image pixels element by element. Formula: `g = normalize(f1 * f2)`.
- **Average K images** reduces independent noise by averaging registered states. Formula: `g = (1/K) * sum(f_i)`.

### Chapter 3: Spatial Domain

- **Negative** inverts intensities. Formula: `s = 255 - r`.
- **Log transform** expands darker values more than brighter values. Formula: `s = c log(1 + r)`.
- **Power-law / gamma** changes brightness and contrast with an exponent. Formula: `s = c r^gamma`.
- **Gray-level dynamic range** stretches a selected intensity range to the full display range. Formula: `[low, high] -> [0, 255]`.
- **Gray-level slicing** highlights pixels inside a chosen range. Formula: highlight where `A <= r <= B`.
- **Bit-plane slicing** displays one binary bit of each gray value. Formula: `bit_k(r)`.
- **Noise filter** adds test noise. Gaussian noise uses `g = f + n`; salt-and-pepper noise randomly sets pixels to `0` or `255`.
- **Average N noisy copies** generates `N` independent Gaussian-noisy copies of the current image and averages them into one result. Formula: `result = (1/N) * sum_i(f + n_i)`.
- **Periodic noise** adds a repeating sinusoidal row and column pattern. Formula: `g(x,y) = f(x,y) + A sin(2*pi*y/T) + A sin(2*pi*x/T)`.
- **Average / box filter** smooths an image with a uniform mask. Formula: `g = imfilter(f, ones(K,K) / K^2)`.
- **Weighted average filter** smooths with the slide mask `1/16 * [[1,2,1],[2,4,2],[1,2,1]]`.
- **Gaussian filter** smooths using a Gaussian mask controlled by size `K` and variance `Q`. Formula: `G(x,y) = exp(-(x^2+y^2)/(2Q))`.
- **Median filter** replaces each pixel with the neighborhood median, useful for salt-and-pepper noise. Formula: `g(x,y) = median(S_xy)`.
- **Max filter** replaces each pixel with the local maximum. Formula: `g(x,y) = max(S_xy)`.
- **Min filter** replaces each pixel with the local minimum. Formula: `g(x,y) = min(S_xy)`.
- **Laplacian sharpening masks** use the taught cross or diagonal sharpening masks to emphasize fine detail. Formula: `g = imfilter(f, selected mask)`.
- **Gradient operators** use Sobel or Roberts mask pairs for edges. Formula: `g = |imfilter(f,Gx)| + |imfilter(f,Gy)|`.
- **High-boost / edge emphasis** sharpens by subtracting a blurred image from an amplified original. Formula: `f_hb = A f - blurred(f)`, where `A >= 1`.

### Chapter 4: Frequency Domain

- **FFT/DFT spectrum view** shows the log magnitude of the image in the frequency domain. Formula: `log(1 + |fftshift(fft2(f))|)`. Apply it to a periodic-noisy state to see the noise peaks.
- **Inverse FFT reconstruction** reconstructs from a previously saved FFT state. Formula: `f = real(ifft2(ifftshift(F)))`.

### Chapter 6: RGB Color Processing

- **Convert to grayscale** uses configurable RGB weights, matching MATLAB-style luminance by default. Formula: `gray = 0.299R + 0.587G + 0.114B`.
- **RGB channel view** displays one color channel as grayscale. Formula: show `R`, `G`, or `B`.

## API

- `POST /api/images/`
- `POST /api/process/`
- `POST /api/batch/`
- `GET /api/jobs/{job_id}/`

Images are stored as ephemeral sessions and removed by the cleanup task after the configured TTL.
