问题
i am using the new EmguCV 3.0.0 alpha to detect a chessboard with webcam and have an understanding problem with the corners matrix.
Size patternSize = new Size(5, 4);
Matrix<float> corners = new Matrix<float>(1, 2);
bool find = CvInvoke.FindChessboardCorners(grayFrame, patternSize, corners, CalibCbType.AdaptiveThresh | CalibCbType.FilterQuads);
CvInvoke.DrawChessboardCorners(grayFrame, patternSize, corners, find);
if (find)
{
Console.Write(corners.Size);
}
The chessboard will be detected and shown correct!
But, how big must be the size of the corners matrix and how do i extract the corner positions?
All samples i found on internet are using older versions of EmguCV and there is a complete different syntax now. I would use the older version but the newer alpha is much faster and timing is a big issue in my app.
回答1:
The CvInvoke.FindChessboardCorners Method has this signature1:
public static bool FindChessboardCorners(
IInputArray image,
Size patternSize,
IOutputArray corners,
CalibCbType flags = CalibCbType.Default|CalibCbType.AdaptiveThresh|CalibCbType.NormalizeImage
)
The third parameter is of type IOutputArray2. I do not understand why they introduced these super generic input/output interfaces that are implemented by various classes that cannot be used interchangeably.
You are right, the Matrix class does implement that interface (via super class CvArray) and thus your code compiles.
However, CvInvoke.FindChessboardCorners
is supposed to return a few points (depending on the size of the pattern). I googled for classes that implement IOutputArray
and found VectorOfPoints. That kind of made sense to me, more so than using a Matrix
.
I hacked together a little console app for calibration that reads all image files from a directory and detects the corners in them, because for me it makes more sense to capture the images beforehand.
That should give you a starting point:
public class Calibration
{
static void Main(string[] args)
{
// chessboard pattern size
Size patternSize = new Size(9, 7);
// for each image, have one Image object and one VectorOfPoints
// for many images have a List of each
List<VectorOfPoint> corners = new List<VectorOfPoint>();
List<Image<Gray, Byte>> images = new List<Image<Gray, byte>>();
// get paths to image files
string[] imageFiles = Directory.GetFiles(@"C:\your\directory", "*.jpg");
// for every image
foreach (string imageFile in imageFiles)
{
// create new image object from file path
var image = new Image<Gray, byte>(imageFile);
images.Add(image);
// create new list of corner points
var cornerPoints = new VectorOfPoint();
corners.Add(cornerPoints);
// find chessboard corners
bool result = CvInvoke.FindChessboardCorners(image, patternSize, cornerPoints);
// some debug output
Console.WriteLine("=== " + Path.GetFileName(imageFile) + " === " + result);
if (!result)
{
continue;
}
// list points
foreach (Point cornerPoint in cornerPoints.ToArray())
{
Console.WriteLine(cornerPoint.X + ", " + cornerPoint.Y);
}
}
Console.ReadLine();
}
}
For some reason I could not get CvInvoke.DrawChessboardCorners
to execute. It did not finish executing the function in a reasonable amount of time. That's why I printed the results to Console
, which looks like this for me:
I verified a few visually in an image editor and they seem to be correct.
tl;dr
Pick an appropriate type that can represent a list of points and that implements IOutputArray
like VectorOfPoints
for example.
1 some say the return type is not included in a signature so calling the above a signature might be total nonsense, but you still get the idea when I say "signature".
2 now that's some useful documentation!
来源:https://stackoverflow.com/questions/29557197/how-to-use-findchessboardcorners