gusucode.com > vision工具箱matlab源码程序 > vision/pcfitplane.m
function [model, inlierIndices, outlierIndices, rmse] = pcfitplane(varargin) %PCFITPLANE Fit plane to a 3-D point cloud. % model = PCFITPLANE(ptCloud, maxDistance) fits a plane to the point % cloud, ptCloud. The plane is described by a planeModel object. % maxDistance is a maximum allowed distance from an inlier point to the % plane. This function uses the M-estimator SAmple Consensus (MSAC) % algorithm to find the plane. % % model = PCFITPLANE(..., referenceVector) fits a plane to the point % cloud with additional orientation constraints. referenceVector is a % 1-by-3 vector used as a reference orientation. % % model = PCFITPLANE(..., referenceVector, maxAngularDistance) fits a % plane to the point cloud with additional orientation constraints. % maxAngularDistance specifies the maximum allowed absolute angular % distance in degrees between the normal vector of fitted plane and the % reference orientation. If it is not specified, the default is 5 % degrees. % % [..., inlierIndices, outlierIndices] = PCFITPLANE(...) additionally % returns linear indices to the inlier and outlier points in ptCloud. % % [..., rmse] = PCFITPLANE(...) additionally returns root mean square % error of the distance of inlier points to the model. % % [...] = PCFITPLANE(..., Name,Value) specifies additional name-value % pair arguments described below: % % 'SampleIndices' A vector specifying the linear indices of points % to be sampled in the input point cloud. The % indices, for example, can be generated by % findPointsInROI method of pointCloud object. % By default, the entire point cloud is processed. % % Default: [] % % 'MaxNumTrials' A positive integer scalar specifying the maximum % number of random trials for finding the inliers. % Increasing this value will improve the robustness % of the output at the expense of additional % computation. % % Default: 1000 % % 'Confidence' A numeric scalar, C, 0 < C < 100, specifying the % desired confidence (in percentage) for finding % the maximum number of inliers. Increasing this % value will improve the robustness of the output % at the expense of additional computation. % % Default: 99 % % Class Support % ------------- % ptCloud must be a pointCloud object. % % Example: Detect multiple planes from point cloud % ------------------------------------------------ % load('object3d.mat') % % figure % pcshow(ptCloud) % xlabel('X(m)') % ylabel('Y(m)') % zlabel('Z(m)') % title('Original Point Cloud') % % % Set the maximum point-to-plane distance (2cm) for plane fitting % maxDistance = 0.02; % % Set the normal vector of a plane % referenceVector = [0, 0, 1]; % % Set the maximum angular distance (5 degrees) % maxAngularDistance = 5; % % % Detect the table and extract it from the point cloud % [model1, inlierIndices, outlierIndices] = pcfitplane(ptCloud, ... % maxDistance, referenceVector, maxAngularDistance); % plane1 = select(ptCloud, inlierIndices); % remainPtCloud = select(ptCloud, outlierIndices); % % % Set the roi to constrain the search for the left wall % roi = [-inf, inf, 0.4, inf, -inf, inf]; % sampleIndices = findPointsInROI(remainPtCloud, roi); % % % Detect the left wall and extract it from the remaining point cloud % [model2, inlierIndices, outlierIndices] = pcfitplane(remainPtCloud, ... % maxDistance, 'SampleIndices', sampleIndices); % plane2 = select(remainPtCloud, inlierIndices); % remainPtCloud = select(remainPtCloud, outlierIndices); % % % Plot the two planes and the remaining points % figure % pcshow(plane1) % title('First Plane') % % figure % pcshow(plane2) % title('Second Plane') % % figure % pcshow(remainPtCloud) % title('Remaining Point Cloud') % % See also pointCloud, pointCloud>findPointsInROI, planeModel, pcfitsphere, % pcfitcylinder, pcshow % Copyright 2015 The MathWorks, Inc. % % References: % ---------- % P. H. S. Torr and A. Zisserman, "MLESAC: A New Robust Estimator with % Application to Estimating Image Geometry," Computer Vision and Image % Understanding, 2000. % Parse input arguments [ptCloud, ransacParams, sampleIndices, ... referenceVector, maxAngularDistance] = ... vision.internal.ransac.validateAndParseRansacInputs(mfilename, true, varargin{:}); % Use three points to fit a plane sampleSize = 3; ransacParams.sampleSize = sampleSize; % Initialization [statusCode, status, pc, validPtCloudIndices] = ... vision.internal.ransac.initializeRansacModel(ptCloud, sampleIndices, sampleSize); % Compute the geometric model parameter with MSAC if status == statusCode.NoError ransacFuncs.fitFunc = @fitPlane; ransacFuncs.evalFunc = @evalPlane; if isempty(referenceVector) ransacFuncs.checkFunc = @checkPlane; [isFound, modelParams] = vision.internal.ransac.msac(pc.Location, ... ransacParams, ransacFuncs); else % Fit the plane with orientation constraint ransacFuncs.checkFunc = @checkPerpendicularPlane; denorm = sqrt(dot(referenceVector,referenceVector)); normAxis = referenceVector ./ denorm; [isFound, modelParams] = vision.internal.ransac.msac(pc.Location, ... ransacParams, ransacFuncs, normAxis, maxAngularDistance); if isFound % Adjust the plane normal vector so that its direction matches the % referenceVector. This makes the absolute angular distance always % smaller than 90 degrees. a = min(1, max(-1, dot(normAxis, modelParams(1:3)))); angle = abs(acos(a)); if angle > pi/2 modelParams = -modelParams; end end end if ~isFound status = statusCode.NotEnoughInliers; end end if status == statusCode.NoError % Construct the plane object model = planeModel(modelParams); else model = planeModel.empty; end % Report runtime error vision.internal.ransac.checkRansacRuntimeStatus(statusCode, status); % Extract inliers needInlierIndices = (nargout > 1); needOutlierIndices = (nargout > 2); needRMSE = (nargout > 3); if needInlierIndices if status == statusCode.NoError % Re-evaluate the best model if ~isempty(sampleIndices) [pc, validPtCloudIndices] = removeInvalidPoints(ptCloud); end distances = evalPlane(modelParams, pc.Location); inlierIndices = validPtCloudIndices(distances < ransacParams.maxDistance); else inlierIndices = []; end end % Extract outliers if needOutlierIndices if status == statusCode.NoError flag = true(ptCloud.Count, 1); flag(inlierIndices) = false; outlierIndices = find(flag); else outlierIndices = []; end end % Report RMSE if needRMSE if status == statusCode.NoError rmse = mean(distances(distances < ransacParams.maxDistance)); else rmse = []; end end %========================================================================== % Plane equation: ax + by + cz + d = 0; %========================================================================== function model = fitPlane(points, varargin) a = points(2, :) - points(1, :); b = points(3, :) - points(1, :); % Cross product normal = [a(2).*b(3)-a(3).*b(2), ... a(3).*b(1)-a(1).*b(3), ... a(1).*b(2)-a(2).*b(1)]; denom = sum(normal.^2); if denom < eps(class(points)) model = []; else normal = normal / sqrt(denom); d = -points(1,:) * normal'; model = [normal, d]; end %========================================================================== % Calculate the distance from the point to the plane. % D = (a*x + b*y + c*z + d)/sqrt(a^2+b^2+c^2). Denominator is 1 because % the normal is a unit vector here. %========================================================================== function dis = evalPlane(model, points, varargin) dis = abs(points * model(1:3)' + model(4)); %========================================================================== % Validate the plane coefficients %========================================================================== function isValid = checkPlane(model) isValid = (numel(model) == 4 & all(isfinite(model))); %========================================================================== % Validate the plane coefficients with orientation constraints %========================================================================== function isValid = checkPerpendicularPlane(model, normAxis, threshold) isValid = checkPlane(model); if isValid a = min(1, max(-1, normAxis*model(1:3)')); angle = abs(acos(a)); angle = min(angle, pi-angle); isValid = (angle < threshold); end