鼠标单击事件坐标与找到的棋盘角坐标不匹配或对齐 - EmguCV / WPF

Mouse click event coordinates are not matching or aligned with the found chessboard corner coordinates - EmguCV / WPF

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

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

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);
                }

            }
        }
    }
}

必须根据图像缩放鼠标位置。得到正确的像素值

所以在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);
                }

            }
        }
    }