Main Content

detectPatternPoints

Detect calibration pattern keypoints in images from multiple cameras

Since R2025a

Description

Natively Supported Patterns

imagePoints = detectPatternPoints(imageFileNames,"charuco-board",patternDims,markerFamily,checkerSize,markerSize) detects the keypoints of a ChArUco board calibration pattern in images imageFileNames, with dimensions specified by patternDims, markerFamily, and checkerSize.

example

imagePoints = detectPatternPoints(imageFileNames,"aprilgrid",patternDims,tagFamily) detects the keypoints of an AprilGrid calibration pattern in images imageFileNames, with dimensions specified by patternDims.

imagePoints = detectPatternPoints(imageFileNames,"checkerboard",patternDims) detects the keypoints of a fully visible checkerboard calibration pattern in images imageFileNames, with dimensions specified by patternDims. The values of the elements of patternDims must not be equal.

imagePoints = detectPatternPoints(imageFileNames,"circle-grid-asymmetric",patternDims) detects keypoints of a circle grid calibration pattern in images imageFileNames, with dimensions specified by patternDims.

Custom Pattern Detector

imagePoints = detectPatternPoints(imageFileNames,patternDetector,numKeyPoints) detects the specified number of uniquely detectable keypoints numKeyPoints of a custom calibration pattern that can be detected in an image using the specified detector function patternDetector.

Optional Arguments

imagePoints = detectPatternPoints(___,Name=Value) specifies options using one or more name-value arguments in addition to any combination of arguments from previous syntaxes. For example, Verbose=true displays the progress of the detection process.

Examples

collapse all

Download the calibration images.

calibImagesURL = "https://www.mathworks.com/supportfiles/vision/data/overlapping-cameras-aprilgrid.zip";
calibImagesDir = fullfile(pwd,"overlapping-cameras-aprilgrid");
calibImagesZip = fullfile(pwd,"overlapping-cameras-aprilgrid.zip");
if ~exist(calibImagesZip,"file")
    disp("Downloading calibration images (54 MB)...")
    websave(calibImagesZip,calibImagesURL);
end
Downloading calibration images (54 MB)...
if ~exist(calibImagesDir,"dir")
    unzip(calibImagesZip,pwd)
end

Specify calibration image filenames for each camera.

numCameras = 6;
camDirPrefix = "Cam00";
imageFiles = cell(1,numCameras);
for i = 1:numCameras
    camDir = fullfile(calibImagesDir,camDirPrefix+i);
    imds = imageDatastore(camDir);
    imageFiles{i} = imds.Files;
end
imageFiles = [imageFiles{:}];

Define the AprilGrid properties.

patternDims = [6 6];
tagFamily = "tag36h11";

Detect the key points of the AprilGrid in the calibration images.

imagePoints = detectPatternPoints(imageFiles, "aprilgrid", ...
    patternDims,tagFamily);
[==================================================] 100%
Elapsed time: 00:00:32
Estimated time remaining: 00:00:00

Display the detected keypoints of the AprilGrid in the first two views for three of the six cameras.

tiledlayout(2,3,TileSpacing="compact",Padding="compact");
for viewIdx = 1:2
    for camIdx = 1:3
        nexttile
        imshow(imageFiles{viewIdx,camIdx})
        title("Camera " + camIdx + "|View " + viewIdx)
        hold on
        plot(imagePoints(:,1,viewIdx,camIdx),imagePoints(:,2,viewIdx,camIdx), ...
            "ro",MarkerSize=3)
    end
end

Figure contains 6 axes objects. Hidden axes object 1 with title Camera 1 |View 1 contains 2 objects of type image, line. One or more of the lines displays its values using only markers Hidden axes object 2 with title Camera 2 |View 1 contains 2 objects of type image, line. One or more of the lines displays its values using only markers Hidden axes object 3 with title Camera 3 |View 1 contains 2 objects of type image, line. One or more of the lines displays its values using only markers Hidden axes object 4 with title Camera 1 |View 2 contains 2 objects of type image, line. One or more of the lines displays its values using only markers Hidden axes object 5 with title Camera 2 |View 2 contains 2 objects of type image, line. One or more of the lines displays its values using only markers Hidden axes object 6 with title Camera 3 |View 2 contains 2 objects of type image, line. One or more of the lines displays its values using only markers

Estimate the relative position and orientation of six cameras with overlapping fields of view by using calibration images that contain a single ChArUco board.

Download the calibration images.

calibImagesURL = "https://www.mathworks.com/supportfiles/vision/data/overlapping-cameras-charuco.zip";
calibImagesDir = fullfile(pwd,"overlapping-cameras-charuco");
calibImagesZip = fullfile(pwd,"overlapping-cameras-charuco.zip");
if ~exist(calibImagesZip,"file")
    disp("Downloading calibration images (52 MB)...")
    websave(calibImagesZip,calibImagesURL);
end
if ~exist(calibImagesDir,"dir")
    unzip(calibImagesZip,pwd)
end

Specify calibration image filenames for each camera.

numCameras = 6;
camDirPrefix = "Cam00";
imageFiles = cell(1,numCameras);
for i = 1:numCameras
    camDir = fullfile(calibImagesDir,camDirPrefix+i);
    imds = imageDatastore(camDir);
    imageFiles{i} = imds.Files;
end
imageFiles = [imageFiles{:}];

Define the ChArUco board properties. Specify checker size and marker size in centimeters.

markerFamily = "DICT_6X6_1000";
patternDims = [5 5];
markerSize = 6.8;   % in cm
checkerSize = 9.15; % in cm
numKeyPoints = prod(patternDims - 1);

Create a function handle for detectCharucoBoardPoints that specifies the non-zero minimum marker ID of the board.

minMarkerId = 144;
funcHandle = @(image) detectCharucoBoardPoints(image,patternDims, ...
    markerFamily,checkerSize,markerSize,MinMarkerID=minMarkerId);

Detect the key points of the ChArUco board in the calibration images.

imagePoints = detectPatternPoints(imageFiles,funcHandle,numKeyPoints);
[==================================================] 100%
Elapsed time: 00:00:04
Estimated time remaining: 00:00:00

Generate the world points for the pattern.

worldPoints = patternWorldPoints("charuco-board",patternDims,checkerSize);

Load the intrinsic parameters of the six cameras. These parameters have been estimated using the Using the Single Camera Calibrator App.

ld = load("sixCameraIntrinsics.mat");

Perform multi-camera calibration.

params = estimateMultiCameraParameters(imagePoints,worldPoints,ld.intrinsics,WorldUnits="cm");

Visualize the calibration accuracy.

figure(Position=[100,100,1000,400])
showReprojectionErrors(params)

Figure contains 3 axes objects. Axes object 1 with title Mean Reprojection Error per Image, xlabel View, ylabel Camera contains an object of type patch. Axes object 2 with title Mean Reprojection Error per View, xlabel View, ylabel Mean Error in Pixels contains 2 objects of type bar, line. This object represents Overall Mean Error: 0.37 pixels. Axes object 3 with title Mean Reprojection Error per Camera, xlabel Camera, ylabel Mean Error in Pixels contains 2 objects of type bar, line.

Visualize the camera extrinsic parameters.

figure
showExtrinsics(params)
view(2)

Figure contains an axes object. The axes object with title Extrinsic Parameters Visualization, xlabel X (cm), ylabel Z (cm) contains 56 objects of type patch, text, line.

Input Arguments

collapse all

Filenames of the camera calibration patterns, specified as a numViews-by-numCameras string or cell array. numViews is the number of calibration pattern views for each camera, and numCameras is the number of cameras. Because you must specify more than two cameras, numCameras must be greater than 2.

Organize your calibration data into folders that contain synchronized images for each camera, ensuring that the filenames are consistent across all camera folders. This arrangement aligns images from different cameras that correspond to the same scene or subject. By using identical filenames in the folder for each camera, you can ensure that the images are properly synchronized.

Pattern dimensions, specified as a two-element vector that represents the number of checker boxes or circles along the rows (dim1) and columns (dim2) of the pattern. For an AprilGrid pattern, ensure that the pattern is oriented with the origin at the top-left as you count the rows and columns. For more information on patterns, see Calibration Patterns.

ArUco marker family, specified as one of these options:

  • "DICT_ARUCO_ORIGINAL"

  • "DICT_4X4_1000"

  • "DICT_5X5_1000"

  • "DICT_6X6_1000"

  • "DICT_7X7_1000"

ChArUco board checker box side length, specified as a scalar in world units, such as millimeters or inches. You must specify checkerSize and markerSize in the same world units, and checkerSize must be a larger value than markerSize.

Size of ArUco marker, in pixels, specified as a positive integer. This value sets the length of one side of a square ArUco marker in world units such as millimeters, centimeters, meters, or inches. The value of checkerSize must be greater than the value of markerSize.

AprilTag family, specified as "tag36h11", "tag25h9", or "tag16h5".

Custom pattern detector, specified as a function handle with this syntax:

[imagePoints,hasDetected] = patternDetector(filename).

Input

  • filename — Name of the image to be processed, specified as a string scalar or character vector.

Output

  • imagePoints — Coordinates of the detected keypoints in the image, returned as a numKeyPoints-by-2 matrix. N is the number of keypoints.

  • hasDetected — Logical that indicates whether the function detected the pattern, returned as true when the function detects the pattern and false when it does not.

Number of keypoints that can be detected in the custom pattern, specified as a positive integer.

Name-Value Arguments

collapse all

Specify optional pairs of arguments as Name1=Value1,...,NameN=ValueN, where Name is the argument name and Value is the corresponding value. Name-value arguments must appear after other arguments, but the order of the pairs does not matter.

Example: detectPatternPoints(imageFileNames,"circle-grid-asymmetric",patternDims,UseParallel=1) enables parallel processing.

Use parallel processing, specified as a logical 0 (false) or 1 (true). If you do not set this value, the function uses the value set by the Computer Vision Toolbox™ parallel preferences to determine what parallel processing to use, if any.

Display detection progress information in the Command Window, specified as a numeric or logical 1 (true) or 0 (false). Set Verbose to true to display progress information.

Output Arguments

collapse all

Image coordinates for the keypoints found in each image, returned as a numKeyPoints-by-numViews-by-numCameras matrix. numKeyPoints is the number of keypoints found for each image. numViews is the number of views with respect to the camera, and numCameras is the number of cameras. For example, imagePoints(:,:,i,j) contains the points from camera j when the pattern is located at the ith view. For images in which a camera does not detect a pattern, the corresponding keypoint values are NaNs.

Version History

Introduced in R2025a