Detection of Diamond Markers Demo

Detection and pose estimation using ChArUco markers.

Sources:

Contents

Parameters

% options
vidFile = '';              % Use video file instead of camera as input
squareLength = 120;        % Square side length (in pixels)
markerLength = 60;         % Marker side length (in pixels)
dictionaryId = '6x6_250';  % Dictionary id
showRejected = false;      % Show rejected candidates too
estimatePose = true;       % Wheather to estimate pose or not
if estimatePose
    % calibrated camera parameters
    load camera_parameters.mat -mat camMatrix distCoeffs
    %camMatrix = eye(3);
    %distCoeffs = zeros(1,5);
else
    camMatrix = [];
    distCoeffs = [];
end
autoScale = false;
autoScaleFactor = 1.0;     % Automatic scale. The provided number is multiplied
                           % by the last diamond id becoming an indicator of
                           % the square length. In this case, the squareLength
                           % and markerLength values are only used to know the
                           % relative length relation between squares and
                           % markers

% marker detector parameters
detectorParams = struct();
if false
    %detectorParams.nMarkers = 1024;
    detectorParams.adaptiveThreshWinSizeMin = 3;
    detectorParams.adaptiveThreshWinSizeMax = 23;
    detectorParams.adaptiveThreshWinSizeStep = 10;
    detectorParams.adaptiveThreshConstant = 7;
    detectorParams.minMarkerPerimeterRate = 0.03;
    detectorParams.maxMarkerPerimeterRate = 4.0;
    detectorParams.polygonalApproxAccuracyRate = 0.05;
    detectorParams.minCornerDistanceRate = 0.05;
    detectorParams.minDistanceToBorder = 3;
    detectorParams.minMarkerDistanceRate = 0.05;
    detectorParams.cornerRefinementMethod = 'None';
    detectorParams.cornerRefinementWinSize = 5;
    detectorParams.cornerRefinementMaxIterations = 30;
    detectorParams.cornerRefinementMinAccuracy = 0.1;
    detectorParams.markerBorderBits = 1;
    detectorParams.perspectiveRemovePixelPerCell = 8;
    detectorParams.perspectiveRemoveIgnoredMarginPerCell = 0.13;
    detectorParams.maxErroneousBitsInBorderRate = 0.04;
    detectorParams.minOtsuStdDev = 5.0;
    detectorParams.errorCorrectionRate = 0.6;
end

% dictionary
dictionary = {'Predefined', dictionaryId};

Input source

if ~isempty(vidFile) && exist(vidFile, 'file') == 2
    vid = cv.VideoCapture(vidFile);
    waitTime = 1;     % 1 sec
else
    vid = createVideoCapture([], 'charuco');
    waitTime = 0.01;  % 10 msec
end
if ~vid.isOpened(), error('failed to initialize VideoCapture'); end

Main loop

totalTime = 0;
totalIterations = 0;
hImg = [];
while true
    % grab frame
    img = vid.read();
    if isempty(img), break; end

    tId = tic();

    % detect markers
    [markerCorners, markerIds, rejectedMarkers] = cv.detectMarkers(...
        img, dictionary, 'DetectorParameters',detectorParams);

    % detect diamonds
    if ~isempty(markerIds)
        [diamondCorners, diamondIds] = cv.detectCharucoDiamond(...
            img, markerCorners, markerIds, squareLength / markerLength, ...
            'CameraMatrix',camMatrix, 'DistCoeffs',distCoeffs);
    end

    % estimate diamond pose
    if estimatePose && ~isempty(diamondIds)
        if ~autoScale
            [rvecs, tvecs] = cv.estimatePoseSingleMarkers(...
                diamondCorners, squareLength, camMatrix, distCoeffs);
        else
            % if autoscale, extract square size from last diamond id
            rvecs = cell(size(diamondCorners));
            tvecs = cell(size(diamondCorners));
            for i=1:numel(diamondCorners)
                autoSquareLength = autoScaleFactor * double(diamondIds{i}(4));
                currentCorners = {diamondCorners{i}};
                [currentRvec, currentTvec] = cv.estimatePoseSingleMarkers(...
                    currentCorners, autoSquareLength, camMatrix, distCoeffs);
                rvecs{i} = currentRvec{1};
                tvecs{i} = currentTvec{1};
            end
        end
    end

    % tic/toc
    currentTime = toc(tId);
    totalTime = totalTime + currentTime;
    totalIterations = totalIterations + 1;
    if mod(totalIterations, 30) == 0
        fprintf('Detection time = %f ms (Mean = %f ms)\n', ...
            1000*currentTime, 1000*totalTime/totalIterations);
    end

    % draw results
    if ~isempty(markerIds)
        img = cv.drawDetectedMarkers(img, markerCorners);  % 'IDs',markerIds
    end

    if showRejected && ~isempty(rejectedMarkers)
        img = cv.drawDetectedMarkers(img, rejectedMarkers, ...
            'BorderColor',[255 0 100]);
    end

    if ~isempty(markerIds) && ~isempty(diamondIds)
        img = cv.drawDetectedDiamonds(img, diamondCorners, 'IDs',diamondIds);

        if estimatePose
            for i=1:numel(diamondIds)
                img = cv.drawAxis(img, camMatrix, distCoeffs, ...
                    rvecs{i}, tvecs{i}, squareLength * 0.5);
            end
        end
    end

    if isempty(hImg)
        hImg = imshow(img);
    elseif ishghandle(hImg)
        set(hImg, 'CData',img);
    else
        break;
    end
    drawnow; pause(waitTime);
end
vid.release();
Detection time = 92.399476 ms (Mean = 95.749196 ms)
Detection time = 91.688747 ms (Mean = 93.386428 ms)