20240930

using System.IO;
using System.Diagnostics;
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using System;
using System.Windows.Controls; // 对于 WPF 中的 Image 控件
using System.Windows;
using System.Windows.Media.Imaging;
using Point = OpenCvSharp.Point;
using System.Collections.Generic;
using System.Windows.Input;
using System.Windows.Media; // 添加这一行
using System.Windows.Shapes; // 用于 Polyline 和 Ellipse




namespace OpenCvWpfApp
{
    public partial class MainWindow : System.Windows.Window
    {
         private double zoomFactor = 1.0; // 初始缩放因子
         private double offsetX = 0; // 添加 offsetX
         private double offsetY = 0; // 添加 offsetY
         private List<Point> selectedContourPoints = new List<Point>();
         private Point[][] contours;
         private Mat baseImage;
         private Mat drawImage;
         private double epsilon = 0.003;
         private List<LineSegmentPoint> lineSegments = new List<LineSegmentPoint>(); // 存储线段
         private Scalar[] colors; // 颜色数组


         public MainWindow()
        {
            InitializeComponent();
            colors = new Scalar[] // 移到构造函数中
            {
                Scalar.Red,
                Scalar.Green,
                Scalar.Blue,
                Scalar.Yellow,
                Scalar.Cyan,
                Scalar.Magenta
            };
            LoadImages();
            this.WindowState = WindowState.Maximized; // 窗口启动时最大化
            this.ResizeMode = ResizeMode.CanResize; // 允许调整窗口大小
        }
 
         private void LoadImages()
        {
            string baseImagePath = @"D:/BodorCV/SpaceEye/MultiTask/SegLoc/71.bmp";
            string maskImagePath = @"D:/BodorCV/SpaceEye/MultiTask/SegLoc/72.bmp";
            baseImage = Cv2.ImRead(baseImagePath, ImreadModes.Color);
            drawImage = baseImage.Clone();
            Mat maskImage = Cv2.ImRead(maskImagePath, ImreadModes.Grayscale);

            if (baseImage.Empty() || maskImage.Empty())
            {
                MessageBox.Show("Failed to load images.");
                return;
            }

            //MessageBox.Show($"Loaded base image size: {baseImage.Size()}");
            //MessageBox.Show($"Loaded mask image size: {maskImage.Size()}");

            //LogMessage($"Loaded base image size: {baseImage.Size()}");
            //LogMessage($"Loaded mask image size: {maskImage.Size()}");


            //UpdateContours(baseImage.CvtColor(ColorConversionCodes.BGR2GRAY));

            // 使用 Dispatcher 延迟调用 UpdateContours
            //避免在控件尚未完全初始化时进行图像处理和显示
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                UpdateContours(baseImage.CvtColor(ColorConversionCodes.BGR2GRAY));
            }), System.Windows.Threading.DispatcherPriority.Loaded);
        }


         private void epsilonSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (baseImage == null)
                return; // 确保图像已加载

            epsilon = e.NewValue;
            UpdateContours(baseImage.CvtColor(ColorConversionCodes.BGR2GRAY));
        }

        private void UpdateContours(Mat maskImage)
        {
            // 清空画布
            drawingCanvas.Children.Clear();

            // 将 Mat 转换为 BitmapSource
            BitmapSource bitmapSource = drawImage.ToBitmapSource();

            double canvasWidth = drawingCanvas.ActualWidth;
            double canvasHeight = drawingCanvas.ActualHeight;

            // 计算显示比例
            double scaleX = canvasWidth / bitmapSource.PixelWidth;
            double scaleY = canvasHeight / bitmapSource.PixelHeight;
            double scale = Math.Min(scaleX, scaleY);

            // 计算居中偏移
            double offsetX = (canvasWidth - bitmapSource.PixelWidth * scale) / 2;
            double offsetY = (canvasHeight - bitmapSource.PixelHeight * scale) / 2;

            // 添加底图
            Image backgroundImage = new Image
            {
                Source = bitmapSource,
                Width = bitmapSource.PixelWidth * scale,
                Height = bitmapSource.PixelHeight * scale,
                Stretch = Stretch.Uniform
            };
            Canvas.SetLeft(backgroundImage, offsetX);
            Canvas.SetTop(backgroundImage, offsetY);
            drawingCanvas.Children.Add(backgroundImage);

            // 查找轮廓
            Cv2.FindContours(maskImage, out contours, out HierarchyIndex[] hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);

            // 基础色数组(红色系、绿色系、蓝色系)
            Brush[][] colorSchemes = new Brush[][]
            {
            new Brush[] { Brushes.Red, Brushes.OrangeRed, Brushes.IndianRed, Brushes.LightCoral }, // 红色系
            new Brush[] { Brushes.Green, Brushes.LimeGreen, Brushes.LightGreen, Brushes.DarkGreen }, // 绿色系
            new Brush[] { Brushes.Blue, Brushes.CornflowerBlue, Brushes.LightBlue, Brushes.DarkBlue } // 蓝色系
            };

            // 存储近似点和线段
            List<Ellipse> approxPoints = new List<Ellipse>();
            List<Polyline> segmentPolylines = new List<Polyline>();

            // 绘制轮廓中的点和线
            for (int i = 0; i < contours.Length; i++)
            {
                var contour = contours[i];
                PointCollection originalPoints = new PointCollection();
                foreach (var point in contour)
                {
                    // 计算并添加点
                    var scaledPoint = new System.Windows.Point(point.X * scale + offsetX, point.Y * scale + offsetY);
                    originalPoints.Add(scaledPoint);
                }

                // 选择基础色
                Brush baseColor = colorSchemes[i % colorSchemes.Length][0]; // 使用基础色

                // 创建并添加原始轮廓的 Polyline
                Polyline originalPolyline = new Polyline
                {
                    Points = originalPoints,
                    Stroke = baseColor, // 使用基础色
                    StrokeThickness = 2
                };

                originalPolyline.MouseLeftButtonDown += OriginalPolyline_MouseLeftButtonDown;//为原始线段添加鼠标点击事件
                drawingCanvas.Children.Add(originalPolyline);

                // 近似多边形绘制
                Point[] approx = Cv2.ApproxPolyDP(contour, epsilon * Cv2.ArcLength(contour, true), true);
                PointCollection approxPointsCollection = new PointCollection();
                foreach (var point in approx)
                {
                    var scaledPoint = new System.Windows.Point(point.X * scale + offsetX, point.Y * scale + offsetY);
                    approxPointsCollection.Add(scaledPoint);
                }

                // 确保近似多边形闭合
                if (approxPointsCollection.Count > 0)
                {
                    approxPointsCollection.Add(approxPointsCollection[0]); // 将第一个点添加到最后以闭合多边形
                }

                // 创建并添加每一段的 Polyline
                for (int j = 0; j < approxPointsCollection.Count - 1; j++)
                {
                    // 选择近似线段的颜色(交替深色和浅色)
                    Brush approxColor = (j % 2 == 0) ? colorSchemes[i % colorSchemes.Length][1] : colorSchemes[i % colorSchemes.Length][2]; // 深色或浅色

                    // 创建当前线段的 Polyline
                    Polyline segmentPolyline = new Polyline
                    {
                        Points = new PointCollection { approxPointsCollection[j], approxPointsCollection[j + 1] },
                        Stroke = approxColor, // 使用近似线段的颜色
                        StrokeThickness = 2
                    };

                    // 为当前线段添加鼠标点击事件
                    segmentPolyline.MouseLeftButtonDown += ApproxPolyline_MouseLeftButtonDown;//为近似线段添加鼠标点击事件
                    drawingCanvas.Children.Add(segmentPolyline);// 将轮廓添加到画布
                    segmentPolylines.Add(segmentPolyline); // 存储线段
                }

                // 绘制近似点(黄色)
                foreach (var point in approxPointsCollection)
                {
                    Ellipse pointEllipse = new Ellipse
                    {
                        Fill = Brushes.Yellow,
                        Width = 10, // 点的宽度
                        Height = 10  // 点的高度
                    };
                    Canvas.SetLeft(pointEllipse, point.X - pointEllipse.Width / 2);
                    Canvas.SetTop(pointEllipse, point.Y - pointEllipse.Height / 2);

                    // 添加鼠标事件以实现拖动
                    pointEllipse.MouseLeftButtonDown += (sender, e) =>
                    {
                        pointEllipse.CaptureMouse();
                        System.Windows.Point mousePosition = e.GetPosition(drawingCanvas);

                        // 使用不同的名称以避免冲突
                        double dragOffsetX = mousePosition.X - Canvas.GetLeft(pointEllipse);
                        double dragOffsetY = mousePosition.Y - Canvas.GetTop(pointEllipse);

                        // 拖动事件
                        drawingCanvas.MouseMove += (moveSender, moveArgs) =>
                        {
                            if (pointEllipse.IsMouseCaptured)
                            {
                                System.Windows.Point currentMousePosition = moveArgs.GetPosition(drawingCanvas);
                                Point newPosition = new Point(currentMousePosition.X - dragOffsetX, currentMousePosition.Y - dragOffsetY);

                                // 更新点的位置
                                Canvas.SetLeft(pointEllipse, currentMousePosition.X - dragOffsetX);
                                Canvas.SetTop(pointEllipse, currentMousePosition.Y - dragOffsetY);

                                // 更新连接的线段
                                UpdateSegmentLines(segmentPolylines, approxPointsCollection);
                            }
                        };

                        // 释放鼠标
                        pointEllipse.MouseLeftButtonUp += (upSender, upArgs) =>
                        {
                            pointEllipse.ReleaseMouseCapture();
                            drawingCanvas.MouseMove -= (moveSender, moveArgs) => { }; // 移除拖动事件
                        };

                    };
                    drawingCanvas.Children.Add(pointEllipse);
                    approxPoints.Add(pointEllipse); // 存储近似点
                }
            }

            // 添加 MouseMove 事件处理程序
            drawingCanvas.MouseMove += DrawingCanvas_MouseMove;
        }

        // 更新连接线段的位置
        private void UpdateSegmentLines(List<Polyline> segmentPolylines, PointCollection approxPoints)
        {
            for (int i = 0; i < segmentPolylines.Count; i++)
            {
                var polyline = segmentPolylines[i];
                if (i < approxPoints.Count - 1)
                {
                    polyline.Points.Clear();
                    polyline.Points.Add(approxPoints[i]);
                    polyline.Points.Add(approxPoints[i + 1]);
                }
            }
        }

        private void DrawingCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            System.Windows.Point mousePosition = e.GetPosition(drawingCanvas);
            Point openCvPoint = new Point((int)mousePosition.X, (int)mousePosition.Y);


            // 遍历画布中的所有子元素
            foreach (var child in drawingCanvas.Children)
            {
                if (child is Polyline polyline)
                {
                    // 检查鼠标是否在 Polyline 上
                    if (IsMouseOverPolyline(polyline, openCvPoint))
                    {
                        polyline.StrokeThickness = 4; // 增加线条粗细
                    }
                    else
                    {
                        polyline.StrokeThickness = 2; // 恢复线条粗细
                    }
                }
            }
        }

         // 检查鼠标是否在 Polyline 上
         private bool IsMouseOverPolyline(Polyline polyline, OpenCvSharp.Point mousePosition)
    {
        // 将 OpenCvSharp.Point 转换为 System.Windows.Point
        var mousePoint = new System.Windows.Point(mousePosition.X, mousePosition.Y);

        // 使用 Geometry 对象来检查点是否在多边形上
        var geometry = new PathGeometry();
        var figure = new PathFigure { StartPoint = polyline.Points[0] };
        for (int i = 1; i < polyline.Points.Count; i++)
        {
            figure.Segments.Add(new LineSegment(polyline.Points[i], true));
        }
        geometry.Figures.Add(figure);

        // 检查鼠标位置是否在多边形的 Geometry 内
        return geometry.FillContains(mousePoint) || IsPointOnPolyline(geometry, mousePosition);
    }

         // 辅助方法:检查点是否在多边形的边界上
         private bool IsPointOnPolyline(Geometry geometry, Point point)
    {
        // 创建一个 Pen 来定义边界的宽度
        var pen = new Pen(Brushes.Black, 1); // 这里的宽度可以根据需要调整
        var strokeGeometry = geometry.GetWidenedPathGeometry(pen);

        var Point = new System.Windows.Point(point.X, point.Y);
        return strokeGeometry.FillContains(Point);
    }
        // 处理原始轮廓的点击事件
        private void OriginalPolyline_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Polyline polyline = sender as Polyline;
            if (polyline != null)
            {
                // 选中效果,例如改变颜色
                polyline.Stroke = Brushes.Red; // 改变颜色以表示选中
                MessageBox.Show("原始轮廓被选中!");
            }
        }

         // 处理近似轮廓的点击事件
          private void ApproxPolyline_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Polyline polyline = sender as Polyline;
            if (polyline != null)
            {
                // 选中效果,例如改变颜色
                polyline.Stroke = Brushes.Yellow; // 改变颜色以表示选中
                MessageBox.Show("近似轮廓被选中!");
            }
        }

         //获取所有轮廓
         private List<Point> GetContourSegment(Point[] contour, Point start, Point end)//存在bug,选中所有轮廓了
            {
                List<Point> segment = new List<Point>();
                bool isCollecting = false;
                bool hasWrapped = false; // 添加标志以检测是否已经环绕一周

                // 遍历轮廓点,收集从 start 到 end 的所有点
                foreach (var point in contour)
                {
                    if (point == start)
                    {
                        if (isCollecting && segment.Count > 0 && segment[0] == start)
                        {
                            // 如果再次遇到起始点且已开始收集,则停止(防止无限循环)
                            break;
                        }
                        isCollecting = true;
                        segment.Add(point);
                    }
                    else if (point == end && isCollecting)
                    {
                        segment.Add(point);
                        break;
                    }
                    else if (isCollecting)
                    {
                        segment.Add(point);
                    }
                }

                // 如果没有找到结束点,可能是因为轮廓是闭合的,需要从头开始收集
                if (segment.Count > 0 && segment[segment.Count - 1] != end)
                {
                    foreach (var point in contour)
                    {
                        if (hasWrapped && point == start)
                        {
                            // 如果再次到达起始点,则停止(防止无限循环)
                            break;
                        }
                        segment.Add(point);
                        if (point == end)
                        {
                            break;
                        }
                        hasWrapped = true; // 标记已经环绕一周
                    }
                }

                return segment;
            }


         //↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓缩放操作↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
         private void DrawingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
            {
                // 检查是否按下了 Ctrl 键
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    // 获取鼠标相对于 Canvas 的位置
                    System.Windows.Point mousePosition = e.GetPosition(drawingCanvas);

                    // 根据滚轮的方向调整缩放因子
                    if (e.Delta > 0) // 向上滚动
                    {
                        zoomFactor *= 1.1; // 放大
                    }
                    else // 向下滚动
                    {
                        zoomFactor /= 1.1; // 缩小
                    }

                    // 更新画布上的内容
                    UpdateCanvas(mousePosition);

                    // 防止滚动事件被进一步处理
                    e.Handled = true;
                }
            }
         private void UpdateCanvas(System.Windows.Point mousePosition)
            {
                // 假设 drawImage 是一个可绘制的对象,转换为位图
                BitmapSource bitmap = drawImage.ToWriteableBitmap();
                double imageWidth = bitmap.PixelWidth * zoomFactor; // 计算缩放后的宽度
                double imageHeight = bitmap.PixelHeight * zoomFactor; // 计算缩放后的高度

                // 计算图像重心
                double centerX = imageWidth / 2;
                double centerY = imageHeight / 2;

                // 创建或更新背景图像
                Image backgroundImage = new Image
                {
                    Source = bitmap,
                    Width = imageWidth,
                    Height = imageHeight,
                    Stretch = Stretch.Uniform
                };

                // 计算新的图像位置以保持重心不变
                double newLeft = (drawingCanvas.ActualWidth - imageWidth) / 2 + (centerX - mousePosition.X) * (zoomFactor - 1);
                double newTop = (drawingCanvas.ActualHeight - imageHeight) / 2 + (centerY - mousePosition.Y) * (zoomFactor - 1);

                // 清空画布并重新绘制图像
                drawingCanvas.Children.Clear();
                Canvas.SetLeft(backgroundImage, newLeft);
                Canvas.SetTop(backgroundImage, newTop);
                drawingCanvas.Children.Add(backgroundImage); // 添加图像到画布

                // 应用缩放变换
                ScaleTransform scaleTransform = new ScaleTransform(zoomFactor, zoomFactor, centerX, centerY);
                drawingCanvas.RenderTransform = scaleTransform;

                // 重新绘制矢量图形
                DrawVectorGraphics();
            }

         private void DrawVectorGraphics()
            {
                // 绘制轮廓中的点和线
                foreach (var contour in contours)
                {
                    PointCollection originalPoints = new PointCollection();
                    foreach (var point in contour)
                    {
                        // 根据缩放和偏移量计算点的位置
                        double scaledX = point.X * zoomFactor + offsetX; // 使用 zoomFactor
                        double scaledY = point.Y * zoomFactor + offsetY; // 使用 zoomFactor

                        originalPoints.Add(new System.Windows.Point(scaledX, scaledY));

                         绘制点
                        //Ellipse ellipse = new Ellipse
                        //{
                        //    Fill = Brushes.Red,
                        //    Width = 5,
                        //    Height = 5
                        //};
                        //Canvas.SetLeft(ellipse, scaledX - 2.5); // 中心对齐
                        //Canvas.SetTop(ellipse, scaledY - 2.5);   // 中心对齐
                        //drawingCanvas.Children.Add(ellipse);
                    }

                    // 创建并添加原始轮廓的 Polyline
                    Polyline originalPolyline = new Polyline
                    {
                        Points = originalPoints,
                        Stroke = Brushes.Blue,
                        StrokeThickness = 2
                    };
                    drawingCanvas.Children.Add(originalPolyline);

                    // 近似多边形
                    Point[] approx = Cv2.ApproxPolyDP(contour, epsilon * Cv2.ArcLength(contour, true), true);
                    PointCollection approxPoints = new PointCollection();
                    foreach (var point in approx)
                    {
                        // 根据缩放和偏移量计算近似多边形的点的位置
                        double approxScaledX = point.X * zoomFactor + offsetX; // 使用 zoomFactor
                        double approxScaledY = point.Y * zoomFactor + offsetY; // 使用 zoomFactor
                        approxPoints.Add(new System.Windows.Point(approxScaledX, approxScaledY));

                        // 绘制近似多边形的点
                        Ellipse approxEllipse = new Ellipse
                        {
                            Fill = Brushes.Yellow, // 设置为黄色
                            Width = 5,
                            Height = 5
                        };
                        Canvas.SetLeft(approxEllipse, approxScaledX - 2.5); // 中心对齐
                        Canvas.SetTop(approxEllipse, approxScaledY - 2.5);   // 中心对齐
                        drawingCanvas.Children.Add(approxEllipse);
                    }

                    // 确保近似多边形闭合
                    if (approxPoints.Count > 0)
                    {
                        approxPoints.Add(approxPoints[0]); // 将第一个点添加到最后以闭合多边形
                    }

                    // 创建并添加近似多边形的 Polyline
                    Polyline approxPolyline = new Polyline
                    {
                        Points = approxPoints,
                        Stroke = Brushes.Green,
                        StrokeThickness = 2
                    };
                    drawingCanvas.Children.Add(approxPolyline);
                }

                // 其他矢量图形的绘制逻辑...
            }
         //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑缩放操作↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


         private void DrawingCanvas_MouseEnter(object sender, MouseEventArgs e)
        {

        }

         private void DrawingCanvas_MouseLeave(object sender, MouseEventArgs e)
        {

        }

         private double DistanceToSegment(Point p, Point v, Point w)
        {
            double l2 = Math.Pow(v.X - w.X, 2) + Math.Pow(v.Y - w.Y, 2); // 线段的平方长度
            if (l2 == 0) return Math.Sqrt(Math.Pow(p.X - v.X, 2) + Math.Pow(p.Y - v.Y, 2)); // v 和 w 重合

            // 投影计算
            double t = ((p.X - v.X) * (w.X - v.X) + (p.Y - v.Y) * (w.Y - v.Y)) / l2;
            t = Math.Max(0, Math.Min(1, t)); // 限制 t 在 [0, 1] 范围内

            Point projection = new Point(v.X + t * (w.X - v.X), v.Y + t * (w.Y - v.Y)); // 计算投影点
            return Math.Sqrt(Math.Pow(p.X - projection.X, 2) + Math.Pow(p.Y - projection.Y, 2)); // 返回距离
        }

         private void LogMessage(string message)
        {
            string logFilePath = @"C:\Users\011241\Desktop\surplus.txt";
            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                writer.WriteLine($"{DateTime.Now}: {message}");
            }
        }

    }

    public struct LineSegmentPoint
    {
        public Point P1;
        public Point P2;
        public Scalar Color; // 颜色属性
        public int ContourIndex; // 该线段所属的轮廓索引
        public List<Point> ContourPoints; // 包含的轮廓点
        public bool IsHighlighted; // 是否被高亮的标志

        public LineSegmentPoint(Point p1, Point p2, Scalar color, int contourIndex, List<Point> contourPoints, bool isHighlighted)
        {
            P1 = p1;
            P2 = p2;
            Color = color;
            ContourIndex = contourIndex; // 记录轮廓索引
            ContourPoints = contourPoints; // 记录轮廓点
            IsHighlighted = isHighlighted; // 记录是否被高亮
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值