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

    %PCPLAYER Player for visualizing streaming 3-D point cloud data
% player = PCPLAYER(xlimits, ylimits, zlimits) returns a player for
% visualizing 3-D point cloud data streams. The xlimits, ylimits, and
% zlimits inputs specify the X, Y, and Z axis limits of the player. Specify
% the limits as two-element vectors of the form [min max]. Point cloud data
% outside these limits are not displayed. Use this player to visualize 3-D
% point cloud data from devices such as Microsoft Kinect(TM).
%
% player = PCPLAYER(..., 'Name','Value') specifies additional name-value
% pair arguments described below:
%
%   'MarkerSize'       A positive scalar specifying the approximate
%                      diameter of the point marker in points, a unit
%                      defined by MATLAB graphics.
%
%                      Default: 6
%
%   'VerticalAxis'     A string specifying the vertical axis, whose value
%                      is 'X', 'Y' or 'Z'.
%
%                      Default: 'Z'
%
%   'VerticalAxisDir'  A string specifying the direction of the vertical
%                      axis, whose value is 'Up' or 'Down'.
%
%                      Default: 'Up'
%
% PCPLAYER properties:
%  Axes - Handle to the player axes.
%
% PCPLAYER methods:
%  view   - View point cloud data.
%  show   - Turn on the visibility of point cloud player figure.
%  hide   - Turn off the visibility of the point cloud player figure.
%  isOpen - Returns true if the player is visible, otherwise returns false.
%
% Notes
% -----
% 1) Points with NaN or Inf coordinates will not be plotted.
% 2) A 'MarkerSize' greater than 6 points may reduce rendering performance.
% 3) cameratoolbar will be automatically turned on in the player.
%
% Example - View rotating 3-D point cloud
% ---------------------------------------
% ptCloud = pcread('teapot.ply');
%               
% % Define a rotation matrix and 3-D transform
% x = pi/180; 
% R = [ cos(x) sin(x) 0 0
%      -sin(x) cos(x) 0 0
%       0         0   1 0
%       0         0   0 1];
% 
% tform = affine3d(R);
% 
% % Compute proper x-y limits to ensure rotated teapot is not clipped.
% maxLimit = max(abs([ptCloud.XLimits ptCloud.YLimits]));
% 
% xlimits = [-maxLimit maxLimit];
% ylimits = [-maxLimit maxLimit];
% zlimits = ptCloud.ZLimits;
%
% % Create the player
% player = PCPLAYER(xlimits, ylimits, zlimits);
%        
% % Customize player axis labels
% xlabel(player.Axes, 'X (m)');
% ylabel(player.Axes, 'Y (m)');
% zlabel(player.Axes, 'Z (m)');
%
% % Rotate the teapot around the z-axis
% for i = 1:360      
%     ptCloud = pctransform(ptCloud, tform);  
%     view(player, ptCloud);     
% end
%
% See also pcplayer>view, pcshow, pointCloud, plot3, scatter3,
%          cameratoolbar

classdef pcplayer < vision.internal.EnforceScalarHandle
    % ---------------------------------------------------------------------    
    properties(GetAccess = public, SetAccess = protected, Transient) 
        % Axes - Handle to the player axes
        Axes
    end
    
    % ---------------------------------------------------------------------
    properties(Hidden, Access = protected)
        MarkerSize  
        VerticalAxis
        VerticalAxisDir                
        XLimits
        YLimits
        ZLimits     
        ptCloudThreshold
    end 
    
    % ---------------------------------------------------------------------
    properties(Hidden, Access = protected, Transient) 
        IsInitialized = false    
        Figure
        Primitive
    end
        
    % ---------------------------------------------------------------------
    methods
        
        function this = pcplayer(varargin)
            
            params = pcplayer.parseParameters(varargin{:});
                        
            initialize(this, params);            
        end
        
        % -----------------------------------------------------------------
        function view(this, varargin)
            % VIEW(player, ptCloud) displays points with locations and
            % colors stored in the pointCloud object, ptCloud.
            %
            % VIEW(player, xyzPoints) displays points at the locations
            % that are contained in an M-by-3 or M-by-N-by-3 xyzPoints
            % matrix. The matrix, xyzPoints, contains M or M-by-N [x,y,z]
            % points. The color of each point is determined by its Z value,
            % which is linearly mapped to a color in the current colormap.
            %
            % VIEW(player,xyzPoints,C) displays points at the locations
            % that are contained in the M-by-3 or M-by-N-by-3 xyzPoints
            % matrix with colors specified by C. To specify the same color
            % for all points, C must be a color string or a 1-by-3 RGB
            % vector. To specify a different color for each point, C must
            % be one of the following: 
            % - A vector or M-by-N matrix containing values that are 
            %   linearly mapped to a color in the current colormap.            
            % - An M-by-3 or M-by-N-by-3 matrix containing RGB values for
            %   each point.
            %
            % Example - View noisy 3-D point cloud
            % ------------------------------------
            %   ptCloud = pcread('teapot.ply');
            %
            %   xlimits = ptCloud.XLimits;
            %   ylimits = ptCloud.YLimits;
            %   zlimits = ptCloud.ZLimits;
            %
            %   % Create the player
            %   player = pcplayer(xlimits, ylimits, zlimits);
            %
            %   for i = 1:360                        
            %       % add noise to point cloud
            %       xyzPoints = ptCloud.Location + 0.1 * randn(ptCloud.Count,3);            
            %       VIEW(player, xyzPoints);
            %   end
            
            narginchk(2, 3);
            
            [X,Y,Z,C] = pcplayer.parseInputs(varargin{:});
                       
            if ~ishandle(this.Axes)                                                       
                % player is in an invalid state. initialize again.                
                cleanupFigure(this);                
                initialize(this);           
            end
            updateViewer(this, X, Y, Z, C);
        end
        
        % -----------------------------------------------------------------
        function tf = isOpen(this)
            % isOpen(player) returns true while the player figure window is
            % open.
            %
            % Example - Terminating a point cloud processing loop.
            % ----------------------------------------------------
            % player = pcplayer([0 1], [0 1], [0 1]);
            %
            % disp('Terminate while-loop by closing pcplayer figure window.')
            %
            % while isOpen(player) 
            %    ptCloud = pointCloud(rand(1000, 3, 'single'));
            %    view(player, ptCloud);           
            % end            
            if ishandle(this.Figure) && strcmpi(this.Figure.Visible,'on')
                tf = true;
            else
                tf = false;
            end
        end
        
        % -----------------------------------------------------------------
        function delete(this)
            cleanupFigure(this);
        end               
        
        % -----------------------------------------------------------------
        function show(this)
            % SHOW(player) makes the player figure window visible.
            makeVisible(this);
        end
        
        % -----------------------------------------------------------------        
        function hide(this)
            % HIDE(player) makes the player figure window invisible.            
            makeInvisible(this);
        end    
        
        % -----------------------------------------------------------------
        function s = saveobj(this)
            s.MarkerSize      = this.MarkerSize;
            s.VerticalAxis    = this.VerticalAxis;
            s.VerticalAxisDir = this.VerticalAxisDir;
            s.XLimits         = this.XLimits;
            s.YLimits         = this.YLimits;
            s.ZLimits         = this.ZLimits;             
            s.IsOpen          = isOpen(this);
        end                
    end
   
    % ---------------------------------------------------------------------
    methods(Hidden, Access = protected)
        
        function initialize(this, varargin)
            createFigure(this);
            
            if nargin == 2
                setParams(this, varargin{1});
            end
            
            initializeFigure(this);
                       
            this.Figure.Visible = 'on';
        end
        
        % -----------------------------------------------------------------
        function makeInvisible(this, varargin)           
            % proceed if figure exists, else leave it be.
            if ishandle(this.Figure)             
                this.Figure.Visible = 'off';            
                drawnow;
            end            
        end
        
        % -----------------------------------------------------------------
        function makeVisible(this)     
            if ishandle(this.Figure)                                     
                this.Figure.Visible = 'on';
                figure(this.Figure); % bring to front
            else                
                % player is in an invalid state. initialize again.                
                cleanupFigure(this);                
                initialize(this);     
            end
            drawnow;
        end   
        
        % -----------------------------------------------------------------
        function createFigure(this)        
            % Create figure to draw into
            this.Figure = figure('Visible','off',...
                                 'HandleVisibility','callback',...
                                 'Name','Point Cloud Player');
            this.Axes   = newplot(this.Figure);                                    
        end
        
        % -----------------------------------------------------------------
        function initializeFigure(this)
            
            checkRenderer(this);
                        
            % create an nice empty axes
            initializeScatter3(this); 
            
            % Lower and upper limit of auto downsampling.
            this.ptCloudThreshold = [1920*1080, 1e8];
            
            % Initialize point cloud viewer controls.
            vision.internal.pc.initializePCSceneControl(...
                this.Figure, this.Axes, this.VerticalAxis, this.VerticalAxisDir,...
                this.ptCloudThreshold,true);
            
            % set axes limits to manual
            this.Axes.XLimMode = 'manual';
            this.Axes.YLimMode = 'manual';
            this.Axes.ZLimMode = 'manual'; 
            
            % set view angle to auto to ensure a pleasant view point
            % after setting axis limits.
            this.Axes.CameraViewAngleMode = 'auto';
            
            % set limits
            xlim(this.Axes, this.XLimits);
            ylim(this.Axes, this.YLimits);
            zlim(this.Axes, this.ZLimits);                    
            
            drawnow; % to make sure camera position changes take effect
            
            % Decorate axes
            xlabel(this.Axes, 'X');
            ylabel(this.Axes, 'Y');
            zlabel(this.Axes, 'Z');
            
            grid(this.Axes, 'on');
            
            attachCallbacks(this);
            
            makeVisible(this);
            
            % save the current view. This allows cameratoolbar's reset
            % button to restore the original view.
            resetplotview(this.Axes,'SaveCurrentView');
            
            this.IsInitialized = true;
        end                        
        
        % -----------------------------------------------------------------
        function updateViewer(this, X, Y, Z, C)            
            if this.isOpen                                
                checkRenderer(this);                       
                updateScatter3(this, X, Y, Z, C);               
            end
        end
        
        % ------------------------------------------------------------------
        function attachCallbacks(this)
            this.Figure.CloseRequestFcn = @pcplayer.makeFigureInvisible;           
        end
               
        % ------------------------------------------------------------------
        function cleanupFigure(this,varargin)
            delete(this.Axes);
            delete(this.Figure);
            drawnow;            
        end
        
        % ------------------------------------------------------------------
        function setParams(this, params)
            this.MarkerSize      = double(params.MarkerSize);
            this.VerticalAxis    = params.VerticalAxis;
            this.VerticalAxisDir = params.VerticalAxisDir;
            
            this.XLimits = double(params.XLimits);
            this.YLimits = double(params.YLimits);
            this.ZLimits = double(params.ZLimits);
        end       
        
        % -----------------------------------------------------------------
        function checkRenderer(this)             
            if strcmpi(this.Figure.Renderer, 'painters')
                error(message('vision:pointcloud:badRenderer'));
            end
        end
    end
    
    % ---------------------------------------------------------------------
    % scatter3 based implementation
    % ---------------------------------------------------------------------
    methods(Hidden, Access = protected)
                
        function initializeScatter3(this)
            
            % produce an empty initial axes
            this.Primitive = scatter3(this.Axes, nan, nan, nan, ...
                this.MarkerSize, nan, '.');                        
            
            % Prevent extent checks when limits are not automatically
            % adjusted.
            this.Primitive.XLimInclude = 'off';
            this.Primitive.YLimInclude = 'off';
            this.Primitive.ZLimInclude = 'off';
        end
        
        % -----------------------------------------------------------------
        function updateScatter3(this, X, Y, Z, C)
            
            this.Primitive.XData = X;
            this.Primitive.YData = Y;
            this.Primitive.ZData = Z;
            
            if isempty(C)
                % use Z for false coloring
                this.Primitive.CData = Z;
            else
                this.Primitive.CData = C;
            end
            
            % maximize frame rate while handling mouse events
            drawnow('limitrate'); 
        end                
    end
    
    % ---------------------------------------------------------------------
    methods(Static,Hidden)
        function this = loadobj(s)
            this = pcplayer(s.XLimits, s.YLimits, s.ZLimits, ...
                'MarkerSize', s.MarkerSize, 'VerticalAxis', s.VerticalAxis, ...
                'VerticalAxisDir', s.VerticalAxisDir);
            
            if ~s.IsOpen
                hide(this);
            end                            
        end
        % -----------------------------------------------------------------
        function makeFigureInvisible(varargin)
            % callback attached to figure close request function                        
            set(gcbo,'Visible','off');
            drawnow;
        end
    end
    
    % ---------------------------------------------------------------------
    methods(Hidden, Static, Access = protected)
        
        function [X, Y, Z, C] = parseInputs(varargin)              
            
            if isa(varargin{1}, 'pointCloud')
                narginchk(1,1);
                [X, Y, Z, C] = vision.internal.pc.validateAndParseInputsXYZC(mfilename, varargin{1});
            else
                narginchk(1,2);
                [X, Y, Z, C] = vision.internal.pc.validateAndParseInputsXYZC(mfilename, varargin{:});
            end
            
            if ischar(C)                
                C = vision.internal.pc.colorspec2RGB(C);
            end
          
        end               
        
        % ------------------------------------------------------------------
        function params = parseParameters(varargin)
            
            parser = vision.internal.pc.getSharedParamParser(mfilename);            
            
            parser.addRequired('XLimits', @(x)pcplayer.checkLimits('XLimits',x));
            parser.addRequired('YLimits', @(x)pcplayer.checkLimits('YLimits',x));
            parser.addRequired('ZLimits', @(x)pcplayer.checkLimits('ZLimits',x));
            
            parser.parse(varargin{:});
            
            params = parser.Results;
            
        end                
        
        % ------------------------------------------------------------------
        function checkLimits(varname, range)
            validateattributes(range, {'numeric'}, ...
                {'vector', 'numel', 2, 'finite', 'real', 'nonsparse', 'increasing'}, ...
                mfilename, varname);
        end
               
    end
    
end