gusucode.com > vision工具箱matlab源码程序 > vision/imageSet.m
%imageSet Define collection of images. % % ----------------------------------------------------------------------- % Use imageDatastore, which offers more functionality and is recommended % instead of imageSet. % ----------------------------------------------------------------------- % % imgSet = imageSet(imageLocation) defines a collection of images by % specifying imageLocation. imageLocation can be a string specifying a % folder full of images or a cell array of image file locations such % as {'imagePath1','imagePath2', ..., 'imagePathX'}. % % imgSetVector = imageSet(imgFolder, 'recursive') travels the folder structure % recursively starting in folder, imgFolder. Images found in each folder % are assigned into 1-by-NumFolders imgSetVector. NumFolders is % a number of directories that contained at least one image. % The Description property for each element of imgSetVector is set % to the folder name. % % imageSet methods: % read - Reads an image at a specified index % partition - Divides an image set into two or more groups % select - Selects a subset of images from the image set % % imageSet properties: % Description - Information about the imageSet % Count - Number of images held by the object % ImageLocation - Cell array defining image locations % % Example 1: Create an image set from a folder % -------------------------------------------- % % Create an image set from a folder full of images % imgFolder = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages'); % imgSet = imageSet(imgFolder); % % %Display first image in the collection % imshow(read(imgSet, 1)); % % Example 2: Create an array of image sets from multiple folders % -------------------------------------------------------------- % % Recursively scan the entire calibration examples folder % imgFolder = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata','imageSets'); % % imgSets = imageSet(imgFolder,'recursive') % {imgSets.Description} % Display names of the scanned folders % % % Display 2nd image from the 'cups' folder % imshow(read(imgSets(2), 2)); % % Example 3: Create an image set by specifying individual images % -------------------------------------------------------------- % % Create an image set by specifying individual images % imgFiles = { fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages','image001.jpg'),... % fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages','image002.jpg') }; % % Alternatively, you can pick the files manually using imgetfile: % % imgFiles = imgetfile('MultiSelect', true); % imgSet = imageSet(imgFiles); % % See also imageDatastore, imgetfile % Copyright 2014 MathWorks, Inc. classdef imageSet properties(Access = public) Description = ''; % Information about the imageSet end % Read only properties properties (SetAccess='protected', GetAccess='public') ImageLocation = {''}; % Image locations end % Dependent properties properties (SetAccess='protected', GetAccess='public', Dependent = true) Count; % Number of images end properties(Hidden, Dependent, Transient) Files; % For compatibility with imageDatastore end %---------------------------------------------------------------------- % Private methods %---------------------------------------------------------------------- methods (Access = private) %------------------------------------------------------------------ function this = parseInput(this, varargin) if nargin >= 2 % this plus input in = varargin{1}; validateattributes(in,{'char','cell'}, {'nonempty'}, ... mfilename, 'ImageLocation'); if ischar(in) % we are dealing with a folder input this = this.parseDirInput(varargin{:}); else % the input was a cell array narginchk(2,2); % cell input can't be followed by anything else this = this.parseCellInput(in); end else this.ImageLocation = {}; end end %------------------------------------------------------------------ function this = parseDirInput(this, varargin) dirName = varargin{1}; dirName = imageSet.expandDirToAbsPath(dirName); if numel(varargin) > 1 % we have a second input argIdx = 2; modifier = varargin{argIdx}; validatestring(modifier, {'recursive'}, argIdx); isRecursive = true; else isRecursive = false; end if ~isdir(dirName) % This also covers the case of 'in' not being a % scalar error(message('vision:imageSet:inputMustBeValidFolderName')); end if isRecursive % pre-pend the root folder and fetch all subdirectories allDirs = [{dirName}, imageSet.getSubDirNames(dirName)]; n = numel(allDirs); this(n) = imageSet.makeDefaultObject(this); % pre-allocate object array for i=1:n this(i) = parseInput(this(i), allDirs{i}); end % purge the empty sets this([this.Count]==0) = []; else this.ImageLocation = imageSet.parseFolder(dirName); % If a dot was used, turn it into actual path if strcmp(dirName,'.') dirName = pwd; end % Set the description to the folder name [~, name, ext] = fileparts(dirName); % Directory name can contain a dot. This handles it correctly. this.Description = [name, ext]; end end %------------------------------------------------------------------ function this = parseCellInput(this, in) % make sure that it's a vector validateattributes(in,{'cell'}, {'vector'}, ... mfilename, 'ImageLocation'); % verify that all entries are strings areAllFilenamesValid = iscellstr(in); if ~areAllFilenamesValid error(message('vision:imageSet:allFilenamesMustBeStrings')); end % verify that all files exist areAllFilenamesValid = all(cellfun(@(x) (exist(x,'file')==2), in)); if ~areAllFilenamesValid error(message('vision:imageSet:allFilesMustExist')); end % If relative path was specified, expand to absolute path. Even % if current directory is changed, the object will still be % able to read the images when absolute paths are used. this.ImageLocation = imageSet.expandFileToAbsPath(in); % set Description to '' because this could be any set of files. this.Description = ''; end end %---------------------------------------------------------------------- % Private static methods %---------------------------------------------------------------------- methods (Access = private, Static) %------------------------------------------------------------------ function absPathOut = expandFileToAbsPath(in) for i=1:length(in) fid = fopen(in{i},'r'); in{i} = fopen(fid); % returns absolute path fclose(fid); end absPathOut = in; end %------------------------------------------------------------------ function absPathOut = expandDirToAbsPath(in) try [~, info] = fileattrib(in); absPathOut = info.Name; catch % It's possible that we were handed an invalid directory % name. If that's the case, pass it forward for further % error checking absPathOut = in; end end %------------------------------------------------------------------ function imageFilenames = parseFolder(fileFolder) % get a list of valid image extensions formats = imformats(); ext = [formats(:).ext]; % scan the folder for files contents = dir(fileFolder); imageFilenames = contents(~[contents(:).isdir]); imageFilenames = {imageFilenames(:).name}; exp = sprintf('(.*\\.%s$)|',ext{:}); % filter filenames by extension idx = cellfun(@(x)~isempty(x),regexpi(imageFilenames, exp,'once')); imageFilenames = fullfile(fileFolder, imageFilenames(idx)); end %------------------------------------------------------------------ function subDirNames = getSubDirNames(rootDir) filelist = dir(rootDir); % get list of subdirectories. dirList = filelist([filelist.isdir]); % filter by excluding '.', '..' filteredDirList = dirList(cellfun(@isempty,regexp({dirList.name},'^(\.|\.\.)$'))); % prepend root dir to the path subDirNames = cellfun(@(in)fullfile(rootDir,in),{filteredDirList.name},... 'UniformOutput',false); if ~isempty(subDirNames) for i=1:numel(subDirNames) tempDirNames = imageSet.getSubDirNames(subDirNames{i}); subDirNames = [subDirNames, tempDirNames]; %#ok<AGROW> end end end end %---------------------------------------------------------------------- % Set/Get methods %---------------------------------------------------------------------- methods %------------------------------------------------------------------ function out = get.Count(this) out = numel(this.ImageLocation); end %------------------------------------------------------------------ function this = set.Description(this,desc) if numel(desc) > 0 % Description may be set to a string validateattributes(desc,{'char'},{'row'},mfilename,'Description'); else % Description may be set to an empty string '' validateattributes(desc,{'char'},{'numel',0},mfilename,'Description'); end this.Description = desc; end %------------------------------------------------------------------ function files = get.Files(this) % Get results from ImageLocation. Used to match imageDatastore % API. files = this.ImageLocation; end end %---------------------------------------------------------------------- % Public methods %---------------------------------------------------------------------- methods (Access = public) %------------------------------------------------------------------ function this = imageSet(varargin) narginchk(0,2); % cell or dir or dir+'recursive' % imageSet constructor this = parseInput(this, varargin{:}); end %------------------------------------------------------------------ function imOut = read(this, index) %read Read image specified by index % % image = read(imgSet, idx) returns an image at index, % idx, from the imageSet object imgSet. % % Example % ------- % imDir = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages'); % imgSet = imageSet(imDir); % % % Display the fourth image from the set % imshow(read(imgSet, 4)); validateattributes(index, {'double','single','uint32','uint16','uint8'}, ... {'scalar','nonempty','integer','positive'}, ... mfilename, 'idx'); if ~isscalar(this) error(message('vision:imageSet:methodNotSupportedForArrays')); end try imOut = imread(this.ImageLocation{index}); catch exRead % set could be empty if this.Count == 0 error(message('vision:imageSet:setIsEmpty')); end % indicate which file could not be read, in addition to % the error message from imread error(message('vision:imageSet:couldNotReadFile',... this.ImageLocation{index}, exRead.message)); end end end % end methods %---------------------------------------------------------------------- % Sealed public methods %---------------------------------------------------------------------- methods(Access = public, Sealed) %------------------------------------------------------------------ function out = select(this, index) %select Select images specified by index % imgSetOut = select(imgSet, idx) returns a new imageSet, % imgSetOut, with images selected using index, idx. idx can % be a scalar or a vector of indices. % % Example % ------- % imgFolder = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages'); % imgSet = imageSet(imgFolder); % % % Select images 2 and 4 % imgSetOut = select(imgSet, [2, 4]); if islogical(index) validateattributes(index, {'logical'},... {'vector','nonempty'}, ... mfilename, 'idx'); else validateattributes(index, {'double','single','uint32','uint16','uint8'}, ... {'vector','nonempty','integer','positive'}, ... mfilename, 'idx'); end n = numel(this); if n > 1 if isanyempty(this) error(message('vision:imageSet:arrayContainsEmptyImageSet')); end else if isempty(this) || this.Count == 0 error(message('vision:imageSet:setIsEmpty')); end end out(n) = imageSet.makeDefaultObject(this); out(n) = selectProperties(this(end), index); for i = 1:n-1 out(i) = selectProperties(this(i), index); end end %------------------------------------------------------------------ function varargout = partition(this, groupSizes, varargin) %partition Divide set into subsets % [set1, set2, ..., setN] = partition(imgSet, groupSizes) partitions % imgSet into, [set1, set2, ..., setN]. For example, groupSizes = [20 60], % would result in 20 images going into set1, 60 images going into % set2 and the remainder into set3. The number of output % arguments, N, must be between 1 and length(groupSizes)+1. % % [set1, set2, ..., setN] = partition(imgSet, groupPercentages) % specifies the partitions in terms of percentages. For example, % [0.1 0.5] would result in 10% of images going into set1, % 50% going into set2, and the remainder into set3. % % [...] = partition(..., method) additionally specifies a method, % 'sequential' or 'randomized'. When the method is % 'randomized', the images are drawn at random to form the new sets. % The default method is 'sequential'. % % Example % ------- % imgFolder = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata', 'stopSignImages'); % imgSet = imageSet(imgFolder); % % % Divide the set into two groups with sizes: 5 and imgSet.Count-5 % [setA1, setA2] = partition(imgSet, 5); % % % Randomly partition the set into 20%, 30% and 50% groups % [setB1, setB2, setB3] = partition(imgSet, [0.2, 0.3], 'randomized'); [groupSizes, params, isSplitInPercent] = ... parsePartitionInputs(groupSizes, varargin{:}); % verify partition amounts if isSplitInPercent if sum(groupSizes) > 1 error(message('vision:imageSet:invalidPercentageSplitRequest')); end else if any(sum(groupSizes) > [this.Count]) error(message('vision:imageSet:invalidSplitRequest')); end end numSplits = length(groupSizes) + 1; nargoutchk(1, numSplits); if nargout < numSplits numSplits = nargout; % make num outputs optional, and less then or equal to the maximum allowed end varargout(1:nargout) = {this.empty()}; % initialize output numSets = numel(this); for setIdx = 1:numSets; currentSet = this(setIdx); % grab a set from an array of sets if isSplitInPercent % groupSizes are expressed in percentages absoluteGroupSizes = round(currentSet.Count*groupSizes); if sum(absoluteGroupSizes) > currentSet.Count absoluteGroupSizes(end) = currentSet.Count - sum(absoluteGroupSizes(1:end-1)); end splitAmounts = [absoluteGroupSizes, ... currentSet.Count - sum(absoluteGroupSizes)]; else % groupSizes are expressed in absolute amounts splitAmounts = [groupSizes, currentSet.Count - sum(groupSizes)]; end % pad with 0 to avoid 'if' in a loop splitAmounts = [splitAmounts, 0]; %#ok<AGROW> startIdx = 1; endIdx = splitAmounts(1); if strcmpi(params.Method, 'randomized') indices = randperm(currentSet.Count); else indices = 1:currentSet.Count; end isAnySplitEmpty = false; for splitIdx = 1:numSplits range = indices(startIdx:endIdx); % make a split if isempty(range) varargout{splitIdx} = [varargout{splitIdx}, imageSet.makeDefaultObject(this)]; isAnySplitEmpty = true; else varargout{splitIdx} = [varargout{splitIdx}, currentSet.select(range)]; end startIdx = startIdx + splitAmounts(splitIdx); endIdx = sum(splitAmounts(1:splitIdx+1)); end if isAnySplitEmpty warning(message('vision:imageSet:atLeastOneOutputEmpty')); end end % end of setIdx = ... end % end of partition method end %---------------------------------------------------------------------- % Protected methods %---------------------------------------------------------------------- methods(Access = protected) %------------------------------------------------------------------ % imgSet = selectProperties(imgSet, index) returns a copy of the % input imageSet, imgSet, that contains a subset of the property % data selected by index. index can be a scalar or a vector of % indices. % % This method is called by the SELECT method. A derived subclass of % imageSet should overload this method to ensure that the SELECT % method returns the correct results for the subclass. The subclass % version of selectProperties must perform the indexing operation % required for each subclass property, including ImageLocation and % Description. %------------------------------------------------------------------ function imgSet = selectProperties(imgSet, index) imgSet.ImageLocation = imgSet.ImageLocation(index); imgSet.Description = imgSet.Description; end end %---------------------------------------------------------------------- % Hidden methods %---------------------------------------------------------------------- methods(Hidden) %------------------------------------------------------------------ function out = isanyempty(this) out = any([this.Count] == 0); end %------------------------------------------------------------------ % saveobj and loadobj are implemented to ensure compatibility across % releases even if architecture of this class changes function that = saveobj(this) that.Description = this.Description; that.ImageLocation = this.ImageLocation; end %------------------------------------------------------------------ function I = readimage(this, idx) I = read(this, idx); end %------------------------------------------------------------------ function tbl = countEachLabel(this) tbl = table(... reshape({this.Description},[],1), ... reshape([this.Count],[],1)); end end % methods (Hidden) %---------------------------------------------------------------------- methods (Static, Hidden) function this = loadobj(that) this = imageSet(); this.ImageLocation = that.ImageLocation; this.Description = that.Description; end %------------------------------------------------------------------ % Returns a default version of this object. Used to preserve class % information during array creation of a derived class. %------------------------------------------------------------------ function default = makeDefaultObject(this) default = feval(class(this)); end end end %-------------------------------------------------------------------------- function [groupSizes, params, isSplitInPercent] = parsePartitionInputs(varargin) % parse varargin parser = inputParser; parser.addRequired('groupSizes'); parser.addOptional('Method', 'sequential', @validatePartitionMethod); parser.parse(varargin{:}); % validate inputs validateattributes(parser.Results.groupSizes, ... {'double','single','uint32','uint16','uint8'}, ... {'vector','nonempty','real','positive'}, ... mfilename, 'groupSizes'); [~, params.Method] = validatePartitionMethod(parser.Results.Method); groupSizes = double(parser.Results.groupSizes); % cast groupSizes to double groupSizes = groupSizes(:)'; % turn into row vector % Determine whether we are dealing with absolute partitions or percentages if groupSizes(1) < 1 validateattributes(groupSizes, {'double'}, {'<',1}, mfilename, 'groupPercentages'); isSplitInPercent = true; else validateattributes(groupSizes, {'double'}, {'integer'}, mfilename, 'groupSizes'); isSplitInPercent = false; end end %-------------------------------------------------------------------------- function [tf, method] = validatePartitionMethod(val) method = validatestring(val, ... {'randomized' ,'sequential'}, mfilename,'Method'); tf = true; end