gusucode.com > vision工具箱matlab源码程序 > vision/detectMSERFeatures.m

    function [regions, cc] = detectMSERFeatures(I, varargin)
%detectMSERFeatures Finds MSER features.
%   regions = detectMSERFeatures(I) returns an MSERRegions object, regions,
%   containing region pixel lists and other information about MSER features
%   detected in a 2-D grayscale image I. detectMSERFeatures uses Maximally
%   Stable Extremal Regions (MSER) algorithm to find regions.
%
%   [..., cc] = detectMSERFeatures(I) optionally returns MSER regions in a
%   connected component structure. This output is useful for measuring
%   region properties using the <a href="matlab:help regionprops">regionprops</a> function. The connected 
%   component structure, cc, contains four fields:
%    
%       Connectivity   Connectivity of the MSER regions (default is 8)
% 
%       ImageSize      Size of I.
% 
%       NumObjects     Number of MSER regions in I.
% 
%       PixelIdxList   1-by-NumObjects cell array where the kth element
%                      in the cell array is a vector containing the linear
%                      indices of the pixels in the kth MSER region.
%
%   regions = detectMSERFeatures(I,Name,Value) specifies additional
%   name-value pair arguments described below:
%
%   'ThresholdDelta'   Scalar value, 0 < ThresholdDelta <= 100, expressed 
%                      as a percentage of the input data type range. This 
%                      value specifies the step size between intensity 
%                      threshold levels used in selecting extremal regions 
%                      while testing for their stability. Decrease this 
%                      value to return more regions. Typical values range 
%                      from 0.8 to 4.
%
%                      Default: 2
%
%   'RegionAreaRange'  Two-element vector, [minArea maxArea], which
%                      specifies the size of the regions in pixels. This  
%                      value allows the selection of regions containing 
%                      pixels between minArea and maxArea, inclusive.
%
%                      Default: [30 14000]
%
%   'MaxAreaVariation' Positive scalar. Increase this value to return a  
%                      greater number of regions at the cost of their
%                      stability. Stable regions are very similar in
%                      size over varying intensity thresholds. Typical 
%                      values range from 0.1 to 1.0.
%
%                      Default: 0.25
%
%   'ROI'              A vector of the format [X Y WIDTH HEIGHT],
%                      specifying a rectangular region in which corners
%                      will be detected. [X Y] is the upper left corner of
%                      the region.                                     
%                 
%                      Default: [1 1 size(I,2) size(I,1)]
%
%   Class Support
%   -------------
%   The input image I can be uint8, int16, uint16, single or double, 
%   and it must be real and nonsparse.
%
%   Example 1 - Detect and plot MSER regions
%   ----------------------------------------
%   % Find MSER regions
%   I = imread('cameraman.tif');
%   regions = detectMSERFeatures(I);
%
%   % Visualize MSER regions which are described by pixel lists stored 
%   % inside the returned 'regions' object
%   figure
%   imshow(I)
%   hold on
%   plot(regions, 'showPixelList', true, 'showEllipses', false)
%
%   % Display ellipses and centroids fit into the regions
%   figure
%   imshow(I)
%   hold on
%   plot(regions) % by default, plot displays ellipses and centroids
%
%   Example 2 - Find circular MSER regions
%   --------------------------------------
%   % Detect MSER regions
%   I = imread('coins.png');
%   [regions, mserCC] = detectMSERFeatures(I);
% 
%   % Show all detected MSER REgions
%   figure
%   imshow(I)
%   hold on
%   plot(regions, 'showPixelList', true, 'showEllipses', false)
% 
%   % Measure MSER region eccentricity to gauge region circularity.
%   stats = regionprops('table', mserCC, 'Eccentricity');
% 
%   % Circular regions have low eccentricity. Threshold eccentricity values to
%   % only keep the circular regions.
%   eccentricityIdx = stats.Eccentricity < 0.55;
%   circularRegions = regions(eccentricityIdx);
% 
%   % Show circular regions
%   figure
%   imshow(I)
%   hold on
%   plot(circularRegions, 'showPixelList', true, 'showEllipses', false)
%   
%   See also MSERRegions, extractFeatures, matchFeatures,
%            detectBRISKFeatures, detectFASTFeatures, detectHarrisFeatures,
%            detectMinEigenFeatures, detectSURFFeatures, SURFPoints

%   Copyright 2011 The MathWorks, Inc.

%   References:
%      Jiri Matas, Ondrej Chum, Martin Urban, Tomas Pajdla. "Robust
%      wide-baseline stereo from maximally stable extremal regions",
%      Proc. of British Machine Vision Conference, pages 384-396, 2002.
%
%      David Nister and Henrik Stewenius, "Linear Time Maximally Stable 
%      Extremal Regions", European Conference on Computer Vision, 
%      pages 183-196, 2008. 

%#codegen
%#ok<*EMCA>

[Iu8, params] = parseInputs(I,varargin{:});

if isSimMode()
    % regionsCell is pixelLists in a cell array {a x 2; b x 2; c x 2; ...} and
    % can only be handled in simulation mode since cell arrays are not supported
    % in code generation
    regionsCell = ocvExtractMSER(Iu8, params);
    
    if params.usingROI && ~isempty(params.ROI)        
        regionsCell = offsetPixelList(regionsCell, params.ROI);
    end
    
    regions = MSERRegions(regionsCell);
    
else
    [pixelList, lengths] = ...
        vision.internal.buildable.detectMserBuildable.detectMser_uint8(Iu8, params);
    
    if params.usingROI && ~isempty(params.ROI) % offset location values
        pixelList = offsetPixelListCodegen(pixelList, params.ROI);
    end
    
    regions = MSERRegions(pixelList, lengths);
    
end

if nargout == 2      
    cc = region2cc(regions, size(I));   
end

%==========================================================================
% Convert MSER regions to connected component struct
%==========================================================================
function cc = region2cc(regions, imageSize)

if isempty(coder.target)
    % Convert PixelList to PixelIdxList and pack into connected component struct.
    
    pixelIdxList = cell(1, regions.Count);
    for i = 1:regions.Count
        locations = regions.PixelList{i};
        pixelIdxList{i} = sub2ind(imageSize, locations(:,2), locations(:,1));
    end
    
    cc.Connectivity = 8;
    cc.ImageSize    = imageSize;
    cc.NumObjects   = regions.Count;
    cc.PixelIdxList = pixelIdxList;
    
else
    % Code generation path    
    idxCount = coder.internal.indexInt([0;cumsum(regions.Lengths)]);
    regionIndices = coder.nullcopy(zeros(sum(regions.Lengths),1));
    
    % MSER regions are stored as x,y locations. convert them to
    % linear indices for return in the CC struct.
    for k = 1:regions.Count
        
        range = idxCount(k)+1:idxCount(k+1);
        
        locations = regions.PixelList(range, :);
        
        idx = sub2ind(imageSize, locations(:,2), locations(:,1));
        
        regionIndices(range,1) = idx;
    end
    
    cc.Connectivity  = 8;
    cc.ImageSize     = imageSize;
    cc.NumObjects    = regions.Count;
    cc.RegionIndices = regionIndices;
    cc.RegionLengths = cast(regions.Lengths, 'like', idxCount);
    
end

%==========================================================================
% Parse and check inputs
%==========================================================================
function [img, params] = parseInputs(I, varargin)

vision.internal.inputValidation.validateImage(I, 'I', 'grayscale');

Iu8 = im2uint8(I);

imageSize = size(I);
if isSimMode()
    params = parseInputs_sim(imageSize, varargin{:});
else
    params = parseInputs_cg(imageSize, varargin{:});
end

%--------------------------------------------------------------------------
% Other OpenCV parameters which are not exposed in the main interface
%--------------------------------------------------------------------------
params.minDiversity  = single(0.2);
params.maxEvolution  = int32(200);
params.areaThreshold = 1;
params.minMargin     = 0.003;
params.edgeBlurSize  = int32(5);

img = vision.internal.detector.cropImageIfRequested(Iu8, params.ROI, params.usingROI);

%==========================================================================
function params = parseInputs_sim(imageSize, varargin)
% Parse the PV pairs
parser = inputParser;

defaults = getDefaultParameters(imageSize);

parser.addParameter('ThresholdDelta',   defaults.ThresholdDelta);
parser.addParameter('RegionAreaRange',  defaults.RegionAreaRange);
parser.addParameter('MaxAreaVariation', defaults.MaxAreaVariation);
parser.addParameter('ROI',              defaults.ROI)

% Parse input
parser.parse(varargin{:});

checkThresholdDelta(parser.Results.ThresholdDelta);

params.usingROI  = ~ismember('ROI', parser.UsingDefaults);

roi = parser.Results.ROI;
if params.usingROI
    vision.internal.detector.checkROI(roi, imageSize);
end

isAreaRangeUserSpecified = ~ismember('RegionAreaRange', parser.UsingDefaults);

if isAreaRangeUserSpecified 
    checkRegionAreaRange(parser.Results.RegionAreaRange, imageSize, ...
        params.usingROI, roi);
end

checkMaxAreaVariation(parser.Results.MaxAreaVariation);

% Populate the parameters to pass into OpenCV's ocvExtractMSER()
params.delta        = parser.Results.ThresholdDelta*255/100;
params.minArea      = parser.Results.RegionAreaRange(1);
params.maxArea      = parser.Results.RegionAreaRange(2);
params.maxVariation = parser.Results.MaxAreaVariation;
params.ROI          = parser.Results.ROI;

%==========================================================================
function params = parseInputs_cg(imageSize, varargin)

% Optional Name-Value pair: 3 pairs (see help section)
defaults = getDefaultParameters(imageSize);
defaultsNoVal = getDefaultParametersNoVal();
properties    = getEmlParserProperties();

optarg = eml_parse_parameter_inputs(defaultsNoVal, properties, varargin{:});
parser_Results.ThresholdDelta = (eml_get_parameter_value( ...
        optarg.ThresholdDelta, defaults.ThresholdDelta, varargin{:}));
parser_Results.RegionAreaRange = (eml_get_parameter_value( ...
    optarg.RegionAreaRange, defaults.RegionAreaRange, varargin{:}));
parser_Results.MaxAreaVariation = (eml_get_parameter_value( ...
    optarg.MaxAreaVariation, defaults.MaxAreaVariation, varargin{:}));
parser_ROI  = eml_get_parameter_value(optarg.ROI, defaults.ROI, varargin{:});

checkThresholdDelta(parser_Results.ThresholdDelta);

% check whether ROI parameter is specified
usingROI = optarg.ROI ~= uint32(0);

if usingROI
    vision.internal.detector.checkROI(parser_ROI, imageSize);    
end

% check whether area range parameter is specified
isAreaRangeUserSpecified = optarg.RegionAreaRange ~= uint32(0);

if isAreaRangeUserSpecified 
    checkRegionAreaRange(parser_Results.RegionAreaRange, imageSize,...
        usingROI, parser_ROI);
end

checkMaxAreaVariation(parser_Results.MaxAreaVariation);

params.delta        = cCast('int32_T', parser_Results.ThresholdDelta*255/100);
params.minArea      = cCast('int32_T', parser_Results.RegionAreaRange(1));
params.maxArea      = cCast('int32_T', parser_Results.RegionAreaRange(2));
params.maxVariation = cCast('real32_T', parser_Results.MaxAreaVariation);
params.ROI          = parser_ROI;
params.usingROI     = usingROI;

%==========================================================================
% Offset pixel list locations based on ROI
%==========================================================================
function pixListOut = offsetPixelList(pixListIn, roi)
n = size(pixListIn,1);
pixListOut = cell(n,1);
for i = 1:n   
    pixListOut{i} = vision.internal.detector.addOffsetForROI(pixListIn{i}, roi, true);
end

%==========================================================================
% Offset pixel list locations based on ROI
%==========================================================================
function pixListOut = offsetPixelListCodegen(pixListIn, roi)

pixListOut = vision.internal.detector.addOffsetForROI(pixListIn, roi, true);

%==========================================================================
function defaults = getDefaultParameters(imgSize)
       
defaults = struct(...
    'ThresholdDelta', 5*100/255, ...
    'RegionAreaRange', [30 14000], ...
    'MaxAreaVariation', 0.25,...
    'ROI', [1 1 imgSize(2) imgSize(1)]);

%==========================================================================
function defaultsNoVal = getDefaultParametersNoVal()

defaultsNoVal = struct(...
    'ThresholdDelta', uint32(0), ... 
    'RegionAreaRange', uint32(0), ... 
    'MaxAreaVariation', uint32(0), ...
    'ROI', uint32(0));

%==========================================================================
function properties = getEmlParserProperties()

properties = struct( ...
    'CaseSensitivity', false, ...
    'StructExpand',    true, ...
    'PartialMatching', false);

%==========================================================================
function tf = checkThresholdDelta(thresholdDelta)
validateattributes(thresholdDelta, {'numeric'}, {'scalar',...
    'nonsparse', 'real', 'positive', '<=', 100}, mfilename);
tf = true;

%==========================================================================
function checkRegionAreaRange(regionAreaRange, imageSize, usingROI, roi)

if usingROI
    % When an ROI is specified, the region area range validation should
    % be done with respect to the ROI size.
    sz = int32([roi(4) roi(3)]);
else
    sz = int32(imageSize);
end

imgArea = sz(1)*sz(2);
validateattributes(regionAreaRange, {'numeric'}, {'integer',... 
    'nonsparse', 'real', 'positive', 'size', [1,2]}, mfilename);

coder.internal.errorIf(regionAreaRange(2) < regionAreaRange(1), ...
    'vision:detectMSERFeatures:invalidRegionSizeRange');

% When the imageSize is less than area range, throw a warning.
if imgArea < int32(regionAreaRange(1))
    coder.internal.warning('vision:detectMSERFeatures:imageAreaLessThanAreaRange')
end


%==========================================================================
function tf = checkMaxAreaVariation(maxAreaVariation)
validateattributes(maxAreaVariation, {'numeric'}, {'nonsparse', ...
    'real', 'scalar', '>=', 0}, mfilename);
tf = true;

%==========================================================================
function flag = isSimMode()

flag = isempty(coder.target);

%==========================================================================
function outVal = cCast(outClass, inVal)
outVal = coder.nullcopy(zeros(1,1,outClass));
outVal = coder.ceval(['('   outClass  ')'], inVal);