%SerialLink.plot Graphical display and animation
%
% R.plot(Q, options) displays a graphical animation of a robot based on
% the kinematic model.  A stick figure polyline joins the origins of
% the link coordinate frames. The robot is displayed at the joint angle Q (1xN), or
% if a matrix (MxN) it is animated as the robot moves along the M-point trajectory.
%
% Options::
% 'workspace', W    Size of robot 3D workspace, W = [xmn, xmx ymn ymx zmn zmx]
% 'floorlevel',L    Z-coordinate of floor (default -1)
%-
% 'delay',D         Delay betwen frames for animation (s)
% 'fps',fps         Number of frames per second for display, inverse of 'delay' option
% '[no]loop'        Loop over the trajectory forever
% '[no]raise'       Autoraise the figure
% 'movie',M         Save an animation to the movie M
% 'trail',L         Draw a line recording the tip path, with line style L.
%                   L can be a cell array, eg. {'r', 'LineWidth', 2}
%-
% 'scale',S         Annotation scale factor
% 'zoom',Z          Reduce size of auto-computed workspace by Z, makes
%                   robot look bigger
% 'ortho'           Orthographic view
% 'perspective'     Perspective view (default)
% 'view',V          Specify view V='x', 'y', 'top' or [az el] for side elevations,
%                   plan view, or general view by azimuth and elevation
%                   angle.
% 'top'             View from the top.
%-
% '[no]shading'     Enable Gouraud shading (default true)
% 'lightpos',L      Position of the light source (default [0 0 20])
% '[no]name'        Display the robot's name
%-
% '[no]wrist'       Enable display of wrist coordinate frame
% 'xyz'             Wrist axis label is XYZ
% 'noa'             Wrist axis label is NOA
% '[no]arrow'       Display wrist frame with 3D arrows
%-
% '[no]tiles'       Enable tiled floor (default true)
% 'tilesize',S      Side length of square tiles on the floor
% 'tile1color',C   Color of even tiles [r g b] (default [0.5 1 0.5]  light green)
% 'tile2color',C   Color of odd tiles [r g b] (default [1 1 1] white)
%-
% '[no]shadow'      Enable display of shadow (default true)
% 'shadowcolor',C   Colorspec of shadow, [r g b]
% 'shadowwidth',W   Width of shadow line (default 6)
%-
% '[no]jaxes'       Enable display of joint axes (default false)
% '[no]jvec'        Enable display of joint axis vectors (default false)
% '[no]joints'      Enable display of joints
% 'jointcolor',C    Colorspec for joint cylinders (default [0.7 0 0])
% 'pjointcolor',C   Colorspec for prismatic joint boxes (default [0.4 1 .03])
% 'jointdiam',D     Diameter of joint cylinder in scale units (default 5)
%-
% 'linkcolor',C     Colorspec of links (default 'b')
%-
% '[no]base'        Enable display of base 'pedestal'
% 'basecolor',C     Color of base (default 'k')
% 'basewidth',W     Width of base (default 3)
%
% The options come from 3 sources and are processed in order:
% - Cell array of options returned by the function PLOTBOTOPT (if it exists)
% - Cell array of options given by the 'plotopt' option when creating the
%   SerialLink object.
% - List of arguments in the command line.
%
% Many boolean options can be enabled or disabled with the 'no' prefix.  The
% various option sources can toggle an option, the last value encountered is used.
%
% Graphical annotations and options::
%
% The robot is displayed as a basic stick figure robot with annotations
% such as:
% - shadow on the floor
% - XYZ wrist axes and labels
% - joint cylinders and axes
% which are controlled by options.
%
% The size of the annotations is determined using a simple heuristic from
% the workspace dimensions.  This dimension can be changed by setting the
% multiplicative scale factor using the 'mag' option.
%
% Figure behaviour::
%
% - If no figure exists one will be created and the robot drawn in it.
% - If no robot of this name is currently displayed then a robot will
%   be drawn in the current figure.  If hold is enabled (hold on) then the
%   robot will be added to the current figure.
% - If the robot already exists then that graphical model will be found
%   and moved.
%
% Multiple views of the same robot::
%
% If one or more plots of this robot already exist then these will all
% be moved according to the argument Q.  All robots in all windows with
% the same name will be moved.
%
%  Create a robot in figure 1
%         figure(1)
%         p560.plot(qz);
%  Create a robot in figure 2
%         figure(2)
%         p560.plot(qz);
%  Now move both robots
%         p560.plot(qn)
%
% Multiple robots in the same figure::
%
% Multiple robots can be displayed in the same plot, by using "hold on"
% before calls to robot.plot().
%
%  Create a robot in figure 1
%         figure(1)
%         p560.plot(qz);
%  Make a clone of the robot named bob
%         bob = SerialLink(p560, 'name', 'bob');
%  Draw bob in this figure
%         hold on
%         bob.plot(qn)
%
%  To animate both robots so they move together:
%         qtg = jtraj(qr, qz, 100);
%         for q=qtg'
%           p560.plot(q');
%           bob.plot(q');
%         end
%
% Making an animation::
%
% The 'movie' options saves the animation as a movie file or separate frames in a folder
% - 'movie','file.mp4' saves as an MP4 movie called file.mp4
% - 'movie','folder' saves as files NNNN.png into the specified folder
%   - The specified folder will be created
%   - NNNN are consecutive numbers: 0000, 0001, 0002 etc.
%   - To convert frames to a movie use a command like:
%          ffmpeg -r 10 -i %04d.png out.avi
%
% Notes::
% - The options are processed when the figure is first drawn, to make different options come
%   into effect it is neccessary to clear the figure.
% - The link segments do not neccessarily represent the links of the robot, they are a pipe
%   network that joins the origins of successive link coordinate frames.
% - Delay betwen frames can be eliminated by setting option 'delay', 0 or
%   'fps', Inf.
% - By default a quite detailed plot is generated, but turning off labels,
%   axes, shadows etc. will speed things up.
% - Each graphical robot object is tagged by the robot's name and has UserData
%   that holds graphical handles and the handle of the robot object.
% - The graphical state holds the last joint configuration
% - The size of the plot volume is determined by a heuristic for an all-revolute
%   robot.  If a prismatic joint is present the 'workspace' option is
%   required.  The 'zoom' option can reduce the size of this workspace.
%
% See also SerialLink.plot3d, plotbotopt, SerialLink.animate, SerialLink.teach.

% HANDLES:
%
% A robot comprises a bunch of individual graphical elements and these are
% kept in a structure:
%
%   h.link     the graphical elements that comprise each joint/link
%   h.wrist     the coordinate frame marking the wrist frame
%   h.shadow    the robot's shadow
%   h.floorlevel the z-coordinate of the tiled floor
%   h.robot pointer to the robot object
%   h.opt   the final options structure
%
% The h.link graphical element is tagged with the robot's name and has this
% struct as its UserData.
%
%  h.links -> h -> robot
%
%  This enables us to find all robots with a given name, in all figures,
% and update them.

% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

% TODO
% deal with base transform and tool
% more consistent option names, scale, mag etc.
function plot(robot, qq, varargin)

    % check the joint angle data matches the robot
    n = robot.n;
    assert(numcols(qq) == n, 'RTB:SerialLink:plot:badarg', 'Insufficient columns in q')

    % process options, these come from:
    %  - passed arguments
    %  - the robot object itself
    %  - the file plotopt.m
    opt = RTBPlot.plot_options(robot, varargin);

    % logic to handle where the plot is drawn, are old figures updated or
    % replaced?
    %  calls create_floor() and create_robot() as required.

    if strcmp(get(gca,'Tag'), 'RTB.plot')
        % this axis is an RTB plot window

        rhandles = findobj('Tag', robot.name);

        if isempty(rhandles)
            % this robot doesnt exist here, create it or add it

            if ishold
                % hold is on, add the robot, don't change the floor
                handle = create_robot(robot, opt);

                % tag one of the graphical handles with the robot name and hang
                % the handle structure off it
%                 set(handle.joint(1), 'Tag', robot.name);
%                 set(handle.joint(1), 'UserData', handle);
            else
                % create the robot and floor
                newplot();

                RTBPlot.create_floor(opt);

                handle = create_robot(robot, opt);
                set(gca, 'Tag', 'RTB.plot');
            end

        end

    else
        % this axis never had a robot drawn in it before, let's use it
        RTBPlot.create_floor(opt);
        handle = create_robot(robot, opt);
        set(gca, 'Tag', 'RTB.plot');
        set(gcf, 'Units', 'Normalized');
        pf = get(gcf, 'Position');
%         if strcmp( get(gcf, 'WindowStyle'), 'docked') == 0
%             set(gcf, 'Position', [0.1 1-pf(4) pf(3) pf(4)]);
%         end
    end

    % deal with a few options that need to be stashed in the SerialLink object
    % movie mode has not already been flagged
    if opt.movie
        robot.movie = Animate(opt.movie);
    end
    robot.delay = opt.delay;
    robot.loop = opt.loop;

    if opt.raise
        % note this is a very time consuming operation
        figure(gcf);
    end

    if strcmp(opt.projection, 'perspective')
        set(gca, 'Projection', 'perspective');
    end

    if isstr(opt.view)
        switch opt.view
            case 'top'
                view(0, 90);
                set(gca, 'OuterPosition', [-0.8 -0.8 2.5 2.5]);
            case 'x'
                view(0, 0);
            case 'y'
                view(90, 0)
            otherwise
                error('rtb:plot:badarg', 'view must be: x, y, top')
        end
    elseif isnumeric(opt.view) && length(opt.view) == 2
        view(opt.view)
    end

    % enable mouse-based 3D rotation
    rotate3d on

    robot.trail = []; % clear the previous trail

    robot.animate(qq);

    if opt.movie
        robot.movie.close();
    end
end

% Create a new graphical robot in the current figure.
% Returns a structure of handles that describe the various graphical entities in the robot model
% Make extensive use of hgtransform, all entities are defined at the origin, then moved to their
% proper pose
%
% The graphical hiearchy is:
%  hggroup: Tag = robot name
%     hgtransform: Tag = 'link#'
%
% The top-level group has user data which is the handle structure.

function h = create_robot(robot, opt)

    %disp('creating new robot');

    links = robot.links;
    s = opt.scale;

    % create an axis
    ish = ishold();
    if ~ishold
        % if hold is off, set the axis dimensions
        axis(opt.workspace);
        hold on
    end

    N = robot.n;

    % create the base
    if opt.base
        bt = robot.base.t;
        bt = [bt'; bt'];
        bt(1,3) = opt.floorlevel;
        line(bt(:,1), bt(:,2), bt(:,3), 'LineWidth', opt.basewidth, 'Color', opt.basecolor);
    end
    view(3)

    % add the robot's name
    if opt.name
        b = robot.base.t;
        bz = 0;
        if opt.base
            bz = 0.5*opt.floorlevel;
        end
        text(b(1), b(2)-s, bz, [' ' robot.name], 'FontAngle', 'italic', 'FontWeight', 'bold')
    end
    group = hggroup('Tag', robot.name);
    h.group = group;

    % create the graphical joint and link elements
    for L=1:N
        if opt.debug
            fprintf('create graphics for joint %d\n', L);
        end

        % create the transform for displaying this element (joint cylinder + link)
        h.link(L) = hgtransform('Tag', sprintf('link%d', L), 'Parent', group);

        % create a joint cylinder
        if opt.joints
            % create the body of the joint
            if links(L).isrevolute
                RTBPlot.cyl('z', opt.jointdiam*s, opt.jointlen*s*[-1 1], opt.jointcolor, [], 'Parent', h.link(L));
            else
                % create an additional hgtransform for positioning and scaling the prismatic
                % element.  The element is created with unit length.
                h.pjoint(L) = hgtransform('Tag', 'prismatic', 'Parent', h.link(L));
                if links(L).mdh
                    % make the box extend in negative z-dir because scaling factor in animate
                    % must be positive
                    RTBPlot.box('z', s, [0 -1], opt.jointcolor, [], 'Parent', h.pjoint(L));
                else
                    RTBPlot.box('z', s, [0 1], opt.jointcolor, [], 'Parent', h.pjoint(L));
                end
            end
        end

        % create the body of the link

        % create elements to represent translation between joint frames, ie. the link itself.
        % This is drawn to resemble orthogonal plumbing.
        if robot.mdh
            % modified DH convention
            if L < N
                A = links(L+1).A(0);
                t = transl(A);
                if t(1) ~= 0
                    RTBPlot.cyl('x', s, [s t(1)], opt.linkcolor, [], 'Parent', h.link(L));
                end
                if t(2) ~= 0
                    RTBPlot.cyl('y', s, [s t(2)], opt.linkcolor, [t(1) 0 0], 'Parent', h.link(L));
                end
                if t(3) ~= 0
                    RTBPlot.cyl('z', s, [s t(3)], opt.linkcolor, [t(1) t(2) 0], 'Parent', h.link(L));
                end
            end
        else
            % standard DH convention
            if L > 1
                Ainv = inv(links(L-1).A(0));
                t = Ainv.t;
                if t(1) ~= 0
                    RTBPlot.cyl('x', s, [0 t(1)], opt.linkcolor, [], 'Parent', h.link(L));
                end
                if t(2) ~= 0
                    RTBPlot.cyl('y', s, [s t(2)], opt.linkcolor, [t(1) 0 0], 'Parent', h.link(L));
                end
                if t(3) ~= 0
                    RTBPlot.cyl('z', s, [s t(3)], opt.linkcolor, [t(1) t(2) 0], 'Parent', h.link(L));
                end
                %line([0 t(1)]', [0 t(2)]', [0 t(3)]', 'Parent', h.link(L));
            end
        end

        assert( ~(opt.jaxes && opt.jvec), 'RTB:plot:badopt', 'Can''t specify ''jaxes'' and ''jvec''')
        % create the joint axis line
        if opt.jaxes
            line('XData', [0 0], ...
                'YData', [0 0], ...
                'ZData', 14*s*[-1 1], ...
                'LineStyle', ':', 'Parent', h.link(L));

            % create the joint axis label
            text(0, 0, 14*s, sprintf('q%d', L), 'Parent', h.link(L))
        end
         % create the joint axis vector
        if opt.jvec
            daspect([1 1 1]);
            ha = arrow3([0 0 -12*s], [0 0 15*s], 'c');
            set(ha, 'Parent', h.link(L));

            % create the joint axis label
            text(0, 0, 20*s, sprintf(' q%d', L), 'Parent', h.link(L))
        end
    end
    if opt.debug
        fprintf('create graphics for tool\n');
    end
    % display the tool transform if it exists
    h.link(N+1) = hgtransform('Tag', sprintf('link%d', N+1), 'Parent', group);
    tool = SE3();
    if ~robot.mdh
        tool = links(L).A(0);
    end
    if ~isempty(robot.tool)
        tool = tool * robot.tool;
    end
    Tinv = inv(tool);
    t = Tinv.t;
    if t(1) ~= 0
        RTBPlot.cyl('x', s, [0 t(1)], 'r', [], 'Parent', h.link(N+1));
    end
    if t(2) ~= 0
        RTBPlot.cyl('y', s, [s t(2)], 'r', [t(1) 0 0], 'Parent', h.link(N+1));
    end
    if t(3) ~= 0
        RTBPlot.cyl('z', s, [s t(3)], 'r', [t(1) t(2) 0], 'Parent', h.link(N+1));
    end

    % display the wrist coordinate frame
    if opt.wrist
        if opt.arrow
            % compute arrow3 scale factor...
            ax = gca; d = [ax.XLim ax.YLim ax.ZLim];
            d = norm( d(4:6)-d(1:3) ) / 72;
            extra = {'arrow', 'width', 1.5*s/d};
        else
            extra = {};
        end
        h.wrist = trplot(eye(4,4), 'labels', upper(opt.wristlabel), ...
                'rgb', 'length', opt.wristlen*s, extra{:});

    else
        h.wrist = [];
    end

    % display a shadow on the floor
    if opt.shadow
        % create the polyline which is the shadow on the floor
        h.shadow = line('LineWidth', opt.shadowwidth, 'Color', opt.shadowcolor);
    end

    if ~isempty(opt.trail)
        if iscell(opt.trail)
            h.trail = plot(0, 0, opt.trail{:});
        else
            h.trail = plot(0, 0, opt.trail);
        end
        robot.trail = [];
    end

    % deal with some display options
    if opt.shading
        lighting gouraud
        light('position', opt.lightpos)
    end
    xlabel('X')
    ylabel('Y')
    zlabel('Z')
    grid on

    % restore hold setting
    if ~ish
        hold off
    end
    h.floorlevel = opt.floorlevel;
    h.robot = robot;
    h.opt = opt;

    % attach the handle structure to the top graphical element
    set(group, 'UserData', h);
end

% draw a cylinder of radius r in the direction specified by ax, with an
% extent from extent(1) to extent(2)


function img = readFlowFile(filename)

% readFlowFile read a flow file FILENAME into 2-band image IMG

%   According to the c++ source code of Daniel Scharstein
%   Contact: schar@middlebury.edu

%   Author: Deqing Sun, Department of Computer Science, Brown University
%   Contact: dqsun@cs.brown.edu
%   $Date: 2007-10-31 16:45:40 (Wed, 31 Oct 2006) $

% Copyright 2007-2010, Brown University, Providence, RI. USA
%
%
%                         All Rights Reserved
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for any purpose other than its incorporation into a
% commercial product is hereby granted without fee, provided that the
% above copyright notice appear in all copies and that both that
% copyright notice and this permission notice appear in supporting
% documentation, and that the name of the author and Brown University not be used in
% advertising or publicity pertaining to distribution of the software
% without specific, written prior permission.
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
% INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
% PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR BROWN UNIVERSITY BE LIABLE FOR
% ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

TAG_FLOAT = 202021.25;  % check for this when READING the file

% sanity check
if isempty(filename) == 1
    error('readFlowFile: empty filename');
end;

idx = findstr(filename, '.');
idx = idx(end);

if length(filename(idx:end)) == 1
    error('readFlowFile: extension required in filename %s', filename);
end;

if strcmp(filename(idx:end), '.flo') ~= 1
    error('readFlowFile: filename %s should have extension ''.flo''', filename);
end;

fid = fopen(filename, 'r');
if (fid < 0)
    error('readFlowFile: could not open %s', filename);
end;

tag     = fread(fid, 1, 'float32');
width   = fread(fid, 1, 'int32');
height  = fread(fid, 1, 'int32');

% sanity check

if (tag ~= TAG_FLOAT)
    error('readFlowFile(%s): wrong tag (possibly due to big-endian machine?)', filename);
end;

if (width < 1 || width > 99999)
    error('readFlowFile(%s): illegal width %d', filename, width);
end;

if (height < 1 || height > 99999)
    error('readFlowFile(%s): illegal height %d', filename, height);
end;

nBands = 2;

% arrange into matrix form
tmp = fread(fid, inf, 'float32');
tmp = reshape(tmp, [width*nBands, height]);
tmp = tmp';
img(:,:,1) = tmp(:, (1:width)*nBands-1);
img(:,:,2) = tmp(:, (1:width)*nBands);

fclose(fid);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% step1:
% use
%     pipeline = pipeline_init('upper');
% for initiating a fashion landmark detection pipeline
%
% step2:
% use
%     prediction = pipeline_forword(img,pipeline);
% for getting landmarks of images
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% initiate pipeline
addpath(genpath('../caffe/matlab'));
pipeline = pipeline_init('upper');

image_path = '../data/FLD_upper/';

name_list = dir(image_path);

for i = 1:length(name_list)

    if name_list(i).isdir
        continue;
    end
    img_name = [image_path, name_list(i).name];
    img = imread(img_name);

    % forward
    prediction = pipeline_forword(img, pipeline);

    % show result
    pipeline_show_results(img, prediction);

end

% release pipeline
pipeline_release;


%CALCOPTICALFLOWPYRLK  Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids
%
%     nextPts = cv.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts)
%     [nextPts, status, err] = cv.calcOpticalFlowPyrLK(...)
%     [...] = cv.calcOpticalFlowPyrLK(..., 'OptionName', optionValue, ...)
%
% ## Input
% * __prevImg__ First 8-bit single-channel or 3-channel input image, or
%   pyramid constructed by cv.buildOpticalFlowPyramid
% * __nextImg__ Second input image or pyramid of the same size and the same
%   type as `prevImg`.
% * __prevPts__ Vector of 2D points for which the flow needs to be found;
%   point coordinates must be single-precision floating-point numbers.
%   Cell-array of 2-element vectors is accepted: `{[x,y], ...}`
%
% ## Output
% * __nextPts__ Output vector of 2D points (with single-precision
%   floating-point coordinates) containing the calculated new positions of
%   input features in the second image. A cell array of 2-elements vectors of
%   the same size as `prevPts`.
% * __status__ Output status vector. Each element of the vector is set to 1 if
%   the flow for the corresponding features has been found. Otherwise, it is
%   set to 0.
% * __err__ Output vector of errors; each element of the vector is set to an
%   error for the corresponding feature, type of the error measure is
%   determined by `GetMinEigenvals` option; if the flow wasn't found then the
%   error is not defined (use `status` to find such cases).
%
% ## Options
% * __InitialFlow__ Vector of 2D points to be used for the initial estimate of
%   `nextPts`. If not specified, `prevPts` will be used as an initial
%   estimate. The vector must have the same size as in the input. Not set by
%   default.
% * __WinSize__ Size of the search window at each pyramid level. Default to
%   [21, 21].
% * __MaxLevel__ 0-based maximal pyramid level number. If set to 0, pyramids
%   are not used (single level). If set to 1, two levels are used, and so on;
%   if pyramids are passed to input then algorithm will use as many levels as
%   pyramids have but no more than `MaxLevel`. Default to 3.
% * __Criteria__ Parameter specifying the termination criteria of the
%   iterative search algorithm (after the specified maximum number of
%   iterations `Criteria.maxCount` or when the search window moves by less
%   than `Criteria.epsilon`. Struct with `{'type','maxCount','epsilon'}`
%   fields is accepted. The type field should have one of 'Count', 'EPS', or
%   'Count+EPS' to indicate which criteria to use. Default to
%   `struct('type','Count+EPS', 'maxCount',30, 'epsilon',0.01)`.
% * __GetMinEigenvals__ Use minimum eigen values as an error measure (see
%   `MinEigThreshold` description); if the flag is not set, then L1 distance
%   between patches around the original and a moved point, divided by number
%   of pixels in a window, is used as a error measure. Default to false.
% * __MinEigThreshold__ The algorithm calculates the minimum eigen value of a
%   2x2 normal matrix of optical flow equations (this matrix is called a
%   spatial gradient matrix in [Bouguet00]), divided by number of pixels in a
%   window; if this value is less than `MinEigThreshold`, then a corresponding
%   feature is filtered out and its flow is not processed, so it allows to
%   remove bad points and get a performance boost. Default to 1e-4.
%
% The function implements a sparse iterative version of the Lucas-Kanade
% optical flow in pyramids. See [Bouguet00]. The function is parallelized with
% the TBB library.
%
% ## References
% [Bouguet00]:
% > Jean-Yves Bouguet. "Pyramidal Implementation of the Lucas Kanade Feature
% > Tracker. Description of the algorithm", Intel Corporation, 2001.
%
% ## Example
%
%     prevIm = rgb2gray(imread('prev.jpg'));
%     nextIm = rgb2gray(imread('next.jpg'));
%     prevPts = cv.goodFeaturesToTrack(prevIm);
%     nextPts = cv.calcOpticalFlowPyrLK(prevIm, nextIm, prevPts);
%
% See also: cv.SparsePyrLKOpticalFlow, cv.calcOpticalFlowFarneback,
%  cv.goodFeaturesToTrack, vision.PointTracker
%


function auto_cell = automobile_read ( input_filename )

%*****************************************************************************80
%
%% AUTOMOBILE_READ reads data from the automobile dataset.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 April 2011
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    A Frank, A Asuncion,
%    UCI Machine Learning Repository,
%    http://archive.ics.uci.edu/ml,
%    School of Information and Computer Science,
%    University of California, Irvine, California.
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Output, cell array AUTO_CELL(205,26), the information from the file.
%
  auto_cell = cell ( 205, 26 );
%
%  Open the file.
%
  input_unit = fopen ( input_filename );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'AUTOMOBILE_READ - Error!\n' );
    fprintf ( 1, '  Could not open the input file.\n' );
    error ( 'AUTOMOBILE_READ - Error!' );
  end
%
%  Read the records.
%
  i = 0;

  while ( 1 )

    line = fgets ( input_unit );

    if ( line == -1 )
      break
    end
%
%  Read the I-th record.
%
    i = i + 1;
%
%  Replace commas by spaces, so the line consists of 26 "words".
%
    line = s_replace_ch ( line, ',', ' ' );
%
%  Replace ? by -1, so missing values are marked.
%
    line = s_replace_ch_by_s ( line, '?', '-1' );
%
%  Read the 26 words, using an integer format for the first word,
%  a real format for others, and a string format for others.
%
    done = 1;

    for j = 1 : 26
      [ w, done ] = word_next_read ( line, done );
      if ( j == 1 )
        auto_cell{i,j} = sscanf ( w, '%d' );
      elseif ( j == 2 || j == 10 || j == 12 || j == 13 || j == 14 || j == 17 || ...
               j == 19 || j == 20 || j == 21 || j == 22 || j == 23 || j == 24 || ...
               j == 25 || j == 26 )
        auto_cell{i,j} = sscanf ( w, '%f' );
      else
        auto_cell{i,j} = w;
      end
    end

  end

  fclose ( input_unit );

  if ( i ~= 205 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'AUTOMOBILE_READ - Warning!\n' );
    fprintf ( 1, '  The data file should contain 205 records.\n' );
    fprintf ( 1, '  This program found %d records.\n', i );
  end

  return
end
function s = s_replace_ch ( s, c1, c2 )

%*****************************************************************************80
%
%% S_REPLACE_CH replaces all occurrences of one character by another.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 January 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input/output, character S(*), the string.
%
%    Input, character C1, C2, the character to be replaced, and the
%    replacement character.
%
  for i = 1 : length ( s )
    if ( s(i) == c1 )
      s(i) = c2;
    end
  end

  return
end
function s_new = s_replace_ch_by_s ( s_old, c, s_rep )

%*****************************************************************************80
%
%% S_REPLACE_CH_BY_S replaces all occurrences of a character by a string.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 April 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S_OLD, the string to be modified.
%
%    Input, character C, the character to be replaced.
%
%    Input, string S_REP, the replacement string.
%
%    Output, string S_NEW, the modified string.
%
  n_old = length ( s_old );
  n_rep = length ( s_rep );

  i_new = 1;

  for i_old = 1 : n_old

    if ( s_old(i_old) ~= c )
      s_new(i_new) = s_old(i_old);
      i_new = i_new + 1;
    else
      s_new(i_new:i_new+n_rep-1) = s_rep;
      i_new = i_new + n_rep;
    end

  end

  return
end
function [ word, done ] = word_next_read ( s, done )

%*****************************************************************************80
%
%% WORD_NEXT_READ "reads" words from a string, one at a time.
%
%  Special cases:
%
%    The following characters are considered to be a single word,
%    whether surrounded by spaces or not:
%
%      " ( ) { } [ ]
%
%    Also, if there is a trailing comma on the word, it is stripped off.
%    This is to facilitate the reading of lists.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 December 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, a string, presumably containing words
%    separated by spaces.
%
%    Input, logical DONE.
%    TRUE, if we are beginning a new string;
%    FALSE, if we are continuing to process the current string.
%
%    Output, string WORD.
%    If DONE is FALSE, then WORD contains the "next" word read.
%    If DONE is TRUE, then WORD is blank, because there was no more to read.
%
%    Output, logical DONE.
%      FALSE if another word was read,
%      TRUE if no more words could be read.
%
  persistent lenc;
  persistent next;

  tab = char ( 9 );
%
%  We "remember" LENC and NEXT from the previous call.
%
%  An input value of DONE = TRUE signals a new line of text to examine.
%
  if ( done )

    next = 1;
    done = 0;
    lenc = length ( s );

    if ( lenc <= 0 )
      done = 1;
      word = ' ';
      return
    end

  end
%
%  Beginning at index NEXT, search the string for the next nonblank,
%  which signals the beginning of a word.
%
  ilo = next;
%
%  ...S(NEXT:) is blank.  Return with WORD = ' ' and DONE = TRUE.
%
  while ( 1 )

    if ( lenc < ilo )
      word = ' ';
      done = 1;
      next = lenc + 1;
      return
    end
%
%  If the current character is blank, skip to the next one.
%
    if ( s(ilo) ~= ' ' && s(ilo) ~= tab )
      break
    end

    ilo = ilo + 1;

  end
%
%  ILO is the index of the next nonblank character in the string.
%
%  If this initial nonblank is a special character,
%  then that's the whole word as far as we're concerned,
%  so return immediately.
%
  if ( s(ilo) == '"' || ...
       s(ilo) == '(' || ...
       s(ilo) == ')' || ...
       s(ilo) == '{' || ...
       s(ilo) == '}' || ...
       s(ilo) == '[' || ...
       s(ilo) == ']' )

    word = s(ilo);
    next = ilo + 1;
    return

  end
%
%  Now search for the last contiguous character that is not a
%  blank, TAB, or special character.
%
  next = ilo + 1;

  while ( next <= lenc )

    if ( s(next) == ' ' )
      break;
    elseif ( s(next) == tab )
      break;
    elseif ( s(next) == '"' )
      break;
    elseif ( s(next) == '(' )
      break;
    elseif ( s(next) == ')' )
      break;
    elseif ( s(next) == '{' )
      break;
    elseif ( s(next) == '}' )
      break;
    elseif ( s(next) == '[' )
      break;
    elseif ( s(next) == ']' )
      break;
    end

    next = next + 1;

  end

  if ( s(next-1) == ',' )
    word = s(ilo:next-2);
  else
    word = s(ilo:next-1);
  end

  return
end


function save_voxel_grid_as_bin(voxel,filename)

fp = fopen(filename,'w');
fwrite(fp,uint16(size(voxel)),'uint16');
fwrite(fp,uint8(voxel),'uint8');
fclose(fp);


function regModel = readBooleanRegModel(metModel, fileName)
% Reads Boolean regulatory network model
%
% USAGE:
%
%    regModel = readBooleanRegModel(metModel, fileName)
%
% INPUT:
%    metModel:    model
%
% OPTIONAL INPUT:
%    fileName:    file name
%
% OUTPUTS
%    regModel:    model containing the following fields:
%
%                   * .mets - Metabolite rules:
%
%                     * name - Metabolite/pool name (internal to the reg network model)
%                     * rule - Metabolite 'activation' rule
%                     * type - Metabolite type (extra/intracellular/pool)
%                     * excInd - Exchange flux indices corresponding to extracellular
%                       metabolites
%                     * icmRules - Intracellular metabolite 'activation' rules (based on
%                       a flux vector - `fluxVector`)
%                     * pool - Pool components
%                   * .regs - Regulator rules
%
%                     * name - Regulator name
%                     * rule - Regulator rule
%                     * comp - Regulator rule components (i.e. metabolites or other
%                       regulators that affect the state of this regulator)
%                     * ruleParsed - Rule in parsed format (based on metabolite state -
%                       `metState`, regulator state - `regState`)
%                   * .tars - Target rules
%
%                     * name - Target name
%                     * rule - Target rule
%                     * comp - Target rule components (i.e. metabolites or other
%                       regulators that affect the state of this regulator)
%                     * ruleParsed - Rule in parsed format (based on metabolite state -
%                       `metState`, regulator state - `regState`)
%
% .. Author: - Markus Herrgard 12/5/07

if (nargin < 2)
    fileName = 'iMHruletest.xls';
end

%% Read xls file
[tmp,textData] = xlsread(fileName);
nameList = textData(2:end,1);
ruleList = textData(2:end,2);
ruleType = textData(2:end,3);

%% Assign metabolite, regulator, and target rules
regModel = [];

metCnt = 0;
regCnt = 0;
tarCnt = 0;
nameList = strrep(nameList,'[','_');
nameList = strrep(nameList,']','');
nameList = deblank(nameList);
ruleList = strrep(ruleList,'[','_');
ruleList = strrep(ruleList,']','');
ruleList = deblank(ruleList);
for i = 1:length(ruleList)
    ruleList{i} = strrep(ruleList{i},'if ','');
    switch ruleType{i}
        case {'xcm','icm','xcp','icp'}
            metCnt = metCnt + 1;
            regModel.mets.name{metCnt} = nameList{i};
            regModel.mets.rule{metCnt} = ruleList{i};
            if (strcmp(ruleType{i},'xcp') | strcmp(ruleType{i},'icp'))
                regModel.mets.rule{metCnt} = splitString(ruleList{i},'+');
            end
            regModel.mets.type{metCnt} = ruleType{i};
        case {'reg','regc'}
            regCnt = regCnt + 1;
            regModel.regs.name{regCnt} = nameList{i};
            regModel.regs.rule{regCnt} = ruleList{i};
            [elements,newRule] = parseBoolean(ruleList{i});
            regModel.regs.comp{regCnt} = elements;
            regModel.regs.ruleParsed{regCnt} = newRule;
        case 'tar'
            tarCnt = tarCnt + 1;
            regModel.tars.name{tarCnt} = nameList{i};
            regModel.tars.rule{tarCnt} = ruleList{i};
            [elements,newRule] = parseBoolean(ruleList{i});
            regModel.tars.comp{tarCnt} = elements;
            regModel.tars.ruleParsed{tarCnt} = newRule;
    end
end

%% Parse metabolite rules

regModel.mets.name = columnVector(regModel.mets.name);
regModel.mets.rule = columnVector(regModel.mets.rule);
regModel.mets.type = columnVector(regModel.mets.type);

% Extracellular
selEcMets = find(strcmp(regModel.mets.type,'xcm'));
xcMets = strrep(regModel.mets.rule(selEcMets),'-','_');
regModel.mets.excInd = findRxnIDs(metModel,xcMets);

notInModel = xcMets(regModel.mets.excInd == 0);
for i = 1:length(notInModel)
    if (~strcmp(notInModel{i},'NA'))
        fprintf([regModel.mets.name{selEcMets(i)} ': exchange rxn for ' notInModel{i} ' not in metabolic model\n']);
    end
end

% Intracellular
selIcMets = find(strcmp(regModel.mets.type,'icm'));

for i = 1:length(selIcMets)
    [elements,newRule] = parseBoolean(regModel.mets.rule{selIcMets(i)});
    rxnInd = findRxnIDs(metModel,elements);
    for j = 1:length(rxnInd)
        if (rxnInd(j) > 0)
            newRule = strrep(newRule,['x(' num2str(j) ')'],['fluxVector(' num2str(rxnInd(j)) '_TMP_)']);
        else
            if (~strcmp(elements{j},'=0'))
                fprintf([regModel.mets.name{selIcMets(i)} ': rxn ' elements{j} ' not found in the metabolic model']);
            end
        end
    end
    regModel.mets.icmRules{i} = strrep(newRule,'_TMP_','');
end
regModel.mets.icmRules = columnVector(regModel.mets.icmRules);

% Pools

selPoolMets = find(strcmp(regModel.mets.type,'xcp') | strcmp(regModel.mets.type,'icp'));

for i = 1:length(selPoolMets)
    poolMets = regModel.mets.rule{selPoolMets(i)};
    [isInModel,metInd] = ismember(poolMets,regModel.mets.name);
    notInModel = poolMets(~isInModel);
    for j = 1:length(notInModel)
        fprintf([regModel.mets.name{selPoolMets(i)} ': metabolite ' notInModel{j} ' not in regulatory network model\n']);
    end
    regModel.mets.pool{i} = metInd(isInModel == 1);
end
regModel.mets.pool = columnVector(regModel.mets.pool);

%% Parse regulator rules

regModel.regs.name = columnVector(regModel.regs.name);
regModel.regs.rule = columnVector(regModel.regs.rule);
regModel.regs.comp = columnVector(regModel.regs.comp);
regModel.regs.ruleParsed = columnVector(regModel.regs.ruleParsed);

for i = 1:length(regModel.regs.name)
    elements = regModel.regs.comp{i};
    [isMet,metInd] = ismember(elements,regModel.mets.name);
    [isReg,regInd] = ismember(elements,regModel.regs.name);
    newRule = regModel.regs.ruleParsed{i};
    for j = 1:length(elements)
        if (metInd(j) > 0)
            newRule = strrep(newRule,['x(' num2str(j) ')'],['metState(' num2str(metInd(j)) '_TMP_)']);
        elseif (regInd(j) > 0)
            newRule = strrep(newRule,['x(' num2str(j) ')'],['regState(' num2str(regInd(j)) '_TMP_)']);
        else
            if (~strcmp(elements{j},'NA'))
                fprintf([regModel.regs.name{i} ': metabolite or regulator ' elements{j} ' not found in the model\n']);
            end
            newRule = '';
        end
    end
    regModel.regs.ruleParsed{i} = strrep(newRule,'_TMP_','');
end

%% Parse target rules

regModel.tars.name = columnVector(regModel.tars.name);
regModel.tars.rule = columnVector(regModel.tars.rule);
regModel.tars.comp = columnVector(regModel.tars.comp);
regModel.tars.ruleParsed = columnVector(regModel.tars.ruleParsed);

for i = 1:length(regModel.tars.name)
    elements = regModel.tars.comp{i};
    [isMet,metInd] = ismember(elements,regModel.mets.name);
    [isReg,regInd] = ismember(elements,regModel.regs.name);
    newRule = regModel.tars.ruleParsed{i};
    for j = 1:length(elements)
        if (metInd(j) > 0)
            newRule = strrep(newRule,['x(' num2str(j) ')'],['metState(' num2str(metInd(j)) '_TMP_)']);
        elseif (regInd(j) > 0)
            newRule = strrep(newRule,['x(' num2str(j) ')'],['regState(' num2str(regInd(j)) '_TMP_)']);
        else
            if (~strcmp(elements{j},'NA'))
                fprintf([regModel.tars.name{i} ': metabolite or regulator ' elements{j} ' not found in the model\n']);
            end
            newRule = '';
        end
    end
    regModel.tars.ruleParsed{i} = strrep(newRule,'_TMP_','');
end


function cmap = classpal

nClasses = 51;

hFig  = gcf;
hAxes = gca;

if strcmpi(hAxes.Visible, 'on')
    bgColor = hAxes.Color;
else
    bgColor = hFig.Color;
end

cmap = distinguishable_colors(nClasses, bgColor);

end


%DECOLOR  Transforms a color image to a grayscale image
%
%     [grayscale, color_boost] = cv.decolor(src)
%     [grayscale, color_boost] = cv.decolor(src, 'OptionName',optionValue, ...)
%
% ## Input
% * __src__ Input 8-bit 3-channel color image.
%
% ## Output
% * __grayscale__ Output 8-bit 1-channel grayscale image.
% * **color_boost** Output 8-bit 3-channel contrast-boosted color image. It is
%   obtained by converting `src` to Lab color space, replacing the lightness
%   channel with `grayscale`, and converting back to RGB color space.
%
% ## Options
% * __FlipChannels__ whether to flip the order of color channels in input
%   `src` and output `color_boost`, between MATLAB's RGB order and OpenCV's
%   BGR (input: RGB->BGR, output: BGR->RGB). default false
%
% It is a basic tool in digital printing, stylized black-and-white photograph
% rendering, and in many single channel image processing applications [CL12].
%
% This function is to be applied on color images.
%
% ## References
% [CL12]:
% > Cewu Lu, Li Xu, and Jiaya Jia. "Contrast preserving decolorization".
% > In Computational Photography (ICCP), 2012 IEEE International Conference
% > on, pages 1-7. IEEE, 2012.
%
% See also: cv.cvtColor
%


function [xOpt,fval] = psorunhybridfcn(fitnessfcn,xOpt,...
    Aineq,bineq,Aeq,beq,LB,UB,nonlcon,options)
% Calls the hybrid function defined in options.HybridFcn, from PSO.

if iscell(options.HybridFcn)
    HybridFcn = options.HybridFcn{1} ;
    hybridOptions = options.HybridFcn{2} ;
else
    HybridFcn = options.HybridFcn ;
    hybridOptions = optimset('Display',options.Display,...
        'LargeScale','off') ;
    if isfield(hybridOptions,'Algorithm')
        hybridOptions.Algorithm = 'active-set' ;
    end
end

if options.Verbosity > 0
    fprintf('\nBest point before hybrid function: %s',...
        mat2str(xOpt,5))
    fprintf('\n\nTurning over to hybrid function %s...\n\n',...
        func2str(HybridFcn))
end

if exist(func2str(HybridFcn),'file') ~= 2
    warning('pso:hybridfcn:nofile',...
        'Hybrid function %s cannot be found. Check toolboxes.',...
        func2str(HybridFcn))
    fval = fitnessfcn(xOpt) ;
    return
end

% Check for constraints
if strcmp(func2str(HybridFcn),func2str(@fmincon)) && ...
        all([isempty([Aineq,bineq]), isempty([Aeq,beq]), ...
        isempty([LB;UB]),isempty(nonlcon)])
    if options.Verbosity > 0
        msg = sprintf('Warning: %s does not accept problems without',...
            func2str(HybridFcn)) ;
        fprintf('%s constraints. Switching to fminunc.\n\n',msg)
    end % if options.Verbosity
    HybridFcn = @fminunc ;
elseif (strcmp(func2str(HybridFcn),func2str(@fminunc)) || ...
        strcmp(func2str(HybridFcn),func2str(@fminsearch))) && ...
        ~all([isempty([Aineq,bineq]), isempty([Aeq,beq]), ...
        isempty([LB;UB]),isempty(nonlcon)])
    if options.Verbosity > 0
        msg = sprintf('Warning: %s does not accept problems with',...
            func2str(HybridFcn)) ;
        fprintf(0,'%s constraints. Switching to fmincon.\n\n',msg)
    end % if options.Verbosity
    HybridFcn = @fmincon ;
end

if strcmp(func2str(HybridFcn),func2str(@fmincon)) || ...
        strcmp(func2str(HybridFcn),func2str(@patternsearch))
    [xOpt,fval] = HybridFcn(fitnessfcn,xOpt,Aineq,bineq,...
        Aeq,beq,LB,UB,nonlcon,hybridOptions) ;
elseif strcmp(func2str(HybridFcn),func2str(@fminunc)) || ...
        strcmp(func2str(HybridFcn),func2str(@fminsearch))
    [xOpt,fval] = HybridFcn(fitnessfcn,xOpt,hybridOptions) ;
else
    warning('pso:hybridfcn:unrecognized',...
        'Unrecognized hybrid function. Ignoring for it now.')
end


% Firmament Autopilot
% MLog (Mat Log) Parser
% @brief: parse mlog.bin file
function [LogHeader, LogMsg] = mlog_parser(logfile)

%% BLog Data Type Definition
TYPE_CAST = ["int8=>int8", "uint8=>uint8", "int16=>int16", "uint16=>uint16",...
    "int32=>int32", "uint32=>uint32", "float=>float", "double=>double"];

% mlog message start/end flag
MLOG_BEGIN_MSG1 = hex2dec('92');
MLOG_BEGIN_MSG2 = hex2dec('05');
MLOG_END_MSG = hex2dec('26');

%% Open Log File
fileID = fopen(logfile, 'r');
fileDir = dir(logfile);
if ~fileID
    disp('log file open fail');
    return;
end

%% Read Log Header
% Read Log Information
LogHeader.version = fread(fileID, 1, 'uint16=>uint16');
LogHeader.timestamp = fread(fileID, 1, 'uint32=>uint32');
LogHeader.max_name_len = fread(fileID, 1, 'uint16=>uint16');
LogHeader.max_desc_len = fread(fileID, 1, 'uint16=>uint16');
LogHeader.max_model_info_len = fread(fileID, 1, 'uint16=>uint16');
LogHeader.description = fread(fileID, LogHeader.max_desc_len, 'char=>char');
LogHeader.model_info = fread(fileID, LogHeader.max_model_info_len, 'char=>char');

fprintf('MLog File:%s\n', logfile);
fprintf('Version:%d\n', LogHeader.version);
fprintf('Timestamp:%d(ms)\n', LogHeader.timestamp);
fprintf('Description:%s\n', LogHeader.description);
fprintf('Model Information:\n%s\n', LogHeader.model_info);

% Read bus number
LogHeader.num_bus = fread(fileID, 1, 'uint8=>uint8');
% Preallocate memory
MsgCount = zeros(1, LogHeader.num_bus);
LogMsg = cell(1, LogHeader.num_bus);
% Read bus data
for n = 1:LogHeader.num_bus
    LogHeader.bus(n).name = fread(fileID, [1 LogHeader.max_name_len], 'uint8=>char');
    LogHeader.bus(n).msg_id = fread(fileID, 1, 'uint8=>uint8');
    LogHeader.bus(n).num_elem = fread(fileID, 1, 'uint8=>uint8');
    % Read bus elements
    for k = 1:LogHeader.bus(n).num_elem
        LogHeader.bus(n).elem_list(k).name = fread(fileID, [1 LogHeader.max_name_len], 'uint8=>char');
        LogHeader.bus(n).elem_list(k).type = fread(fileID, 1, 'uint16=>uint16');
        LogHeader.bus(n).elem_list(k).number = fread(fileID, 1, 'uint16=>uint16');
    end
    % Preallocate memory
    LogMsg{n} = cell(1, LogHeader.bus(n).num_elem);
end

% Read Parameter
LogHeader.num_param_group = fread(fileID, 1, 'uint8=>uint8');

for n = 1:LogHeader.num_param_group
    LogHeader.param_group_list(n).name = fread(fileID, [1 LogHeader.max_name_len], 'uint8=>char');
    LogHeader.param_group_list(n).num_param = fread(fileID, 1, 'uint32=>uint32');
    LogHeader.param_group_list(n).name = LogHeader.param_group_list(n).name(~isspace(LogHeader.param_group_list(n).name));

    for k = 1:LogHeader.param_group_list(n).num_param
        LogHeader.param_group_list(n).param(k).name = fread(fileID, [1 LogHeader.max_name_len], 'uint8=>char');
        LogHeader.param_group_list(n).param(k).type = fread(fileID, 1, 'uint8=>uint8');
        index = LogHeader.param_group_list(n).param(k).type+1;
        LogHeader.param_group_list(n).param(k).val = fread(fileID, 1, TYPE_CAST(index));
        LogHeader.param_group_list(n).param(k).name = LogHeader.param_group_list(n).param(k).name(~isspace(LogHeader.param_group_list(n).param(k).name));
    end
end

%% Read Log Msg
while ~feof(fileID) && ftell(fileID)<fileDir.bytes

    %%% Read Msg Begin Flag %%%
    begin_state = 0;
    while begin_state < 2
        switch begin_state
            case 0
                % search for MLOG_BEGIN_MSG1
                msg_begin = fread(fileID, 1, 'uint8=>uint8');
                if msg_begin == MLOG_BEGIN_MSG1
                    begin_state = 1;
                end
            case 1
                % search for MLOG_BEGIN_MSG2
                msg_begin = fread(fileID, 1, 'uint8=>uint8');
                if msg_begin == MLOG_BEGIN_MSG2
                    begin_state = 2;
                elseif msg_begin == MLOG_BEGIN_MSG1
                    begin_state = 1;
                else
                    begin_state = 0;
                end
            otherwise
                break;
        end
    end

    %%% Read Msg ID %%%
    msg_id = fread(fileID, 1, 'uint8=>uint8');

    % msg_id start from 0 and index start from 1
    index = msg_id + 1;
    if index > LogHeader.num_bus
        index = -1; % invalid msg id
    end

    if index < 0
        fprintf('invalid msg id:%d\r\n', msg_id);
        % continue to search next msg
        continue;
    end

    %%% Read Msg Payload %%%

    % read bus elements
    for k = 1:LogHeader.bus(index).num_elem
        type = LogHeader.bus(index).elem_list(k).type+1;
        len = LogHeader.bus(index).elem_list(k).number;

        [elem_val, rb] = fread(fileID, [len, 1], TYPE_CAST(type));

        if rb < len
            fprintf('%s %s cnt %d read err, delete it\n', LogHeader.bus(index).name, LogHeader.bus(index).elem_list(k).name, MsgCount(index));
            % TODO: handle this error
            break;
        else
            % LogMsg{msg_id}{elem_index}(len:cnt)
            LogMsg{index}{k}(1:len, MsgCount(index)+1) = elem_val;
        end
    end

    %%% Read Msg End Flag %%%
    msg_end = fread(fileID, 1, 'uint8=>uint8');
    if msg_end == MLOG_END_MSG
        % valid msg received
        MsgCount(index) = MsgCount(index) + 1;
    else
        fprintf('invalid msg end flag:%d, msg id:%d\r\n', msg_end, msg_id);
        % delete invalid msg
        for k = 1:LogHeader.bus(index).num_elem
            try
                LogMsg{index}{k}(:, MsgCount(index)+1) = [];
            catch
                continue
            end
        end
    end
end
fclose(fileID);

%% Output Parsed Information
fprintf('\nLog parse finish!\n');
% fprintf('log elapsed time: %f(s)\n', )
for n = 1:LogHeader.num_bus
    BusName = strrep(LogHeader.bus(n).name, '"', '');
    BusName = BusName(~isspace(BusName));
	fprintf('%s: %d msg recorded\n', BusName, MsgCount(n));
end

%% Generate .MAT file
generate_MAT(LogHeader, LogMsg, fileDir.folder);
end

function generate_MAT(LogHeader, LogMsg, Path)
%% create Bus variable and save into .mat file
save(strcat(Path, '/LogHeader.mat'), 'LogHeader'); % save log header

for n = 1:LogHeader.num_bus
    msg_id = LogHeader.bus(n).msg_id;
    index = msg_id + 1;
    if isempty(LogMsg{index})
       continue;
    end

    BusName = strrep(LogHeader.bus(n).name, '"', '');
    BusName = BusName(~isspace(BusName));

    % find timestamp
    timestamp_id = 0;
    for k = 1:LogHeader.bus(n).num_elem
        ElemName = strrep(LogHeader.bus(n).elem_list(k).name, '"', '');
        ElemName = ElemName(~isspace(ElemName));
        if strcmp(ElemName, "timestamp_ms") || strcmp(ElemName, "timestamp")
            timestamp_id = k;
        end
    end

    if timestamp_id <= 0
       fprintf("can't find timestamp element in %s\n", LogHeader.bus(n).name);
       continue;
    else
       time_stamp = double(LogMsg{index}{timestamp_id}-LogMsg{index}{timestamp_id}(1)) * 0.001;   % milli second to second
    end

    % construct Bus variable
    for k = 1:LogHeader.bus(n).num_elem
        ElemName = strrep(LogHeader.bus(n).elem_list(k).name, '"', '');
        ElemName = ElemName(~isspace(ElemName));

        exp = sprintf('timeseries(LogMsg{index}{k}'', time_stamp);');
        if ~isempty(ElemName)
            eval([BusName, '.', ElemName, '=', exp]);
        else
            eval([BusName, '=', exp]);
        end

    end

    % save as .mat file
    out_file = strcat(Path, ['/', BusName, '.mat']);
    save(out_file, BusName);
    fprintf("Save to path:%s\n", out_file);
end
end


function [bbci_cls, data_adapt]= bbci_adaptation_pcovmean(bbci_cls, data_adapt, marker, varargin)
%BBCI_ADAPTATIOIN_PCOVMEAN - Supervised adapt class means and pooled covariance matrix of an LDA classifier
%
%Technique by Carmen Vidaurre, see
%  Viduarre C et al, J Neural Eng, 2011
%  http://dx.doi.org/10.1088/1741-2560/8/2/025009
%
%Synopsis:
%  [BBCI_CLS, DATA_ADAPT]= ...
%      bbci_adaptation_pcovmean(BBCI_CLS, DATA_ADAPT, 'init', PARAMs, ...)
%  [BBCI_CLS, DATA_ADAPT]= ...
%      bbci_adaptation_pcovmean(BBCI_CLS, DATA_ADAPT, MARKER, FEATURE)
%
%This function is called internally by bbci_apply_adaptation.
%
%The selectable parameters are
%  'UC_mean' - [DOUBLE, default 0.05] Update coefficient for supervised
%              adaptation of the class means.
%  'UC_pcov' - [DOUBLE, default 0.03] Update coefficient for unsupervised
%              adaptation of the pooled covariance matrix (inverse of the
%              extended ..., to be exact).
%  'ival' - [1x2 DOUBLE] Time interval relative to the start marker, during
%              which features are averaged and used for adaptation;
%              no default - needs to be set.
%              Note: When choosing the start of the adaptation interval,
%              you have to take into account bbci.feature.ival (meaning
%              that feature are based on retrospective signals).
%  'mrk_start' - {1xnClasses CELL} defines the markers that trigger the
%              adaptation for each class; no default - needs to be set.
%  'mrk_end' - [1 nMarkers INT, default []] specifies markers that indicate
%              the end of a trial. Gathering feature information for the
%              adaptation of one trial ends, when one of those end-markers
%              is received AND the end of the adaptation interval 'ival'
%              (see above) is reached. If 'mrk_end' is empty, the first part
%              of the condition is ignored, i.e., only 'ival' is taken into
%              account.
%  'scaling' - [BOOL, default true] Defines whether the updated classifier
%              should be (re-) scaled.
%  'log_mean_limit' - [INT, default 100].

% 01-2012 Benjamin Blankertz
% 04-2011 Claudia Sannelli

if ischar(marker) && strcmp(marker, 'init'),
  props= {'UC_mean'          0.05    '!DOUBLE[1]'
          'UC_pcov'          0.03    '!DOUBLE[1]'
          'ival'             []      '!DOUBLE[2]'
          'scaling'          1       '!BOOL'
          'mrk_start'        {}      'CELL'
          'mrk_end'          []      'INT'
          'log_mean_limit'   100     '!INT'
          'tag'              ''      'CHAR'
         };
  opt= opt_proplistToStruct(varargin{:});
  opt= opt_setDefaults(opt, props, 2);
  data_adapt.opt= opt;
  data_adapt.feature= zeros(size(bbci_cls.C.w));
  data_adapt.trial_start= NaN;
  data_adapt.lastcheck= -inf;
  bbci_log_write(data_adapt.log.fid, ...
                 '# %s started with bias=%g and options %s.', ...
                 data_adapt.opt.tag, bbci_cls.C.b, util_toString(opt));
  return;
else
  feature= varargin{1};
end

time= marker.current_time;
check_ival= [data_adapt.lastcheck time];
events= bbci_apply_queryMarker(marker, check_ival);
data_adapt.lastcheck= time;

if ~isempty(events) && isnan(data_adapt.trial_start),
  data_adapt.clidx= 0;
  for k= 1:length(data_adapt.opt.mrk_start),
    marker_idx= find(ismember([events.desc], data_adapt.opt.mrk_start{k},'legacy'));
    if ~isempty(marker_idx),
      data_adapt.clidx= k;
      break;
    end
  end
  if data_adapt.clidx>0,
    data_adapt.trial_start= events(marker_idx(1)).time;
    data_adapt.end_marker_received= isempty(data_adapt.opt.mrk_end);
    data_adapt.counter= 0;
    bbci_log_write(data_adapt.log.fid, ...
        ['# %s at ' data_adapt.log.time_fmt ...
         ' trial started with marker %d -> class %d.'], ...
        data_adapt.opt.tag, data_adapt.trial_start/1000, ...
        events(marker_idx(1)).desc, data_adapt.clidx);
  end
end

if isnan(data_adapt.trial_start),
  return;
end

% within the adaptation interval, add up the features and count them
adapt_ival= data_adapt.trial_start + data_adapt.opt.ival;
if time >= adapt_ival(1) && time <= adapt_ival(2),
  data_adapt.feature= data_adapt.feature + feature.x(:);
  data_adapt.counter= data_adapt.counter + 1;
end

if ~isempty(events) && any(ismember([events.desc], data_adapt.opt.mrk_end,'legacy'));
  data_adapt.end_marker_received= 1;
end
if data_adapt.end_marker_received && time >= adapt_ival(2),
  if data_adapt.counter==0,
    return;
  end
  % handy definitions
  UCm= data_adapt.opt.UC_mean;
  UCp= data_adapt.opt.UC_pcov;
  feat= data_adapt.feature/data_adapt.counter;
  % adapt class means (supervised)
  bbci_cls.C.mean(:,data_adapt.clidx)= UCm * feat + ...
      (1 - UCm) * bbci_cls.C.mean(:,data_adapt.clidx);
  % adapt (inverse of extended) pooled covariance matrix (unsupervised)
  extfeat= [1; feat];
  v= bbci_cls.C.extinvcov*extfeat;
  bbci_cls.C.extinvcov= (1/(1 - UCp)) * ...
    (bbci_cls.C.extinvcov - UCp/(1 - UCp + UCp * extfeat' * v) * v*v');
  bbci_cls.C.extinvcov= 0.5 * (bbci_cls.C.extinvcov + bbci_cls.C.extinvcov');
  % recalculate classifier
  diff_mean= diff(bbci_cls.C.mean, 1, 2);
  bbci_cls.C.w= bbci_cls.C.extinvcov(2:end, 2:end) * diff_mean;

  % rescale projection vector
  if data_adapt.opt.scaling,
    bbci_cls.C.w= bbci_cls.C.w/(bbci_cls.C.w' * diff_mean)*2;
  end
  bbci_cls.C.b= -bbci_cls.C.w' * mean(bbci_cls.C.mean, 2);
  if numel(bbci_cls.C.mean) < data_adapt.opt.log_mean_limit,
    bbci_log_write(data_adapt.log.fid, ...
                   ['# %s at ' data_adapt.log.time_fmt ...
                   ' bias adapted to %g, mean adapted to %s' ...
                   ' with %d features.'], ...
                   data_adapt.opt.tag, marker.current_time/1000, ...
                   bbci_cls.C.b, util_toString(bbci_cls.C.mean), ...
                   data_adapt.counter);
  else
    bbci_log_write(data_adapt.log.fid, ...
                   ['# %s at ' data_adapt.log.time_fmt ...
                   ' bias adapted to %g with %d features.'], ...
                   data_adapt.opt.tag, marker.current_time/1000, ...
                   bbci_cls.C.b, data_adapt.counter);
  end
  data_adapt.feature(:)= 0;
  data_adapt.trial_start= NaN;
end


function [paramsOut] = referenceGUI(hObject, callbackdata, inputData)%#ok<INUSL>
title = 'Reference parameters';
defaultStruct = inputData.userData.reference;
referenceTypeMenu = {'Robust'; 'Average'; 'Specific'; 'None'};
reportingLevelMenu = {'Minimum'; 'Verbose'};
meanEstimateTypeMenu = {'Huber'; 'Median'; 'Mean'; 'None'};
interpolationOrderMenu = {'Post-reference'; 'Pre-reference'};
while(true)
    mainFigure = findobj('Type', 'Figure', '-and', 'Name', inputData.name);
    userdata = get(mainFigure, 'UserData');
    if isempty(userdata) || ~isfield(userdata, 'reference')
        paramsOut = struct();
    else
        paramsOut = userdata.reference;
    end
    [defaultStruct, errors] = checkStructureDefaults(paramsOut, defaultStruct);

    if ~isempty(errors)
        warning('referenceGUI:bad parameters', getMessageString(errors)); %#ok<CTPCT>
    end

    % Creates structure for
    fNamesDefault = fieldnames(defaultStruct);
    for k = 1:length(fNamesDefault)
        textColorStruct.(fNamesDefault{k}) = 'k';
    end

    if defaultStruct.ransacOff.value
        ransacOffValue = 1;
    else
        ransacOffValue = 0;
    end

    referenceTypeValue = typeMenuPosition(...
        defaultStruct.referenceType.value, referenceTypeMenu);
    reportingLevelValue = typeMenuPosition(...
        defaultStruct.reportingLevel.value, reportingLevelMenu);
    meanEstimateTypeValue = typeMenuPosition( ...
        defaultStruct.meanEstimateType.value, meanEstimateTypeMenu);
    closeOpenWindows(title);
    geometry = {[1, 1.75,1], [1, 1.75,1], [1, 1.75,1], 1, [1.35,1,1.75,1], [1.35,1,1.75,1], ...
        [1.35,1,1.75,1], 1, [1.35,1,1.75,1], [1.35,1,1.75,1], [1.35,1,1.75,1], 1, ...
        [1.35,1,1.75,1], [1.35,1,1.75,1], [1.35,1,1.75,1], 1};
    geomvert = [];
    uilist={{'style', 'text', 'string', 'Reference channels', ...
        'TooltipString', defaultStruct.referenceChannels.description}...
        {'style', 'edit', 'string', ...
        vector2str(defaultStruct.referenceChannels.value), 'tag', ...
        'referenceChannels', 'ForegroundColor', ...
        textColorStruct.referenceChannels}...
        {'style', 'text', 'string', ''} ...
        {'style', 'text', 'string', 'Evaluation channels', ...
        'TooltipString', defaultStruct.evaluationChannels.description}...
        {'style', 'edit', 'string', ...
        vector2str(defaultStruct.evaluationChannels.value), ...
        'tag', 'evaluationChannels', 'ForegroundColor', ...
        textColorStruct.evaluationChannels}...
        {'style', 'text', 'string', ''} ...
        {'style', 'text', 'string', 'Re-referenced channels', ...
        'TooltipString', defaultStruct.rereferencedChannels.description}...
        {'style', 'edit', 'string', ...
        vector2str(defaultStruct.rereferencedChannels.value), ...
        'tag', 'rereferencedChannels', 'ForegroundColor', ...
        textColorStruct.rereferencedChannels}...
        {'style', 'text', 'string', ''} ...
        {'style', 'text', 'string', ''}...
        {'style', 'text', 'string', 'Turn ransac off', ...
        'TooltipString', defaultStruct.ransacOff.description}...
        {'style', 'checkbox', 'Value', ransacOffValue, ...
        'tag', 'ransacOff', 'ForegroundColor', textColorStruct.ransacOff}...
        {'style', 'text', 'string', 'Ransac sample size', ...
        'TooltipString', defaultStruct.ransacSampleSize.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.ransacSampleSize.value), ...
        'tag', 'ransacSampleSize', 'ForegroundColor', ...
        textColorStruct.ransacSampleSize}...
        {'style', 'text', 'string', 'Ransac channel fraction', ...
        'TooltipString', defaultStruct.ransacChannelFraction.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.ransacChannelFraction.value), ...
        'tag','ransacChannelFraction', 'ForegroundColor', ...
        textColorStruct.ransacChannelFraction}...
        {'style', 'text', 'string', 'Ransac correlation threshold', ...
        'TooltipString', defaultStruct.ransacCorrelationThreshold.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.ransacCorrelationThreshold.value), ...
        'tag','ransacCorrelationThreshold', 'ForegroundColor', ...
        textColorStruct.ransacCorrelationThreshold}...
        {'style', 'text', 'string','Ransac unbroken time', ...
        'TooltipString', defaultStruct.ransacUnbrokenTime.description}...
        {'style','edit','string', ...
        num2str(defaultStruct.ransacUnbrokenTime.value), ...
        'tag', 'ransacUnbrokenTime', 'ForegroundColor', ...
        textColorStruct.ransacUnbrokenTime}...
        {'style', 'text', 'string', 'Ransac window', ...
        'TooltipString', defaultStruct.ransacWindowSeconds.description}...
        {'style','edit','string', ...
        num2str(defaultStruct.ransacWindowSeconds.value), ...
        'tag', 'ransacWindowSeconds', 'ForegroundColor', ...
        textColorStruct.ransacWindowSeconds}...
        {'style', 'text', 'string', ''}...
        {'style', 'text', 'string', 'Sampling rate', ...
        'TooltipString', defaultStruct.srate.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.srate.value), ...
        'tag', 'srate', 'ForegroundColor', textColorStruct.srate}...
        {'style', 'text', 'string', 'Robust deviation threshold', ...
        'TooltipString', defaultStruct.robustDeviationThreshold.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.robustDeviationThreshold.value), ...
        'tag', 'robustDeviationThreshold', 'ForegroundColor', ...
        textColorStruct.robustDeviationThreshold}...
        {'style', 'text', 'string', 'Correlation window', ...
        'TooltipString', defaultStruct.correlationWindowSeconds.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.correlationWindowSeconds.value), ...
        'tag','correlationWindowSeconds', 'ForegroundColor', ...
        textColorStruct.correlationWindowSeconds}...
        {'style', 'text', 'string', 'High frequency noise threshold', ...
        'TooltipString', defaultStruct.highFrequencyNoiseThreshold.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.highFrequencyNoiseThreshold.value), ...
        'tag', 'highFrequencyNoiseThreshold', 'ForegroundColor', ...
        textColorStruct.highFrequencyNoiseThreshold}...
        {'style', 'text', 'string','Correlation threshold', ...
        'TooltipString',defaultStruct.correlationThreshold.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.correlationThreshold.value), ...
        'tag', 'correlationThreshold', 'ForegroundColor', ...
        textColorStruct.correlationThreshold}...
        {'style', 'text', 'string', 'Bad time threshold', ...
        'TooltipString', defaultStruct.badTimeThreshold.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.badTimeThreshold.value), ...
        'tag', 'badTimeThreshold', 'ForegroundColor', ...
        textColorStruct.badTimeThreshold}...
        {'style', 'text', 'string', ''}...
        {'style', 'text', 'string', 'Max reference iterations', ...
        'TooltipString', defaultStruct.maxReferenceIterations.description}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.maxReferenceIterations.value), ...
        'tag', 'maxReferenceIterations', 'ForegroundColor', ...
        textColorStruct.maxReferenceIterations}...
        {'style', 'text', 'string', 'Reference type', ...
        'TooltipString', defaultStruct.referenceType.description}...
        {'style', 'popupmenu', 'string', 'Robust|Average|Specific', ...
        'value', referenceTypeValue, 'tag', 'referenceType', ...
        'ForegroundColor', textColorStruct.referenceType}...
        {'style', 'text', 'string', 'Reporting level', ...
        'TooltipString', defaultStruct.reportingLevel.description}...
        {'style', 'popupmenu', 'string', 'Minimum|Verbose', ...
        'value', reportingLevelValue, ...
        'tag', 'reportingLevel', 'ForegroundColor', ...
        textColorStruct.reportingLevel}...
        {'style', 'text', 'string', 'Interpolation order', ...
        'TooltipString', defaultStruct.interpolationOrder.description}...
        {'style', 'popupmenu', 'string', 'Post-reference|Pre-reference', ...
        'tag', 'interpolationOrder', 'ForegroundColor', ...
        textColorStruct.interpolationOrder}...
        {'style', 'text', 'string', 'Mean estimate type', ...
        'TooltipString', defaultStruct.meanEstimateType.description}...
        {'style', 'popupmenu', 'string', 'Huber|Median|Mean|None', ...
        'value', meanEstimateTypeValue, 'tag', 'meanEstimateType', ...
        'ForegroundColor', textColorStruct.reportingLevel}...
        {'style', 'edit', 'string', ...
        num2str(defaultStruct.samples.value), ...
        'tag', 'samples', 'visible', 'off'}...
        {'style', 'text', 'string', ''},...
        {'style', 'text', 'string', ''}};

    [~, ~, ~, paramsOut] = ...
        inputgui('geometry', geometry, 'geomvert', geomvert, ...
        'uilist', uilist, 'title', title, 'helpcom', ...
        'pophelp(''pop_prepPipeline'')');
    if(isempty(paramsOut))
        break;
    end
    [paramsOut, typeErrors, fNamesErrors] = ...
        changeType(paramsOut, defaultStruct);
    paramsOut.referenceType = ...
        typeMenuString(paramsOut.referenceType, referenceTypeMenu);
    paramsOut.reportingLevel = ...
        typeMenuString(paramsOut.reportingLevel, reportingLevelMenu);
    paramsOut.interpolationOrder = ...
        typeMenuString(paramsOut.interpolationOrder, interpolationOrderMenu);
    paramsOut.meanEstimateType = ...
        typeMenuString(paramsOut.meanEstimateType, meanEstimateTypeMenu);
    mainFigure = findobj('Type', 'Figure', '-and', 'Name', inputData.name);
    userdata = get(mainFigure, 'UserData');
    userdata.reference = paramsOut;
    set(mainFigure, 'UserData', userdata);
    if isempty(typeErrors)
        break;
    end
    textColorStruct = highlightErrors(fNamesErrors, ...
        fNamesDefault, textColorStruct);
    displayErrors(typeErrors); % Displays the errors and restarts GUI
end

    function position = typeMenuPosition(theString, menuString)
        menuIndex = 1:length(menuString);
        position = strcmpi(theString, menuString);
        position = menuIndex(position);
    end

    function theString = typeMenuString(position, menuString)
        theString = menuString{position};
    end

end


function metrics = track_seq(seq_idx, seq_set, tracker, opt)

is_print = 1;   % set is_print to 1 to display the printed info

opt.is_print = is_print;
opt.exit_thre = 0.3;

if strcmp(seq_set, 'train') == 1
    seq_name = opt.mot2d_train_seqs{seq_idx};
    seq_len = opt.mot2d_train_nums(seq_idx);
else
    seq_name = opt.mot2d_test_seqs{seq_idx};
    seq_len = opt.mot2d_test_nums(seq_idx);
end

% mkdir img_traj
if exist('img_traj') ~= 7
    mkdir('img_traj');
end

if exist(['img_traj/' seq_name]) ~= 7
    mkdir(['img_traj/' seq_name]);
end

% read detections
det_file = fullfile(opt.mot, opt.mot2d, seq_set, seq_name, 'det', 'det.txt');
bboxes_det = read_bboxes(det_file);

if strcmp(seq_set, 'train') == 1
    % read ground truth
    gt_file = fullfile(opt.mot, opt.mot2d, seq_set, seq_name, 'gt', 'gt.txt');
    bboxes_gt = read_bboxes(gt_file);
    index_considered = find(bboxes_gt.r == 1);
    bboxes_gt = sub_bboxes(bboxes_gt, index_considered);
end

% initialize frame settings
frame_path = fullfile(opt.mot, opt.mot2d, seq_set, seq_name, 'img1', sprintf('%06d.jpg', 1));
frame_image = imread(frame_path);
frame_size.x = 1;
frame_size.y = 1;
frame_size.w = size(frame_image, 2);
frame_size.h = size(frame_image, 1);

% intialize tracker
tracker.image_width = frame_size.w;
tracker.image_height = frame_size.h;
tracker.max_width = max(bboxes_det.w);
tracker.max_height = max(bboxes_det.h);
tracker.max_score = max(bboxes_det.r);
tracker.min_score = min(bboxes_det.r);
tracker.num_tracked = 0;
tracker.fps = opt.fps(seq_idx);

% for each frame
trackers = [];
id = 0;
for fr = 1:seq_len
    if is_print
        fprintf('%s/%s frame %d\n', seq_set, seq_name, fr);
    else
        fprintf('.');
        if mod(fr, 100) == 0
            fprintf('\n');
        end
    end

    % read frame image
    frame_path = fullfile(opt.mot, opt.mot2d, seq_set, seq_name, 'img1', sprintf('%06d.jpg', fr));
    frame_image = imread(frame_path);

    % extract detection
    sub_idx = find(bboxes_det.fr == fr);
    bboxes = sub_bboxes(bboxes_det, sub_idx);

    % Detection preprocessing based on the scene context
    if strcmp(seq_set, 'test')
        sub_idx = [];
        for idx = 1:numel(bboxes.x)
            FP_flag = 0;
            % filter detections which are too large to be pedestrians
            if ~isempty(opt.h_max{seq_idx})
                if bboxes.h(idx) > opt.h_max{seq_idx}
                    FP_flag = 1;
                end
            end

            % filter detections which are too small to be pedestrians
            if ~isempty(opt.h_min{seq_idx})
                if bboxes.h(idx) < opt.h_min{seq_idx}
                    FP_flag = 1;
                end
            end

            % filter detections in impossible locations
            if ~isempty(opt.backgrounds{seq_idx})
                cx_det = bboxes.x(idx) + bboxes.w(idx) / 2; % center x of the detection
                cy_det = bboxes.y(idx) + bboxes.h(idx) / 2; % center y of the detection
                for bg_idx = 1:size(opt.backgrounds{seq_idx}, 1)
                    bg = opt.backgrounds{seq_idx}(bg_idx,:);
                    if cx_det > bg(1) && cx_det < bg(3) && cy_det > bg(2) && cy_det < bg(4)
                        FP_flag = 1;
                        continue;
                    end
                end
            end
            if FP_flag == 0
                sub_idx = [sub_idx, idx];
            end
        end
        bboxes = sub_bboxes(bboxes, sub_idx);
    end

    % nms
     boxes = [bboxes.x bboxes.y bboxes.x+bboxes.w bboxes.y+bboxes.h bboxes.r];
     sub_idx = nms(boxes, 0.6);
     bboxes = sub_bboxes(bboxes, sub_idx);

    % sort trackers
    [index1, index2] = sort_trackers(trackers, opt);
    index_processed = [];
    for k = 1:2
        % process trackers in the first class or the second class
        if k == 1
            index_track = index1;
        else
            index_track = index2;
        end

        % process trackers
        for i = 1:numel(index_track)
            ind = index_track(i);
            if trackers{ind}.state == opt.STATE_TRACKED || trackers{ind}.state == opt.STATE_ACTIVATED
                % track target
                [bboxes_tmp, index] = find_candidate_detections(trackers(index_processed), bboxes, opt);
                bboxes_eco_track = sub_bboxes(bboxes_tmp, index);
                trackers{ind} = MOT_track(fr, frame_image, frame_size, bboxes_eco_track, trackers{ind}, opt, seq_name);

                if trackers{ind}.state == opt.STATE_TRACKED || trackers{ind}.state == opt.STATE_ACTIVATED
                    index_processed = [index_processed; ind];
                end
            end
        end
        for i = 1:numel(index_track)
            ind = index_track(i);
            if trackers{ind}.state == opt.STATE_LOST
                % associate target
                [bboxes_tmp, index] = find_candidate_detections(trackers(index_processed), bboxes, opt);
                bboxes_associate = sub_bboxes(bboxes_tmp, index);
                trackers{ind} = MOT_associate(fr, frame_image, frame_size, bboxes_associate, trackers{ind}, opt, seq_name);
                index_processed = [index_processed; ind];
            end
        end
    end

    % find detections for initialization
    [bboxes, index] = find_candidate_detections(trackers, bboxes, opt);

    for i = 1:numel(index)
        % extract features
        bbox = sub_bboxes(bboxes, index(i));

        % filter detections using SVM
        det_feat = extract_det_feat(tracker, bbox);
        label = svmpredict(1, det_feat, tracker.w_active, '-q');
        if label < 0
           continue;
        end

        % reset tracker for the new object identity
        tracker.state = opt.STATE_START;
        id = id + 1;
        trackers{end+1} = initialize_tracker(fr, frame_image, id, bboxes, index(i), tracker, opt);
    end

    % resolve tracker conflict
    trackers = handle_conflicting_trackers(trackers, bboxes, opt);

    bboxes_track = [];
    for i = 1:numel(trackers)
        if isempty(bboxes_track)
            bboxes_track = trackers{i}.bboxes;
        else
            bboxes_track = concatenate_bboxes(bboxes_track, trackers{i}.bboxes);
        end
    end

    for i = 1:numel(trackers)
        if trackers{i}.state == opt.STATE_START || trackers{i}.state == opt.STATE_TRACKED || trackers{i}.state == opt.STATE_ACTIVATED
            bbox = sub_bboxes(trackers{i}.bboxes, numel(trackers{i}.bboxes.fr));
            x1 = floor(max(1, bbox.x));
            y1 = floor(max(1, bbox.y));
            x2 = ceil(min(frame_size.w, bbox.x+bbox.w-1));
            y2 = ceil(min(frame_size.h, bbox.y+bbox.h-1));
            img_traj = frame_image(y1:y2, x1:x2, :);
            if exist(['img_traj/' seq_name '/' num2str(trackers{i}.target_id)]) ~= 7
                mkdir(['img_traj/' seq_name '/' num2str(trackers{i}.target_id)]);
            end
            imwrite(img_traj, ['img_traj/' seq_name '/' num2str(trackers{i}.target_id) '/' num2str(fr) '.jpg']);
        end
    end
end

% write tracking results
file_name = sprintf('%s/%s.txt', opt.results_dir, seq_name);
fprintf('write results: %s\n', file_name);
save_results(seq_name, file_name, bboxes_track, tracker.fps*opt.initialization_thre, opt);


% 0.02

totalNum = 1867290;

loopCompress(0.1, '/home/huyin/weightVector.txt', '/home/huyin/visMatrix/', 50, totalNum, 333, '/home/huyin/gurobi_compress_0.02/');

ratio = salientNumCnt( '/home/huyin/gurobi_compress_0.02/', totalNum ) / totalNum


function f = simplify(f, varargin)
%SIMPLIFY  Simplifys a DELTAFUN object F.
%   F = SIMPLIFY(F) simplifies the FUNPART and removes any trivial delta
%   functions from the delta fun F. Preferences can be passed via VARARGIN.
%
% See also SIMPLIFY, CLEANROWS, CLEANCOLUMNS

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

f.funPart = simplify(f.funPart, varargin{:});
f = simplifyDeltas(f, varargin{:});

end


function signal = set_fit_dipoles(varargin)
% Fit dipoles for each independent component of an IC-decomposed dataset.
%
% This function uses the Dipfit plugin for EEGLAB to automatically derive dipole locations
% for all IC's in the data set. The returned coordinates are in the MNI coordinate system.
% In addition, (probabilistic) anatomical labels can be looked up from different brain atlases [1,2].
%
%
% In:
%   Signal           : data set with valid IC decomposition
%
%   HeadModel        : head model file (see pop_dipfit_settings) (default: standard BEM volume)
%
%   MRImage          : anatomical MR head image file (default: standard BEM image)
%
%   ChannelLocations : coregistered channel locations file (default: standard 10-20 locations)
%
%   LookupLabels     : whether to look up anatomical labels & probabilities (default: true)
%
%   ConfusionRange   : radius (in mm) of uncertainty over which to scan for labels (default: 4)
%
%   BrainAtlas       : brain atlas to use. Talairach has a larger repertoire of areas, but is (in
%                      this version) non-probabilistic. The LONI LBPA40 atlas is a high-quality
%                      probabilistic atlas.
%
% Out:
%   Signal : data set with added dipole annotations
%
% Notes:
%   In the default settings, a standard Eurasian BEM head model amd MR image is used, and channel
%   locations are assumed to be standard 10-20 locations if not specifically given.
%
% Examples:
%   % for a data set which is annotated with independent components, e.g. via
%   eeg = flt_ica(raw);
%
%   % ... fit dipoles for each component using default settings, and look up the nearby anatomical
%   % structures and their hit probabilities)
%   eeg = set_fit_dipoles(eeg)
%
%   % ... fit dipoles and and look up anatomical structures within a radius of 10mm around each
%   % dipole coordinate (passing arguments by name)
%   eeg = set_fit_dipoles('Signal',eeg,'ConfusionRange',10)
%
%   % ... fit dipoles but do not look up anatomical structures
%   eeg = set_fit_dipoles('Signal',eeg,'LookupLabels',false)
%
%   % ... fit dipoles using a (subject-) specific head model and MR file
%   eeg = set_fit_dipoles('Signal',eeg,'HeadModel','volXY.mat','MRImage','mriXY.mat')
%
%   % ... fit dipoles using a (subject-) specific head model and MR file, as well as digitized
%   % channel locations
%   eeg = set_fit_dipoles('Signal',eeg,'HeadModel','my_vol.mat','MRImage','my_mri.mat','ChannelLocations','my_locs.mat')
%
% References:
%   [1] Lancaster JL, Woldorff MG, Parsons LM, Liotti M, Freitas CS, Rainey L, Kochunov PV, Nickerson D, Mikiten SA, Fox PT, "Automated Talairach Atlas labels for functional brain mapping".
%       Human Brain Mapping 10:120-131, 2000
%   [2] Shattuck DW, Mirza M, Adisetiyo V, Hojatkashani C, Salamon G, Narr KL, Poldrack RA, Bilder RM, Toga AW, "Construction of a 3D probabilistic atlas of human cortical structures."
%       Neuroimage. 2008 39(3):1064-80
%
% See also:
%   flt_ica, coregister, pop_multifit
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2011-01-21

% set_fit_dipoles_version<0.91> -- for the cache

if ~exp_beginfun('filter') return; end

% declare GUI name, etc.
declare_properties('name',{'DipoleFitting','dipfit'}, 'depends','flt_ica', 'precedes','flt_project', 'independent_channels',true, 'independent_trials',true);

% define arguments...
arg_define(varargin, ...
    arg_norep({'signal','Signal'}), ...
    arg({'hdm_file','HeadModel'}, '', [],'Head model file. The BEM head model that should be used by dipfit (using a standard model if empty).'),...
    arg({'mri_file','MRImage'}, '', [],'MR head image file. The MR head image that should be used by dipfit (using a standard image if empty).'),...
    arg({'chan_file','ReferenceLocations'}, '', [],'Coregistered reference chanlocs. The coregistered electrode locations that should be used as reference for alignment warping.'),...
    arg({'lookup_labels','LookupLabels'},true,[], 'Look up dipole labels. If enabled, look up anatomical labels from the selected brain atlas.'),...
    arg({'confusion_range','ConfusionRange'}, 4, [1 4 15 30], 'Confusion Radius (mm). Assumed standard deviation of uncertainty in the dipole fits, in millimeters.'),...
    arg({'brain_atlas','BrainAtlas'}, 'Talairach', {'Talairach','LBPA40'}, 'Brain atlas to use. Talairach has a larger repertoire of areas, but is (in this version) non-probabilistic. The LONI LBPA40 atlas is a high-quality probabilistic atlas; however, you have to to download it yourself.'),...
    arg({'var_threshold','VarianceThreshold'}, 15, [1 10 25 100], 'Residual Variance Thresold (%). The threshold in dipole fit residual variance above which dipoles models are rejected.'),...
    arg({'mri_constraints','UseMRIConstraints'}, false, [], 'Use MRI constraints. If enabled, restricts dipole solutions to the grey-matter volume. The currently requires the SPM toolbox to be in the path.'),...
    arg({'discard_nonlocalizable','DiscardNonlocalizable'}, false, [], 'Discard non-localizable components.'),...
    arg({'verbose','VerboseOutput'}, false, [], 'Verbose output.'),...
    arg_norep('dipfit_info'));

if ~exist('dipfit_info','var')
    % use standard data if unspecified
    if isempty(hdm_file) %#ok<*NODEF>
        hdm_file = env_translatepath('resources:/standard_BEM/standard_vol.mat'); end
    if isempty(mri_file)
        if mri_constraints
            mri_file = env_translatepath('resources:/standard_BEM/standard_mri_gm.mat');
        else
            mri_file = '';
        end
    end
    if isempty(chan_file)
        % figure out the labeling scheme to determine the correct coregistration...
        if ~isfield(signal.chaninfo,'labelscheme')
            signal.chaninfo.labelscheme = '10-20'; end
        switch signal.chaninfo.labelscheme
            case '10-20'
                chan_file = env_translatepath('resources:/standard_BEM/elec/standard_1005.elc');
            case 'sccn_128_v1'
                chan_file = env_translatepath('resources:/sccn_BEM_coregistered_128_v1.xyz');
            case 'sccn_128_v2'
                chan_file = env_translatepath('resources:/sccn_BEM_coregistered_128_v2.xyz');
            case 'sccn_256_v1'
                chan_file = env_translatepath('resources:/sccn_BEM_coregistered_256_v1.xyz');
            case 'sccn_256_v2'
                chan_file = env_translatepath('resources:/sccn_BEM_coregistered_256_v2.xyz');
            otherwise
                error('Unknown channel labeling scheme -- please supply a chan_file argument.');
        end
    end

    disp(['Now fitting dipoles... (montage reference: ' chan_file ')']);
    % fit icaweights
    if verbose
        dipfit_info = hlp_diskcache('dipfits',@do_fitting,signal,mri_file,hdm_file,chan_file,lookup_labels,brain_atlas,confusion_range,var_threshold);
    else
        [text,dipfit_info] = evalc('hlp_diskcache(''dipfits'',@do_fitting,signal,mri_file,hdm_file,chan_file,lookup_labels,brain_atlas,confusion_range,var_threshold)');
    end
    try
        % check if we need to fit Amica models, too...
        if isfield(signal.etc,'amica')
            sig = signal;
            multimodel = {};
            for m=1:size(signal.etc.amica.W,3)
                sig.icaweights = signal.etc.amica.W(:,:,m);
                sig.icawinv = signal.etc.amica.A(:,:,m);
                sig.icasphere = signal.etc.amica.S;
                if verbose
                    tmp = hlp_diskcache('dipfits',@do_fitting,sig,mri_file,hdm_file,chan_file,lookup_labels,brain_atlas,confusion_range,var_threshold);
                else
                    [text,tmp] = evalc('hlp_diskcache(''dipfits'',@do_fitting,sig,mri_file,hdm_file,chan_file,lookup_labels,brain_atlas,confusion_range,var_threshold);');
                end
                multimodel{m} = tmp.model; %#ok<AGROW>
            end
            dipfit_info.multimodel = multimodel;
        end
    catch
        disp('Could not compute dipfit solutions for Amica models.');
    end
end

signal.dipfit = dipfit_info;
if discard_nonlocalizable
    retain_ics = ~cellfun(@isempty,{signal.dipfit.model.posxyz});
    % update the dipole model
    signal.dipfit.model = signal.dipfit.model(retain_ics);
    % restrict the ICs & some derived data
    signal.icaweights = signal.icaweights(retain_ics,:);
    signal.icawinv = signal.icawinv(:,retain_ics);
    if ~isempty(signal.icaact) && ~isscalar(signal.icaact)
        signal.icaact = signal.icaact(retain_ics,:,:); end
end

if isfield(signal.etc,'amica')
    signal.etc.amica.dipfit = dipfit_info; end

global tracking;
tracking.inspection.dipfit = dipfit_info;

% when applied online, include the dipfit info into the parameters (so it gets attached immediately)
exp_endfun('append_online',{'dipfit_info',dipfit_info});

function result = do_fitting(signal,mri_file,hdm_file,chan_file,lookup_labels,brain_atlas,confusion_range,var_threshold)

% coregister chanlocs to reference channels
[dummy,warping] = coregister(signal.chanlocs,chan_file,'warp','auto','manual','off'); %#ok<ASGLU>
% generate the dipfit info
%nosedir needs to be set to +X here for dipfit to work
signal.chaninfo.nosedir = '+X';
tmp = pop_multifit(pop_dipfit_settings(pop_select(signal,'channel',signal.icachansind),  ...
    'mrifile',mri_file, 'hdmfile',hdm_file,'chanfile',chan_file,'coordformat','MNI','coord_transform',warping), 1:size(signal.icaweights,1),'threshold',var_threshold);
% optionally derive anatomical labels & probabilities
if lookup_labels
    switch lower(brain_atlas)

        case 'talairach'
            db = org.talairach.Database;
            db.load(env_translatepath('resources:/talairach.nii'));
            for k=1:length(tmp.dipfit.model)
                try
                    p = icbm_spm2tal(tmp.dipfit.model(k).posxyz);
                    tmp.dipfit.model(k).labels = cellfun(@(d)char(d),cell(db.search_range(p(1),p(2),p(3),1.5*confusion_range)),'UniformOutput',false);
                    % and compute structure probabilities within the selected volume
                    [structures,x,idxs] = unique(hlp_split(sprintf('%s,',tmp.dipfit.model(k).labels{:}),',')); %#ok<ASGLU>
                    probabilities = mean(bsxfun(@eq,1:max(idxs),idxs'));
                    [probabilities,reindex] = sort(probabilities,'descend');
                    structures = structures(reindex);
                    mask = ~strcmp(structures,'*');
                    tmp.dipfit.model(k).structures = structures(mask);
                    tmp.dipfit.model(k).probabilities = probabilities(mask)*5; % there are 5 partitions
                    % figure('Position',[0 0 2560 900]); topoplot(tmp.icawinv(:,k),tmp.chanlocs); title([hlp_tostring(structures(mask)) 10 hlp_tostring(5*probabilities(mask))]); pop_dipplot(tmp,k);
                catch
                    tmp.dipfit.model(k).labels = {};
                    tmp.dipfit.model(k).structures = {};
                    tmp.dipfit.model(k).probabilities = [];
                end
            end

        case 'lbpa40'
            mask = find(~cellfun('isempty',{tmp.dipfit.model.posxyz}));
            % build query
            coords = vertcat(tmp.dipfit.model.posxyz);
            coords = [coords confusion_range * ones(size(coords,1),1)];
            % look up from atlas (note: slow!)
            [probs,labels] = label_dipoles(coords);
            % determine overlapped specialty regions to match up with Talairach's labeling scheme
            L = ~cellfun('isempty',strfind(labels,' L '));
            R = ~cellfun('isempty',strfind(labels,' R '));
            B = ~cellfun('isempty',strfind(labels,'Brainstem'));
            C = ~cellfun('isempty',strfind(labels,'Cerebellum'));
            allprobs = [sum(probs(:,L),2) sum(probs(:,R),2) sum(probs(:,C),2)*[0.5 0.5] sum(probs(:,B),2)];
            allstructs = {'Left Cerebrum' 'Right Cerebrum' 'Left Cerebellum' 'Right Cerebellum' 'Brainstem'};
            % go through all gyri and add up left & right probabilities
            gyri = unique(cellfun(@(l)l(12:end),labels(1:end-2),'UniformOutput',false))';
            allstructs = [allstructs gyri];
            for g=1:length(gyri)
                curgyrus = gyri{g};
                matches = ~cellfun('isempty',strfind(labels,curgyrus));
                allprobs = [allprobs sum(probs(:,matches),2)];
            end
            for k=1:length(mask)
                % retain only those with non-zero probability
                sel = allprobs(k,:) ~= 0;
                probabilities = allprobs(k,sel);
                structures = allstructs(sel);
                % sort probs & associated structs by descending probability
                [probabilities,reindex] = sort(probabilities,'descend');
                structures = structures(reindex);
                % store in the model...
                tmp.dipfit.model(mask(k)).structures = structures;
                tmp.dipfit.model(mask(k)).probabilities = probabilities;
                % figure('Position',[0 0 2560 900]);topoplot(tmp.icawinv(:,k),tmp.chanlocs); title([hlp_tostring(structures) 10 hlp_tostring(probabilities)]); pop_dipplot(tmp,k);
            end
    end
end
result = tmp.dipfit;


function[dir]=whichdir(name)
%   WHICHDIR  Returns directory name containing file in search path.
%
%   WHICHDIR NAME returns the directory containing a file called NAME,
%   i.e. the full path of the file excluding NAME and the trailing '/'.
%
%   If more than one directory contains a file called NAME, then
%   WHICHDIR returns a cell array of directories names.
%
%   If NAME does not include an extension, then it is interpreted as
%   the name of an m-file, i.e. having extension '.m' .
%   _________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2006--2015 J.M. Lilly --- type 'help jlab_license' for details

if isempty(strfind(name,'.'))
    name=[name '.m'];
end

dir=which(name,'-all');

for i=1:length(dir)
   dir{i}=dir{i}(1:end-length(name)-1);
end

if i==1
    dir=dir{1};
end


function res = rcnn_test_bbox_regressor(imdb, rcnn_model, bbox_reg, suffix)
% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

conf = rcnn_config('sub_dir', imdb.name);
image_ids = imdb.image_ids;

% assume they are all the same
feat_opts = bbox_reg.training_opts;
num_classes = length(rcnn_model.classes);

if ~exist('suffix', 'var') || isempty(suffix)
  suffix = '_bbox_reg';
else
  if suffix(1) ~= '_'
    suffix = ['_' suffix];
  end
end

try
  aboxes = cell(num_classes, 1);
  for i = 1:num_classes
    load([conf.cache_dir rcnn_model.classes{i} '_boxes_' imdb.name suffix]);
    aboxes{i} = boxes;
  end
catch
  aboxes = cell(num_classes, 1);
  box_inds = cell(num_classes, 1);
  for i = 1:num_classes
    load([conf.cache_dir rcnn_model.classes{i} '_boxes_' imdb.name]);
    aboxes{i} = boxes;
    box_inds{i} = inds;
    clear boxes inds;
  end

  for i = 1:length(image_ids)
    fprintf('%s: bbox reg test (%s) %d/%d\n', procid(), imdb.name, i, length(image_ids));
    d = rcnn_load_cached_pool5_features(feat_opts.cache_name, ...
        imdb.name, image_ids{i});
    if isempty(d.feat)
      continue;
    end

    d.feat = rcnn_pool5_to_fcX(d.feat, feat_opts.layer, rcnn_model);
    d.feat = rcnn_scale_features(d.feat, feat_opts.feat_norm_mean);

    if feat_opts.binarize
      d.feat = single(d.feat > 0);
    end

    for j = 1:num_classes
      I = box_inds{j}{i};
      boxes = aboxes{j}{i};
      if ~isempty(boxes)
        scores = boxes(:,end);
        boxes = boxes(:,1:4);
        assert(sum(sum(abs(d.boxes(I,:) - boxes))) == 0);
        boxes = rcnn_predict_bbox_regressor(bbox_reg.models{j}, d.feat(I,:), boxes);
        boxes(:,1) = max(boxes(:,1), 1);
        boxes(:,2) = max(boxes(:,2), 1);
        boxes(:,3) = min(boxes(:,3), imdb.sizes(i,2));
        boxes(:,4) = min(boxes(:,4), imdb.sizes(i,1));
        aboxes{j}{i} = cat(2, single(boxes), single(scores));

        if 0
          % debugging visualizations
          im = imread(imdb.image_at(i));
          keep = nms(aboxes{j}{i}, 0.3);
          for k = 1:min(10, length(keep))
            if aboxes{j}{i}(keep(k),end) > -0.9
              showboxes(im, aboxes{j}{i}(keep(k),1:4));
              title(sprintf('%s %d score: %.3f\n', rcnn_model.classes{j}, ...
                  k, aboxes{j}{i}(keep(k),end)));
              pause;
            end
          end
        end
      end
    end
  end

  for i = 1:num_classes
    save_file = [conf.cache_dir rcnn_model.classes{i} '_boxes_' imdb.name suffix];
    boxes = aboxes{i};
    inds = box_inds{i};
    save(save_file, 'boxes', 'inds');
    clear boxes inds;
  end
end

% ------------------------------------------------------------------------
% Peform AP evaluation
% ------------------------------------------------------------------------
for model_ind = 1:num_classes
  cls = rcnn_model.classes{model_ind};
  try
    ld = load([conf.cache_dir cls '_pr_' imdb.name suffix]);
    fprintf('!!! %s : %.4f %.4f\n', cls, ld.res.ap, ld.res.ap_auc);
    res(model_ind) = ld.res;
  catch
    res(model_ind) = imdb.eval_func(cls, aboxes{model_ind}, imdb, suffix);
  end
end

fprintf('\n~~~~~~~~~~~~~~~~~~~~\n');
fprintf('Results (bbox reg):\n');
aps = [res(:).ap]';
disp(aps);
disp(mean(aps));
fprintf('~~~~~~~~~~~~~~~~~~~~\n');