gusucode.com > vision工具箱matlab源码程序 > vision/+vision/+internal/FeaturePointsImpl.m
classdef FeaturePointsImpl %#codegen properties (Access='public', Dependent = true) %Location Array of [x y] point coordinates Location; %Metric Value indicating feature's strength Metric; end properties (SetAccess='private', GetAccess='public', Dependent = true) %Count Number of stored interest points Count; end properties (Access='protected') pLocation = ones(0,2,'single'); pMetric = ones(0,1,'single'); end methods %------------------------------------------------------------------ function this = FeaturePointsImpl(varargin) if nargin > 0 inputs = parseInputs(this, varargin{:}); validate(this,inputs); this = configure(this,inputs); end end %------------------------------------------------------------------ function strongest = selectStrongest(this, N) % selectStrongest Return N points with strongest metrics % % strongestPoints = selectStrongest(points, N) keeps N points % with strongest metrics. validateattributes(N, {'numeric'}, {'scalar', 'integer', ... 'positive'}, class(this)); coder.varsize('idx', [inf, 1]); idx = coder.nullcopy(zeros(size(this.pMetric), 'like', this.pMetric)); [~, idx(:,1)] = sort(this.pMetric,'descend'); if N > length(idx) NN = length(idx); else NN = N; end if isempty(coder.target) % Use this's subsref implementation s.type = '()'; s.subs = {idx(1:NN)}; strongest = subsref(this,s); else strongest = getIndexedObj(this, idx(1:NN)); end end %------------------------------------------------------------------ function pointsOut = selectUniform(this, numPoints, imageSize) % selectUniform Return a uniformly distributed subset of feature points % pointsOut = selectUniform(pointsIn, N, imageSize) keeps N % points with the strongest metrics approximately uniformly % distributed throughout the image. imageSize is a 2-element % vector containing the size of the image. validateattributes(numPoints, {'numeric'}, {'scalar', 'integer', ... 'positive', 'nonsparse', 'real'}, class(this)); validateattributes(imageSize, {'numeric'}, {'vector', 'integer', ... 'positive', 'nonsparse'}, class(this)); if numel(imageSize) > 3 validateattributes(imageSize, {'numeric'}, {'vector', 'integer', ... 'positive', 'numel', 2}, class(this)); end coder.varsize('metric', [inf, 1]); coder.varsize('origIdx', [1, inf]); coder.varsize('points', [inf, 2]); coder.varsize('idxOut', [inf, 1]); coder.varsize('idx', [inf, 1]); coder.varsize('idxNum', [1, inf]); imageSize = imageSize([2,1]); points = this.Location; metric = this.Metric; origIdx = 1:this.Count; idxOut = coder.nullcopy(zeros(size(this.pMetric), 'like', this.pMetric)); if numPoints > length(idxOut) NN = length(idxOut); else NN = numPoints; end first = 1; if isempty(coder.target) && ~isa(this.Location, 'gpuArray') idxNum = visionSelectUniformPoints(double(points), imageSize,... double(metric), NN); idxNum = sort(idxNum); idx = false(size(origIdx)); idx(idxNum) = true; else idx = selectPoints(points, imageSize, metric, NN); idxNum = origIdx(idx); end idxOut(first:numel(idxNum)) = idxNum'; first = numel(idxNum) + 1; while(first <= NN) origIdx = origIdx(~idx); points = points(~idx, :); metric = metric(~idx); n = NN - (first - 1); if isempty(coder.target) && ~isa(this.Location, 'gpuArray') idxNum = visionSelectUniformPoints(double(points), imageSize,... double(metric), n); idx = false(size(points,1), 1); idx(idxNum) = true; idxNum = origIdx(idx); else idx = selectPoints(points, imageSize, metric, n); idxNum = origIdx(idx); end idxOut(first:first+numel(idxNum)-1) = idxNum'; first = first+numel(idxNum); end if isempty(coder.target) s.type = '()'; s.subs = {idxOut(1:NN)}; pointsOut = subsref(this, s); else pointsOut = getIndexedObj(this, idxOut(1:NN)); end end %------------------------------------------------------------------ % Note: NUMEL is not overridden because it interferes with the % desired operation of this object. FeaturePoints is a scalar % object which pretends to be a vector. NUMEL is used during % subsref operations and therefore needs to represent true % number of elements for the object, which is always 1. %------------------------------------------------------------------ function out = length(this) %length Returns number of points out = this.Count; end %------------------------------------------------------------------ function out = isempty(this) %isempty Returns true if the object is empty out = this.Count == 0; end %------------------------------------------------------------------- function ind = end(this,varargin) %END Last index in indexing expression for FeaturePoints % end(V,K,N) is called for indexing expressions involving the % FeaturePoints vector V when END is part of the K-th index out of % N indices. For example, the expression V(end-1,:) calls the % FeaturePoints vector's END method with END(V,1,2). % % See also end if isempty(varargin) || varargin{1} == 1 ind = this.Count; else ind = 1; end end %----------------------------------------------- function this = set.Location(this, in) this.checkForResizing(in); this.checkLocation(in); this.pLocation(:) = single(in); end function out = get.Location(this) out = this.pLocation; end %------------------------------------------------ function this = set.Metric(this, in) this.checkForResizing(in); this.checkMetric(in); this.pMetric(:) = single(in); end function out = get.Metric(this) out = this.pMetric; end %------------------------------------------------- function out = get.Count(this) out = size(this.Location,1); end end methods(Access = protected) function inputs = parseInputs(~, varargin) if isempty(coder.target) % Parse the PV pairs parser = inputParser; parser.addRequired('Location') parser.addParameter('Metric', single(0)); % Parse input parser.parse(varargin{:}); inputs = parser.Results; else defaultsNoVal = struct('Metric', uint32(0)); properties = struct( ... 'CaseSensitivity', false, ... 'StructExpand', true, ... 'PartialMatching', false); inputs.Location = single(varargin{1}); defaults = vision.internal.FeaturePointsImpl.getParameterDefaults(); optarg = eml_parse_parameter_inputs(defaultsNoVal, properties, varargin{2:end}); inputs.Metric = (eml_get_parameter_value( ... optarg.Metric, defaults.Metric, varargin{2:end})); end end function validate(this, inputs) this.checkLocation(inputs.Location); this.checkMetric(inputs.Metric); numPts = size(inputs.Location,1); % Parameters must have the same number of elements or be a scalar vision.internal.FeaturePointsImpl.validateParamLength(numel(inputs.Metric), 'Metric', numPts); end function checkForResizing(this, in) % Prevent resizing of public properties coder.internal.errorIf(size(in,1) ~= this.Count, ... 'vision:FeaturePoints:cannotResizePoints', class(this)); end %------------------------------------------------------------------ function this = configure(this,inputs) if ~isempty(coder.target) if eml_is_const(size(inputs.Location)) eml_invariant(all(size(inputs.Location) > 0) , ... eml_message('vision:FeaturePoints:constSizeEmpty')); end end n = size(inputs.Location,1); % If either location or metric is a gpuArray then store both as % gpuArrays. if isa(inputs.Metric, 'gpuArray') || isa(inputs.Location, 'gpuArray') prototype = zeros(0,1,'single','gpuArray'); else % built-in type/codegen code path prototype = zeros(0,1,'single'); end this.pLocation = coder.nullcopy(zeros(n,2,'like',prototype)); this.pLocation = single(inputs.Location); this.pMetric = coder.nullcopy(zeros(n,1,'like',prototype)); this.pMetric(:) = ... vision.internal.FeaturePointsImpl.assignValue(single(inputs.Metric),n); end function checkLocation(this, location) if isa(location, 'gpuArray') checkGPULocation(this, location); else validateattributes(location, {'numeric'}, {'nonnan', ... 'finite', 'nonsparse', 'real', 'positive', 'size',[NaN,2]}, ... class(this)); %#ok<*EMCA> end end function checkGPULocation(this, location) hValidateAttributes(location, {'numeric'}, {'nonnan', ... 'finite','real'}, ... class(this)); %#ok<*EMCA> % positive if any(location(:) <= 0) validateattributes(-1, {'numeric'}, {'positive'}, class(this)); end % size if size(location,2) ~= 2 validateattributes(ones(3,3),{'numeric'},{'size',[NaN,2]},class(this)); end end function checkMetric(this, metric) checkParam(metric, class(this),'Metric'); end function checkScale(this, scale) checkParam(scale,class(this),'Scale'); end function checkOrientation(this, orientation) checkParam(orientation, class(this),'Orientation'); end end methods (Static, Access = protected) function validateParamLength(numelParam, paramName, numPts) coder.internal.errorIf(~(numelParam == 1 || numelParam == numPts), ... 'vision:FeaturePoints:invalidParamLength', paramName); end function defaults = getParameterDefaults() defaults = struct('Metric', single(0)); end function v = assignValue(x,N) % copy x into v, expanding scalars if needed coder.inline('always'); v = coder.nullcopy(ones(N,1,'like',x)); if isscalar(x) v = repmat(x(:),N,1); else v = x(:); end end end end function checkParam(in,fname,pname) if isa(in, 'gpuArray') hValidateAttributes(in, {'numeric'},... {'nonnan', 'finite', 'real','vector'},... fname, pname); else validateattributes(in, {'numeric'},... {'nonnan', 'finite', 'nonsparse','real','vector'},... fname, pname); end end %-------------------------------------------------------------------------- function pointsIdx = selectPoints(points, imageSize, metric, numPoints) if numPoints == 1 [~, numericIdx] = max(metric); pointsIdx = false(size(points, 1), 1); pointsIdx(numericIdx) = true; return; end aspectRatio = imageSize(1) / imageSize(2); h = max(floor(sqrt(numPoints / aspectRatio)), 1); w = max(floor(h * aspectRatio), 1); nBins = [w, h]; gridStep = imageSize ./ (nBins + 1); binIdx = zeros(nBins); for i = 1:size(points, 1) whichBin = min([floor(points(i, :) ./ gridStep) + 1; nBins]); idx = binIdx(whichBin(1), whichBin(2)); if idx < 1 || metric(idx) < metric(i) binIdx(whichBin(1), whichBin(2)) = i; end end numericIdx = binIdx(binIdx > 0); numericIdx = numericIdx(:); pointsIdx = false(size(points, 1), 1); pointsIdx(numericIdx) = true; end % In order for method help to work properly for subclasses, this classdef % file cannot have a comment block at the top, so the following remark and % copyright/version information are provided here at the end. Please do % not move them. % Copyright 2013 The MathWorks, Inc.