panoramerge 0.1.2
panoramerge: ^0.1.2 copied to clipboard
Pure Dart panorama registration, seam finding, and multiband blending for RGB and CMYK rasters.
Panoramerge #
Panoramerge is a pure Dart panorama engine. It takes already decoded, overlapping rasters and returns one registered, seamed, multiband-blended canonical raster. On request it also retains each aligned source and its seam mask so an image editor can build an editable layer stack. It has no Flutter, codec, OpenCV, FFI, or platform runtime dependency.
The implementation includes:
- binomial Gaussian and Laplacian image pyramids;
- multiscale FAST-9 corner detection, intensity-centroid orientation, and a deterministic 256-bit rotated BRIEF descriptor;
- brute-force Hamming matching with a nearest-neighbour ratio test and mutual cross-check;
- deterministic RANSAC with normalized homography, affine, and translation solvers;
- perspective, cylindrical, and spherical source projection;
- a weighted overlap graph and maximum-quality spanning registration tree;
- bilinear inverse warping and RGB exposure compensation;
- minimum-cost vertical or horizontal seams found by dynamic programming; and
- Gaussian-mask, Laplacian-pyramid multiband blending.
Canonical pixels #
PanoramaRaster samples are interleaved, premultiplied, and little-endian:
| Colour model | Components | Supported depths |
|---|---|---|
| RGB | red, green, blue, alpha | uint8, uint16, float32 |
| CMYK | cyan, magenta, yellow, black, alpha | uint8, uint16, float32 |
Integer samples are unsigned normalized values. Alpha and CMYK ink are bounded to 0–1. Float32 RGB components may exceed 1, so HDR values survive projection and blending. Geometry and pyramid operations run on floating premultiplied components and quantize only when the final raster is encoded.
Colour profiles remain an application concern. All sources passed to one
stitch must use the same pixel format and colour interpretation. Panoramerge
does not rewrite process plates; it uses RGB luminance or a deterministic
generic device-CMYK conversion only to derive registration and seam evidence.
Hosts that already enforce this canonical contract can adopt owned buffers with
PanoramaRaster.takeTrustedBytes, avoiding a copy and a second full sample
scan.
Usage #
The package does not decode files. Pass canonical bytes produced by the host application or construct an RGBA8 raster from straight bytes:
import 'dart:typed_data';
import 'package:panoramerge/panoramerge.dart';
Future<PanoramaResult> mergeDecodedImages(
Uint8List firstRgba,
Uint8List secondRgba, {
required int width,
required int height,
}) {
final PanoramaRaster first = PanoramaRaster.fromStraightRgba8(
width: width,
height: height,
bytes: firstRgba,
);
final PanoramaRaster second = PanoramaRaster.fromStraightRgba8(
width: width,
height: height,
bytes: secondRgba,
);
return const PanoramaStitcher(
options: PanoramaStitcherOptions(
projection: PanoramaProjection.automatic,
cropTransparentBorders: true,
includeSourceLayers: true,
),
).stitchAsync([first, second]);
}
stitchAsync moves CPU work to a Dart isolate. stitch is the synchronous
equivalent and accepts a progress callback. A successful PanoramaResult
contains the output raster, each original-source-to-output mapping, feature
counts, pairwise match/inlier evidence, the chosen reference source, and the
composition order.
With includeSourceLayers, PanoramaResult.sourceLayers contains one
full-canvas PanoramaSourceLayer per input, ordered from bottom to top. Each
item owns its projected, exposure-compensated canonical raster and, except for
the base layer, a one-byte grayscale seam mask. The ordinary flattened raster
remains available for preview, export, and pixel-parity checks. Editable output
is disabled by default because retaining both representations and the floating
projections until transfer increases the byte-accounted working set.
Built for Focale, an advanced local image editor. Discover what these packages make possible in a real creative workflow.
