Git Product home page Git Product logo

one_dollar_unistroke_recognizer's Introduction

A Dart port of the $1 Unistroke Recognizer with some enhancements:

  • The Protractor enhancement
  • A way to get a "perfect" (canonical) shape from the user's stroke
  • A better suited algorithm for detecting straight lines
  • Type safety (with the DefaultUnistrokeNames enum, or another if you're using custom unistrokes)

By default it recognizes lines, circles, rectangles, and triangles. But you can also recognize any custom unistrokes (see below).

I'm building and maintaining this package for my open source note-taking app, Saber.

Pub BSD 3-Clause License

Usage

Basic usage

final points = <Offset>[...];
final recognized = recognizeUnistroke(points);
if (recognized == null) {
  print('No match found');
} else {
  // e.g. DefaultUnistrokeNames.circle
  print('Stroke recognized as ${recognized.name}');
}

Protractor enhancement

The Protractor enhancement is enabled by default. You can disable it by setting useProtractor to false.

final recognized = recognizeUnistroke(
  points,
  useProtractor: false,
);

Getting the "perfect" (canonical) shape

You can get a "perfect" shape from the user's stroke by calling one of the following methods on the RecognizedUnistroke object:

  • convertToCanonicalPolygon(): Returns the closest template match, scaled and translated to match the input gesture. Note that this method returns a list of points, instead of a perfect circle or rectangle like the other methods. (Shown in 🔴red in the examples below.)
  • convertToLine(): Returns the first and last input points. (Shown in 🟠orange in the examples below.)
  • convertToCircle(): Returns the radius and center of the best-fit circle. (Shown in 🔵blue in the examples below.)
  • convertToOval(): The same as convertToCircle() but doesn't take the average of the width and height. (Not shown in the examples below.)
  • convertToRect(): Returns the Rect of the best-fit (bounding box) rectangle. Tip: you can round the corners of the Rect with RRect.fromRectAndRadius. (Shown in 🟢green in the examples below.)
Line Circle Rectangle Triangle
Line Circle Rectangle Triangle
Line HQ Circle HQ Rectangle HQ Triangle HQ
final recognized = recognizeUnistroke(points);
switch (recognized?.name) {
  case null:
    break;
  case DefaultUnistrokeNames.line:
    final (start, end) = recognized!.convertToLine();
    canvas.drawLine(start, end, paint);
  case DefaultUnistrokeNames.circle:
    final (center, radius) = recognized!.convertToCircle();
    canvas.drawCircle(center, radius, paint);
  case DefaultUnistrokeNames.rectangle:
    final rect = recognized!.convertToRect();
    if (youWantARoundedRectangle) {
      canvas.drawRRect(
        RRect.fromRectAndRadius(rect, Radius.circular(10)),
        paint,
      );
    } else {
      canvas.drawRect(rect, paint);
    }
  case DefaultUnistrokeNames.triangle:
    final polygon = recognized!.convertToCanonicalPolygon();
    canvas.drawPoints(PointMode.polygon, polygon, paint);
}

Using custom unistroke templates

You can recognize custom unistrokes by setting the referenceUnistrokes list.

Note that this will disable the default unistroke templates defined in default$1Unistrokes.

If your key type isn't DefaultUnistrokeNames, you'll need to call recognizeCustomUnistroke<MyKey>(...) instead of recognizeUnistroke(), which will return a RecognizedCustomUnistroke<MyKey> instead of a RecognizedUnistroke.

Also note that straight lines are a special case in the default unistroke templates, and aren't available by default with custom unistroke templates. To recognize straight lines, see the Straight lines section below.

enum MyUnistrokeNames {
  circle,
  rectangle,
  triangle,
  leaf,
}

referenceUnistrokes = <Unistroke<MyUnistrokeNames>>[
  Unistroke(MyUnistrokeNames.circle, [...]),
  Unistroke(MyUnistrokeNames.rectangle, [...]),
  Unistroke(MyUnistrokeNames.triangle, [...]),
  Unistroke(MyUnistrokeNames.leaf, [...]),
];

final recognized = recognizeCustomUnistroke<MyUnistrokeNames>(points);

Alternatively, you can temporarily override the referenceUnistrokes list for a single call to recognizeUnistroke by setting the overrideReferenceUnistrokes list.

final recognized = recognizeCustomUnistroke<MyUnistrokeNames>(
  points,
  overrideReferenceUnistrokes: [...],
);

Straight lines

Straight lines are a special case in the default unistroke templates, in that they're best recognized by a different algorithm than the other shapes (i.e. not $1).

If you're using default$1Unistrokes (the default), you don't need to worry about this, and straight lines will be detected as DefaultUnistrokeNames.line.

But if you're using custom unistroke templates, ensure that your straight line unistroke template has exactly 2 points and that they're distinct.

referenceUnistrokes = <Unistroke<MyUnistrokeNames>>[
  Unistroke(MyUnistrokeNames.line, [
    // This template should have exactly 2 distinct points.
    Offset(0, 0),
    Offset(0, 100),
  ]),
  // ...
];

About the $1 Unistroke Recognizer

The $1 Unistroke Recognizer is a 2-D single-stroke recognizer designed for rapid prototyping of gesture-based user interfaces. In machine learning terms, $1 is an instance-based nearest-neighbor classifier with a 2-D Euclidean distance function, i.e., a geometric template matcher. $1 is a significant extension of the proportional shape matching approach used in SHARK2, which itself is an adaptation of Tappert's elastic matching approach with zero look-ahead. Despite its simplicity, $1 requires very few templates to perform well and is only about 100 lines of code, making it easy to deploy. An optional enhancement called Protractor improves $1's speed.

You can read more about the $1 Unistroke Recognizer at depts.washington.edu/acelab/proj/dollar.

On that link, you'll see a demo with 16 templates. This package uses a different set of templates by default, but you can use the original templates by setting referenceUnistrokes to example$1Unistrokes.

This Dart package is a port of the JavaScript version of the $1 Unistroke Recognizer, which you can find at depts.washington.edu/acelab/proj/dollar/dollar.js.

one_dollar_unistroke_recognizer's People

Contributors

adil192 avatar qubab avatar dependabot[bot] avatar

Stargazers

mcp avatar Alpha-00 avatar Pathompong Puengrostham avatar

Watchers

 avatar  avatar

Forkers

qubab lushan1314

one_dollar_unistroke_recognizer's Issues

bug: convertToCanonicalPolygon() returns incorrectly rotated shapes

Here is a screenshot of the examples in the README:
circle, rectangle, and triangle

The red shape is the output of recognized.convertToCanonicalPolygon() and it isn't rotated correctly.
Interestingly, its rotation doesn't match the input OR the template's original points, but instead the first point from the templates original points always seems to be on the centerLeft of the red shape.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.