news 2026/4/16 14:05:01

基于WPFOpencv 高级显示控件2.0 全新优化,支持图像拖入显示,使用wpf的adno...

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于WPFOpencv 高级显示控件2.0 全新优化,支持图像拖入显示,使用wpf的adno...

基于WPF&Opencv 高级显示控件2.0 全新优化,支持图像拖入显示,使用wpf的adnoner和thumb实现可交互的绘图对象。

一、项目基础信息与环境配置

(一)项目结构与依赖

根据代码文件目录,项目分为WindowControl控件库与WindowControlDemo演示程序两大模块,总计57个文件,核心文件分布如下:

模块核心文件功能定位
WindowControlDrawingObject.cs、WindowSmartControl.xaml.cs、ImageConvertor.cs控件核心逻辑,含绘图对象、交互控制、图像转换
WindowControlGraphicsDrawing.cs、MathMethods.cs、ViewWithModel.cs图形绘制、数学计算、MVVM数据绑定
WindowControlDemoMainWindow.xaml.cs、App.xaml.cs演示程序界面交互、功能调用示例
配置文件App.config、WindowControl.csproj、WindowControlDemo.csproj框架版本、项目依赖、编译配置

(二)环境配置参数

  1. 框架版本:所有项目目标框架为.NETFramework,Version=v4.8(见App.config、WindowControl.csproj);
  2. 依赖库:OpenCvSharp4(版本4.9.0.20240103)、System.Buffers、System.Memory等(见packages.config);
  3. 编译配置:Debug模式生成pdb调试文件,Release模式优化代码;支持AnyCPU平台,WindowControlDemo额外配置x64平台目标(见WindowControlDemo.csproj);
  4. 资源复制:PreBuild事件自动复制WindowControl.dll及依赖库到输出目录(见WindowControlDemo.csproj PreBuildEvent)。

二、核心控件库(WindowControl)代码解读

(一)DrawingObject.cs:可交互绘图对象基类与实现

1. 基类DrawingObject
  • 核心枚举
  • Param:定义绘图对象基础参数(Stroke边框画笔、StrokeThickness边框厚度);
  • CallBackType:定义回调类型(OnDrag拖拽、OnResize缩放、OnAttached绑定、OnDisattached解绑)。
  • 关键属性
  • ScaleToImage:依赖属性,绑定图像与控件的缩放比例,变化时触发OnScaleToImageChanged更新图形位置;
  • _mShape:绘图对象对应的WPF Shape(如Ellipse、Rectangle、Line),作为Adorner装饰器的目标元素。
  • 核心方法
  • AttachToWindowControl:将绘图对象绑定到WindowSmartControl,建立缩放比例绑定;
  • DisAttachWithWindowControl:解绑绘图对象,清除绑定与回调;
  • SetDrawingObjectCallback/GetDrawingObjectParam:设置回调函数、获取/设置绘图对象参数,含类型校验(如Stroke需为Brush类型)。
2. 派生绘图对象实现
(1)CircleDrawingObject(圆形)
  • 专属Param:CenterX(圆心X)、CenterY(圆心Y)、Radius(半径);
  • 创建与更新CreateDrawingObject初始化圆心与半径,UpdateShapePos通过PosToControlCoordinate转换图像坐标到控件坐标,计算椭圆(Ellipse)的左上角位置与尺寸;
  • 交互逻辑ThumbDrag处理两种Thumb事件——Center标签(拖拽移动圆心)、CenterRight标签(调整半径),触发OnDrag/OnResize回调。
(2)RectDrawingObject(矩形)
  • 专属Param:Left(左上角X)、Top(左上角Y)、Width(宽度)、Height(高度);
  • 交互逻辑:支持9个Thumb手柄(TopLeft、TopCenter等),ThumbDrag根据手柄标签计算矩形位置/尺寸变化(如TopLeft手柄同时调整Left/Top/Width/Height)。
(3)Rect2DrawingObject(旋转矩形)
  • 专属Param:CenterX、CenterY、Width、Height、Angle(旋转角度);
  • 创建与旋转CreateDrawingObject初始化旋转角度,UpdateShapePos通过MathMethods.GetRect2Points计算旋转后矩形的四个顶点;
  • 交互逻辑:新增Rotate标签Thumb,通过Vector.AngleBetween计算角度变化,更新矩形旋转状态。
(4)LineDrawingObject(直线)
  • 专属Param:StartX、StartY(起点)、EndX、EndY(终点);
  • 交互逻辑:3个Thumb手柄(CenterLeft起点、CenterRight终点、Center移动),ThumbDrag调整端点坐标或整体移动直线。
(5)PolygonDrawingObject(多边形)
  • 专属Param:CentroidX(质心X)、CentroidY(质心Y)、Points(顶点集合);
  • 创建与更新CreateDrawingObject接收顶点列表,计算质心坐标;SetDrawingObjectParam支持动态添加顶点(如Demo中“Add Random Point”功能);
  • 交互逻辑:每个顶点对应一个Thumb,支持顶点拖拽调整与整体移动,自动更新质心坐标。

(二)WindowSmartControl.xaml.cs:控件交互核心

1. 自定义Canvas(RudeCanvas)
  • 重写VisualChildrenCountGetVisualChild,维护_visuals列表管理视觉元素;
  • 提供AddVisual/RemoveVisual/ClearVisual方法,支持添加/移除绘图视觉对象,排除Shape类型元素(避免与绘图对象冲突)。
2. 核心属性与事件
  • 依赖属性ScaleToImage(图像缩放比例)、IsEnableAdaptiveDisplay(自适应显示开关)、IsEnableAutomaticDisplayClear(自动清除显示开关);
  • 拖放事件rootCanvasDragEnter/rootCanvasDrop支持图像文件拖入,通过LoadBitmapImage/LoadMat加载图像,触发UpdateImageCanvas更新显示尺寸。
3. 图像交互控制
  • 鼠标移动rootCanvas_MouseMove转换鼠标坐标到图像坐标,调用viewModel.UpdateImageCanvas更新鼠标位置与像素信息(BGR值);
  • 缩放平移imageCanvasMouseWheel计算缩放因子(鼠标滚轮 delta 控制),更新mImageCanvasScaleX/Y,支持最大80倍缩放;imageCanvasMouseLeftButtonDown/Move实现图像拖拽平移;
  • 自适应显示AdaptiveDisplay方法根据控件尺寸调整图像显示位置与比例,重置平移偏移。
4. 绘图与显示接口

提供两类绘图接口(DisplayXXX临时显示、DrawXXX永久绘制到图像),核心接口如下:

  • DisplayCircle/DrawCircle:绘制圆形,支持填充与边框设置;
  • DisplayRect2/DrawRect2:绘制旋转矩形,传入中心坐标、角度、宽高等参数;
  • DisplayText:在指定位置显示文本,支持字体、大小、颜色设置;
  • ClearDisplay/ClearWindow:清除临时显示元素/清空整个窗口(含图像与绘图对象)。

(三)ImageConvertor.cs:图像格式转换

  • 格式映射mPixelFormatDict定义WPF PixelFormat与System.Drawing PixelFormat的映射(如Bgr24对应Format24bppRgb);
  • 核心转换方法
  • Bitmap2Writable:将System.Drawing.Bitmap转换为WPF WriteableBitmap,通过LockBits/UnlockBits处理像素数据;
  • Writable2Bitmap:反向转换,支持不安全代码(unsafe)复制内存数据;
  • Bitmap2Mat/Mat2Bitmap:通过OpenCvSharp.Extensions.BitmapConverter实现Bitmap与OpenCV Mat的转换,灰度图(8bpp/4bpp)单独处理。

(四)MathMethods.cs:数学计算工具

  • 坐标与几何计算
  • GetRectCenter:计算矩形(WPF Rect/OpenCV Rect2d等)中心坐标;
  • GetRectLT:根据中心坐标与半宽高计算左上角坐标;
  • GetPPDistance:计算两点间距离;
  • RotatePoint:绕中心点旋转坐标点,通过三角函数计算旋转后位置;
  • GetRect2Points:计算旋转矩形的四个顶点坐标,为Rect2DrawingObject提供支撑。

(五)ViewWithModel.cs:MVVM数据绑定

1. 数据模型(Model)
  • 维护图像源(imageSource)、位图(bitmap)、缩放比例(_ScaleToImage)等核心数据;
  • 提供DrawCircle/DrawRect2/DrawPolygon等OpenCV绘图方法,将几何图形绘制到Mat对象。
2. 视图模型(ViewModel)
  • 属性绑定mImageSource(图像源)、mScaleToImage(缩放比例)、mCurPosDisplay(鼠标位置显示)等属性,通过Do方法触发PropertyChanged事件;
  • 图像加载与显示LoadImage支持加载Bitmap/Mat格式图像,Display更新图像显示;
  • 图形生成GenCircle/GenRect2/GenPolygon生成WPF DrawingVisual对象,用于临时显示(不修改原图像)。

三、演示程序(WindowControlDemo)代码解读

(一)MainWindow.xaml.cs:界面交互逻辑

1. 初始化与变量
  • 声明5种绘图对象实例(CircleDrawingObject/RectDrawingObject等);
  • 维护OpenCV Mat(src)与Bitmap(srcBitmap),存储原始图像数据。
2. Button_Click:核心功能触发

根据按钮内容执行对应操作,逐段解读如下:

private void Button_Click(object sender, RoutedEventArgs e) { string szContent = (sender as Button).Content.ToString(); // 1. 圆形绘图对象:创建、绑定到控件、设置拖拽/缩放回调 if(szContent == "圆形绘图图像") { drawingObject.CreateDrawingObject(); drawingObject.AttachToWindowControl(WindowControl); drawingObject.SetDrawingObjectCallback(DrawingObject.CallBackType.OnDrag, DrawObjCallback); drawingObject.SetDrawingObjectCallback(DrawingObject.CallBackType.OnResize, DrawObjCallback); } // 2. 矩形绘图对象:创建、绑定、设置拖拽回调 else if (szContent == "矩形绘图图像") { rectDrawingObject.CreateDrawingObject(); rectDrawingObject.AttachToWindowControl(WindowControl); rectDrawingObject.SetDrawingObjectCallback(DrawingObject.CallBackType.OnDrag, DrawObjCallback); } // 3. 直线绘图对象:创建、绑定(无回调) else if (szContent == "直线绘图图像") { lineDrawingObject.CreateDrawingObject(); lineDrawingObject.AttachToWindowControl(WindowControl); } // 4. 旋转矩形绘图对象:指定初始位置(0,0)、尺寸(125,125)、角度(0),绑定拖拽回调 else if (szContent == "旋转矩形绘图图像") { double d = 0; rect2DrawingObject.CreateDrawingObject(0, 0, 125, 125, d); rect2DrawingObject.AttachToWindowControl(WindowControl); rect2DrawingObject.SetDrawingObjectCallback(DrawingObject.CallBackType.OnDrag, DrawObjCallback); } // 5. 多边形绘图对象:指定初始顶点列表,创建并绑定 else if(szContent == "多边形矩形绘图图像") { List<Point> points = new List<Point> { new Point(50, 50), new Point(100, 150), new Point(250, 250), new Point(350, 250),new Point(250, 100) }; polygonDrawingObject.CreateDrawingObject(points); polygonDrawingObject.AttachToWindowControl(WindowControl); } // 6. 为多边形添加随机顶点:获取质心坐标,生成随机点并添加到顶点列表 else if (szContent == "Add Random Point") { if(polygonDrawingObject == null) { return; } polygonDrawingObject.GetDrawingObjectParam((int)PolygonDrawingObject.Param.CentroidX, out double objX); polygonDrawingObject.GetDrawingObjectParam((int)PolygonDrawingObject.Param.CentroidY, out double objY); Random random1 = new Random(); Point p = new Point(random1.Next((int)objX - 50, (int)objX + 50), random1.Next((int)objY - 50, (int)objY + 50)); polygonDrawingObject.GetDrawingObjectParam((int)PolygonDrawingObject.Param.Points, out List<Point> lPoints); lPoints.Add(p); polygonDrawingObject.SetDrawingObjectParam((int)PolygonDrawingObject.Param.Points, lPoints); } // 7. 清空绘图对象:所有绘图对象解绑 else if(szContent == "清空绘图对象") { drawingObject.DisAttachWithWindowControl(WindowControl); rectDrawingObject.DisAttachWithWindowControl(WindowControl); lineDrawingObject.DisAttachWithWindowControl(WindowControl); rect2DrawingObject.DisAttachWithWindowControl(WindowControl); polygonDrawingObject.DisAttachWithWindowControl(WindowControl); } // 8. 清空窗口:清除控件显示,重置原始图像变量 else if(szContent == "清空窗口") { WindowControl.ClearWindow(); _src = null; _srcBitmap = null; } // 9. 获得显示图像:从控件获取Mat格式图像,通过OpenCV显示 else if (szContent == "获得显示图像") { OpenCvSharp.Mat mat = WindowControl.GetDisplay<OpenCvSharp.Mat>(); OpenCvSharp.Cv2.ImShow("Display", mat); OpenCvSharp.Cv2.WaitKey(0); } }
3. DrawObjCallback:绘图对象回调处理

根据绘图对象类型执行对应逻辑,逐段解读:

private void DrawObjCallback(DrawingObject.CallBackType callBackType, DrawingObject drawingObject) { // 1. 圆形对象:拖拽/缩放时触发Sobel边缘检测 if (drawingObject is CircleDrawingObject) { CircleDrawingObject circleDrawingObject = drawingObject as CircleDrawingObject; circleDrawingObject.GetDrawingObjectParam((int)CircleDrawingObject.Param.CenterX, out double dCenterX); circleDrawingObject.GetDrawingObjectParam((int)CircleDrawingObject.Param.CenterY, out double dCenterY); circleDrawingObject.GetDrawingObjectParam((int)CircleDrawingObject.Param.Radius, out double dR); if (SobelcheckBox.IsChecked == true) { if (_src == null) { _src = WindowControl.GetDisplay<OpenCvSharp.Mat>(); // 转换为灰度图(若为多通道) if (_src.Channels() > 1) { OpenCvSharp.Cv2.CvtColor(_src, _src, OpenCvSharp.ColorConversionCodes.BGR2GRAY); WindowControl.Display(_src); } } // 生成Sobel处理后的图像并显示 OpenCvSharp.Mat sobelMat = SobelMat(_src, new Point(dCenterX, dCenterY), dR); WindowControl.Display(sobelMat); } } // 2. 旋转矩形对象:拖拽时在图像上绘制蓝色旋转矩形(缩小10单位) else if (drawingObject is Rect2DrawingObject) { drawingObject.GetDrawingObjectParam((int)Rect2DrawingObject.Param.CenterX, out double dCenterX); drawingObject.GetDrawingObjectParam((int)Rect2DrawingObject.Param.CenterY, out double dCenterY); drawingObject.GetDrawingObjectParam((int)Rect2DrawingObject.Param.Width, out double dWidth); drawingObject.GetDrawingObjectParam((int)Rect2DrawingObject.Param.Height, out double dHeight); drawingObject.GetDrawingObjectParam((int)Rect2DrawingObject.Param.Angle, out double dAngle); if (drawToImageCheckBox.IsChecked == true) { if (_srcBitmap == null) { _srcBitmap = WindowControl.GetDisplay<sd.Bitmap>(); } WindowControl.Display(_srcBitmap); WindowControl.DrawRect2(new Point(dCenterX, dCenterY), dAngle, dWidth - 10, dHeight - 10, Colors.Blue, 3, false); } } // 3. 矩形对象:拖拽时清除显示,若勾选显示文本则在矩形内显示指定文本 else if (drawingObject is RectDrawingObject) { WindowControl.ClearDisplay(); drawingObject.GetDrawingObjectParam((int)RectDrawingObject.Param.Left, out double dLeft); drawingObject.GetDrawingObjectParam((int)RectDrawingObject.Param.Top, out double dTop); drawingObject.GetDrawingObjectParam((int)RectDrawingObject.Param.Width, out double dW); drawingObject.GetDrawingObjectParam((int)RectDrawingObject.Param.Height, out double dH); if (showTextCheckBox.IsChecked == true) { WindowControl.DisplayText(showTBX.Text, new Point(dLeft + 50, dTop + 50), new FontFamily("Arial"), 20, Colors.LightGreen); } } }
4. 其他交互逻辑
  • colorCombo_SelectionChanged:下拉选择颜色(红/绿/蓝),更新所有绘图对象的Stroke参数;
  • TextBox_TextChanged:输入数值,更新所有绘图对象的StrokeThickness参数(边框厚度);
  • SobelMat:Sobel边缘检测核心方法,通过掩码提取圆形ROI,用Scharr算子计算边缘,与原图叠加后返回。

四、关键功能与程序意图还原

(一)核心功能清单(基于代码实存功能)

  1. 图像加载与显示:支持拖入加载、路径加载,格式含BMP/PNG/JPG,支持Mat/Bitmap互转;
  2. 可交互绘图:圆形(拖拽+缩放)、矩形(拖拽+多方向缩放)、直线(拖拽+端点调整)、旋转矩形(拖拽+缩放+旋转)、多边形(拖拽+顶点添加+调整);
  3. 图像交互:鼠标滚轮缩放(1~80倍)、鼠标拖拽平移、鼠标位置与像素BGR值实时显示;
  4. 图像处理:Sobel边缘检测(圆形区域)、旋转矩形绘制、文本叠加;
  5. 控制功能:清空绘图对象、清空窗口、获取当前显示图像、自适应显示。

(二)程序设计意图

  1. 控件复用性WindowControl作为独立控件库,通过接口暴露绘图、显示、交互功能,供外部程序调用;
  2. 交互友好性:用Adorner+Thumb实现可视化交互手柄,支持实时反馈(如颜色、尺寸变化);
  3. 功能扩展性:绘图对象通过继承DrawingObject可扩展,图像处理接口预留扩展空间(如新增Canny检测);
  4. 数据安全性:参数获取/设置含类型校验,避免错误类型导致崩溃;图像操作前判断对象是否为空,减少异常。

(三)代码约束与限制(基于原始代码)

  1. 框架依赖:仅支持.NET Framework 4.8,不兼容.NET Core/.NET 5+;
  2. 平台限制:OpenCvSharp.runtime.win依赖Windows系统,无跨平台支持;
  3. 功能边界:Sobel检测仅支持圆形绘图对象,其他对象无此功能;多边形仅支持顶点添加,不支持删除;
  4. 性能约束:大尺寸图像(如4K及以上)缩放时可能卡顿,无异步处理逻辑。

基于WPF&Opencv 高级显示控件2.0 全新优化,支持图像拖入显示,使用wpf的adnoner和thumb实现可交互的绘图对象。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:43:12

AppImageLauncher完全攻略:让Linux桌面应用管理变得简单高效

AppImageLauncher完全攻略&#xff1a;让Linux桌面应用管理变得简单高效 【免费下载链接】AppImageLauncher Helper application for Linux distributions serving as a kind of "entry point" for running and integrating AppImages 项目地址: https://gitcode.c…

作者头像 李华
网站建设 2026/4/15 3:01:17

AI隐私卫士部署指南:教育行业数据保护

AI隐私卫士部署指南&#xff1a;教育行业数据保护 1. 引言 1.1 教育场景中的隐私挑战 在教育信息化快速发展的今天&#xff0c;校园监控、课堂录播、学生活动记录等场景中积累了大量包含人脸信息的图像与视频数据。这些数据一旦泄露或被滥用&#xff0c;将严重侵犯师生的个人…

作者头像 李华
网站建设 2026/4/15 21:03:02

MediaPipe Pose部署详解:极速CPU版的环境配置

MediaPipe Pose部署详解&#xff1a;极速CPU版的环境配置 1. 引言 1.1 AI 人体骨骼关键点检测的现实需求 在智能健身、动作捕捉、虚拟试衣和人机交互等前沿应用中&#xff0c;人体骨骼关键点检测&#xff08;Human Pose Estimation&#xff09;已成为一项核心技术。它能够从…

作者头像 李华
网站建设 2026/4/15 2:56:16

Windows 10 PL2303驱动失效诊断与完整修复教程

Windows 10 PL2303驱动失效诊断与完整修复教程 【免费下载链接】pl2303-win10 Windows 10 driver for end-of-life PL-2303 chipsets. 项目地址: https://gitcode.com/gh_mirrors/pl/pl2303-win10 还在为Windows 10系统下PL2303 USB转串口设备无法正常工作而困扰吗&…

作者头像 李华
网站建设 2026/4/16 12:44:56

基于MediaPipe的手势追踪实战:WebUI集成详细步骤

基于MediaPipe的手势追踪实战&#xff1a;WebUI集成详细步骤 1. 引言&#xff1a;AI 手势识别与交互的现实价值 随着人机交互技术的不断演进&#xff0c;手势识别正逐步从科幻场景走向日常应用。无论是智能驾驶中的非接触控制、AR/VR中的自然交互&#xff0c;还是智能家居的远…

作者头像 李华
网站建设 2026/4/16 0:05:41

没显卡怎么做骨骼检测?云端GPU开箱即用,2块钱玩一下午

没显卡怎么做骨骼检测&#xff1f;云端GPU开箱即用&#xff0c;2块钱玩一下午 引言&#xff1a;健身教练的AI体态分析困境 最近很多健身教练朋友刷到AI体态分析视频后跃跃欲试&#xff0c;想用这项技术给学员做专业评估。但现实很骨感——工作室电脑没有独立显卡&#xff0c;…

作者头像 李华