seika 0.1.0
seika: ^0.1.0 copied to clipboard
Smart inpainting for Flutter. Routes automatically between PatchMatch and LaMa neural based on mask complexity analysis.
seika #
Smart on-device image inpainting for Flutter.
Seika combines a zero-MB PatchMatch engine (works offline, no download needed) with downloadable neural models โ LaMa and MI-GAN โ running via ONNX Runtime. Pick the engine manually or let seika route automatically based on mask complexity.
Features #
- ๐ผ Three engines โ PatchMatch (0 MB), LaMa (209 MB), MI-GAN (80 MB)
- ๐ฆ On-demand model downloads โ models are stored on device, not bundled in the APK or IPA. Your app stays small.
- ๐ Auto routing โ analyzes texture variance and edge coherence to pick the best engine automatically
- ๐ญ Mask dilation โ expands the mask 8 px before neural inference to reduce edge artifacts
- ๐ชก Soft boundary blending โ BFS distance-field blend for seamless transitions between filled and original regions
- ๐ SHA-256 verification โ model integrity checked after download
- ๐งต Isolate-safe โ PatchMatch runs in a background isolate, neural
inference runs via
OrtSession.runAsync. Both are safe to call from the UI thread. - ๐ฑ Android & iOS โ native C compiled as
.soon Android and asseika.frameworkon iOS via Flutter native assets
Platform support #
| Platform | PatchMatch | LaMa | MI-GAN | Min version |
|---|---|---|---|---|
| Android | โ | โ | โ | API 21 |
| iOS | โ | โ | โ | iOS 16.0 |
Installation #
dependencies:
seika: ^0.1.0
Android #
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
iOS #
Set the minimum deployment target to iOS 16.0 in ios/Podfile:
platform :ios, '16.0'
onnxruntime-objc 1.23.0 (used internally) requires iOS 16.0 or higher.
Quick start #
import 'package:seika/seika.dart';
final seika = Seika();
if (!await seika.modelManager.isAvailable()) {
await for (final p in seika.modelManager.download()) {
print('${(p.fraction * 100).toStringAsFixed(0)}%');
}
}
// 2. Inpaint โ auto-selects the best engine
final result = await seika.inpaint(
rgbaBytes, // Uint8List โ RGBA pixels, width ร height ร 4 bytes
maskBytes, // Uint8List โ grayscale mask, width ร height bytes
// 255 = fill this pixel, 0 = keep original
width,
height,
);
print(result.engineUsed); // SeikaEngine.neural
print(result.duration); // Duration(milliseconds: 1200)
// result.image โ Uint8List RGBA ready for display
Engines #
| Engine | Download | Quality | Speed | Best for |
|---|---|---|---|---|
| PatchMatch | 0 MB | โ โ โ โ | Fast | Textures, sky, walls, simple backgrounds |
| LaMa | 209 MB | โ โ โ โ | Medium | Object removal, watermarks, text |
| MI-GAN | 80 MB | โ โ โ โ | Fast | Mobile deployments, small objects |
PatchMatch #
Pure C implementation โ no model files required, works fully offline. Uses a multi-scale pyramid, bidirectional NNF with EM voting, and seam blending.
LaMa #
Large Mask inpainting via Fast Fourier Convolutions (WACV 2022). ONNX model from Carve/LaMa-ONNX.
MI-GAN #
Mobile Inpainting GAN (ICCV 2023) by Picsart AI Research. Pipeline ONNX with built-in pre/post-processing. 7ร smaller than LaMa.
API reference #
Seika #
The main entry point.
// Default model: LaMa
final seika = Seika();
// Start with a specific model
final seika = Seika(model: SeikaModelInfo.migan);
inpaint
Future<SeikaInpaintResult> inpaint(
Uint8List rgba,
Uint8List mask,
int width,
int height, {
SeikaInpaintOptions options = const SeikaInpaintOptions(),
})
| Parameter | Type | Description |
|---|---|---|
rgba |
Uint8List |
RGBA pixels, width ร height ร 4 bytes |
mask |
Uint8List |
Grayscale mask, width ร height bytes. 255 = fill, 0 = keep |
options.engine |
SeikaEngine |
auto (default), patchMatch, or neural |
options.quality |
SeikaQuality |
fast, balanced (default), or quality |
Returns SeikaInpaintResult:
| Field | Type | Description |
|---|---|---|
image |
Uint8List |
Output RGBA pixels |
engineUsed |
SeikaEngine |
Which engine ran |
duration |
Duration |
Wall-clock time |
analysis |
SeikaAnalysis |
Mask complexity metrics |
analyze
Runs the complexity analyzer without inpainting:
final analysis = await seika.analyze(rgba, mask, width, height);
print(analysis.recommended); // SeikaEngine.neural
print(analysis.maskRatio); // 0.12
print(analysis.textureVariance); // 340.5
print(analysis.edgeCoherence); // 0.87
switchModel
await seika.switchModel(SeikaModelInfo.migan);
Disposes the current ONNX session and prepares a different model for the
next inpaint() call. The previous model file on disk is not deleted.
unloadModel
await seika.unloadModel();
Releases the ONNX session from memory without changing the selected model.
Useful when the app goes to background. The next inpaint() call reloads
the model from disk.
SeikaModelManager #
Manages the lifecycle of a downloadable ONNX model.
final manager = SeikaModelManager(info: SeikaModelInfo.lama);
// Check if the model file is already on disk
final ready = await manager.isAvailable();
// Download with progress
await for (final p in manager.download()) {
print('${(p.fraction * 100).toInt()}% โ ${p.bytesReceived} bytes');
}
// Get the local file path (to load manually)
final path = await manager.localPath();
// Delete from disk to free storage
await manager.delete();
SeikaModelInfo #
Static model descriptors. Extend the catalog by adding your own entries.
SeikaModelInfo.lama // LaMa FP32, 209 MB
SeikaModelInfo.migan // MI-GAN pipeline v2, 80 MB
SeikaModelInfo.all // List<SeikaModelInfo> of all built-in models
Each entry exposes:
model.id // 'lama-fp32'
model.name // 'LaMa'
model.description // 'High quality inpainting...'
model.sizeMb // '209 MB'
model.tags // ['high quality', 'uniform backgrounds', 'watermarks']
model.type // SeikaModelType.lama
SeikaInpaintOptions #
const SeikaInpaintOptions({
SeikaEngine engine = SeikaEngine.auto,
SeikaQuality quality = SeikaQuality.balanced,
})
| Quality | PatchMatch config | Neural |
|---|---|---|
fast |
patch=5, 2 iterations, single-scale | same model |
balanced |
patch=7, 5 iterations, 3-level pyramid | same model |
quality |
patch=9, 8 iterations, 4-level pyramid | same model |
Quality only affects PatchMatch. LaMa and MI-GAN always run the same ONNX model regardless of quality setting.
Model catalog โ adding a custom model #
static const myModel = SeikaModelInfo(
id: 'my-model-v1',
name: 'My Model',
description: 'Custom inpainting model.',
url: 'https://example.com/model.onnx',
sha256: 'abc123...', // leave empty to skip verification
sizeBytes: 50_000_000,
version: 'my-model-v1',
type: SeikaModelType.lama, // or SeikaModelType.migan
tags: ['custom'],
);
LaMa-compatible models must accept:
image:Float32[1, 3, 512, 512]normalized to[0, 1]mask:Float32[1, 1, 512, 512]binary (1.0= fill)- Output:
Float32[1, 3, 512, 512]in[0, 255]range
MI-GAN-compatible models must accept:
image:Uint8[1, 3, H, W]RGB (CHW)mask:Uint8[1, 1, H, W]โ0= fill,255= keep- Output:
Uint8[1, 3, H, W]RGB
Neural path improvements (applied automatically) #
Seika applies two improvements on every neural inference call:
1. Mask dilation โ expands the user mask by 8 px before passing it to the model. The model receives more boundary context and produces better fills at the edges of the masked region.
2. Soft boundary blending โ after inference, a BFS distance field computes the distance from the mask boundary for each pixel. Pixels near the boundary blend smoothly between the neural output and the original image over a 10 px transition zone, eliminating visible seams.
Both improvements use the original (non-dilated) mask for the final pixel restoration, so the fill is precise to what the user painted.
License #
MIT โ see LICENSE.