鼠标单击事件坐标与找到的棋盘角坐标不匹配或对齐 - 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);
}
}
}
}
我目前正在使用 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);
}
}
}
}