在C# WPF中为给定点集生成平滑拟合曲线(附需求图)
需求:将不规则轮廓点集转换为平滑蛋形/椭圆形曲线

已通过EMGU-CV的FindContours方法获取图中红色标记线条的点集,需要在C# WPF中将其转换为蓝色线条所示的平滑蛋形/椭圆形曲线,消除不规则轮廓的锯齿边缘;也可通过图像处理实现该需求。
方案一:WPF中基于点集拟合平滑曲线
1. 椭圆拟合(最贴合蛋形需求)
既然目标是蛋形/椭圆形,直接对轮廓点集做椭圆拟合是最直接的方式,EMGU-CV原生支持椭圆拟合:
// 假设contour是FindContours得到的轮廓点集(VectorOfPoint类型) if (contour.Size > 5) // 拟合椭圆至少需要5个点 { Ellipse ellipse = CvInvoke.FitEllipse(contour); // 后续将椭圆参数转换为WPF可绘制元素 }
在WPF中绘制拟合后的椭圆:
// 转换EMGU-CV的坐标到WPF坐标系 Point center = new Point(ellipse.Center.X, ellipse.Center.Y); // EMGU返回的椭圆尺寸是直径,WPF的Ellipse用的是宽高(等价于直径) System.Windows.Shapes.Ellipse wpfEllipse = new System.Windows.Shapes.Ellipse() { Width = ellipse.Size.Width, Height = ellipse.Size.Height, Stroke = Brushes.Blue, StrokeThickness = 2, Fill = Brushes.Transparent }; // 设置椭圆位置 Canvas.SetLeft(wpfEllipse, center.X - ellipse.Size.Width / 2); Canvas.SetTop(wpfEllipse, center.Y - ellipse.Size.Height / 2); // 应用旋转角度 RotateTransform rotate = new RotateTransform(ellipse.Angle, center.X, center.Y); wpfEllipse.RenderTransform = rotate; // 添加到目标Canvas yourCanvas.Children.Add(wpfEllipse);
2. 贝塞尔曲线平滑(非严格椭圆场景)
如果需要保留原始轮廓的大致形态同时消除锯齿,可使用WPF的贝塞尔曲线拟合:
// 将EMGU点集转换为WPF的PointCollection PointCollection points = new PointCollection(); foreach (PointF pt in contour.ToArray()) { points.Add(new Point(pt.X, pt.Y)); } // 创建平滑路径几何 PathGeometry geometry = new PathGeometry(); PathFigure figure = new PathFigure { StartPoint = points[0], IsClosed = true }; for (int i = 1; i < points.Count - 1; i++) { Point midPoint = new Point((points[i].X + points[i+1].X)/2, (points[i].Y + points[i+1].Y)/2); QuadraticBezierSegment segment = new QuadraticBezierSegment(points[i], midPoint, true); figure.Segments.Add(segment); } geometry.Figures.Add(figure); // 创建并添加Path元素 Path smoothPath = new Path() { Data = geometry, Stroke = Brushes.Blue, StrokeThickness = 2, Fill = Brushes.Transparent }; yourCanvas.Children.Add(smoothPath);
方案二:图像处理方式(EMGU-CV直接处理)
1. 轮廓点集简化
使用Douglas-Peucker算法对原始轮廓点集做近似处理,减少冗余点的同时保留核心形状:
VectorOfPoint approxContour = new VectorOfPoint(); // 参数0.01为近似精度,可根据实际效果调整(值越大轮廓越简化) CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.01, true); // 之后可直接用approxContour拟合椭圆或绘制轮廓
2. 图像预处理+边缘检测
如果原始图像允许,先做模糊预处理再提取边缘,直接得到平滑轮廓:
// 假设src是原始输入图像 Mat blurred = new Mat(); CvInvoke.GaussianBlur(src, blurred, new Size(5,5), 0); // 高斯模糊消除噪点和锯齿 Mat edges = new Mat(); CvInvoke.Canny(blurred, edges, 50, 150); // 提取平滑边缘 // 对edges图重新执行FindContours,得到的轮廓会更平滑
内容的提问来源于stack exchange,提问作者aru
相关产品推荐
相关产品推荐

