墨迹分隔器示例
此示例基于 Ink 集合示例。 它演示如何使用 分隔器 对象来分析墨迹输入。
更新窗体时,示例将围绕每个分析单元绘制一个边框,分为单词、线条、段落和绘图。 除了使用不同的颜色外,这些矩形还按不同的量放大,以确保没有一个矩形被其他矩形遮盖。 下表指定了每个分析单元的颜色和放大。
分析单位 | Color | 像素放大 |
---|---|---|
Word |
绿色 |
1 |
折线图 |
洋红色 |
3 |
Paragraph |
蓝色 |
5 |
绘图 |
Red |
1 |
设置窗体
加载窗体时,将创建 一个 Divider 对象。 创建 InkOverlay 对象并将其与窗体上的面板相关联。 然后,事件处理程序将附加到 InkOverlay 对象,以跟踪何时添加和删除笔划。 然后,如果识别器可用,则会将默认识别器的 RecognizerContext 对象分配给分隔器。 然后设置分隔符对象的 LineHeight 属性,并将 InkOverlay 对象的 Strokes 集合分配给除法器。 最后,启用 InkOverlay 对象。
// Create the ink overlay and associate it with the form
myInkOverlay = new Microsoft.Ink.InkOverlay(DrawArea.Handle);
// Set the erasing mode to stroke erase.
myInkOverlay.EraserMode = InkOverlayEraserMode.StrokeErase;
// Hook event handler for the Stroke event to myInkOverlay_Stroke.
// This is necessary since the application needs to pass the strokes
// to the ink divider.
myInkOverlay.Stroke += new InkCollectorStrokeEventHandler(myInkOverlay_Stroke);
// Hook the event handler for StrokeDeleting event to myInkOverlay_StrokeDeleting.
// This is necessary as the application needs to remove the strokes from
// ink divider object as well.
myInkOverlay.StrokesDeleting += new InkOverlayStrokesDeletingEventHandler(myInkOverlay_StrokeDeleting);
// Hook the event handler for StrokeDeleted event to myInkOverlay_StrokeDeleted.
// This is necessary to update the layout analysis result when automatic layout analysis
// option is selected.
myInkOverlay.StrokesDeleted += new InkOverlayStrokesDeletedEventHandler(myInkOverlay_StrokeDeleted);
// Create the ink divider object
myInkDivider = new Divider();
// Add a default recognizer context to the divider object
// without adding the recognizer context, the divider would
// not use a recognizer to do its word segmentation and would
// have less accurate results.
// Adding the recognizer context slows down the call to
// myInkDivider.Divide though.
// It is possible that there is no recognizer installed on the
// machine for this language. In that case the divider does
// not use a recognizer to improve its accuracy.
// Get the default recognizer if any
try
{
Recognizers recognizers = new Recognizers();
myInkDivider.RecognizerContext = recognizers.GetDefaultRecognizer().CreateRecognizerContext();
}
catch (InvalidOperationException)
{
//We are in the case where no default recognizers can be found
}
// The LineHeight property helps the InkDivider distinguish between
// drawing and handwriting. The value should be the expected height
// of the user's handwriting in ink space units (0.01mm).
// Here we set the LineHeight to 840, which is about 1/3 of an inch.
myInkDivider.LineHeight = 840;
// Assign ink overlay's strokes collection to the ink divider
// This strokes collection is updated in the event handler
myInkDivider.Strokes = myInkOverlay.Ink.Strokes;
// Enable ink collection
myInkOverlay.Enabled = true;
(通过 InkOverlay 对象的 Ink 属性) 访问,必须将 Divider 对象的 Strokes 集合与 InkOverlay 对象的 Strokes 集合保持同步。 为确保发生这种情况,InkOverlay 对象的 Stroke 事件处理程序编写如下。 请注意,事件处理程序首先测试是否将 EditingMode 设置为 Ink 以筛选掉橡皮擦笔划。 如果用户已请求自动布局分析,则应用程序会调用窗体的 DivideInk 方法并刷新绘图区域。
private void myInkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e )
{
// Filter out the eraser stroke.
if(InkOverlayEditingMode.Ink == myInkOverlay.EditingMode)
{
// Add the new stroke to the ink divider's strokes collection
myInkDivider.Strokes.Add(e.Stroke);
if(miAutomaticLayoutAnalysis.Checked)
{
// Call DivideInk
DivideInk();
// Repaint the screen to reflect the change
DrawArea.Refresh();
}
}
}
划分墨迹
当用户单击“文件”菜单上的“除法”时, 将在 Divideer 对象上调用 Divide 方法。 使用默认识别器(如果可用)。
DivisionResult divResult = myInkDivider.Divide();
变量 引用divResult
的生成的 DivisionResult 对象将传递给实用工具函数 getUnitBBBoxes()
。 实用工具函数返回请求的任何除法类型的矩形数组:段、线条、段落或绘图。
myWordBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Segment, 1);
myLineBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Line, 3);
myParagraphBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Paragraph, 5);
myDrawingBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Drawing, 1);
最后,强制重绘窗体面板,以便显示边框。
DrawArea.Refresh();
墨迹分析结果
在实用工具函数中,根据调用方请求的除法类型,使用 ResultByType 方法查询 DivisionResult 对象的结果。 ResultByType 方法返回 一个 DivisionUnits 集合。 集合中的每个 DivisionUnit 都表示一个绘图、单个手写识别段、一行手写或一个手写块,具体取决于调用实用工具函数时指定的内容。
DivisionUnits units = divResult.ResultByType(divType);
如果至少有一个 DivisionUnit,则会创建包含每个单元一个边界矩形的矩形数组。 (矩形按每种类型的单位的不同量进行膨胀(保存在 inflate 变量中)以防止重叠。)
// If there is at least one unit, we construct the rectangles
if((null != units) && (0 < units.Count))
{
// We need to convert rectangles from ink units to
// pixel units. For that, we need Graphics object
// to pass to InkRenderer.InkSpaceToPixel method
using (Graphics g = DrawArea.CreateGraphics())
{
// InkSpace to Pixel Space conversion setup done here.
// Not shown for brevity.
// Iterate through the collection of division units to obtain the bounding boxes
foreach(DivisionUnit unit in units)
{
// Get the bounding box of the strokes of the division unit
divRects[i] = unit.Strokes.GetBoundingBox();
// Div unit rect Ink space to Pixel space conversion done here.
// Not shown for brevity.
// Inflate the rectangle by inflate pixels in both directions
divRects[i].Inflate(inflate, inflate);
// Increment the index
++i;
}
} // Relinquish the Graphics object
}
重绘窗体
当在上面强制重绘时,以下代码将执行以在墨迹周围的窗体上绘制每个 DivisionUnit 的边界框。
private void DrawArea_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Create the Pen used to draw bounding boxes.
// First set of bounding boxes drawn here are
// the bounding boxes of paragraphs.
// These boxes are drawn with Blue pen.
Pen penBox = new Pen(Color.Blue, 2);
// First, draw the bounding boxes for Paragraphs
if(null != myParagraphBoundingBoxes)
{
// Draw bounding boxes for Paragraphs
e.Graphics.DrawRectangles(penBox, myParagraphBoundingBoxes);
}
// Next, draw the bounding boxes for Lines
if(null != myLineBoundingBoxes)
{
// Color is Magenta pen
penBox.Color = Color.Magenta;
// Draw the bounding boxes for Lines
e.Graphics.DrawRectangles(penBox, myLineBoundingBoxes);
}
// Then, draw the bounding boxes for Words
if(null != myWordBoundingBoxes)
{
// Color is Green
penBox.Color = Color.Green;
// Draw bounding boxes for Words
e.Graphics.DrawRectangles(penBox, myWordBoundingBoxes);
}
// Finally, draw the boxes for Drawings
if(null != myDrawingBoundingBoxes)
{
// Color is Red pen
penBox.Color = Color.Red;
// Draw bounding boxes for Drawings
e.Graphics.DrawRectangles(penBox, myDrawingBoundingBoxes);
}
}
关闭窗体
窗体的 Dispose 方法释放在示例中使用的 InkOverlay、 Divider、 RecognizerContext 对象和 Strokes 集合。