Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use FindChessboardCorners

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.

like image 231
elementarladung Avatar asked Apr 10 '15 08:04

elementarladung


2 Answers

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:

enter image description here

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!

like image 132
null Avatar answered Oct 20 '22 12:10

null


CvInvoke.DrawChessboardCorners works after changing VectorOfPoint to VectorOfPointF

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<VectorOfPointF>();
        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 VectorOfPointF();
            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();
    }
}
like image 20
damann Avatar answered Oct 20 '22 12:10

damann