从传统绘图到现代交互WPF中HSmartWindowControl与HDrawingObject的ROI革命在工业视觉开发领域Halcon一直是许多开发者的首选工具库。然而当我们将Halcon集成到WPF应用程序中时传统的绘图方式往往会遇到各种挑战。特别是对于那些习惯了使用DrawRectangle1等传统函数的开发者来说切换到HSmartWindowControl控件时常常感到困惑和挫败。1. 为什么需要告别DrawRectangle1在传统的Halcon开发中DrawRectangle1这类函数简单直接开发者只需几行代码就能在图像上绘制ROI感兴趣区域。然而这种方式的局限性在WPF环境中变得尤为明显缺乏交互性传统绘图函数创建的ROI是静态的用户无法直接通过鼠标调整位置或大小与现代UI框架的兼容性问题WPF的渲染机制与Halcon原生窗口存在差异直接绘图可能导致显示异常代码维护困难传统方式往往需要大量手动计算坐标代码可读性和可维护性差HSmartWindowControl配合HDrawingObject提供了一套全新的解决方案// 传统方式 HOperatorSet.DrawRectangle1(hWindowHandle, out row1, out column1, out row2, out column2); // 现代方式 HDrawingObject drawingObject HDrawingObject.CreateDrawingObject( HDrawingObject.HDrawingObjectType.RECTANGLE1, height / 4, width / 4, height * 0.75, width * 0.75); hswControl.HalconWindow.AttachDrawingObjectToWindow(drawingObject);2. HDrawingObject的核心优势2.1 交互式操作体验HDrawingObject最大的优势在于它提供了完整的交互支持拖拽调整用户可以直接用鼠标拖动ROI的边缘或角点来调整大小整体移动按住ROI内部可以整体移动位置实时反馈所有调整都会立即反映在界面上无需重新绘制2.2 丰富的ROI类型支持除了常见的矩形HDrawingObject还支持多种ROI类型ROI类型创建方法典型应用场景矩形RECTANGLE1常规物体检测旋转矩形RECTANGLE2方向性物体识别圆形CIRCLE圆形特征测量椭圆ELLIPSE非规则形状分析多边形POLYGON复杂轮廓提取2.3 事件驱动的编程模型HDrawingObject提供了完整的事件系统开发者可以响应各种交互动作drawingObject.OnDrag (sender, e) { // 处理拖拽事件 UpdateROIParameters(); }; drawingObject.OnResize (sender, e) { // 处理大小调整事件 UpdateROIParameters(); };3. 从传统到现代的平滑迁移策略3.1 代码重构指南对于已有项目我们可以采用渐进式迁移策略识别旧代码查找项目中所有使用DrawRectangle1等传统绘图函数的地方创建适配层为传统函数创建基于HDrawingObject的替代实现逐步替换按功能模块逐步替换旧实现确保每个步骤都经过充分测试3.2 参数转换技巧传统绘图函数和HDrawingObject的参数表示方式有所不同需要注意转换// 传统参数获取方式 HTuple row1, column1, row2, column2; HOperatorSet.DrawRectangle1(hWindowHandle, out row1, out column1, out row2, out column2); // HDrawingObject参数获取方式 string[] paramNames { row1, column1, row2, column2 }; HTuple parameters drawingObject.GetDrawingObjectParams(new HTuple(paramNames));3.3 性能优化建议虽然HDrawingObject提供了更好的交互体验但在性能敏感场景下需要注意避免过度更新只在必要时获取ROI参数不要在每个鼠标移动事件中都处理合理使用缓存对于复杂的后续处理可以缓存ROI参数批量操作当需要处理多个ROI时考虑使用HDrawingObject的批量操作接口4. 实战完整的WPF集成示例4.1 XAML界面设计Window x:ClassHalconWPFApp.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml xmlns:halconclr-namespace:HalconDotNet;assemblyhalcondotnet Title高级ROI交互示例 Height600 Width800 Grid Grid.ColumnDefinitions ColumnDefinition Width*/ ColumnDefinition WidthAuto/ /Grid.ColumnDefinitions halcon:HSmartWindowControlWPF x:NamehswControl Grid.Column0 HDoubleClickToFitContentTrue HZoomContentTouchpad/ StackPanel Grid.Column1 Width150 Margin5 Button Content创建矩形ROI ClickOnCreateRectangleClick Margin0,5/ Button Content创建圆形ROI ClickOnCreateCircleClick Margin0,5/ Button Content获取ROI参数 ClickOnGetParametersClick Margin0,5/ Button Content清除ROI ClickOnClearROIClick Margin0,5/ TextBlock x:NameparamDisplay Margin0,20,0,0 TextWrappingWrap/ /StackPanel /Grid /Window4.2 后台逻辑实现public partial class MainWindow : Window { private HDrawingObject currentROI; private HImage currentImage new HImage(); public MainWindow() { InitializeComponent(); LoadSampleImage(); } private void LoadSampleImage() { currentImage.ReadImage(sample.png); hswControl.HalconWindow.DispImage(currentImage); } private void OnCreateRectangleClick(object sender, RoutedEventArgs e) { ClearCurrentROI(); currentImage.GetImageSize(out int width, out int height); currentROI HDrawingObject.CreateDrawingObject( HDrawingObject.HDrawingObjectType.RECTANGLE1, height * 0.2, width * 0.2, height * 0.8, width * 0.8); AttachROIToWindow(); } private void AttachROIToWindow() { hswControl.HalconWindow.AttachDrawingObjectToWindow(currentROI); currentROI.OnDrag UpdateROIDisplay; currentROI.OnResize UpdateROIDisplay; } private void UpdateROIDisplay(object sender, HDrawingObjectEventArgs e) { OnGetParametersClick(null, null); } private void OnGetParametersClick(object sender, RoutedEventArgs e) { if (currentROI null) return; string[] paramNames { row1, column1, row2, column2 }; HTuple parameters currentROI.GetDrawingObjectParams(new HTuple(paramNames)); paramDisplay.Text $ROI参数:\n $左上: ({parameters[0].D}, {parameters[1].D})\n $右下: ({parameters[2].D}, {parameters[3].D}); } private void ClearCurrentROI() { if (currentROI ! null) { currentROI.Dispose(); currentROI null; } } private void OnClearROIClick(object sender, RoutedEventArgs e) { ClearCurrentROI(); paramDisplay.Text ; } }5. 高级技巧与最佳实践5.1 多ROI管理在实际应用中我们经常需要同时处理多个ROIprivate ListHDrawingObject activeROIs new ListHDrawingObject(); private void AddNewROI(HDrawingObject.HDrawingObjectType type) { var roi HDrawingObject.CreateDrawingObject(type, /* 初始参数 */); hswControl.HalconWindow.AttachDrawingObjectToWindow(roi); activeROIs.Add(roi); // 为每个ROI分配唯一颜色 roi.SetDrawingObjectParams(color, GetUniqueColor(activeROIs.Count)); } private string GetUniqueColor(int index) { string[] colors { red, green, blue, yellow, cyan, magenta }; return colors[index % colors.Length]; }5.2 ROI持久化与恢复对于需要保存和加载ROI配置的场景public void SaveROIsToFile(string filePath) { var settings new ListROISettings(); foreach (var roi in activeROIs) { var type roi.GetDrawingObjectParams(type).S; var parameters roi.GetDrawingObjectParams(all); settings.Add(new ROISettings { Type type, Parameters parameters }); } File.WriteAllText(filePath, JsonConvert.SerializeObject(settings)); } public void LoadROIsFromFile(string filePath) { ClearAllROIs(); var settings JsonConvert.DeserializeObjectListROISettings( File.ReadAllText(filePath)); foreach (var setting in settings) { var roi HDrawingObject.CreateDrawingObject( (HDrawingObject.HDrawingObjectType)Enum.Parse( typeof(HDrawingObject.HDrawingObjectType), setting.Type), setting.Parameters); hswControl.HalconWindow.AttachDrawingObjectToWindow(roi); activeROIs.Add(roi); } }5.3 自定义ROI行为通过继承HDrawingObject可以实现更复杂的自定义行为public class SmartROI : HDrawingObject { public SmartROI(HDrawingObject.HDrawingObjectType type, params HTuple[] parameters) : base(HDrawingObject.CreateDrawingObject(type, parameters)) { // 自定义初始化逻辑 } protected override void OnDrag(HDrawingObjectEventArgs e) { base.OnDrag(e); // 添加自定义拖拽逻辑如限制移动范围 var pos GetDrawingObjectParams(position); if (pos[0].D 0) { SetDrawingObjectParams(position, 0, pos[1]); } } }在实际项目中从DrawRectangle1迁移到HDrawingObject不仅解决了交互性问题还显著提高了代码的可维护性和扩展性。特别是在需要频繁调整ROI参数的场景下交互式操作可以节省大量开发时间。