forgo.cloud
Sign in
Repo workspace

forkjoin-ai/gnosis

Style Transfer Pipeline

distributed-inference-host/README-STYLE-TRANSFER.md
forkjoin-ai/gnosis

Style Transfer Pipeline

Companion document to README-DEBLUR.md. This file covers the host-level style-transfer feature that follows the same fork/race/fold shape as the deblur ensemble APIs.

Overview

styleTransferAnyImage(content, style, options) applies deterministic style transfer for 1-channel and RGB images:

  • matches channel mean/std from style image onto content image
  • blends stylized signal with the original content signal (strength)
  • preserves structure via edge-aware reinjection (structurePreservation)
  • passes style through an alpha wave field, then transposes the waved style onto target
  • optional post sharpen for textures

forkRaceFoldStyleTransfer(...) runs multiple style-transfer configs in parallel and folds survivors with Buleyean weighting.

Quick start

import {
  styleTransferAnyImage,
  forkRaceFoldStyleTransfer,
  encodeStyledAsPNG,
} from '@a0n/distributed-inference-host/style';

const single = await styleTransferAnyImage(content, style, {
  method: 'classical',
  strength: 0.75,
  structurePreservation: 0.55,
  alphaWave: { edgeThreshold: 0.22, edgeBoost: 0.7, frequency: 2.2, phase: 0.0 },
});

const ensemble = await forkRaceFoldStyleTransfer({
  content,
  style,
  configs: [
    { label: 'balanced', options: { method: 'classical', strength: 0.7 } },
    { label: 'bold', options: { method: 'classical', strength: 0.9 } },
  ],
});

await writeFile('styled.png', await encodeStyledAsPNG(single));

Golden PNG regression snapshots

Byte-stable PNGs under __tests__/golden/style-transfer/ guard the classical pipeline (plain, mesh stub, mesh + depth) and the FRF style fold (frf-mesh-fold-16.png) on a fixed 16×16 LCG plane pair. The encoder is rgbFloat01InterleavedToPngBuffer (zlib filter-0, same round(clamp01(v)*255) quantization as encodeStyledAsPNG).

Update goldens after an intentional algorithm change:

UPDATE_STYLE_TRANSFER_GOLDEN_SNAPSHOTS=1 pnpm run a0 -- run @a0n/distributed-inference-host:test -- --testPathPattern=style-transfer-golden

See __tests__/golden/style-transfer/README.md. A maintainer script that mirrors the same fixtures lives at scripts/write-style-transfer-golden-pngs.ts (run via gnode when the TS bridge is available, or bundle with esbuild and a footer that calls main() from the package root).

Wasm imaging surface (StyleTransferImagingWasmSurface)

Pass the wasm-bindgen namespace from distributed_inference (same object a Worker loads after init) as the last argument to styleTransferAnyImage, or set imagingWasm on forkRaceFoldStyleTransfer ensemble args for all forks:

  • wasmTopologyMaskBuildRgbF32 — used when meshGate.enabled is true and no explicit topologyAlphaBackend is passed (topology provenance stays JSON-serializable).
  • wasmMeshDepthConfidenceRgbF32 — optional; when meshGate.autoWasmDepth is true and the caller did not supply meshGate.depthConfidence, the host fills the depth channel from wasm (build_mesh_depth_field in the Rust crate). meshGate.wasmMonocularCueBlend forwards monocular cue blend into that wasm entry.

Host-only Gibson proxies (meshGate.hostMonocularAdmissionWeight) multiply into the photometric veto path without wasm.

AdaIN adapter contract

The AdaIN path is exposed as an adapter surface:

  • method: 'adain-adapter' switches to adapter mode
  • if no backend is supplied, output falls back to classical transfer while preserving the method label
  • if a backend is supplied, it must return width*height*channels values

Mesh gate and AdaIN ordering

  1. Classical reference always runs first (with mesh gate when enabled) so meshProvenance, meshFoldMetrics, and fallback stylized stay defined.
  2. The AdaIN backend replaces stylized with its own plane (same contract as before).
  3. Optional meshGate.applyScalarMeshAdmissionToAdaIN: after AdaIN, each channel is pulled toward content with scalar mean_effective_gate from the classical mesh path: out = content + mean_effective_gate * (adain - content) (per-channel, clamped). Per-pixel gating of AdaIN output is not implemented yet; the scalar is an explicit, replayable compromise.

This keeps the API stable while neural backend wiring is still evolving.