# image_cleanup

A RocketRide image filter node that pre-processes images for OCR, significantly improving recognition accuracy on scanned or low-quality input.

## What it does

Sits between an image source and a downstream OCR node and rewrites every image that flows through the `image` lane. The incoming bytes are buffered until the full image is received, then transformed through four sequential stages before being forwarded:

1. **PNG normalization**: if the input is not already `image/png`, it is converted via **Pillow** (RGBA mode). PNG inputs pass through this stage untouched.
2. **Grayscale and contrast enhancement**: decodes the PNG with **OpenCV**, converts to grayscale, applies a 5x5 Gaussian blur to suppress noise, then applies CLAHE (clip limit 2.0, 8x8 tile grid) to lift local contrast without blowing out the grayscale range.
3. **Deskew**: inverts the grayscale image to make text white on black, locates all non-zero pixels, fits a minimum-area bounding rectangle to compute the text angle, then rotates the image back to horizontal using cubic interpolation with replicated borders.
4. **Morphological cleanup**: applies morphological closing with a 2x2 square kernel to fill small holes inside character shapes (such as the interior of an `o`) and remove speckle noise.

The output is always `image/png` regardless of the input format. There are no configuration fields and no agent-callable tools; the cleanup pipeline runs automatically on every image.

---

## Configuration

### Lanes

| Lane in | Lane out | Description                                         |
|---------|----------|-----------------------------------------------------|
| `image` | `image`  | Receives the raw image, emits the cleaned PNG       |

Images are streamed in chunks using `AVI_ACTION` signals (`BEGIN` / `WRITE` / `END`). The node buffers all `WRITE` chunks, processes the complete image on `END`, then re-emits it as a new `BEGIN` / `WRITE` / `END` sequence. The default pass-through is suppressed so only the cleaned image continues down the pipeline.

No configuration fields. Drop the node into the pipeline between an image source and an OCR node and it works as-is with no further setup. The node registers a single empty `default` profile.

---

<!-- ROCKETRIDE:GENERATED:PARAMS START -->
<!-- Generated by nodes:docs-generate. Do not edit by hand. -->

## Schema

_No configuration fields._

## Dependencies

- `pillow`

## Source

[<svg viewBox="0 0 16 16" width="15" height="15" fill="currentColor" aria-hidden="true" style="vertical-align:-0.15em;margin-right:0.35em"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg> View source](https://github.com/rocketride-org/rocketride-server/tree/develop/nodes/src/nodes/image_cleanup)
<!-- ROCKETRIDE:GENERATED:PARAMS END -->
