/// <summary> /// Connects all shapes in a sketch as well as possible. /// /// Precondition: the shapes of the sketch have identified types. /// /// Postconditions: /// - the shapes are connected and oriented according to the context domain. /// - no wires are connected to each other; connected wires are a single shape /// </summary> /// <param name="featureSketch">the sketch to connect</param> public virtual void process(Featurefy.FeatureSketch featureSketch) { recomputeConnectedShapes(featureSketch.Sketch.Shapes, featureSketch.Sketch); //foreach (Sketch.Shape shape in featureSketch.Sketch.ShapesL) //_domain.OrientShape(shape, featureSketch.Sketch); }
/// <summary> /// Uses WEKA to decide if each pair of strokes should be joined, then merges the paired strokes into shapes. /// </summary> public override void group(Featurefy.FeatureSketch featureSketch) { // Compile the substroke classification dictionary. Dictionary <Substroke, string> strokeClassifications = new Dictionary <Substroke, string>(); foreach (Substroke s in featureSketch.Sketch.Substrokes) { strokeClassifications.Add(s, s.Classification); } // Calculate pairwise feature values. Dictionary <string, Dictionary <FeatureStrokePair, double[]> > pairwiseValuesPerClass = featureSketch.GetValuesPairwise(strokeClassifications); List <StrokePair> pairsToJoin = groupWithWeka(pairwiseValuesPerClass); // Using the results from the StrokeGrouper, // make shapes by combining joined strokes. try { makeShapes(pairsToJoin, featureSketch.Sketch); } catch (NullReferenceException nre) { Console.WriteLine("Cannot call makeShapes(). \n" + nre.Message); } }
/// <summary> /// Sets up the caches for a given featureSketch. This step is very important, since without caching /// the search refiner is intolerably slow. /// </summary> /// <param name="featureSketch"></param> public virtual void Start(Featurefy.FeatureSketch featureSketch) { _classifications = new SmartCache <Substroke, string>( s => { return(_classifier.classify(s, featureSketch)); }); _identificationResults = new Dictionary <SubstrokeCollection, Dictionary <ShapeType, RecognitionResult> >(); }
/// <summary> /// Loads a Sketch into the InkSketch /// </summary> /// <param name="sketch">The sketch to load</param> /// Precondition: The InkSketch is clean (all dictionaries cleared etc) /// Postcondition: The InkSketch has the proper data members public StrokeCollection LoadSketch(Sketch.Sketch sketch) { project.sketch = sketch; featureSketch = FeatureSketch.MakeFeatureSketch(project); setUserSpecified(); return(CreateInkStrokesFromSketch()); }
/// <summary> /// Clears out the internal data structures for loading /// </summary> public void Clear() { createEmptySketch(); featureSketch = FeatureSketch.MakeFeatureSketch(project); ink2sketchStr.Clear(); sketchStr2ink.Clear(); substrokeIdMap.Clear(); }
/// <summary> /// Suppose that the given substrokes form a shape. What is the most likely type for it? /// </summary> /// <param name="substrokes"></param> /// <param name="featureSketch"></param> /// <returns></returns> private RecognitionResult Identify(SubstrokeCollection substrokes, Featurefy.FeatureSketch featureSketch) { RecognitionResult best = null; foreach (ShapeType type in LogicDomain.Types) { RecognitionResult result = RecognizeAsType(substrokes, type, featureSketch); double prob = result.Confidence; if (best == null || prob > best.Confidence) { best = result; } } return(best); }
/// <summary> /// Constructor for testing (where we pass in an initialized featureSketch) /// </summary> /// <param name="inkCanvas"></param> /// <param name="featureSketch"></param> public InkCanvasSketch(InkCanvas inkCanvas, FeatureSketch featureSketch) { this.inkCanvas = inkCanvas; this.featureSketch = featureSketch; // Don't have a circuit yet this.circuit = null; alreadyLoaded = new List <string>(); project = new Sketch.Project(); // Comply with XML format requirements dtGuid = new Guid(dtGuidString); idGuid = new Guid(idGuidString); Sketch.Units = DefaultSketchUnits; // Intialize other fields ink2sketchStr = new Dictionary <String, Guid?>(); sketchStr2ink = new Dictionary <Guid?, String>(); substrokeIdMap = new Dictionary <Guid?, Substroke>(); }
public strokeInfoForm(Featurefy.FeatureStroke strokeFeatures, Featurefy.FeatureSketch sketchFeatures, Microsoft.Ink.Stroke inkStroke, Substroke ss) { InitializeComponent(); this.inkMovedX = 0.0f; this.inkMovedY = 0.0f; this.scale = 2.0f; pictureInk = new InkPicture(); pictureInk.Bounds = new Rectangle(0, 0, this.Width - dataView.Width, this.Height); Controls.Add(pictureInk); r = new Renderer(); g = this.pictureInk.CreateGraphics(); pictureInk.Painted += new InkOverlayPaintedEventHandler(pictureInk_Painted); _sketchFeatures = sketchFeatures; _strokeFeatures = strokeFeatures; _inkStroke = inkStroke; _substroke = ss; this.pictureInk.Ink.CreateStroke(_inkStroke.GetPoints()); this.pictureInk.Ink.Strokes[0].DrawingAttributes.Color = Color.Red; populateListView(); //drawPrimitives(this.features); }
public List <SketchModification> SketchModifications(Featurefy.FeatureSketch featureSketch) { Sketch.Sketch sketch = featureSketch.Sketch; if (debug) { Console.WriteLine("Sketch Modifications:"); } // Used to assemble the list of results List <SketchModification> results = new List <SketchModification>(); // Precompute closest contexts for each shape Dictionary <Shape, Tuple <double, ConnectionContext> > closestContexts = new Dictionary <Shape, Tuple <double, ConnectionContext> >(); foreach (Shape shape in sketch.Shapes) { closestContexts.Add(shape, _domain.ClosestContext(shape)); } // ========================================================================================================== /* * Operation zero: running the connector is ALWAYS an option. */ //results.Add(new SketchModification(sketch, new RunConnectorOperation(featureSketch, _connector), computeEnergy)); // ========================================================================================================== /* * First things first: missing connections * This takes care of obvious connector problems. If there is a wire with a dangling endpoint and a * shape that would be better off connected to a wire, we make that connection. The benefit is: * benefit = 1 / distance * where "distance" is the minimum distance from the dangling endpoint to the shape. This will favor * close connections over distant ones. */ List <EndPoint> wiresMissingConnections = findWireEndpointsMissingConnections(sketch); List <Shape> nonWiresMissingWireConnections = findNonWiresMissingConnections(sketch, closestContexts); foreach (EndPoint wireEndpoint in wiresMissingConnections) { foreach (Shape shape in nonWiresMissingWireConnections) { Shape wire = wireEndpoint.ParentShape; if (debug) { Console.WriteLine("ACTION (connect wire endpoint): " + sketch + ", " + wire + ", " + wireEndpoint + ", " + shape); } var op = new ConnectEndpointOperation(sketch, wireEndpoint, shape); var modification = new SketchModification(featureSketch, op, computeEnergy); results.Add(modification); } } // ========================================================================================================== /* * Second: relabeling * Now we go through every shape and see if its context would be better matched as a different shape. * If so, we can change the shape. The benefit is the % improvement in context score plus the % * improvement in recognition quality. */ foreach (Shape shape in sketch.Shapes) { if (shape.AlreadyLabeled) { continue; } Tuple <double, ConnectionContext> currentContext = closestContexts[shape]; List <ShapeType> allTypes = LogicDomain.Types; foreach (ShapeType otherType in AlternateTypes(shape.Type)) { if (debug) { Console.WriteLine("ACTION (relabel shape): " + shape + ", " + otherType); } var op = new RelabelShapeOperation(sketch, shape, RecognizeAsType(shape, otherType, featureSketch)); var modification = new SketchModification(featureSketch, op, computeEnergy); results.Add(modification); } } // ========================================================================================================== /* * Third: stroke steal * This works as follows: * * For every shape, get the set of closeSubstrokes (within a certain threshold). * For every substroke in closeSubstrokes * generate a steal modification (substroke --> shape) * * The steal modifications should have their benefit based on * (1) connection contexts * (2) recognition quality */ foreach (Shape thief in sketch.Shapes) { if (thief.AlreadyLabeled) { continue; } List <Substroke> closeSubstrokes = findSubstrokesCloseTo(thief, sketch, STROKE_STEAL_THRESHOLD); foreach (Substroke gem in closeSubstrokes) // thiefs steal gems { Shape victim = gem.ParentShape; // thiefs steal from victims if (victim.AlreadyLabeled) { continue; } // find the thief's new type var newThiefSubstrokes = new List <Substroke>(thief.SubstrokesL); newThiefSubstrokes.Add(gem); RecognitionResult newThiefRecognition = Identify(newThiefSubstrokes, featureSketch); if (debug) { Console.WriteLine("ACTION (steal stroke): " + thief + ", " + victim + ", " + gem); } var stealOp = new StrokeStealOperation(sketch, thief, gem); var relabelThiefOp = new RelabelShapeOperation(sketch, thief, newThiefRecognition); var runConnectorOp = new RunConnectorOperation(featureSketch, _connector); ISketchOperation op; // if the victim will still be around after the steal if (victim.Substrokes.Length > 1) { var newVictimSubstrokes = new List <Substroke>(victim.SubstrokesL); newVictimSubstrokes.Remove(gem); RecognitionResult newVictimRecognition = Identify(newVictimSubstrokes, featureSketch); var relabelVictimOp = new RelabelShapeOperation(sketch, victim, newVictimRecognition); op = new CompoundSketchOperation(stealOp, relabelThiefOp, relabelVictimOp, runConnectorOp); } else { op = new CompoundSketchOperation(stealOp, relabelThiefOp, runConnectorOp); } var modification = new SketchModification(featureSketch, op, computeEnergy); results.Add(modification); } } if (debug && results.Count == 0) { Console.WriteLine("(none)"); } // Keep only the ones greater than the cutoff results = results.FindAll(r => { return(r.benefit() > BENEFIT_CUTOFF); }); return(results); }
/// <summary> /// Connects all shapes in a sketch as well as possible. /// /// Precondition: the shapes of the sketch have identified types. /// /// Postconditions: /// - the shapes are connected and oriented according to the context domain. /// - no wires are connected to each other; connected wires are a single shape /// </summary> /// <param name="featureSketch">the sketch to connect</param> public virtual void process(Featurefy.FeatureSketch featureSketch) { recomputeConnectedShapes(featureSketch.Sketch.Shapes, featureSketch.Sketch); }