WPF HALCON HSmartWindowControlWPF 鼠标绘制ROI

更新:放出完整源码,供大家学习参考

yStack/SoupImgViewer (github.com)icon-default.png?t=N7T8https://github.com/yStack/SoupImgViewer

0. 需求

在HSmartWindowsControlWPF上用鼠标绘制ROI,且显示绘制时的鼠标交互过程,最终效果如下:

1. 基本思路

  • 在HSmartWindowControl上布置一层透明的Canvas,用于实时显示鼠标绘制ROI的过程

  • 鼠标移动时,在Canvas上用鼠标实时绘制Rectangle等ROI形状,

  • 鼠标在Canvas坐标系中的Position信息(x,y)坐标转换到HALCON图像坐标系,变换为Row、Column等信息

  • 根据Row、Column信息调用HDrawingObject.CreateDrawingObject()方法生成Halcon原生ROI

  • 鼠标左键释放时,隐藏Canvas,将原生ROI附加到窗口中

UI布局如下:

  <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0" Orientation="Vertical">
            <Button Width="75" Height="25" Content="LoadImg" Margin="2.5" Click="Button_Click"></Button>
            <CheckBox Content="Rect" Margin="2.5" x:Name="rect_roi" Checked="rect_roi_Checked" Unchecked="rect_roi_Unchecked"></CheckBox>
            <CheckBox Content="Ellipse" Margin="2.5" x:Name="ellipse_roi" Checked="ellipse_roi_Checked" Unchecked="ellipse_roi_Unchecked"></CheckBox>
        </StackPanel>
        <halcon:HSmartWindowControlWPF HKeepAspectRatio="True" Grid.Column="1" x:Name="HalconWindowControl" HInitWindow="HWind_HInitWindow"></halcon:HSmartWindowControlWPF>
        <Canvas x:Name="Canvas" Visibility="Collapsed" Grid.Column="1" Background="Transparent" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseUp="Canvas_MouseUp" MouseMove="Canvas_MouseMove"></Canvas>
    </Grid>

2. 鼠标事件处理

  1. 初始化时,在Canvas中添加Rectangle等对象,并将其设置为不可见


	   private void Init()
        {
            Canvas.Children.Add(_canvasRect);
            Canvas.Children.Add(_canvasEllipse);
            Canvas.Children.Add(_cross);

            //矩形
            _canvasRect.Stroke = new SolidColorBrush(StokeColor);
            _canvasRect.StrokeThickness = StokeThickness;
            _canvasRect.Width = 0;
            _canvasRect.Height = 0;

            //圆形
            _canvasEllipse.Stroke = new SolidColorBrush(StokeColor);
            _canvasEllipse.StrokeThickness = StokeThickness;

            //十字
            _cross.Stroke = new SolidColorBrush(StokeColor);
            _cross.StrokeThickness = StokeThickness;
            _cross.Data = PathGeometry.Parse("M0,0 L8,8 M8,0 L0,8");
            _cross.Width = 0;
            _cross.Height = 0;

            // HImagePart随着窗口大小变化实时变动,注册事件用于实时更新坐标变换信息
            var dpd = DependencyPropertyDescriptor.FromProperty(HSmartWindowControlWPF.HImagePartProperty, typeof(HSmartWindowControlWPF));
            dpd.AddValueChanged(HalconWindowControl, (o, e) =>
            {
                var imgPart = HalconWindowControl.HImagePart;
                _k = imgPart.Height / HalconWindowControl.ActualHeight;
                _tx = imgPart.X;
                _ty = imgPart.Y;
            });
        }
  1. 鼠标左键单击,记录开始点startPoint


		private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                _startPoint = e.GetPosition(Canvas);
            }
        }
  1. 鼠标移动,在Canvas上实时绘制Rectangle


	    private void Canvas_MouseMove(object sender, MouseEventArgs e)
		{
            if (e.LeftButton == MouseButtonState.Pressed && rect_roi.IsChecked == true)
            {
                _endPoint = e.GetPosition(Canvas);

                _canvasRect.Height = Math.Abs(_endPoint.Y - _startPoint.Y);
                _canvasRect.Width = Math.Abs(_endPoint.X - _startPoint.X);
				
				// 左上往右下拖动
                if (_endPoint.X > _startPoint.X && _endPoint.Y > _startPoint.Y)
                {
                    Canvas.SetLeft(_canvasRect, _startPoint.X);
                    Canvas.SetTop(_canvasRect, _startPoint.Y);
                    
					//坐标转换,Canvas => HWindow
                    ConvertPoint(_startPoint.X, _startPoint.Y, _k, _tx, _ty, out double sx, out double sy);
                    ConvertPoint(_endPoint.X, _endPoint.Y, _k, _tx, _ty, out double ex, out double ey);
                    
                    _r1 = sy;
                    _c1 = sx;
                    _r2 = ey;
                    _c2 = ex;
                }

				// 右下往左上拖动
                if (_endPoint.X < _startPoint.X && _endPoint.Y < _startPoint.Y)
                {
                    Canvas.SetLeft(_canvasRect, _endPoint.X);
                    Canvas.SetTop(_canvasRect, _endPoint.Y);
                }
		}
  1. 鼠标释放时,添加ROI到HalconWindow中


		private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if(rect_roi.IsChecked == true)
            {
                _roi = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.RECTANGLE1, _r1, _c1, _r2, _c2);
                _hwind.AttachDrawingObjectToWindow(_roi);
                rect_roi.IsChecked = false;
            }
            
            if(ellipse_roi.IsChecked == true)
            {
                _roi = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.CIRCLE, _cr, _cc, _cRadius);
                _hwind.AttachDrawingObjectToWindow(_roi);
                ellipse_roi.IsChecked = false;
            }
        }

4. 坐标转换

Canvas坐标系和HWindow坐标系之间仅存在缩放、平移这两种变换关系,和相机标定的原理一样,k为缩放系数,tx、ty为平移量


		private void ConvertPoint(double x, double y, double k, double tx, double ty, out double px, out double py)
        {
            px = k * x + tx;
            py = k * y + ty;
        }
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
WPF绘制ROI(Region of Interest)可以通过添加矩形或圆形对象来实现。在Canvas的MouseUp事件中,根据选择的ROI类型(矩形或圆形),创建相应的绘制对象,并将其附加到HalconWindow中。\[1\] 在绘制完成后,可以进行坐标转换,将ROI之外的内容复制到目标图像中。可以使用numpy库进行坐标转换,根据ROI的边界坐标,将目标图像中对应区域的像素值替换为ROI的像素值。最后,使用plt.imshow函数显示合并后的图像。\[2\] 在初始化时,可以在Canvas中添加Rectangle和Ellipse等对象,并将它们设置为不可见。可以设置它们的边框颜色、边框宽度等属性。同时,可以添加一个十字对象用于显示坐标变换信息。还可以注册事件,实时更新坐标变换信息,以便随着窗口大小的变化而调整HImagePart的大小。\[3\] 综上所述,要在WPF绘制ROI,可以通过添加绘制对象、进行坐标转换和初始化设置来实现。 #### 引用[.reference_title] - *1* *3* [WPF HALCON HSmartWindowControlWPF 鼠标绘制ROI](https://blog.csdn.net/sinat_21001719/article/details/128647619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [图像中任意形状ROI(以opencv为例)](https://blog.csdn.net/liqiming100/article/details/118250360)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值