gusucode.com > vision工具箱matlab源码程序 > vision/+vision/+internal/+hog/Visualization.m

    %Visualization Displays HOG features.
%  Visualization is a visualization of HOG features extracted from an
%  image. This visualization is returned by the extractHOGFeatures function
%  and can be displayed using plot.
%
%  plot(visualization) plots the HOG features as an array of rose
%  plots. Each rose plot shows the distribution of edge directions within a
%  cell. The distribution is visualized by a set of directed lines whose
%  lengths are scaled to indicate the contribution made by the gradients in
%  that particular direction. The line directions are fixed to the bin
%  centers of the orientation histograms and are between 0 and 360 degrees
%  measured counterclockwise from the positive X axis. The bin centers are
%  recorded in the BinCenters property.
%
%  plot(visualization, AX) plots HOG features into the axes AX.
%
%  plot(..., Name, Value) specifies additional name-value pair arguments:
%
%   'Color'
%       <a href="matlab:doc('ColorSpec')">ColorSpec</a>
%       Specifies the color used to plot HOG features.
%
%  Visualization properties:
%
%  CellSize             - Size of cells in pixels
%  BlockSize            - Number of cells in each block
%  BlockOverlap         - Overlap between adjacent blocks
%  NumBins              - Number of orientation bins
%  UseSignedOrientation - Determines if signed orientation values are used
%  BinCenters           - Centers of the histogram bins
%
%  Example 1 - Visualize HOG features
%  ----------------------------------
%
%    I1 = imread('gantrycrane.png');
%    [~, visualization] = extractHOGFeatures(I1,'CellSize',[32 32]);
%    plot(visualization)
%
%  Example 2 - Overlay HOG features on an image
%  --------------------------------------------
%
%    I2 = imread('gantrycrane.png');
%    [~, visualization2] = extractHOGFeatures(I2,'CellSize',[32 32]);
%    figure;
%    imshow(I2);
%    hold on
%    plot(visualization2, 'Color', 'green')
%
%  See also extractHOGFeatures

classdef(HandleCompatible) Visualization < matlab.mixin.CustomDisplay
    % ---------------------------------------------------------------------
    % Public read-only properties
    % ---------------------------------------------------------------------
    properties (GetAccess = public, SetAccess=protected)
        % CellSize - Size of a HOG cell in pixel units
        CellSize
        % BlockSize - Number of cells in each block
        BlockSize
        % BlockOverlap - Number of overlapping cells between adjacent 
        %                blocks
        BlockOverlap
        % NumBins - Number of orientation bins
        NumBins
        % UseSignedOrientation - Determines if signed orientation values
        % are used. When false, the orientation histogram range is
        % from 0 to 180 degrees. Otherwise it is between 0 and 360.
        UseSignedOrientation
        
    end
    
    % ---------------------------------------------------------------------
    % Public read-only properties
    % ---------------------------------------------------------------------
    properties(GetAccess = public, SetAccess = protected, Dependent = true)
        % BinCenters - Centers of the histogram bins
        BinCenters
    end
    
    % ---------------------------------------------------------------------
    % Protected properties
    % ---------------------------------------------------------------------   
    properties(Hidden, SetAccess = protected, GetAccess = protected) 
        Feature
        ImageSize
        Points        
    end
    
    % ---------------------------------------------------------------------
    % Hidden read-only properties
    % ---------------------------------------------------------------------
    properties(Hidden, SetAccess = protected, GetAccess = public)
        % WindowSize is accessed by external helper functions
        WindowSize
    end
    
    % ---------------------------------------------------------------------
    % Private properties
    % ---------------------------------------------------------------------
    properties(Hidden, Access = private, Dependent = true)
        BlockSizeInPixels
        BlockStepSize
    end
    
    methods    
        % -----------------------------------------------------------------
        % Plot method for visualizing HOG features
        % -----------------------------------------------------------------
        function hData = plot(this,varargin)
            %  plot(visualization) plots HOG features as an array of
            %  rose plots.
            %
            %  plot(visualization, AX) plots features into the axes AX.
            %
            %  plot(..., Name, Value) specifies additional name-value pair
            %  arguments:
            %
            %   'Color'
            %       <a href="matlab:doc('ColorSpec')">ColorSpec</a>
            %       Specifies the color used to plot HOG features.                        
            % 
            %  Example - Visualize HOG features
            %  ----------------------------------
            %
            %    I1 = imread('gantrycrane.png');
            %    [~, hogVis] = extractHOGFeatures(I1,'CellSize',[32 32]);
            %    plot(hogVis)
            
            [colorSpec, axes] = parseInputs(this, varargin{:});                        
            
            if isempty(this.Feature)
                warning(message('vision:extractHOGFeatures:nothingToPlot'));
                if nargout > 0
                    hData = [];
                end
            else
                                
                nBins  = this.NumBins;
                
                % average HOGs over overlapping cells
                numHOGs      = size(this.Feature,1);
                featureClass = class(this.Feature);
                avgHogs = zeros([floor(this.WindowSize./this.CellSize) nBins numHOGs], featureClass);
                for idx = 1:numHOGs
                    avgHogs(:,:,:,idx) = this.averageHOGs(idx);
                end
                
                [cellCentersXY, cIdx] = computeCellCenters(this);
                
                x = zeros(2, nBins, size(cellCentersXY,1), numHOGs);
                y = zeros(2, nBins, size(cellCentersXY,1), numHOGs);
                
                % compute spatial offset of HOG blocks when extracted around
                % point locations.
                if ~isempty(this.Points)
                    blockCenter = (this.WindowSize - mod(this.WindowSize,2))./2 + 1;                    
                    dxdy = bsxfun(@minus, round(this.Points), fliplr(blockCenter));
                else
                    dxdy = zeros(1,2);
                end
                
                endPoints = computeLineEndPoints(this);
                
                % scale factor based on cellSize, adjusted to look nice
                lineScale = min(this.CellSize)/2.5;
                
                for k = 1:numHOGs
                    f = avgHogs(:,:,:,k);
                    blockOffset = dxdy(k,:);
                    
                    for idx = 1:size(cellCentersXY,1)
                        startPoints  = ones([nBins 1])*(cellCentersXY(idx,:) + blockOffset);
                        
                        vals = squeeze(f(cIdx(idx,2), cIdx(idx,1), :));
                        
                        vals = vals./(norm(vals,2) + eps);
                        
                        if this.UseSignedOrientation
                            x1y1 = startPoints;
                        else
                            x1y1 = startPoints + lineScale .* bsxfun(@times,-endPoints,vals);
                        end
                        
                        x2y2 = startPoints + lineScale .* bsxfun(@times,endPoints,vals);
                        
                        pts = [x1y1 x2y2];
                        x(:,:,idx,k) = pts(:,[1 3])';
                        y(:,:,idx,k) = pts(:,[2 4])';
                    end
                end
                
                x = reshape(x,2,[]);
                y = reshape(y,2,[]);
                x(end+1,:) = NaN;
                y(end+1,:) = NaN;
                
                try
                    ax = newplot(axes);       
                    
                    % plot the hog cell lines and markers for cell centers.                    
                    lns = plot(x(:), y(:), '-', ...     
                        cellCentersXY(:,1), cellCentersXY(:,2), '.',...
                        'Color', colorSpec, ...
                        'Parent', ax, ...
                        'MarkerSize', 1);
                    
                    rects = zeros(1,numHOGs);
                    if ~isempty(this.Points)       
                        % add a rectangle around point locations
                        for k = 1:numHOGs
                            rects(k) = rectangle('Parent',ax,...
                                'EdgeColor',colorSpec,...
                                'Position',[dxdy(k,:)+0.5 ...
                                fliplr(this.CellSize.*this.BlockSize)]);
                        end                        
                    end
                catch aError
                    throwAsCaller(aError);
                end
                
                if ~ishold
                    ax = get(lns(1),'Parent');
                    set(ax,'Ydir','reverse','Color',[0 0 0]);                    
                    axis(ax,'image');
                    set(ax, ...
                        'XLim',[0 this.ImageSize(2)]+0.5, ...
                        'YLim',[0 this.ImageSize(1)]+0.5, ...
                        'YTickLabel','', ...
                        'XTickLabel','');
                end
                
                if nargout == 1
                    hData = [lns(1) rects];
                end
            end
        end
    end
    
    % ---------------------------------------------------------------------
    % Get methods for dependent properties
    % ---------------------------------------------------------------------
    methods
        % -----------------------------------------------------------------
        % Convert block size from cells to pixels
        % -----------------------------------------------------------------
        function sz = get.BlockSizeInPixels(this)
            sz = this.CellSize .* this.BlockSize;
        end
        
        % -----------------------------------------------------------------
        % Compute block step size from the overlap
        % -----------------------------------------------------------------
        function sz = get.BlockStepSize(this)
            sz = this.CellSize.*(this.BlockSize - this.BlockOverlap);
        end
        
        % -----------------------------------------------------------------
        % Compute bin centers based on NumBins and UseSignedOrientation
        % -----------------------------------------------------------------
        function centers = get.BinCenters(this)
            centers = computeBinCenters(this);
            if ~this.UseSignedOrientation
                centers = [centers; centers + 180];                
            end
            centers = double(sort(mod(centers, 360)));
        end
    end
    
    methods (Hidden)
        % -----------------------------------------------------------------
        % Constructor
        % -----------------------------------------------------------------
        function this = Visualization(features, params)
            if nargin > 0
                this.Feature    = features;
                this.NumBins    = single(params.NumBins);
                this.CellSize   = single(params.CellSize);
                this.ImageSize  = single(params.ImageSize);
                this.BlockSize  = single(params.BlockSize);
                this.WindowSize = single(params.WindowSize);
                this.BlockOverlap = single(params.BlockOverlap);
                this.UseSignedOrientation = params.UseSignedOrientation;  
                
                % check if HOG features are extracted around points
                if isfield(params,'Points')
                    if isnumeric(params.Points)
                        this.Points = params.Points;
                    else
                        this.Points = params.Points.Location;
                    end
                end
            end
        end
    end
    
    methods(Hidden, Access = private)
        % -----------------------------------------------------------------
        % Average HOG cells across overlapping blocks
        % -----------------------------------------------------------------
        function hog = averageHOGs(this, idx)
            
            numCellsPerWindow = floor(this.WindowSize./this.CellSize);                        
            accum = zeros([numCellsPerWindow this.NumBins], 'single');
            count = zeros(numCellsPerWindow);            
            
            hBlockSize = [this.NumBins this.BlockSize];
            
            numBlocks = single(vision.internal.hog.getNumBlocksPerWindow(this));
            
            % reshape features to simplify averaging
            features = reshape(this.Feature(idx,:), [prod(hBlockSize) numBlocks]);
            
            blockStep = this.BlockStepSize ./ this.CellSize;
            for j = 1:numBlocks(2)
                for i = 1:numBlocks(1)
                    hBlock = reshape(features(:,i,j), hBlockSize);
                    % offset for cells based on current block position
                    ox = (j-1)*blockStep(2);
                    oy = (i-1)*blockStep(1);
                    for x = 1:this.BlockSize(2)
                        for y = 1:this.BlockSize(1)
                            accum(oy+y, ox+x,:) = ...
                                squeeze(accum(oy+y,ox+x,:)) + hBlock(:,y,x);
                            count(oy+y, ox+x)   = count(oy+y, ox+x) + 1;
                        end
                    end
                end
            end
            
            % average overlapping cells
            count = repmat(count,[1 1 this.NumBins]);
            hog   = accum./(count + eps);
        end
    end
    
    % ---------------------------------------------------------------------
    % Custom display using matlab.mixin.CustomDisplay
    % ---------------------------------------------------------------------
    methods(Hidden, Access = protected)
        
        % -----------------------------------------------------------------
        % Create header for disp method
        % -----------------------------------------------------------------
        function header = getHeader(this)
            if ~isscalar(this)
                header = getHeader@matlab.mixin.CustomDisplay(this);
            else
                % Create a hyperlink that invokes the plot method
                headerStr = matlab.mixin.CustomDisplay.getClassNameForHeader(this);
                cmd = sprintf('<a href="matlab:plot(%s)">plot(%s)</a>',...
                    inputname(1),inputname(1));
                msg = sprintf('Type %s to visualize.', cmd);
                header = sprintf('%s\n\n   %s\n',headerStr,msg);
            end
            
        end
        % -----------------------------------------------------------------
        % Customize property display
        % -----------------------------------------------------------------
        function group = getPropertyGroups(~)
            plist = {'CellSize', 'BlockSize', 'BlockOverlap', ...
                'NumBins', 'UseSignedOrientation','BinCenters'};
            
            title = sprintf('Read-only properties:');
            group = matlab.mixin.util.PropertyGroup(plist,title);
            
        end
    end
    
    % ---------------------------------------------------------------------
    % Helper methods
    % ---------------------------------------------------------------------
    methods(Hidden, Access = protected)
        
        % -----------------------------------------------------------------
        % Compute cell centers in spatial and pixel coordinates
        % -----------------------------------------------------------------
        function [centers, indices] = computeCellCenters(this)
            cellSize = this.CellSize;            
            winSize  = this.WindowSize - rem(this.WindowSize,this.CellSize);
            
            % cell centers in spatial coordinates
            [cx,cy] = ndgrid(0.5 + (cellSize(2)/2:cellSize(2):winSize(2)),...
                0.5 + (cellSize(1)/2:cellSize(1):winSize(1)));
            
            % cell centers in pixel coordinates
            numCells = floor(this.WindowSize./this.CellSize);
            [cxIdx,cyIdy] = ndgrid(1:numCells(2),1:numCells(1));
            
            centers = [cx(:) cy(:)];
            indices = [cxIdx(:) cyIdy(:)];
        end
        
        % -----------------------------------------------------------------
        % Compute the bin centers in degrees
        % -----------------------------------------------------------------
        function binCenters = computeBinCenters(this)
            if this.UseSignedOrientation
                binRange = 360;
            else
                binRange = 180;
            end
            binWidth = binRange/this.NumBins;
            
            binCenters = (binWidth/2:binWidth:binRange)';  
            binCenters = binCenters + 90; % rotate to show edges
        end
        
        % -----------------------------------------------------------------
        % Compute the end points of the lines used to represent bin centers        
        % -----------------------------------------------------------------
        function endPoints = computeLineEndPoints(this)             
            centers = (computeBinCenters(this)) * pi/180;            
            endPoints = [cos(centers) -sin(centers)];
        end       
    end
end

% -------------------------------------------------------------------------
% Input parser for plot method
% -------------------------------------------------------------------------
function [colorSpec, axes] = parseInputs(x,varargin)

validateattributes(x,{'vision.internal.hog.Visualization'},...
    {'scalar'},'plot','',1);

p = inputParser;
addOptional  (p, 'axes', [], ...
    @vision.internal.inputValidation.validateAxesHandle);
addParameter(p, 'Color', 'white');

parse(p, varargin{:});

colorSpec = p.Results.Color;
axes      = p.Results.axes;

end