Skip to content

Commit b1cdccb

Browse files
author
Aaron Hill
committed
2 parents c748447 + 05e3213 commit b1cdccb

File tree

3 files changed

+226
-3
lines changed

3 files changed

+226
-3
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ This project framework provides examples for the following services:
4444
* Using the **Computer Vision SDK** [azure-cognitiveservices-vision-computervision](http://pypi.python.org/pypi/azure-cognitiveservices-vision-computervision) for the [Computer Vision API](https://azure.microsoft.com/services/cognitive-services/computer-vision/)
4545
* Using the **Content Moderator SDK** [azure-cognitiveservices-vision-contentmoderator](http://pypi.python.org/pypi/azure-cognitiveservices-vision-contentmoderator) for the [Content Moderator API](https://azure.microsoft.com/services/cognitive-services/content-moderator/)
4646
* Using the **Custom Vision SDK** [azure-cognitiveservices-vision-customvision](http://pypi.python.org/pypi/azure-cognitiveservices-vision-customvision) for the [Custom Vision API](https://azure.microsoft.com/services/cognitive-services/custom-vision-service/)
47+
* Using the **Ink Recognizer SDK** [azure-cognitiveservices-inkrecognizer](https://pypi.org/project/azure-cognitiveservices-inkrecognizer/) for the [Ink Recognizer API](https://azure.microsoft.com/services/cognitive-services/ink-recognizer/)
4748

4849
We provide several meta-packages to help you install several packages at a time. Please note that meta-packages are only recommended for development purpose. It's recommended in production to always pin specific version of individual packages.
4950

@@ -105,6 +106,7 @@ We provide several meta-packages to help you install several packages at a time.
105106
4. Set up the environment variable `CONTENTMODERATOR_SUBSCRIPTION_KEY` with your key if you want to execute Content Moderator tests. You might override too `CONTENTMODERATOR_LOCATION` (westcentralus by default).
106107
4. Set up the environment variable `CUSTOMVISION_TRAINING_KEY` with your key if you want to execute CustomVision Training tests.
107108
4. Set up the environment variable `CUSTOMVISION_PREDICTION_KEY` with your key if you want to execute CustomVision Prediction tests.
109+
4. Set up the environment variable `INK_RECOGNIZER_SUBSCRIPTION_KEY` with your key if you want to execute ink recognition tests.
108110
109111
## Demo
110112
@@ -114,9 +116,10 @@ To run the complete demo, execute `python example.py`
114116
115117
To run each individual demo, point directly to the file. For example (i.e. not complete list):
116118
117-
2. `python samples/language/spellcheck_samples.py`
118-
1. `python samples/search/entity_search_samples.py`
119-
2. `python samples/search/video_search_samples.py`
119+
1. `python samples/language/spellcheck_samples.py`
120+
2. `python samples/search/entity_search_samples.py`
121+
3. `python samples/search/video_search_samples.py`
122+
4. `python samples/vision/inkrecognizer_sample.py`
120123
121124
To see the code of each example, simply look at the examples in the Samples folder. They are written to be isolated in scope so that you can see only what you're interested in.
122125

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ azure-cognitiveservices-vision-contentmoderator>=1.0.0 # sample won't work with
1616
azure-cognitiveservices-vision-customvision>=0.4.0 # sample won't work with previous versions
1717
azure-cognitiveservices-vision-face
1818
azure-cognitiveservices-anomalydetector>=0.2.0 # sample won't work with previous versions
19+
azure-cognitiveservices-inkrecognizer>=1.0.0b1
1920
pandas
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import os
2+
try:
3+
from tkinter import *
4+
from tkinter import messagebox
5+
except ImportError:
6+
# python <= 2.7
7+
from Tkinter import *
8+
import tkMessageBox as messagebox
9+
10+
from collections import namedtuple
11+
from azure.cognitiveservices.inkrecognizer import ApplicationKind, InkStrokeKind
12+
from azure.cognitiveservices.inkrecognizer import InkRecognizerClient
13+
14+
15+
import logging
16+
logging.basicConfig(level=logging.DEBUG)
17+
18+
# <InkRecognizerClientConfig>
19+
URL = "https://api.cognitive.microsoft.com/inkrecognizer"
20+
CREDENTIAL = os.environ['INK_RECOGNIZER_SUBSCRIPTION_KEY'].strip()
21+
# You can also use Azure credential instance
22+
23+
24+
# Recognition Config
25+
# This tell Ink Recognizer Service that the sample is in en-US.
26+
# Default value is "en-US".
27+
# If "language" in a stroke is specified, this will be overlaped in that stroke.
28+
LANGUAGE_RECOGNITION_LOCALE = "en-US"
29+
# This tell Ink Recognizer Service that domain of the application is mixed,
30+
# so Ink Recognizer Service will detect kind of each stroke.
31+
# You can set it into ApplicationKind.WRITING or ApplicationKind.DRAWING to specify
32+
# default kind of strokes and skip stroke kind detection precedure.
33+
# Default value is ApplicationKind.MIXED.
34+
# If "kind" in a stroke is specified, this will be overlaped in that stroke.
35+
APPLICATION_KIND = ApplicationKind.MIXED
36+
# </InkRecognizerClientConfig>
37+
38+
39+
# <StrokeImplementations>
40+
# Shows simple implementation of InkPoint and InkStroke
41+
InkPoint = namedtuple("InkPoint", "x y")
42+
43+
44+
class InkStroke():
45+
def __init__(self,
46+
ink_stroke_id,
47+
ink_points,
48+
stroke_kind=InkStrokeKind.UNKNOWN,
49+
stroke_language=""):
50+
self.id = ink_stroke_id
51+
self.points = ink_points
52+
self.kind = stroke_kind
53+
self.language = stroke_language
54+
# </StrokeImplementations>
55+
56+
57+
# <KeyScenarioExample>
58+
# Wrapper for InkRecognizerClient that shows how to
59+
# (1) Convert stroke unit from pixel to mm
60+
# (2) Set language recognition locale
61+
# (3) Indexing a key word from recognition results
62+
# (4) Set application kind if user know expected type of ink content
63+
class RecognitionManager:
64+
def __init__(self, pixel_per_mm):
65+
self._pixel_per_mm = pixel_per_mm
66+
self._client = InkRecognizerClient(
67+
URL,
68+
CREDENTIAL,
69+
# <SetApplicationKind>
70+
application_kind=APPLICATION_KIND,
71+
# </SetApplicationKind>
72+
)
73+
# Aruments in constructor becomes default arguments for each request
74+
# You can also specify these arguments in recognize_ink() requests,
75+
# which influence that request only
76+
self.reset_ink()
77+
78+
def _reset_stroke(self):
79+
self._curr_stroke_points = []
80+
81+
def _pixel_to_mm(self, pixel):
82+
return pixel * 1.0 / self._pixel_per_mm
83+
84+
def reset_ink(self):
85+
self._ink_stroke_list = []
86+
self._root = None
87+
self._reset_stroke()
88+
89+
def add_point(self, x, y):
90+
# <UnitConversion>
91+
# Convert from pixel to mm before sending to InkPoint.
92+
# You can also specify keyword argument "unit_multiple" in
93+
# InkRecognizerClient constructor or in recognize_ink() request.
94+
self._curr_stroke_points.append(
95+
InkPoint(self._pixel_to_mm(x), self._pixel_to_mm(y)))
96+
# </UnitConversion>
97+
98+
def stroke_end(self):
99+
stroke = InkStroke(len(self._ink_stroke_list), self._curr_stroke_points)
100+
self._ink_stroke_list.append(stroke)
101+
self._reset_stroke()
102+
103+
def recognize(self):
104+
self._root = None
105+
try:
106+
root = self._client.recognize_ink(
107+
self._ink_stroke_list,
108+
# <SetRecognitionLocale>
109+
language=LANGUAGE_RECOGNITION_LOCALE,
110+
# </SetRecognitionLocale>
111+
logging_enable=True
112+
)
113+
# Aruments in request is for this request only
114+
# You can also specify these arguments in InkRecognizerClient constructor,
115+
# which will be default arguments for each call.
116+
result_text = []
117+
for word in root.ink_words:
118+
result_text.append(word.recognized_text)
119+
for shape in root.ink_drawings:
120+
result_text.append(shape.recognized_shape.value)
121+
result_text = "\n".join(result_text)
122+
messagebox.showinfo("Result", result_text)
123+
self._root = root
124+
except Exception as e:
125+
messagebox.showinfo("Error", e)
126+
127+
def search(self, word):
128+
# <IndexingKeyword>
129+
if self._root is not None:
130+
num_words = len(self._root.find_word(word))
131+
else:
132+
num_words = 0
133+
search_result = "Find %s word%s" % (num_words, "s" if num_words != 1 else "")
134+
messagebox.showinfo("Search Result", search_result)
135+
# </IndexingKeyword>
136+
# </KeyScenarioExample>
137+
138+
139+
# <SampleUIConfig>
140+
CANVAS_WIDTH = 800
141+
CANVAS_HEIGHT = 500
142+
STROKE_COLOR = "#476042" # python green
143+
STROKE_WIDTH = 3
144+
# </SampleUIConfig>
145+
146+
147+
# <SampleUI>
148+
class InkRecognizerDemo:
149+
def __init__(self):
150+
self._master = Tk()
151+
self._pack_widgets()
152+
153+
self._recognition_manager = RecognitionManager(
154+
pixel_per_mm=self._master.winfo_fpixels("1m"))
155+
# point for drawing stroke
156+
self._last_point = None
157+
158+
def _pack_widgets(self):
159+
self._master.title("Ink Recognizer Demo")
160+
# search words
161+
self._search_variable = StringVar(value="")
162+
search_entry = Entry(self._master, textvariable=self._search_variable)
163+
search_button = Button(self._master, text="search a word", command=self._search)
164+
search_entry.pack(pady=5)
165+
search_button.pack()
166+
# main canvas
167+
self._canvas = Canvas(
168+
self._master,
169+
width=CANVAS_WIDTH,
170+
height=CANVAS_HEIGHT)
171+
self._canvas.pack(expand=YES, fill = BOTH)
172+
self._canvas.bind("<B1-Motion>", self._draw)
173+
self._canvas.bind("<Button-1>", self._stroke_start)
174+
self._canvas.bind("<ButtonRelease-1>", self._stroke_end)
175+
# recognize and clear buttons
176+
recognize_button = Button(
177+
self._master, text="Recognize", command=self._recognize)
178+
recognize_button.pack(pady=5)
179+
clear_button = Button(
180+
self._master, text="Clear", command=self._clear_canvas)
181+
clear_button.pack(pady=5)
182+
183+
def _draw(self, event):
184+
# paint on canvas
185+
x_curr, y_curr = event.x, event.y
186+
if self._last_point is not None:
187+
x_last, y_last = self._last_point[0], self._last_point[1]
188+
self._canvas.create_line(
189+
x_last, y_last, x_curr, y_curr, fill=STROKE_COLOR, width=STROKE_WIDTH)
190+
self._last_point = x_curr, y_curr
191+
# add point to stroke store
192+
self._recognition_manager.add_point(x_curr, y_curr)
193+
194+
def _stroke_start(self, event):
195+
# nothing need to do
196+
pass
197+
198+
def _stroke_end(self, event):
199+
self._recognition_manager.stroke_end()
200+
self._last_point = None
201+
202+
def _clear_canvas(self):
203+
self._canvas.delete("all")
204+
self._recognition_manager.reset_ink()
205+
206+
def _recognize(self):
207+
self._recognition_manager.recognize()
208+
209+
def _search(self):
210+
self._recognition_manager.search(self._search_variable.get())
211+
212+
def run(self):
213+
mainloop()
214+
# </SampleUI>
215+
216+
217+
if __name__ == "__main__":
218+
demo = InkRecognizerDemo()
219+
demo.run()

0 commit comments

Comments
 (0)