gusucode.com > vision工具箱matlab源码程序 > vision/showExtrinsics.m
function ax = showExtrinsics(cameraParams, varargin) %showExtrinsics Visualize extrinsic camera parameters. % showExtrinsics(cameraParams) renders a 3-D visualization of extrinsic % parameters of a single calibrated camera or a calibrated stereo pair. % It plots a 3-D view of the calibration patterns with respect to the % camera. cameraParams can be either a cameraParameters object or a % stereoParameters object returned by the estimateCameraParameters function. % % showExtrinsics(cameraParams, view) displays visualization of % the camera extrinsic parameters using the style specified by view. % Values of view can be: % % 'CameraCentric': Use it if you kept your camera stationary while % moving the calibration pattern. % 'PatternCentric' Use it if the pattern was stationary while you moved % your camera. % % ax = showExtrinsics(...) returns the plot's axes. % % showExtrinsics(...,Name,Value) specifies additional name-value pair % arguments described below: % % 'HighlightIndex' Select patterns to highlight. The index is specified % as a vector. For example, to highlight patterns 1 and % 4, you would use [1, 4], which increases the opacity % of these two patterns in contrast to the rest of the % patterns. % % Default: [] % % 'Parent' Specify an output axes for displaying the visualization. % % Class Support % ------------- % cameraParams must be a either a cameraParameters or a stereoParameters % object. % % Example 1 - Single camera % ------------------------ % % Create a set of calibration images. % images = imageDatastore(fullfile(toolboxdir('vision'), 'visiondata', ... % 'calibration', 'webcam')); % imageFileNames = images.Files(1:5); % % % Detect calibration pattern. % [imagePoints, boardSize] = detectCheckerboardPoints(imageFileNames); % % % Generate world coordinates of the corners of the squares. % squareSide = 25; % square size in millimeters % worldPoints = generateCheckerboardPoints(boardSize, squareSide); % % % Calibrate the camera. % cameraParams = estimateCameraParameters(imagePoints, worldPoints); % % % Visualize pattern locations. % figure; showExtrinsics(cameraParams); % % % Visualize camera locations. % figure; showExtrinsics(cameraParams, 'patternCentric'); % % Example 2 - Stereo camera % --------------------------------- % % Specify calibration images % imageDir = fullfile(toolboxdir('vision'), 'visiondata', ... % 'calibration', 'stereo'); % leftImages = imageDatastore(fullfile(imageDir, 'left')); % rightImages = imageDatastore(fullfile(imageDir, 'right')); % % % Detect the checkerboards % [imagePoints, boardSize] = detectCheckerboardPoints(... % leftImages.Files, rightImages.Files); % % % Specify world coordinates of checkerboard keypoints % squareSize = 108; % millimeters % worldPoints = generateCheckerboardPoints(boardSize, squareSize); % % % Calibrate the stereo camera system % cameraParams = estimateCameraParameters(imagePoints, worldPoints); % % % Visualize pattern locations % figure; % showExtrinsics(cameraParams); % % % Visualize camera locations % figure; % showExtrinsics(cameraParams, 'patternCentric'); % % See also showReprojectionErrors, cameraCalibrator, stereoCameraCalibrator, % estimateCameraParameters, cameraParameters, stereoParameters, % extrinsics, plotCamera % Copyright 2014 The MathWorks, Inc. [offset, wpConvexHull, extView, highlightIndex, numBoards, hAxes] = ... parseInputs(cameraParams, varargin{:}); % colormap for board highlighting boardColorLookup = im2double(label2rgb(1:numBoards, 'lines','c','shuffle')); if strcmp(extView, 'PatternCentric') patternCentric; else cameraCentric; end title(hAxes, getString(message('vision:calibrate:showExtrinsicsTitle'))); setAxesProperties(); if nargout == 1 ax = hAxes; end %-------------------------------------------------------------------------- function setAxesProperties rotate3d(hAxes,'on'); grid(hAxes, 'on'); axis(hAxes, 'equal'); end %-------------------------------------------------------------------------- function [offset, wpConvHull, extView, highlightIndex, numBoards, ... hAxes] = parseInputs(camParams, varargin) validateattributes(camParams, {'cameraParameters', 'stereoParameters'},... {}, mfilename, 'cameraParams'); numBoards = camParams.NumPatterns; % Parse the P-V pairs parser = inputParser; parser.addOptional('View', 'CameraCentric', @checkView); parser.addParameter('HighlightIndex', [], @checkIndex); parser.addParameter('Parent', [], ... @vision.internal.inputValidation.validateAxesHandle); parser.parse(varargin{:}); % re-parse one more time to expand partial strings extView = validatestring(parser.Results.View,... {'PatternCentric','CameraCentric'}, ... mfilename, 'View'); if any(parser.Results.HighlightIndex > numBoards) error(message('vision:calibrate:invalidHighlightIndex')); end % turn the highlight index into a logical vector highlightIndex = false(1,numBoards); highlightIndex(unique(parser.Results.HighlightIndex)) = true; hAxes = newplot(parser.Results.Parent); [wpConvHull, offset] = computeConvexHull(camParams); end %-------------------------------------------------------------------------- function r = checkView(in) validatestring(in, {'PatternCentric','CameraCentric'}, ... mfilename, 'View'); r = true; end %-------------------------------------------------------------------------- function r = checkIndex(in) if ~isempty(in) % permit any kind of empty including [] validateattributes(in, {'numeric'},{'integer','vector'}); end r = true; end %-------------------------------------------------------------------------- function ret = addUnits(in) units = cameraParams.WorldUnits; ret = [in, ' (', units, ')']; end %-------------------------------------------------------------------------- function [wpConvHull, offset] = computeConvexHull(camParams) x = camParams.WorldPoints(:,1); y = camParams.WorldPoints(:,2); k = convhull(x, y, 'simplify',true); % pad with zeros so that Z = 0; wpConvHull = [x(k), y(k), zeros(length(k),1)]'; % compute the longest side of a convex hull enclosing points % collected from the calibration pattern maxDist = 0; for i = 1:length(k)-1 % compute distances between all vertices of the convex hull d = norm(wpConvHull(1:2,i) - wpConvHull(1:2,i+1)); if d > maxDist maxDist = d; end end % We'll use this value as a drawing unit proportional to the % calibration board size. This value is picked to make the plots % "look good". offset = maxDist/6; % In the case of stereo, prevent the offset from being too big % to cause the cameras to overlap. isStereo = isa(camParams, 'stereoParameters'); if isStereo distBetweenCameras = sqrt(sum(camParams.TranslationOfCamera2.^2)); offset = min(offset, 0.8 * distBetweenCameras); end end %-------------------------------------------------------------------------- function cameraCentric plotFixedCam; set(hAxes,'XAxisLocation','top','YAxisLocation',... 'left','ZDir','reverse'); [rotationMatrices, translationVectors] = ... getRotationAndTranslation(cameraParams); for boardIdx = 1:numBoards R = rotationMatrices(:, :, boardIdx)'; t = translationVectors(boardIdx, :)'; [color, alpha] = getColor(boardIdx, boardColorLookup, highlightIndex); worldBoardCoords = bsxfun(@plus, R * wpConvexHull, t); [xIdx, yIdx, zIdx] = getAxesIdx(); wX = worldBoardCoords(xIdx,:); wY = worldBoardCoords(yIdx,:); wZ = worldBoardCoords(zIdx,:); h = patch(wX,wY,wZ, color, 'Parent', hAxes); if (highlightIndex(boardIdx)) tagStr = ['HighlightedExtrinsicsObj' num2str(boardIdx)]; else tagStr = ['ExtrinsicsObj' num2str(boardIdx)]; end set(h,'FaceColor',color,'FaceAlpha',alpha, ... 'EdgeColor',color,'LineWidth',1.0, ... 'Tag',tagStr); % label each board ulCorner = t - 0.3*[offset; offset; 0]; text(ulCorner(xIdx),ulCorner(yIdx),ulCorner(zIdx),... num2str(boardIdx),'fontsize',14,'color',color, ... 'Parent', hAxes); end labelPlotAxesCameraCentric(hAxes); end %-------------------------------------------------------------------------- function patternCentric plotPatternCentricBoard(hAxes, wpConvexHull, offset); % Record the current 'hold' state so that we can restore it later holdState = get(hAxes,'NextPlot'); set(hAxes, 'NextPlot', 'add'); % hold on [rotationMatrices, translationVectors] = ... getRotationAndTranslation(cameraParams); % Draw the cameras for camIdx = 1:numBoards rotation = rotationMatrices(:, :, camIdx)'; translation = translationVectors(camIdx, :)'; [camColor, alpha] = getColor(camIdx, boardColorLookup, highlightIndex); isStereo = isa(cameraParams, 'stereoParameters'); if isStereo plotStereoMovingCam(camIdx, rotation, translation,... camColor, alpha, highlightIndex); else % plot the camera label = num2str(camIdx); plotMovingCam(rotation, translation, ... camColor, alpha, camIdx, highlightIndex, label); end end set(hAxes, 'NextPlot', holdState); % restore the hold state labelPlotAxesPatternCentric(hAxes); end %-------------------------------------------------------------------------- function plotPatternCentricBoard(hAxes, wpConvexHull, offset) wX = wpConvexHull(1,:); wY = wpConvexHull(2,:); wZ = wpConvexHull(3,:); % Draw a small axis in the corner of the board. BTW. Invoking plot3 % first, sets up good default for azimuth and elevation. plot3(hAxes, 3*offset*[1 0 0 0 0],3*offset*[0 0 1 0 0],... 3*offset*[0 0 0 0 1],'r-','linewidth',2); % The origin of the coordinate system is in upper left corner, with % x-axis increasing to the right and y-axis increasing in the down % direction; this is for the right-handed coordinate system that we % used for computing the extrinsics set(hAxes,'XAxisLocation','top','YAxisLocation',... 'left','YDir','reverse'); % Draw the board h = patch(wX,wY,wZ, 'Parent', hAxes); set(h,'FaceColor', [0.4 0.4 0.4]); set(h,'EdgeColor', 'black','linewidth',1); end %-------------------------------------------------------------------------- function plotStereoMovingCam(camIdx, rotation, translation, camColor, alpha, highlightIndex) % plot camera 1 [center1, hHggroup1] = plotMovingCam(rotation, translation, ... camColor, alpha, camIdx, highlightIndex); labelStereoCamera(hHggroup1, center1, '1', camColor); % plot camera 2 t = cameraParams.CameraParameters2.TranslationVectors(camIdx,:)'; R = cameraParams.CameraParameters2.RotationMatrices(:,:,camIdx)'; [center2, hHggroup2] = plotMovingCam(R , t, ... camColor, alpha, camIdx, highlightIndex); labelStereoCamera(hHggroup2, center2, '2', camColor); % connect the two cameras with a line % assign the plot3 to hHggroup1 plot3(hHggroup1, [center1(1), center2(1)], ... [center1(2), center2(2)], [center1(3), center2(3)], ... '-', 'Color', camColor, 'LineWidth', 2,'HitTest','off'); % label the stereo pair % assign the label to hHggroup1 midPoint = (center2 + center1) / 2 + [8; 8; 12]; text(midPoint(1), midPoint(2), midPoint(3), num2str(camIdx), ... 'Parent', hHggroup1, 'fontsize', 15, 'Color', camColor, 'HitTest','off'); end %-------------------------------------------------------------------------- function labelPlotAxesPatternCentric(hAxes) xlabel(hAxes, addUnits('X')); ylabel(hAxes, addUnits('Y')); zlabel(hAxes, addUnits('Z')); % Z goes into the board. Reversing Z direction to display the % cameras above the board. set(hAxes, 'ZDir', 'reverse'); end %-------------------------------------------------------------------------- function labelPlotAxesCameraCentric(hAxes) xlabel(hAxes, addUnits('X')); % note that the Y and the Z axes are switched ylabel(hAxes, addUnits('Z')); zlabel(hAxes, addUnits('Y')); end %-------------------------------------------------------------------------- function labelStereoCamera(hHggroup, center, label, camColor) text(center(1), center(2), center(3), label, 'Parent', hHggroup, ... 'Color', camColor, 'FontSize', 11, 'FontWeight','bold','HitTest','off'); end %-------------------------------------------------------------------------- function [camColor, alpha] = getColor(idx, colorLookup, highlightIndex) camColor = squeeze(colorLookup(1, idx, :))'; % transparency values for board highlighting normalAlpha = 0.2; highlightAlpha = 0.8; if highlightIndex(idx) alpha = highlightAlpha; else alpha = normalAlpha; end end %-------------------------------------------------------------------------- function [rotationMatrices, translationVectors] = ... getRotationAndTranslation(cameraParams) isStereo = isa(cameraParams, 'stereoParameters'); if isStereo rotationMatrices = cameraParams.CameraParameters1.RotationMatrices; translationVectors = cameraParams.CameraParameters1.TranslationVectors; else rotationMatrices = cameraParams.RotationMatrices; translationVectors = cameraParams.TranslationVectors; end end %-------------------------------------------------------------------------- function [camPts, camAxis] = rotateAndShiftCam(camPts, camAxis,... rot, tran) % since we swapped the camera and the board, apply the % transformation backwards: first we translate, then we rotate in % the opposite direction (take transpose of the rotation matrix) so % that the relative positioning of the camera with respect to the % board remains the same while the board is placed at an origin rot = rot'; camAxis = rot*bsxfun(@minus, camAxis, tran); camPts = rot*bsxfun(@minus, camPts, tran); end %-------------------------------------------------------------------------- function [camPts, camAxis] = getCamPts(factor) cu = offset*factor; ln = cu+cu; % cam length % back camPts = [0 0 cu cu 0;... 0 cu cu 0 0;... 0 0 0 0 0]; % sides camPts = [camPts, ... [0 0 0 0 cu cu cu cu cu cu 0; ... 0 cu cu cu cu cu cu 0 0 0 0; ... ln ln 0 ln ln 0 ln ln 0 ln ln]]; ro = cu/2; % rim offset rm = ln+2*ro; % rim z offset (extent) % lens camPts = [camPts, ... [ -ro -ro cu+ro cu+ro -ro; ... -ro cu+ro cu+ro -ro -ro; ... rm rm rm rm rm] ]; % rim around the lens camPts = [camPts, ... [0 0 -ro 0 cu cu+ro cu cu cu+ro cu 0 ;... 0 cu cu+ro cu cu cu+ro cu 0 -ro 0 0 ;... ln ln rm ln ln rm ln ln rm ln ln] ]; camPts = bsxfun(@minus, camPts, [cu/2; cu/2; cu]); % cam axis camAxis = 2*factor*offset*([0 1 0 0 0 0; 0 0 0 1 0 0; 0 0 0 0 0 1]); end %-------------------------------------------------------------------------- function [center, hHggroup] = plotMovingCam(rotationMat, translation, camColor, ... alpha, idx, highlightIndex, label) [camPts, camAxis] = getCamPts(0.6); [camPts, camAxis] = ... rotateAndShiftCam(camPts, camAxis, rotationMat, translation); % Create a hggroup for each camera if highlightIndex(idx) hHggroup = hggroup('Parent',hAxes,'Tag',['HighlightedExtrinsicsObj' num2str(idx)]); else hHggroup = hggroup('Parent',hAxes,'Tag',['ExtrinsicsObj' num2str(idx)]); end % draw camera wire frame if alpha == 0 plot3(hHggroup, camPts(1,:),camPts(2,:),camPts(3,:),'w-','linewidth',1, 'HitTest', 'off'); end % color camera surfaces %%%%%%%%%%%%%%%%%%%%%%%% % cam 'lens' lensPatch = struct('vertices', camPts', 'faces', 17:21); h = patch(lensPatch, 'Parent', hHggroup); set(h,'FaceColor', [0 0.8 1], 'FaceAlpha', alpha, ... 'EdgeColor', camColor, 'HitTest', 'off'); % cam back rimPatch = struct('vertices', camPts', 'faces', 1:5); h = patch(rimPatch, 'Parent', hHggroup); set(h,'FaceColor', camColor, 'FaceAlpha', alpha, ... 'EdgeColor', camColor, 'HitTest', 'off'); % cam sides sidePatch = struct('vertices', camPts', 'faces',... [5 6 7 8 5; 8 9 10 11 8; 11 12 13 14 11; 14 5 6 13 14]); h = patch(sidePatch, 'Parent', hHggroup); set(h,'FaceColor', camColor, 'FaceAlpha', alpha, ... 'EdgeColor', camColor, 'HitTest', 'off'); % cam rim rimPatch = struct('vertices', camPts', 'faces',... [21 22 23 24 21; 24 25 26 27 24;... 27 28 29 30 27; 30 31 32 21 30]); h = patch(rimPatch, 'Parent', hHggroup); set(h,'FaceColor', camColor, 'FaceAlpha', alpha, ... 'EdgeColor', camColor, 'HitTest', 'off'); % Add camera labels %%%%%%%%%%%%%%%%%%%% if nargin > 6 % positions of camera labels (offset from the camera axis) camLabelLoc = [camAxis(1,2), camAxis(2,4), ... 2*camAxis(3,1)-camAxis(3,6) + offset/5]; % label each camera with a number text(camLabelLoc(1),camLabelLoc(2),camLabelLoc(3),label,... 'FontSize',11,'Color',camColor,'FontWeight','bold', ... 'Parent', hHggroup, 'HitTest', 'off'); end center = camAxis(:, 1); end %-------------------------------------------------------------------------- function plotFixedCam [camPts, camAxis] = getCamPts(1); isStereo = isa(cameraParams, 'stereoParameters'); if isStereo color1 = 'b'; plotOneFixedCamera(camPts, color1); plotFixedCameraAxis(hAxes, camAxis); labelFixedCamera(hAxes, camPts, '1', color1); t = cameraParams.TranslationOfCamera2; R = cameraParams.RotationOfCamera2; camPts2 = bsxfun(@minus, camPts', t); camPts2 = (camPts2 * R')'; holdState = get(hAxes,'NextPlot'); set(hAxes, 'NextPlot', 'add'); color2 = 'r'; plotOneFixedCamera(camPts2, color2); labelFixedCamera(hAxes, camPts2, '2', color2); set(hAxes, 'NextPlot', holdState); % restore the state else plotOneFixedCamera(camPts, 'b'); plotFixedCameraAxis(hAxes, camAxis); end end %-------------------------------------------------------------------------- function plotOneFixedCamera(camPts, color) [xIdx, yIdx, zIdx] = getAxesIdx(); % plot the body plot3(hAxes, camPts(xIdx,:),camPts(yIdx,:),camPts(zIdx,:),... [color, '-'],'linewidth',1.5); end %-------------------------------------------------------------------------- function labelFixedCamera(hAxes, camPts, label, color) [xIdx, yIdx, zIdx] = getAxesIdx(); % label the camera textIdx = 20; textOffset = 0.1 * offset; text(camPts(xIdx, textIdx)+textOffset, camPts(yIdx, textIdx)-textOffset, ... camPts(zIdx, textIdx), label, 'fontsize',14,... 'Parent', hAxes, 'Color', color); end %-------------------------------------------------------------------------- function plotFixedCameraAxis(hAxes, camAxis) [xIdx, yIdx, zIdx] = getAxesIdx(); % plot the x/y/z axis holdState = get(hAxes,'NextPlot'); set(hAxes, 'NextPlot', 'add'); plot3(hAxes, camAxis(xIdx,:),camAxis(yIdx,:),camAxis(zIdx,:),'k-',... 'linewidth',1.5); set(hAxes, 'NextPlot', holdState); % restore the state % label camera axis d = 2.4*offset; text( d, 0, 0,'X_c', 'Parent', hAxes); text( 0, d, 0,'Z_c', 'Parent', hAxes); text( 0, 0, d,'Y_c', 'Parent', hAxes); end %-------------------------------------------------------------------------- function [xIdx, yIdx, zIdx] = getAxesIdx() % We are going to swap y and z coordinates because the 3-d plot % rotates around the MATLAB's z-axis by default. Thus the % camera can be displayed horizontally and the 3-d plot will % rotate conveniently around the newly defined vertical y-axis. xIdx = 1; yIdx = 3; zIdx = 2; end end