【问题标题】:Mouse click event coordinates are not matching or aligned with the found chessboard corner coordinates - EmguCV / WPF鼠标单击事件坐标与找到的棋盘角坐标不匹配或对齐 - EmguCV / WPF
【发布时间】:2016-12-22 17:13:45
【问题描述】:

我目前正在使用 EmguCV 库和 Kinect 来使用 WPF 创建一个简单的命中测试。我能够成功找到棋盘角并将它们存储在矩形列表中作为矩形的 4 个角,然后我尝试使用 LeftMouseButtonUp 事件来获取鼠标位置并检查它是否位于边界中矩形。

问题是我怀疑 EmguCV 作为棋盘角返回的坐标和从鼠标单击事件返回的坐标没有对齐,因此它无法检测到命中(即在矩形内单击鼠标)。如何让这两个坐标对齐在一起?我错过了什么吗?

XAML:

<Window x:Class="EmguMotionTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" KeyDown="Window_KeyDown" >
    <Grid>
        <Image Name="rgbImage" Stretch="Fill" MouseLeftButtonUp="rgbImage_MouseLeftButtonUp"/>
        <Line Name="line" Stroke="Red" StrokeThickness="1" Visibility="Visible" />
    </Grid>
</Window>

C#:

public partial class MainWindow : Window
{
    /*Kinect Initialization*/
    KinectSensor _kinectSensor;

    /*Getting the Chessboard corners*/
    PointF[] corners = new PointF[] { };
    PointF[] points = new PointF[4];
    List<PointF> cornerPts = new List<PointF>();
    List<List<PointF>> rectangle = new List<List<PointF>>();
    /*Defining the Chessboard parameters */
    const int width = 4;
    const int height = 4;
    Drawing.Size boardSize = new Drawing.Size(width, height);

    public MainWindow()
    {
        InitializeComponent();

        this.Unloaded += delegate
        {
            _kinectSensor.ColorStream.Disable();
        };

        this.Loaded += delegate
        {
            _kinectSensor = KinectSensor.KinectSensors[0];

            _kinectSensor.ColorStream.Enable();
            _kinectSensor.Start();

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += (a, b) => Pulse();
            bw.RunWorkerCompleted += (c, d) => bw.RunWorkerAsync();
            bw.RunWorkerAsync();
        };
    }

    /*Polling event to retrieve Data from Kinect*/
    private void Pulse()
    {
        using (ColorImageFrame imageFrame = _kinectSensor.ColorStream.OpenNextFrame(200))
        {
            if (imageFrame == null)
                return;

            //Converting a Kinect Color Frame to EmguCV Image
            Image<Bgr, Byte> imageCap = imageFrame.ToOpenCVImage<Bgr, Byte>();

            Image<Gray, Byte> gray = imageCap.Convert<Gray, Byte>();

            corners = CameraCalibration.FindChessboardCorners(gray, boardSize, Emgu.CV.CvEnum.CALIB_CB_TYPE.ADAPTIVE_THRESH | Emgu.CV.CvEnum.CALIB_CB_TYPE.FILTER_QUADS);

            if (corners != null)
            {
                CvInvoke.cvFindCornerSubPix(gray, corners, corners.Length, new Drawing.Size(11, 11), new Drawing.Size(-1, -1), new MCvTermCriteria(30, 0.1));
                CameraCalibration.DrawChessboardCorners(gray, boardSize, corners);

                //Displaying the result in WPF
                this.Dispatcher.Invoke(
                       new Action(() => rgbImage.Source = gray.ToBitmapSource())
                       );
            }
            else
            {
                //Displaying the result in WPF
                this.Dispatcher.Invoke(
                       new Action(() => rgbImage.Source = gray.ToBitmapSource())
                       );
            }

        }
    }

    private void Window_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space)
        {
            //Clear out the List of points 
            if (cornerPts != null)
            {
                cornerPts.Clear();
            }

            //Enter all the found corners into an array stored as polygons
            for (int i = 0; i < boardSize.Height - 1; i++)
            {
                for (int j = 0; j < boardSize.Width - 1; j++)
                {
                    //Getting the corners of the squares (Square 1, 2, 3)..
                    int p1 = (i * boardSize.Width) + j;
                    int p2 = (i * boardSize.Width) + j + 1;
                    int p3 = ((i + 1) * boardSize.Width) + j;
                    int p4 = ((i + 1) * boardSize.Width) + j + 1;

                    //Add range method

                    points[0] = corners[p1];
                    points[1] = corners[p2];
                    points[2] = corners[p3];
                    points[3] = corners[p4];

                    cornerPts.AddRange(points);
                    rectangle.Add(new List<PointF>() { points[0], points[1], points[2], points[3] });
                }
            }
        }

        /*To test the corners points are being added correctly */
        if (e.Key == Key.D)
        {
            Console.WriteLine("D button press registered");

            ///*Test Square */
            for (int c = 0; c < rectangle.Count; c++)
            {
                for (int n = 0; n < 4; n++)
                {
                    Console.WriteLine("Triangle no: " + c + "," + n + rectangle[c][n]);
                }
            }
        }
    }

    private void rgbImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        System.Windows.Point p = Mouse.GetPosition(rgbImage);
        Console.WriteLine("MouseX: " + p.X + "," + "MouseY: " + p.Y);

        Console.WriteLine("-------------Hit Test---------------");
        /*Test Square */
        for (int c = 0; c < rectangle.Count; c++)
        {
            for (int n = 0; n < 4; n++)
            {
                //Console.WriteLine("Triangle no: " + c + "," + n + rectangle[c][n]);

                if ((p.X > rectangle[c][0].X && p.X < rectangle[c][1].X) && (p.Y > rectangle[c][0].Y && p.Y < rectangle[c][2].Y))
                {
                    Console.WriteLine("Triangle HIT is triangle no: " + c);
                }

            }
        }
    }
}

【问题讨论】:

    标签: c# wpf opencv kinect emgucv


    【解决方案1】:

    鼠标位置必须根据图像进行缩放。获取正确的像素值

    所以在Pulse()方法中提取Bitmap的PixelWidth和PixelHeight,并根据图像控件缩放鼠标位置

    /*Polling event to retrieve Data from Kinect*/
        private void Pulse()
        {
    
            using (ColorImageFrame imageFrame = _kinectSensor.ColorStream.OpenNextFrame(200))
            {
                if (imageFrame == null)
                    return;
    
                //Converting a Kinect Color Frame to EmguCV Image
                Image<Bgr, Byte> imageCap = imageFrame.ToOpenCVImage<Bgr, Byte>();
    
                Image<Gray, Byte> gray = imageCap.Convert<Gray, Byte>();
    
                corners = CameraCalibration.FindChessboardCorners(gray, boardSize, Emgu.CV.CvEnum.CALIB_CB_TYPE.ADAPTIVE_THRESH | Emgu.CV.CvEnum.CALIB_CB_TYPE.FILTER_QUADS);
    
                if (corners != null)
                {
                    CvInvoke.cvFindCornerSubPix(gray, corners, corners.Length, new Drawing.Size(11, 11), new Drawing.Size(-1, -1), new MCvTermCriteria(30, 0.1));
                    CameraCalibration.DrawChessboardCorners(gray, boardSize, corners);
    
                    pixelWidth = gray.ToBitmapSource().PixelWidth;
                    pixelHeight = gray.ToBitmapSource().PixelHeight;
    
                    //Displaying the result in WPF
                    this.Dispatcher.Invoke(
                           new Action(() => rgbImage.Source = gray.ToBitmapSource())
                           );
                }
                else
                {
                    //Displaying the result in WPF
                    this.Dispatcher.Invoke(
                           new Action(() => rgbImage.Source = gray.ToBitmapSource())
                           );
    
                }
            }
        }
    
        private void rgbImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            System.Windows.Point p = Mouse.GetPosition(rgbImage);
    
            var pixelMousePosX = e.GetPosition(rgbImage).X * pixelWidth / rgbImage.ActualWidth;
            var pixelMousePosY = e.GetPosition(rgbImage).Y * pixelHeight / rgbImage.ActualHeight;
    
            Console.WriteLine("MousePixelX: " + pixelMousePosX + "," + "MousePixelY: " + pixelMousePosY);
    
            /*Test Square */
            for (int c = 0; c < rectangle.Count; c++)
            {
                for (int n = 0; n < 4; n++)
                {
                    if ((pixelMousePosX > rectangle[c][0].X && pixelMousePosX < rectangle[c][1].X) && (pixelMousePosY > rectangle[c][0].Y && pixelMousePosY < rectangle[c][2].Y))
                    {
                        Console.WriteLine("Triangle HIT is triangle no: " + c);
                    }
    
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-08
      • 2020-07-16
      • 2013-06-29
      • 1970-01-01
      • 1970-01-01
      • 2014-10-20
      相关资源
      最近更新 更多