Pointillize — a Photo-to-Dots Filter
A short Python 3 + OpenCV script that turns a photo into a pointillism-style image — a scatter of non-overlapping coloured dots, each sampled from the source.
Source photo and the pointillized output (radius 6).
How It Works
The output starts as a white canvas and gains one dot at a time:
- Pick a random pixel
(row, col)in the source. - Sample its colour.
- Try to stamp a filled circle of the chosen radius there.
- Keep it only if it does not touch any dot already placed.
- Repeat for a set number of attempts.
The collision test is the neat part: instead of comparing pixel lists, the candidate circle's mask is XOR‑ed against a running mask of every dot placed so far, using the candidate itself as the operation mask. If the result still equals the candidate mask, nothing overlapped and the dot is accepted.
Because circles can never overlap, the canvas saturates and later attempts are mostly rejected — the dot density plateaus on its own, which is what gives the hand‑stippled look rather than a solid mosaic.
Usage
python3 pointillize.py --image ./images/01.jpg --radius 10 --cycles 20 --debug True
| Flag | Meaning |
|---|---|
--image | path to the source image |
--radius | dot radius, pixels |
--cycles | number of placement attempts (not dots placed) |
--debug | True / False |
Needs Python 3, opencv-python and numpy; the result is written to resultado.png.
Another Example
A portrait at a small radius — the effect becomes a fine grain.
Notes
- With a small radius you need tens of thousands of attempts to cover a photo, since
--cyclescounts tries, not hits. - An earlier per‑pixel collision function is still in the file but unused — the mask‑XOR approach replaced it.