top of page

I dreamed of homeomorphic manifolds, then used them to analyze calligraphy

  • Writer: Bloggerary
    Bloggerary
  • 3 days ago
  • 8 min read

Last night I kept dreaming about homeomorphic manifolds. I have no idea why. Nobody in the dream was teaching me a theorem, yet I kept telling myself that I had to use homeomorphic manifolds to analyze calligraphy. When I woke up this morning, I actually started working through the idea.

The first intuition was simple. The same Chinese character can move from a Song typeface to a sans serif, from regular script to running script, or from one person's handwriting to another's. Its outline, thickness, angles and proportions may all change. But if the important connections do not break, the enclosing relationships do not change, and the loops and branches remain, it is still that character. This resembles what topology cares about. It does not ask for exact lengths. It asks whether a structure survives continuous deformation.

As soon as I woke up, though, I saw that topology alone would not be enough. It can answer, "Is this still the same character?" It cannot answer, "Who wrote it? Why did the brush turn that way? Why is the ink dry here, wet there, resistant in one stroke and scattered in another?" A second judgment followed quickly. I would need fractal geometry to deal with the stroke surface, and one fractal dimension would not be enough.

At that point the idea stopped being a collision between two impressive-sounding terms. It began to look like an algorithmic framework that I could code, fail with and disprove by counterexample.

Topology asks first: is this still the same character?

Strictly speaking, the skeleton of a Chinese character is usually not an ordinary manifold. The crossings and branches in characters such as 十, 木 and 米 do not have local neighborhoods that look like a normal line. A graph embedded in the plane, or a stratified space with singularities, is a better object.

Let the centerline skeleton of a character be K_H. Thicken it into a regular neighborhood in the plane, then extend that neighborhood along a third dimension:

K_H -> N_epsilon(K_H) -> M_epsilon(K_H) = N_epsilon(K_H) x [-h, h]

The strokes are no longer black pixels. They are tubes. Intersections and branches become connection structures, while enclosure and closed loops become computable topological relations. A change of style can be written as a family of continuous maps Phi_t. If no break, unwanted joining, new loop or lost loop appears along the way, the change remains a flow within the same topological type:

Phi_t: M_0 -> M_t, 0 <= t <= 1, T(M_t) = constant

This layer protects the identity of the character. It tracks connected components beta_0, independent loops beta_1, endpoints, branches, crossings, adjacency between components and nesting. That is also where its power ends. Two completely different characters can have the same beta_0 and beta_1. The same character can preserve its topology perfectly while one version resembles the model and another does not.

My four-layer model

I expanded the original "homeomorphic manifold plus fractal geometry" idea into four layers:

X(H, F) = (T, G, F_fractal, q)

T is the topological skeleton: which strokes connect, where they branch, where they form loops and which components enclose others.

G is geometric composition: length, angle, curvature, aspect ratio, center of mass, distance between components, density and spacing. Topology keeps the result recognizable as the same character. Geometry decides whether it resembles the particular model.

F_fractal is the finite-scale fractal ink layer: edge roughness, white gaps inside a stroke, ink density and the distribution of empty space across scales. It changes the surface of a stroke without moving its skeleton.

q is latent brush dynamics: position, pressure, speed, brush angle, wetness and pauses. It asks what kind of movement could have produced the static mark.

The final ink image is not emitted by any one layer. It is rendered from all four:

I(x, y) = R(T, G, F_fractal, q)

The boundaries between these layers must be explicit. Fractal texture cannot create new skeletal spurs just to look more like ink. The dynamic model cannot break a closed loop to look more like brush movement. Topology cannot treat every patch of dry-brush white as a structural error simply because topology matters.

Why fractal geometry cannot be reduced to one number

Real calligraphy is not a strict fractal at infinitely many mathematical scales. Paper fibers, scan resolution and pixel size impose a lower bound. The size of the character and the sheet impose an upper one. The more accurate description is statistical self-similarity over a finite range of scales.

A single global box-counting dimension can assign similar values to two characters with very different ink character. I therefore split the fractal layer into generalized dimensions, a multifractal spectrum, local dimensions and lacunarity. For an ink measure mu, a generalized dimension can be written as:

D_q = [1 / (q - 1)] lim_(epsilon -> 0) [log sum_i mu_i(epsilon)^q / log epsilon]

Lacunarity helps distinguish fine, evenly distributed dry-brush gaps from missing ink concentrated in blocks:

Lambda(r) = 1 + Var(M_r) / E(M_r)^2

The rule for this layer is that the large-scale skeleton stays quiet while complexity is allowed at the microscopic edge. Early versions violated that scale boundary. Their "ink texture" became visible spines.

A static image is still missing a moving brush

The final mark cannot uniquely recover the real stroke order or brush movement. The same outline may come from different speeds, pressures, angles and pauses. I therefore do not call the algorithm's output a reconstruction of the true brushwork. It is one latent dynamic explanation that satisfies the static constraints:

q(t) = (x(t), y(t), p(t), v(t), theta(t), eta(t))

Here p is pressure, v is speed, theta is brush direction, and eta is the ink load or wetness state. The algorithm slows down and raises pressure around turns, narrows the line when the brush lifts, and prohibits false beginnings and endings at internal nodes. That helps keep the outline from looking cut out with scissors, but it remains a constrained explanation. It does not extract time information that the photograph never contained.

Turning the idea into an algorithm

Once the idea entered code, the pipeline became:

Reference-mark segmentation -> character statistics -> typeface prior selection -> binary contour -> topology-preserving thinning -> clustered skeleton graph -> continuous centerline -> brush dynamics -> finite-scale ink -> topological and morphological gates.

Branch pixels in the skeleton graph are clustered into nodes first. Otherwise, a single raster crossing can be miscounted as a dozen branches. Each graph edge is traced from an endpoint or branch to the next node. The Ramer-Douglas-Peucker algorithm removes pixel stair-steps, and semantic corners separate straight motion, angular turns and curved hooks.

Later, to stop every stroke from bending like a soft hose, I added a near-straight-stroke constraint. For the path between two semantic turns, I calculate the maximum deviation from the chord joining its endpoints:

rho(P_a, P_b) = max_(a < i < b) d(P_i, [P_a, P_b]) / ||P_b - P_a||

When rho <= 0.10, the segment is treated as nearly straight and replaced by the chord. Loops, hooks and curves above the threshold retain their curvature. I also replaced sinusoidal character-level displacement with affine transformation, for one important reason: a straight line remains straight after an affine transformation.

Candidate selection does not blend every error into one score. If it did, a good texture score could buy its way out of a structural mistake. I use lexicographic gating instead. Topology must remain unchanged first. Morphological distance and persistent-homology distance must then pass their limits. Only after that may the fractal and dynamic layers decide which candidate is better:

L_T = 0 precedes d_G <= epsilon_G, which precedes d_PH <= epsilon_PH, which precedes minimizing L_ink.

Iteration is not a march toward better results

The most useful part of this development cycle was not a final image. It was the discovery that every change that looked more sophisticated could make the result worse. A version record therefore cannot preserve only the last output.

  1. Pixel skeleton. The composition stayed relatively close to the reference typeface, but every pair of neighboring pixels became a tiny line segment. Stroke edges grew spines, and turns became serrated.

  2. Continuous curves and hard-pen bands. Whole paths, cubic Bezier curves and a continuous width field replaced the microsegments. The shape became more coherent, but control handles and endpoint caps still produced unnatural bulges.

  3. Four-layer merger. Topology, composition, fractal ink and brush dynamics entered the renderer together for the first time. The overall character moved closer to the reference, while small black dots appeared on the right and lower parts of 为.

  4. Locally salient false-branch cleanup. The black dots came from short false branches created by medial-axis thinning and enlarged by circular endpoint caps. The new rule deletes a branch only if it lies outside the character's outer envelope, has paired caps or a radial orthogonal structure, and leaves beta_0 and beta_1 unchanged.

  5. Near-straight-stroke constraint. I removed sinusoidal drift from the centerline, reduced visible-scale edge undulation and straightened shallow curves. Total curvature error fell by more than half, but the actual stroke problem remained.

Why the strokes are still wrong

The central problem is that the algorithm has a topological skeleton but not strokes in the calligraphic sense.

The medial axis of a typeface contour is a geometric object. A stroke made by a person is a temporal object. The medial axis naturally grows branches around round caps, loops and high-curvature regions of thick strokes. Those branches may be geometrically valid without corresponding to real brush movement. Treating one edge of the medial-axis graph as one written stroke confuses where a shape is thickest with where the brush traveled.

The second problem is that straight and curved cannot be decided by one ratio threshold. The same chord deviation may be noise in a horizontal stroke but determine the force of a left-falling stroke, right-falling stroke or vertical hook. The algorithm still lacks stroke primitives for horizontal and vertical strokes, left and right falls, turns, hooks and rising strokes. It also lacks constraints from the semantics of character components.

The third problem is the insufficiency of static information. A photograph tells me where the ink is. It does not tell me when the brush arrived, how long it paused or whether it reversed direction. The dynamic layer can offer only one possible explanation. Without real trajectory data, prior knowledge of stroke order or a stronger physical brush-tip model, a turn may have roughly the right shape while requiring an impossible motion.

The honest conclusion is not that I have generated this person's typeface. I have built a research framework that separates kinds of error. I can now say whether the mistake lies in topology, composition, ink behavior or the dynamic explanation of brush movement. That alone is closer to the real problem of copying calligraphy than one aggregate similarity score.

Next: from skeleton edges to actual strokes

The next version will not pile on more texture. It will focus on semantic strokes:

  1. Align the typeface medial-axis graph with ordered stroke data to distinguish geometric branches from real brush contact.

  2. Build primitives for straight lines, circular arcs, gradual curvature, turns and hooks.

  3. Use continuity of pressure and speed at turns instead of filling gaps with round patches.

  4. Keep fractal texture strictly within a finite-scale boundary and out of centerline shape.

  5. Make human visual judgment part of the gate, so that any "optimization" that worsens the composition rolls back automatically.

I still think the dream found the right entrance. Calligraphy is not an outline. It is a multiscale structural system. Topology says whether the character still holds together. Geometry says whether its composition resembles the model. Fractal statistics describe the character of the ink. Dynamics asks whether a brush could actually have moved that way. The failure is not in those layers. It lies in the bridge between a geometric skeleton and a stroke unfolding through time.

Recent Posts

See All

Comments


bottom of page