gusucode.com > vision工具箱matlab源码程序 > vision/+vision/+internal/+calibration/+tool/Session.m
% Session holds the state of the Camera Calibration App % % This class holds the entire state of the camera calibration UI. % It is used to save and load the camera calibration session. It is also % used to pass data amongst other classes. % Copyright 2012-2013 The MathWorks, Inc. classdef Session < handle properties CameraModel; % holds all of the calibration options OptimizationOptions = []; % initial values for intrinsics and radial distortion CameraParameters = []; % actual calibration results EstimationErrors = []; ShouldExportErrors = false; BoardSet = []; % holds all checkerboard information HasEnoughBoards = false; % true if enough images were loaded and processed CanExport = false; % true when cameraParameters can be exported IsChanged = false; % true when session may need saving ExtrinsicsView = 'CameraCentric'; % ErrorsView is no longer used, since we only use the BarGraph view % in the app. However, we have to keep this property around for % compatibility with older versions. ErrorsView = 'BarGraph'; Filename = []; % filename for the session ExportVariableName = 'cameraParams'; % default export variable name ExportErrorsVariableName = 'estimationErrors'; end properties(Access=private, Hidden) Version = ver('vision'); end properties(Dependent) FileName; % Had to add this for backward compatibility % The following properties are NOT mutually exclusive. % An empty session (with empty BoardSet and CameraParameters) can % be either stereo or single camera. IsValidStereoCameraSession; IsValidSingleCameraSession; end methods %------------------------------------------------------------------ function fileName = get.FileName(this) fileName = this.Filename; end %------------------------------------------------------------------ function set.FileName(this, fileName) this.Filename = fileName; end %------------------------------------------------------------------ function tf = get.IsValidStereoCameraSession(this) tf = (isempty(this.CameraParameters) || ... isa(this.CameraParameters, 'stereoParameters')) && ... (isempty(this.BoardSet) || ... size(this.BoardSet.FullPathNames, 1) == 2); end %------------------------------------------------------------------ function tf = get.IsValidSingleCameraSession(this) tf = (isempty(this.CameraParameters) || ... isa(this.CameraParameters, 'cameraParameters')) && ... (isempty(this.BoardSet) || ... size(this.BoardSet.FullPathNames, 1) == 1); end %------------------------------------------------------------------ % return true if the tool went though the calibration %------------------------------------------------------------------ function ret = isCalibrated(this) ret = ~isempty(this.CameraParameters); end function ret = hasAnyBoards(this) ret = ~isempty(this.BoardSet) && ... this.BoardSet.NumBoards ~= 0; end %------------------------------------------------------------------ function reset(this) this.ExtrinsicsView = 'CameraCentric'; this.FileName = []; this.CanExport = false; this.HasEnoughBoards = false; this.CameraParameters = []; this.IsChanged = false; this.CameraModel = []; this.OptimizationOptions = []; if ~isempty(this.BoardSet) this.BoardSet.reset(); end end %------------------------------------------------------------------ % Wipes only the calibration portion of the session %------------------------------------------------------------------ function resetCalibration(this) this.CanExport = false; this.CameraParameters = []; end %------------------------------------------------------------------ function checkImagePaths(this, pathname, filename) if ~isempty(this.BoardSet) this.BoardSet.checkImagePaths(pathname, filename); end end %------------------------------------------------------------------ function imagesUsed = calibrate(this) if isempty(this.OptimizationOptions) || ... isempty(this.OptimizationOptions.InitialDistortion) numRadial = this.CameraModel.NumDistortionCoefficients; else numRadial = numel(this.OptimizationOptions.InitialDistortion); end if ~isempty(this.OptimizationOptions) initIntrinsics = this.OptimizationOptions.InitialIntrinsics; initDistortion = this.OptimizationOptions.InitialDistortion; else initIntrinsics = []; initDistortion = []; end [cameraParams, imagesUsed, estimationErrors] = ... estimateCameraParameters(this.BoardSet.BoardPoints, ... this.BoardSet.WorldPoints,... 'EstimateSkew', this.CameraModel.ComputeSkew, ... 'EstimateTangentialDistortion', ... this.CameraModel.ComputeTangentialDistortion, ... 'NumRadialDistortionCoefficients', numRadial, ... 'WorldUnits', this.BoardSet.Units, ... 'ShowProgressBar', true, ... 'InitialIntrinsicMatrix', initIntrinsics, ... 'InitialRadialDistortion', initDistortion); this.CanExport = true; this.IsChanged = true; this.CameraParameters = cameraParams; this.EstimationErrors = estimationErrors; end %------------------------------------------------------------------ function codeString = generateCode(this) if isa(this.CameraParameters, 'stereoParameters') codeString = generateCodeStereo(this); else codeString = generateCodeSingle(this); end end end methods(Access=private) %------------------------------------------------------------------ function codeString = generateCodeSingle(this) cameraModel = this.CameraModel; codeGenerator = vision.internal.calibration.tool.MCodeGenerator; % Write a header codeGenerator.addHeader('cameraCalibrator'); % Detect checkerboards codeGenerator.addComment('Define images to process'); codeGenerator.addLine(sprintf('imageFileNames = %s;',... cell2str(this.BoardSet.FullPathNames))); codeGenerator.addComment('Detect checkerboards in images'); codeGenerator.addLine('[imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames);'); codeGenerator.addLine('imageFileNames = imageFileNames(imagesUsed);'); % Set up data for the calibration codeGenerator.addComment('Generate world coordinates of the corners of the squares'); codeGenerator.addLine(sprintf('squareSize = %d; %% in units of ''%s''',... this.BoardSet.SquareSize,... this.BoardSet.Units)); codeGenerator.addLine('worldPoints = generateCheckerboardPoints(boardSize, squareSize);'); % Calibrate if isempty(this.OptimizationOptions) initIntrinsics = []; initDistortion = []; else initIntrinsics = this.OptimizationOptions.InitialIntrinsics; initDistortion = this.OptimizationOptions.InitialDistortion; end codeGenerator.addComment('Calibrate the camera'); codeGenerator.addLine(sprintf(['[cameraParams, imagesUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...\n',... '''EstimateSkew'', %s, ''EstimateTangentialDistortion'', %s, ...\n', ... '''NumRadialDistortionCoefficients'', %d, ''WorldUnits'', ''%s'', ...\n', ... '''InitialIntrinsicMatrix'', %s, ''InitialRadialDistortion'', %s);'], ... mat2str(cameraModel.ComputeSkew), ... mat2str(cameraModel.ComputeTangentialDistortion),... cameraModel.NumDistortionCoefficients, this.BoardSet.Units, ... mat2str(initIntrinsics), mat2str(initDistortion))); % Add visualizations % Reprojection errors codeGenerator.addComment('View reprojection errors'); codeGenerator.addLine('h1=figure; showReprojectionErrors(cameraParams);'); % Extrinsics codeGenerator.addComment('Visualize pattern locations'); codeGenerator.addLine(sprintf('h2=figure; showExtrinsics(cameraParams, ''%s'');', ... this.ExtrinsicsView)); % Estimation errors codeGenerator.addComment('Display parameter estimation errors'); codeGenerator.addLine('displayErrors(estimationErrors, cameraParams);'); % Suggest possible next steps codeGenerator.addComment('For example, you can use the calibration data to remove effects of lens distortion.'); codeGenerator.addLine('originalImage = imread(imageFileNames{1});'); codeGenerator.addLine('undistortedImage = undistortImage(originalImage, cameraParams);'); codeGenerator.addComment('See additional examples of how to use the calibration data. At the prompt type:'); codeGenerator.addLine('% showdemo(''MeasuringPlanarObjectsExample'')'); codeGenerator.addLine('% showdemo(''StructureFromMotionExample'')'); % Terminate the file with carriage return codeGenerator.addReturn(); codeString = codeGenerator.CodeString; end %------------------------------------------------------------------ function codeString = generateCodeStereo(this) cameraModel = this.CameraModel; codeGenerator = vision.internal.calibration.tool.MCodeGenerator; % Write a header codeGenerator.addHeader('stereoCalibrator'); % Detect checkerboards codeGenerator.addComment('Define images to process'); codeGenerator.addLine(sprintf('imageFileNames1 = %s;',... cell2str(this.BoardSet.FullPathNames(1, :)))); codeGenerator.addLine(sprintf('imageFileNames2 = %s;',... cell2str(this.BoardSet.FullPathNames(2, :)))); codeGenerator.addComment('Detect checkerboards in images'); codeGenerator.addLine('[imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames1, imageFileNames2);'); % Set up data for the calibration codeGenerator.addComment('Generate world coordinates of the checkerboard keypoints'); codeGenerator.addLine(sprintf('squareSize = %d; %% in units of ''%s''',... this.BoardSet.SquareSize,... this.BoardSet.Units)); codeGenerator.addLine('worldPoints = generateCheckerboardPoints(boardSize, squareSize);'); % Calibrate if isempty(this.OptimizationOptions) initIntrinsics = []; initDistortion = []; else initIntrinsics = this.OptimizationOptions.InitialIntrinsics; initDistortion = this.OptimizationOptions.InitialDistortion; end codeGenerator.addComment('Calibrate the camera'); codeGenerator.addLine(sprintf(['[stereoParams, pairsUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...\n',... '''EstimateSkew'', %s, ''EstimateTangentialDistortion'', %s, ...\n', ... '''NumRadialDistortionCoefficients'', %d, ''WorldUnits'', ''%s'', ...\n', ... '''InitialIntrinsicMatrix'', %s, ''InitialRadialDistortion'', %s);'], ... mat2str(cameraModel.ComputeSkew), ... mat2str(cameraModel.ComputeTangentialDistortion),... cameraModel.NumDistortionCoefficients, this.BoardSet.Units, ... mat2str(initIntrinsics), mat2str(initDistortion))); % Add visualizations % Reprojection errors codeGenerator.addComment('View reprojection errors'); codeGenerator.addLine('h1=figure; showReprojectionErrors(stereoParams);'); % Extrinsics codeGenerator.addComment('Visualize pattern locations'); codeGenerator.addLine(sprintf('h2=figure; showExtrinsics(stereoParams, ''%s'');', ... this.ExtrinsicsView)); % Estimation errors codeGenerator.addComment('Display parameter estimation errors'); codeGenerator.addLine('displayErrors(estimationErrors, stereoParams);'); % Suggest possible next steps codeGenerator.addComment('You can use the calibration data to rectify stereo images.'); codeGenerator.addLine('I1 = imread(imageFileNames1{1});'); codeGenerator.addLine('I2 = imread(imageFileNames2{1});'); codeGenerator.addLine('[J1, J2] = rectifyStereoImages(I1, I2, stereoParams);'); codeGenerator.addComment('See additional examples of how to use the calibration data. At the prompt type:'); codeGenerator.addLine('% showdemo(''StereoCalibrationAndSceneReconstructionExample'')'); codeGenerator.addLine('% showdemo(''DepthEstimationFromStereoVideoExample'')'); % Terminate the file with carriage return codeGenerator.addReturn(); codeString = codeGenerator.CodeString; end end %---------------------------------------------------------------------- % saveobj and loadobj are implemented to ensure compatibility across % releases even if architecture of Session class changes methods (Hidden) function that = saveobj(this) that.version = this.Version; that.cameraModel = this.CameraModel; that.optimizationOptions = this.OptimizationOptions; that.cameraParams = this.CameraParameters; that.estimationErrors = this.EstimationErrors; that.shouldExportErrors = this.ShouldExportErrors; that.boardSet = this.BoardSet; that.hasEnoughBoards = this.HasEnoughBoards; that.canExport = this.CanExport; that.isChanged = this.IsChanged; that.extrinsicsView = this.ExtrinsicsView; that.errorsView = this.ErrorsView; that.filename = this.FileName; that.exportVarName = this.ExportVariableName; end end %---------------------------------------------------------------------- methods (Static, Hidden) function this = loadobj(that) if isa(that, 'vision.internal.calibration.tool.Session') this = that; this.OptimizationOptions.InitialIntrinsics = []; this.OptimizationOptions.InitialDistortion = []; else this = vision.internal.calibration.tool.Session; this.CameraModel = that.cameraModel; this.CameraParameters = that.cameraParams; this.EstimationErrors = that.estimationErrors; this.ShouldExportErrors = that.shouldExportErrors; this.BoardSet = that.boardSet; this.HasEnoughBoards = that.hasEnoughBoards; this.CanExport = that.canExport; this.IsChanged = that.isChanged; this.ExtrinsicsView = that.extrinsicsView; this.FileName = that.filename; this.ExportVariableName = that.exportVarName; if isfield(that, 'optimizationOptions') this.OptimizationOptions = that.optimizationOptions; else this.OptimizationOptions.InitialIntrinsics = []; this.OptimizationOptions.InitialDistortion = []; end end end end end %-------------------------------------------------------------- % This function handles conversion of cell array of strings % to a string representing the entire cell array %-------------------------------------------------------------- function str = cell2str(cellArray) str = '{'; % opening bracket % constants that are easier to read once assigned into % variables quote = ''''; nextLine = sprintf(',...\n'); for i=1:numel(cellArray) str = [str, quote, cellArray{i}, quote, nextLine]; %#ok<AGROW> end str = [str, '}']; % closing bracket end