wpf实现鼠标缩放、移动图片,点击在图片上画点,点随图片缩放、移动。获取原图比例的坐标值

需求:

wpf中,使用canvas和Image实现

  1. 鼠标放在图片上鼠标滚轮缩放图片
  2. 鼠标拖动图片
  3. 鼠标右键点击图片,在图片上画点,所画的点跟随图片缩放和移动
  4. 鼠标悬浮在图片上,实时获取该点上的hsv值(opencv的hsv值)
  5. 能够获取原图比例对应点的坐标值
    实现效果如下图所示
    效果如动图所示

实现

我看到大部分的实现都是在Canvas上进行缩放移动,但这个对我的需求来说可能有点麻烦(或许可能是我能力还不够。。)
后来我尝试了在外层套一个Grid,把缩放移动的事件都放在这个Grid上,Image不放在Canvas里,然后使CanvasImage的大小相同,那么进行缩放和移动的时候,CanvasImage就会同时的缩放和移动

代码

直接放代码,注解看代码里的

!!!注意,以下代码基于源码做了删减,主要展示核心部分,可能有些地方的异常处理也删掉了,不要直接复制整个代码去运行,部分核心代码可以直接复制。以下也没有给出viewmodel的实现,相信读者有能力实现的

.xaml的代码
<Grid Background="Black">
<Grid.RowDefinitions>
    <RowDefinition Height="20*"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>
    <Grid Grid.Row="0" ClipToBounds="True">
        <Grid MouseWheel="Grid_MouseWheel"
              RenderTransformOrigin="0.5, 0.5"
              MouseLeftButtonDown="Grid_MouseLeftButtonDown"
              MouseMove="Grid_MouseMove"
              >
            <Grid.RenderTransform>
                <TransformGroup>
                    <ScaleTransform x:Name="scaleTransform" ScaleX="1" ScaleY="1" />
                    <TranslateTransform x:Name="translateTransform" />
                </TransformGroup>
            </Grid.RenderTransform>
            <!-- Image的Source值,这里我是使用mvvm的模式,绑定了Image值,你也可以把Source直接替换成你的图片路径 -->
            <Image x:Name="image" Source="{Binding Image}"
                   MouseMove="Image_MouseMove"
                   MouseRightButtonDown="Image_MouseRightButtonDown"/>
            <!-- 这里Canvas的宽高一定要和Image的一样大小 -->
            <Canvas x:Name="canvas"
                Width="{Binding ActualWidth,ElementName=image}"
                Height="{Binding ActualHeight,ElementName=image}"
                >
                <!-- 这里使用mvvm模式绑定所画的点,只要往DrawPoints里添加点,Canvas就会把点渲染出来 -->
                <ItemsControl ItemsSource="{Binding DrawPoints}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Ellipse Width="2" Height="2" Fill="Orange"/>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemContainerStyle>
                        <Style TargetType="ContentPresenter">
                            <Setter Property="Canvas.Left" Value="{Binding X}"/>
                            <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                        </Style>
                    </ItemsControl.ItemContainerStyle>
                </ItemsControl>
            </Canvas>
        </Grid>
    </Grid>
    <!-- 实时显示opencv中的hsv值 -->
    <TextBlock Grid.Row="1" x:Name="txtHSV" Foreground="#fff" FontSize="18" VerticalAlignment="Bottom" Margin="5 0 0 0"/>
</Grid>
.cs代码
using CommunityToolkit.Mvvm.DependencyInjection;
using Console.ViewModels.Screw;
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;

namespace Console.Views
{
    public partial class ScrewPreProcessGlue2d : Page
    {
        private ViewModel ViewModel { get; set; }
        private Mat imgMat;
        private System.Windows.Point origin;
        private System.Windows.Point start;

        public ScrewPreProcessGlue2d()
        {
            InitializeComponent();
        }

        private void Grid_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double zoom = e.Delta > 0 ? .2 : -.2;
            // 限制缩小,最小只能缩到1
            if (scaleTransform.ScaleX + zoom <= 1)
            {
                scaleTransform.ScaleX = 1;
                scaleTransform.ScaleY = 1;
                translateTransform.X = 0;
                translateTransform.Y = 0;
                return;
            }
            scaleTransform.ScaleX += zoom;
            scaleTransform.ScaleY += zoom;
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            start = e.GetPosition(canvas);
            origin = new System.Windows.Point(translateTransform.X, translateTransform.Y);
        }

        private void Grid_MouseMove(object sender, MouseEventArgs e)
        {
            if (scaleTransform.ScaleX == 1 && scaleTransform.ScaleY == 1) return;
            if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyUp(Key.LeftCtrl) && Keyboard.IsKeyUp(Key.RightCtrl)))
            {
                Vector v = start - e.GetPosition(canvas);
                translateTransform.X = origin.X - v.X;
                translateTransform.Y = origin.Y - v.Y;
            }
        }

	// 右键点击画点
        private void Image_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var position = e.GetPosition(image);  // 这里获取到的坐标值是图片在界面缩放比为1时的坐标值
            ViewModel.DrawPoints.Add(position); // 把点添加到viewmodel的DrawPoints中,界面会自动把点画出来
            // 如果想要获取原图比例下的坐标值,可以执行这个方法
            var scaled_point = GetScaledPosition(position,image);
        }

        private void Image_MouseMove(object sender, MouseEventArgs e)
        {
            imgMat = ViewModel.Image.ToMat();

            System.Windows.Point p = e.GetPosition(originImgViewer);
            if (p.X >= 0 && p.X < image.ActualWidth &&
                p.Y >= 0 && p.Y < image.ActualHeight)
            {
                // Convert mouse position to image pixel coordinates
                int x = (int)(p.X * (imgMat.Width / image.ActualWidth));
                int y = (int)(p.Y * (imgMat.Height / image.ActualHeight));

                // Get pixel color at mouse position
                Vec3b pixel = imgMat.At<Vec3b>(y, x);

                // Convert pixel color to HSV
                Mat bgr = new Mat(1, 1, MatType.CV_8UC3, new Scalar(pixel.Item0, pixel.Item1, pixel.Item2));
                Mat hsv = new Mat();
                Cv2.CvtColor(bgr, hsv, ColorConversionCodes.BGR2HSV);

                // Extract HSV values
                var hsvValues = hsv.Get<Vec3b>(0, 0);

                // Update UI with HSV values
                txtHSV.Text = $"H: {hsvValues.Item0}, S: {hsvValues.Item1}, V: {hsvValues.Item2}";
            }
        }
		// position是界面图片比例下的坐标值,element是控件名
         private System.Windows.Point GetScaledPosition(System.Windows.Point position, FrameworkElement element)
		 {
		     var actualWidth = element.ActualWidth; // 图片实际渲染的宽高
		     var actualHeight = element.ActualHeight;
		     var imageWidth = ViewModel.Image.PixelWidth; // 原图的宽高
		     var imageHeight = ViewModel.Image.PixelHeight;
		
		     var xRatio = imageWidth / actualWidth;
		     var yRatio = imageHeight / actualHeight;
		
		     var scaledX = position.X * xRatio;
		     var scaledY = position.Y * yRatio;
		
		     return new System.Windows.Point(scaledX, scaledY);
		 }
    }
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值