Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DrawingWithFFT

tests license: MIT

Redraw a picture as a set of smooth closed curves, by tracing the outlines of everything in the image and rebuilding each outline from a truncated Fourier series. Turning the number of retained modes down gives a loose, gestural sketch; turning it up converges back on the original outline.

Available as the original MATLAB script and as a Python port.

Four panels: the input image, then the same shapes redrawn at decreasing Fourier accuracy

As the accuracy drops the sharp corners round off, the specks fall below the size filter, and each outline converges on the handful of epicycles that best describe it.

How it works

  1. Binarize — grayscale, adaptive histogram equalization, then Otsu's threshold to a black-and-white mask.
  2. Trace — pull out every connected object's boundary, holes included. Outlines with fewer than SmallestObj points are discarded as noise.
  3. Parameterize — each boundary comes back already walked in order, so it only needs the repeated closing point dropped and its direction normalized via the signed area (objects and holes are traced opposite ways round). The ordered points are packed into a complex signal z = x + iy. This is the key step: a 2-D closed curve becomes a 1-D complex periodic signal, so each Fourier coefficient is one rotating epicycle.
  4. Truncate — take the FFT, shift so DC sits mid-array, and zero everything outside a symmetric window around the DC bin.
  5. Reconstruct — invert the transform and plot real against -imag.

Knobs

Setting Meaning
FileIn / image Path to the input image
SmallestObj / --min-points Minimum outline length; smaller ones are dropped
AcuFrac / --accuracy Fraction of maximum accuracy — 1 keeps every mode, lower values give a looser drawing

MATLAB

Needs the Image Processing Toolbox (adapthisteq, graythresh, im2bw, bwboundaries). Run DrawingPlay.m; it draws sample.png out of the box. Point FileIn at any other image to draw that instead.

Python

pip install -r python/requirements.txt
python python/drawing_with_fft.py sample.png --accuracy 0.3 -o out.png
from drawing_with_fft import trace_image, plot_curves
plot_curves(trace_image("sample.png", accuracy=0.3))

scikit-image's find_contours returns contours already walked in order, so the ordering step is the same two lines as the MATLAB version.

Watch the indexing when reading the two side by side. MATLAB is 1-based and puts DC at floor(N/2)+1; numpy is 0-based and puts it at N//2. That is what dc_index exists for, and the tests guard it. Getting it wrong is subtle: the error is invisible at full accuracy and only blows up as the accuracy knob comes down, at which point objects lose their centroid and collapse to the origin.

Fidelity between the two

Both implementations on sample.png, default settings:

Result
Binary masks 99.993% pixel agreement (13 of 193,600 differ)
Outlines over threshold 14 in both
Centroid error, accuracy 1 → 0.005 0 in both

Python's contours carry more points for the same outline, since marching squares emits a subpixel vertex per edge crossing where MATLAB's bwboundaries walks pixel centres. The drawn result is the same.

The binarization is the step most sensitive to implementation differences — skimage.exposure.equalize_adapthist and MATLAB's adapthisteq use the same tiling and clip limit but differ internally. Tune with --clip-limit if a particular image diverges.

The sample image

sample.png is generated, not photographed — run python python/make_sample.py to rebuild it. Generating it keeps the repository free of any third-party image rights, and makes the demo reproducible.

It is deliberately line art. Adaptive histogram equalization tiles the image and stretches each tile's tonal range, so a tile sitting entirely inside a solid fill contains almost no range, and equalizing it amplifies quantization noise until the threshold lands on nonsense. Thin strokes keep both ink and paper in every tile. Line art is also the honest use case, since the pipeline traces outlines.

Tests

python python/test_drawing_with_fft.py

numpy only — no imaging stack needed. The DC-index and centroid tests were both checked against a deliberately reintroduced version of the original bug, to confirm they actually fail when it comes back.

License

MIT — see LICENSE.

About

Draw images with truncated Fourier series. MATLAB and Python.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages