Hacker News new | past | comments | ask | show | jobs | submit login
$1 Unistroke Recognizer (2007) (washington.edu)
198 points by jlturner on May 5, 2021 | hide | past | favorite | 65 comments



It only works if the starting point of a gesture is as expected. If I start a rectangle in the top right corner then it is characterized as a caret. Only a start in the top left results in a rectangle.


Right, this is expected. I would think of a "gesture" as a series of points over time (relative to the starting point) - it is path dependent, so a clockwise circle is recognized differently from a counter-clockwise circle.

The paper (citation 11 for the $1 version) goes into more detail. One neat feature is rotation invariance, where you can draw a tilted version and still have it be recognized.


I added a second rectangle as an example starting from a different point, and it never misrecognized any of my rectangles for carets or square brackets again.


Likewise, I added a circle going the "other way" and it got it every time. Cool piece of code, eh?


Adding left and right parenthesis started messing up with the square brackets, but then I added a couple more of each square and round brackets and it worked perfectly.

Differentiating from lowercase y and g was next to impossible, though...


Try the point cloud version, which doesn't care at all: https://depts.washington.edu/acelab/proj/dollar/pdollar.html


The first one recognizes my "five point star" as "delete". The cloud one as an "X"..


I was disappointed by that at first too, but then remembered that it says it detects gestures. A gesture is a series of motions, not the final shape.


This varied a lot for me during testing - It looks like it's actually comparing rotations of the gesture to find a match

It would nail the zigzag and most of the star/box shapes even if I intentionally started in a different place (Very first thing I tested, I'm left handed and start characters/shapes in different places)

It did not handle shapes that are rotationally similar - ex: right square bracket starting from the bottom is always detected as left square bracket, probably because the gesture matches the left bracket, rotated 180 degrees.

It also flubs arrows going right to left (they always come up as v for me)



Palm apparently had to change graffiti later to use multiple strokes for some letters, as someone had a patent on letter-recognition via single-stroke letters.


It's more about not where you start and how rotated is what you are drawing, but rather about if you are drawing it clock-wise or counter clock-wise.


Unistroke recognizer are super easy to write and a nice little afternoon project:

Take the time derivative of the trajectory, and ignore it until it's "large"

Once it becomes "large" normalize it to one of 8 directions (N NE E SE S SW W NW) and push the direction into a list then repeat until the derivative becomes "large" in a new direction or you stop getting input.

At the end you have a string you can look up in a table to get the character.

EDIT: after reading the comments apparently the algorithm PalmOS uses is slightly different.


Cool. Those examples remind me of Palm OS' Graffiti (which worked really well at the time): https://en.wikipedia.org/wiki/Graffiti_(Palm_OS)


There's a good reason for that. Graffiti was....derivative of Unistroke, which was developed at PARC as, IIRC, part of the Parctab project. Xerox even sued.

https://news.ycombinator.com/item?id=12310029

Fun fact: You can implement a "classic" Unistroke recognizer just by dividing the character up into quadrants. Every glyph had a unique sequence of quadrant traversals. http://www.yorku.ca/mack/ExperimentSoftware/javadoc/ca/yorku...


Huh, TIL. Thanks for linking the comment!

> Every glyph had a unique sequence of quadrant traversals.

That's pretty clever.


Somewhat analogous to marching squares

https://en.wikipedia.org/wiki/Marching_squares


It's to bad Palm was run into the ground.

I really liked their products on so many levels, especially the build quality. I thought they would be around forever.


Right, or the handwriting recognition built into RAND’s GRAIL system back in the 60s: https://jackschaedler.github.io/handwriting-recognition/

...which I’ve reimplemented in SQL (yes, SQL) a while ago: https://github.com/doersino/handwriting/blob/master/code/han...


Sorry, correction: «which works really well right now». I still use Graffiti, on Android, as the only keyboard on almost all of my devices. (Exceptions are relevant to technical constraints - no touch, low framerate screens etc.)


There is an improved version of this algorithm called $Q Super-Quick Recognizer [0] which allows multi-stroke gesture and drawing stroke in different direction, a demo I implemented before [1]

The $1 algorithm could be used to implement gesture typing keyboard like SwiftKey/Swype, where direction matters, eg another project of mine [2]

[0] http://depts.washington.edu/acelab/proj/dollar/qdollar.html

[1] https://github.com/wcchoi/dollar-q

[2] https://github.com/wcchoi/swell.sh


I'm a big fan of the $1 Unistroke Recognizer - it's just so cool that it works so well with minimal training. I was itching for a reason to use it and threw it into a flag semaphore decoder. Then I realized it was completely the wrong tool for drawings with only (8 choose 2) combinations where rotation does matter, and did something else instead. So, I'm still itching for a good reason to use it.


I played around with it last few days and I'm impressed by how capable thing is for its size / simplicity.

It is actually cheap enough to run per-frame in real-time, which is a fun way to see it in action and to check how soon it arrives at correct answer.

Other commenters focused on 'issue' of gestures being directional. This is a great feature as you can fit more gestures into a set with correct recognition. For example you can have space and backspace as lines in different directions. It is also trivial to just add the reversed variants if needed.

I had bigger problem with the algorithm being rotation-invariant. This means that '7' will easily be recognized as 'L'. Thankfully this is easy to fix.

The recognizer can quite reliably recognize whole alphabet. I used Palm Graffiti designs as reference for training. One training sample was always enough.

I checked out other multi-stroke recognizers on that page. They don't seem any more reliable, but all add more complexity. You have to detect when multi-stroke gesture is over which is not trivial. This uni-stroke version works wonderfully because gesture is done as soon as mouse button is released.

Thank you for this submission! As say in the published article, this is often needed functionality and most of us think it's too complex to be worth it. Turns out the algorithm is quite simple and reliable.

The Lua fork I worked on is available here: https://github.com/jmiskovic/lua-gestures


I recall experimenting with similar approaches about 2 decades ago; depending on your gestures you can actually simplify a lot:

- normalize the draw height/width

- use polar coordinates before normalizing

- normalize the length of the drawn path

- DAG to recognize shapes faster, using partial paths

- only taking into account corners with angles over a certain treshold

- ...

The possibilities are endless, and this is a good exercise to explain that slight alterations on your problem space can have a huge impact on your solution space.

[update - formatting]


This might be obvious to everyone but me, but how do you read "$1" in this context? Do I read it as "one-dollar", or "dollar-sign one", something else? Thank you in advance


I read it as “one-dollar” and assume most people would read it the same. Although I’d prefer if writing rules put the $ after the number; eg 1$.


My interpretation is $1 reads as "unistroke"/"singlestroke" while $N = "multistroke"


I used it to integrate sketching into a web-based diagram editor ~10 years ago and it was a breeze. OK, I had to train it myself. But it takes only minutes to draw all the shape variants needed. In practice I used 6 shapes and about 5 variants per shape. I conducted a usability test and the $1 recognizer only failed to recognizes the sketches 2-3 times out of ~300 shapes drawn by different users with no additional training.


In case anyone is interested, the $N-Protractor algorithm was ported to Python for use in the Kivy framework [0]. Unfortunately it's tied to kivy's clock among other things, but easy to rip it out should you need it in a different context. There is also anexample application that can be used to create gesture templates [1]

[0] https://github.com/kivy/kivy/blob/master/kivy/multistroke.py

[1] https://github.com/kivy/kivy/tree/master/examples/demo/multi...


Very cool! I think the name is a reference to the 1€ filter?

https://cristal.univ-lille.fr/~casiez/1euro/


It is the opposite. As state on the website you liked: > The name "1€" is an homage to the $1 recognizer.


Where did the name $1 come from?


I believe it is a reference to the US dollar


Because this software cost about dollar to make (it sucks).


It's the other way around, says so on the page you linked


I implemented the multistroke version of this (https://faculty.washington.edu/wobbrock/pubs/gi-12.03.pdf) in a jailbreak tweak for iPhone: https://youtu.be/35SX6A9fE0g

It was very cool at the time, but I don’t think it saved me much time :)



I remember porting this to Objective-C for an iPhone project forever ago. That was fun exercise, and the algorithm works surprisingly well for how simple it is.

https://github.com/ddunkin/dollar-touch


I made my unistroke symbol recognizer in Python for my AI class a year ago. It uses the backpropagation algorithm.

You must have the Numpy and Scipy libraries installed.

https://github.com/smnbgn/unistroke


I expected it to cost $1, and then I thought "I'd gladly pay $1 for a perpetual licence to a good quality library".

Setting aside OSI's definition of OSS, has this been explored as a OSS funding model?


> Setting aside OSI's definition of OSS, has this been explored as a OSS funding model?

Bruce Perens recently published some thoughts on that:

https://perens.com/2020/08/24/what-comes-after-open-source/

https://perens.com/2020/10/06/post-open-source-license-early...


Is this roughly how the various swipe-typing apps on phones work? Use the shape traced to do a range query in a table of words, and use textual context to prioritize the guesses?


It took me long to figure out that this wasn't a one dollar piece of hardware.


Thought "at first" a medical device.

So I drew a heart.

Drawn clockwise, I get a carrot :).

So now I know what to send to my loved ones.

Drawn counter-clockwise, I get a square. And maybe where the carrot will be left to be.


Now I want editor that shows carrot in place of caret.


It keeps telling me my curly brackets are square :/


This breaks pretty easy unfortunately by simply drawing in reverse (e.g. draw circle counter-clockwise instead of clockwise etc.)


That's true, but you can always add the reverse circle as a second example, and then it's happy with either.


That's a different stroke! Of course it shouldn't match.


Yeah but you know what they say about different folks.


HN challenge: draw a circle! (no matter how hard I tried, it's always a triangle for me)


1st thing[0]. I didn't seem hard (and I am exceptionally bad at drawing anything, incl. circles with pen and paper):

[0]: https://imgur.com/a/wfyoPLF


For me, it says rectangle when my "circle" looks more like an elipse.


Does it work on on iPad? Both using finger and pen it scrolls rather then drawing.


When drawing circle slow always says it is 'rectangle' ?


Is it hard to make it recognize mirror strokes?


It should recognize a single stroke house :)


Doesn't work for 7 bridges problem :(


You can add your own shapes.


Draw a circle with multiple turns :)


I wonder if you could make a brain stroke recognizer by filming someone's face and look for one sided paralysis that often comes with it


They all need to be drawn in the same direction of the demo. If I draw them in the opposite direction ( example the circle instead of counter-clockwise, I draw it clockwise ), another shape is recognised:

Triangle -> Delete / Caret

X -> Delete

Rectangle -> Caret

Circle -> Caret

Check -> Right square bracket / Arrow

Caret -> V

Zig-zag -> Zig-zag

Arrow -> V

Left square bracket -> Right square bracket

Right square bracket -> Left square bracket

V -> Caret

Delete -> X

Left curly bracket -> Right curly bracket

Right curly bracket -> Left curly bracket

Star -> Left curly bracket / Delete

Pigtail -> Delete


When I was a teenager playing Dr Kawashima's Brain Training on DS, I had to completely change how I drew my 9s in order to get it to recognise them (it turned out I started in the wrong place for it to recognise the number).

I only played that game for a month or two, but it stuck with me and now more than a decade later I still draw my 9s differently.


Well, it's not magic. It probably recognizes direction of strokes. I imagine that you can start from scratch and train both directions to be valid, but then you will find more mismatches.


Is this a joke? A stroke recogniser, and they decided to go with a gesture that looks like a ball-bag?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: