Samuel Prevost 790f3e9147
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
fix(measurements): labels also dodge handle dots, not just other labels
The collision resolver only avoided overlapping label rects. Labels
could still land on handle dots — easiest to see on a horizontal line
where the endpoint dots sit at the same Y as the midpoint anchor,
making the pill cover the dot the user wants to grab.

Extended `resolveLabelPositions` to push labels past any handle dot
too. Each handle becomes a 20×20 phantom rect (centred on the dot,
sized to match the primary handle's outer reach + ring) that the
resolver dodges with a 4 px gap. The handle-gap is smaller than the
inter-label gap (8 px) since dots are smaller than pills — keeps the
result visually tight.

Per-anchor exception: the handle sitting at a label's own anchor
(ellipse / circle / angle anchors are at the primary handle disk) is
skipped, otherwise the resolver would chase the label arbitrarily far
from its own measurement. The per-type `offsetY` already places the
pill clear of that one specific handle.
2026-05-01 00:34:00 +02:00
2026-04-14 23:25:59 +02:00
2026-04-29 12:54:24 +02:00

Skwik

Client-side image deskewing tool. Upload a photo taken at an angle, place reference measurements on known objects, and get a perspective-corrected output with real-world scale.

Everything runs in the browser -- no server, no uploads.

Example

Before — angled photograph with a paper sheet as a known-size reference
Before — angled shot
After — perspective-corrected top-down view
After — corrected perspective
Measured — the corrected image with measurement annotations baked in
Measured — annotations baked in

How it works

  1. Upload a JPG or HEIC image (HEIC is converted automatically). Past uploads are cached and reopen straight into Measure with their datums and annotations restored.
  2. Review EXIF data -- camera, lens, focal length.
  3. Place datums on the image -- rectangles, lines, or ellipses (circles) with known real-world dimensions. Each datum carries a 1--5 confidence score. One datum can be flagged as the world-axis reference to fix the output orientation.
  4. Deskew -- OpenCV.js computes a perspective transform and produces a corrected image at a configurable px/mm scale, with per-datum residuals and a global RMS error reported.
  5. Measure -- annotate the corrected image with lines, rectangles, ellipses, circles, and angles in real-world units. Export the bare PNG, or the image with measurements baked in (full resolution or current viewport).

The algorithm

The pipeline picks a primary datum that fixes the output gauge (orientation, position, scale): any datum the user explicitly flagged as the world-axis reference, otherwise the highest-confidence rectangle, then ellipse, then line. The primary's known dimensions are mapped onto an axis-aligned output frame via cv.getPerspectiveTransform -- that's the warm-start homography.

That homography is then refined by an alternating-minimization loop around cv.findHomography (which internally runs DLT + Levenberg-Marquardt). On every outer pass, each datum is turned into output-space point correspondences using its shape constraint:

  • Rectangle -- Procrustes-fit an ideal w × h rectangle to the current projection of the user-marked corners.
  • Line -- preserve the projected midpoint and direction, rescale to the expected length.
  • Ellipse -- sample 12 points along the user ellipse, project them, then radially snap to a circle of the expected diameter centred on the projected user-marked centre. Forces circles to stay circular under perspective.

Confidence scores (1--5) are realised as integer replication of correspondences -- cv.findHomography has no native weighting. The primary additionally gets a ×3 gauge boost so its anchors don't drift while secondary datums are being satisfied. The loop runs until the homography stops moving (max-entry relative delta below 1e-6) or 30 iterations, with period-2 oscillation detection logging a warning if the alternating minimization fails to converge.

A single cv.warpPerspective with Lanczos resampling produces the corrected image at the requested px/mm scale; output bounds are derived by projecting the source image corners through the final homography and clamped to a 12288 px maximum dimension to keep WASM heap usage bounded.

Per-datum residuals are reported alongside the result: edge length error and corner perpendicularity for rectangles, length error for lines, and isotropy / skew / equivalent-diameter error from the projected conic for ellipses, plus a global RMS percentage across all of them.

Quick start

pnpm install
pnpm dev

Open http://localhost:5173.

Build

pnpm build      # type-check + production build
pnpm preview    # serve the build locally

Lint & format

pnpm lint       # eslint (strict TS + Vue)
pnpm lint:fix   # auto-fix
pnpm format     # prettier
pnpm type-check # vue-tsc

Stack

Layer Tech
Framework Vue 3 + TypeScript (strict)
Build Vite
Components shadcn-vue + Tailwind CSS v4
Canvas Konva.js + vue-konva
CV OpenCV.js 4.12 (WASM)
HEIC heic-to
EXIF exifr
State Pinia

Datum presets

Rectangles: A3, A4, A5, A6, 15×10 cm. Circles: €1, €2, US 25¢, UK 1p, CD. Custom dimensions supported on every type; lines accept any length.

How Skwik compares

There are plenty of tools that do part of what Skwik does, but none that combine everything:

Tool Client-side Multi-datum weighting Real-world mm scale Measurement tools Scale bar export
Skwik
MYOG Perspective Correction
PerspectiveFix
PicFix.pro
ImageOnline Perspective
Toolschimp Image Measure
Aspose Deskew

Most deskew tools just pull 4 corners to a rectangle without any real-world dimensions -- the output has no scale. Most measurement tools calibrate against a single reference and don't correct perspective. Skwik uses multiple weighted datums (rectangles, lines, and ellipses, each with a confidence score) to solve both problems in one pass, and lets you measure distances or export with a scale bar on the corrected image.

License

GNU General Public License v3.0

Description
Client-side image deskewing tool. Upload a photo taken at an angle, place reference measurements on known objects, and get a perspective-corrected output with real-world scale.
https://serv.e1n.sh/skiwk
Readme GPL-3.0 1.2 MiB
Languages
Vue 74.1%
TypeScript 24.7%
CSS 1.1%