static Point[] ScaleRegion(Point[] region, Point target, bool uniformScaling) { var centroid = Point2f.Zero; var min = new Point(int.MaxValue, int.MaxValue); var max = new Point(int.MinValue, int.MinValue); for (int i = 0; i < region.Length; i++) { centroid.X += region[i].X; centroid.Y += region[i].Y; min.X = Math.Min(min.X, region[i].X); min.Y = Math.Min(min.Y, region[i].Y); max.X = Math.Max(max.X, region[i].X); max.Y = Math.Max(max.Y, region[i].Y); } centroid.X /= region.Length; centroid.Y /= region.Length; var scale = new Point2f( 2 * (target.X - centroid.X) / (max.X - min.X), 2 * (target.Y - centroid.Y) / (max.Y - min.Y)); if (uniformScaling) { var scaleNorm = (float)Math.Sqrt(scale.X * scale.X + scale.Y * scale.Y); scale.X = scaleNorm; scale.Y = scaleNorm; } return(Array.ConvertAll(region, point => new Point( (int)((point.X - centroid.X) * scale.X + centroid.X), (int)((point.Y - centroid.Y) * scale.Y + centroid.Y)))); }
static Point[] CreateRectangularRegion(Point origin, Point location) { return(new[] { origin, new Point(location.X, origin.Y), location, new Point(origin.X, location.Y) }); }
static RotatedRect CreateEllipseRegion(Point origin, Point location) { RotatedRect region; region.Size = new Size2f(Math.Abs(location.X - origin.X), Math.Abs(location.Y - origin.Y)); region.Center = new Point2f((location.X + origin.X) / 2f, (location.Y + origin.Y) / 2f); region.Angle = 0; return(region); }
int NearestPoint(Point[] region, Point location) { return((from point in region.Select((p, i) => new { p, i }) let distanceX = location.X - point.p.X let distanceY = location.Y - point.p.Y orderby distanceX * distanceX + distanceY * distanceY ascending select point.i) .FirstOrDefault()); }
float TestIntersection(RotatedRect region, Point point) { var dx = point.X - region.Center.X; var dy = point.Y - region.Center.Y; var a = region.Size.Width * region.Size.Width / 4; var b = region.Size.Height * region.Size.Height / 4; return(dx * dx / a + dy * dy / b); }
Tuple <int, int> NearestLine(Point[] region, Point location) { var pointIndex = region .Concat(Enumerable.Repeat(region[0], 1)) .Select((p, i) => new { p, i = i % region.Length }); return((from line in pointIndex.Zip(pointIndex.Skip(1), (l0, l1) => Tuple.Create(l0, l1)) let lineDistance = PointLineSegmentDistance(location, line.Item1.p, line.Item2.p) orderby lineDistance ascending select Tuple.Create(line.Item1.i, line.Item2.i)) .FirstOrDefault()); }
double TestIntersection(Point[] region, Point point) { var regionHandle = GCHandle.Alloc(region, GCHandleType.Pinned); try { using (var mat = new Mat(region.Length, 1, Depth.S32, 2, regionHandle.AddrOfPinnedObject())) { return(CV.PointPolygonTest(mat, new Point2f(point.X, point.Y), true)); } } finally { regionHandle.Free(); } }
static Point[] CreateEllipseRegion(Point origin, Point location) { var region = new Point[36]; var scaleX = Math.Abs(location.X - origin.X) / 2f; var scaleY = Math.Abs(location.Y - origin.Y) / 2f; var center = new Point2f((location.X + origin.X) / 2f, (location.Y + origin.Y) / 2f); for (int i = 0; i < region.Length; i++) { var angle = i * 2 * Math.PI / region.Length; region[i].X = (int)Math.Round(Math.Cos(angle) * scaleX + center.X); region[i].Y = (int)Math.Round(Math.Sin(angle) * scaleY + center.Y); } return(region); }
static RotatedRect ScaleRegion(RotatedRect region, Point target, bool uniformScaling) { var size = new Size2f( 2 * Math.Abs(target.X - region.Center.X), 2 * Math.Abs(target.Y - region.Center.Y)); if (uniformScaling) { var sizeNorm = (float)Math.Sqrt(size.Width * size.Width + size.Height * size.Height); region.Size.Width = sizeNorm; region.Size.Height = sizeNorm; } else { region.Size = size; } return(region); }
Point EnsureSizeRatio(Point origin, Point location, bool square) { if (square) { var dx = location.X - origin.X; var dy = location.Y - origin.Y; var width = Math.Abs(dx); var height = Math.Abs(dy); if (width < height) { location.Y -= Math.Sign(dy) * (height - width); } else { location.X -= Math.Sign(dx) * (width - height); } } return(location); }
static RotatedRect MoveRegion(RotatedRect region, Point displacement) { region.Center += new Point2f(displacement); return(region); }
public void SetPoint(int regionIndex, int pointIndex, Point value) { Items[regionIndex][pointIndex] = value; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }
void Canvas_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.PageUp) { ImageScale += ScaleIncrement; } if (e.KeyCode == Keys.PageDown) { ImageScale -= ScaleIncrement; } if (e.Control && e.KeyCode == Keys.Z) { commandExecutor.Undo(); } if (e.Control && e.KeyCode == Keys.Y) { commandExecutor.Redo(); } if (e.Control && e.KeyCode == Keys.V) { var roiText = (string)Clipboard.GetData(DataFormats.Text); try { var mousePosition = PointToClient(MousePosition); var offset = NormalizedLocation(mousePosition.X, mousePosition.Y); var roiData = (int[])ArrayConvert.ToArray(roiText, 1, typeof(int)); var roi = new Point[roiData.Length / 2]; for (int i = 0, k = 0; i < roi.Length && k < roiData.Length; i++, k += 2) { roi[i].X = roiData[k + 0] - roiData[0] + offset.X; roi[i].Y = roiData[k + 1] - roiData[1] + offset.Y; } var selection = selectedRoi; commandExecutor.Execute( () => AddRegion(roi), () => { regions.Remove(roi); SelectedRegion = selection; }); } catch (ArgumentException) { } catch (InvalidCastException) { } catch (FormatException) { } } if (selectedRoi.HasValue) { if (e.Control && e.KeyCode == Keys.C) { var roi = regions[selectedRoi.Value]; var roiData = new int[roi.Length * 2]; for (int i = 0, k = 0; i < roi.Length && k < roiData.Length; i++, k += 2) { roiData[k + 0] = roi[i].X; roiData[k + 1] = roi[i].Y; } Clipboard.SetData(DataFormats.Text, ArrayConvert.ToString(roiData)); } if (e.KeyCode == Keys.Delete) { var selection = selectedRoi.Value; var region = regions[selection]; commandExecutor.Execute( () => { regions.RemoveAt(selection); SelectedRegion = null; }, () => { regions.Insert(selection, region); SelectedRegion = selection; }); } } }
static float PointLineSegmentDistance(Point point, Point line0, Point line1) { return(PointLineSegmentDistance(new Vector2(point.X, point.Y), new Vector2(line0.X, line0.Y), new Vector2(line1.X, line1.Y))); }
static Point[] MoveRegion(Point[] region, Point displacement) { return(Array.ConvertAll(region, point => point + displacement)); }
public ImageRoiPicker() { Canvas.KeyDown += Canvas_KeyDown; commandExecutor.StatusChanged += commandExecutor_StatusChanged; regions.CollectionChanged += regions_CollectionChanged; var mouseDoubleClick = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseDoubleClick").Select(e => e.EventArgs); var mouseMove = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseMove").Select(e => e.EventArgs); var mouseDown = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseDown").Select(e => e.EventArgs); var mouseUp = Observable.FromEventPattern <MouseEventArgs>(Canvas, "MouseUp").Select(e => e.EventArgs); var roiSelected = from downEvt in mouseDown where Image != null let location = NormalizedLocation(downEvt.X, downEvt.Y) let selection = (from region in regions.Select((polygon, i) => new { polygon, i = (int?)i }) let distance = TestIntersection(region.polygon, location) where distance > 0 orderby distance select region.i) .FirstOrDefault() select new Action(() => SelectedRegion = selection); var roiMoveScale = (from downEvt in mouseDown where Image != null && downEvt.Button == MouseButtons.Left && selectedRoi.HasValue let location = NormalizedLocation(downEvt.X, downEvt.Y) let selection = selectedRoi.Value let region = regions[selection] select(from moveEvt in mouseMove.TakeUntil(mouseUp) let target = NormalizedLocation(moveEvt.X, moveEvt.Y) let modifiedRegion = ModifierKeys.HasFlag(Keys.Shift) ? ScaleRegion(region, target, ModifierKeys.HasFlag(Keys.Control)) : MoveRegion(region, target - location) let modifiedRectangle = RegionRectangle(modifiedRegion) where modifiedRectangle.Left >= 0 && modifiedRectangle.Top >= 0 && modifiedRectangle.Right < Image.Width && modifiedRectangle.Bottom < Image.Height select modifiedRegion) .Publish(ps => ps.TakeLast(1).Do(modifiedRegion => commandExecutor.Execute( () => regions[selection] = modifiedRegion, () => regions[selection] = region)) .Merge(ps)) .Select(displacedRegion => new Action(() => regions[selectedRoi.Value] = displacedRegion))) .Switch(); var pointMove = (from downEvt in mouseDown where Image != null && downEvt.Button == MouseButtons.Right && selectedRoi.HasValue let location = NormalizedLocation(downEvt.X, downEvt.Y) let selection = selectedRoi.Value let region = regions[selection] let nearestPoint = NearestPoint(region, location) let source = regions[selection][nearestPoint] select(from moveEvt in mouseMove.TakeUntil(mouseUp) let target = NormalizedLocation(moveEvt.X, moveEvt.Y) select target) .Publish(ps => ps.TakeLast(1).Do(target => commandExecutor.Execute( () => regions.SetPoint(selection, nearestPoint, target), () => regions.SetPoint(selection, nearestPoint, source))) .Merge(ps)) .Select(target => new Action(() => regions.SetPoint(selection, nearestPoint, target)))) .Switch(); var regionInsertion = (from downEvt in mouseDown where Image != null && downEvt.Button == MouseButtons.Left && !selectedRoi.HasValue let count = regions.Count let origin = NormalizedLocation(downEvt.X, downEvt.Y) select(from moveEvt in mouseMove.TakeUntil(mouseUp) let location = EnsureSizeRatio(origin, NormalizedLocation(moveEvt.X, moveEvt.Y), ModifierKeys.HasFlag(Keys.Control)) select ModifierKeys.HasFlag(Keys.Shift) ? CreateEllipseRegion(origin, location) : CreateRectangularRegion(origin, location)) .Publish(ps => ps.TakeLast(1).Do(region => commandExecutor.Execute( () => { if (count == regions.Count) { AddRegion(region); } }, () => { regions.Remove(region); SelectedRegion = null; })) .Merge(ps)) .Select(region => new Action(() => { if (selectedRoi.HasValue) { regions[selectedRoi.Value] = region; } else { AddRegion(region); } }))) .Switch(); var pointInsertion = from clickEvt in mouseDoubleClick where Image != null && clickEvt.Button == MouseButtons.Left && selectedRoi.HasValue let location = NormalizedLocation(clickEvt.X, clickEvt.Y) let region = regions[selectedRoi.Value] let nearestLine = NearestLine(region, location) select new Action(() => { var resizeRegion = region; var line0 = region[nearestLine.Item1]; var line1 = region[nearestLine.Item2]; var midPoint = new Point((line0.X + line1.X) / 2, (line0.Y + line1.Y) / 2); Array.Resize(ref resizeRegion, resizeRegion.Length + 1); for (int i = resizeRegion.Length - 1; i > nearestLine.Item2; i--) { resizeRegion[i] = resizeRegion[i - 1]; } var selection = selectedRoi.Value; resizeRegion[nearestLine.Item2] = midPoint; commandExecutor.Execute( () => regions[selection] = resizeRegion, () => regions[selection] = region); }); var pointDeletion = from clickEvt in mouseDoubleClick where Image != null && clickEvt.Button == MouseButtons.Right && selectedRoi.HasValue let region = regions[selectedRoi.Value] where region.Length > 3 let location = NormalizedLocation(clickEvt.X, clickEvt.Y) let nearestPoint = NearestPoint(region, location) select new Action(() => { var selection = selectedRoi.Value; var resizeRegion = new Point[region.Length - 1]; Array.Copy(region, resizeRegion, nearestPoint); Array.Copy(region, nearestPoint + 1, resizeRegion, nearestPoint, region.Length - nearestPoint - 1); commandExecutor.Execute( () => regions[selection] = resizeRegion, () => regions[selection] = region); }); var roiActions = Observable.Merge(roiSelected, pointMove, roiMoveScale, pointInsertion, pointDeletion, regionInsertion); roiActions.Subscribe(action => { action(); }); }
public MatchPoint(OpenCV.Net.Point pt, double val) { X = pt.X; Y = pt.Y; Punctuality = val; }