% Interface lavel functions for the SLAM toolbox.
%
% Create structures
%   createControls                - Create controls structure Con.
%   createLandmarks               - Create Lmk structure array.
%   createMap                     - Create an empty Map structure.
%   createObservations            - Create Obs structure array.
%   createRobots                  - Create robots structure array.
%   createSensors                 - Create sensors structure array.
%   createSimLmk                  - Create a set of landmarks for simulation.
%   createTime                    - Create Tim structure.
%   initRobots                    - Initialize robots in Map.
%   initSensors                   - Initialize sensors in Map.
%   installSensors                - Install sensors on robots.
%
% Draw graphics
%   drawMapFig                    - Redraw the 3D map figure.
%   drawSenFig                    - Redraw one sensor figure.
%
% Synchronization with Map
%   map2rob                       - Update Rob structure from the Map information.
%   map2sen                       - Update Sen structure from the Map information.
%
% Motion and prediction
%   simMotion                     - Simulated robot motion.
%   motion                        - Robot motion.
%
% Landmark initialization
%   initNewLmk                    - Initialise one landmark.
%   initLmkParams                 - Initialize off-filter landmark parameters.
%
% Landmark correction
%   correctKnownLmks              - Correct known landmarks.
%   simObservation                - Observe simulated landmarks.
%   projectLmk                    - Project landmark estimate into sensor's measurement space.
%   selectLmksToObserve           - Select landmarks to observe.
%   matchFeature                  - Match feature.
%   observationInnovation         - Observation innovation.
%   correctLmk                    - Correct landmark.
%   ekfCorrectLmk                 - Correct landmarks.
%   reparametrizeLmk              - Reparametrize landmark.
%   updateLmkParams               - Update off-filter landmark parameters.
%
% Other
%   deleteLmk                     - Delete landmark.
%   drawObsLin                    - Draw an observed line on the pinHole sensor figure.
%   drawObsPnt                    - Redraw a landmark on the pinHole sensor figure.
%   pluckerSegment                - Segment from Plucker line and endpoint abscissas.
%   createMapFig                  - Create 3D map figure and handles.
%   createSenFig                  - Create sensors figures and handles.
%   drawLmk                       - Draw 3D landmark.
%   drawRawLines                  - Draw raw lines.
%   drawRawPnts                   - Draw raw points.
%   prepareForActiveInit          -
%
% Graph SLAM
%   addKeyFrame                   - Add key frame to trajectory.
%   addKnownLmkFactors            - CORRECTKNOWNLMKS  Correct known landmarks.
%   addNewLmkFactors              - INITNEWLMK  Initialise one landmark.
%   buildAdjacencyMatrix          -
%   checkGraphIntegrity           -
%   composeHmgPnt                 -
%   computeResidual               - Compute the residual.
%   createFactors                 - Create Fac structure array.
%   createFrames                  - Create Frm structure array.
%   errorStateJacobians           - Compute Jacobians for projection onto the manifold.
%   frm2rob                       - Frame to Robot information transfer
%   frmJacobians                  - Compute Jacobians for projection onto the manifold.
%   integrateMotion               - Integrate Robot motion, with covariance.
%   lmkJacobians                  - Compute Jacobians for projection onto the manifold.
%   makeAbsFactor                 - Make absolute factor
%   makeAbsFactorFromMotionFactor -
%   makeMeasFactor                -
%   makeMotionFactor              - Make motion factor
%   resetMotion                   - Reset motion to origin of coordinates
%   retroProjLmk                  - Retro project landmark.
%   rob2frm                       - FRM2ROB Robot to Frame information transfer
%   solveGraph                    - Solve the SLAM problem posed as a graph of states and
%   solveGraphCholesky            - Solves the SLAM graph using Cholesky decomposition.
%   updateKeyFrm                  -
%   updateLmk                     -
%   updateStates                  - Update Frm and Lmk states based on computed error.


%
%  Context-Aware Correlation Filters
%
%  Written by Joao F. Henriques, 2014
%  Adapted by Matthias Mueller, 2016
%
%  This function takes care of setting up parameters, loading video
%  information and computing precisions. For the actual tracking code,
%  check out the TRACKER function.
%
%  RUN_TRACKER
%    Without any parameters, will ask you to choose a video,
%    and show the results in an interactive figure.
%    Press 'Esc' to stop the tracker early. You can navigate the
%    video using the scrollbar at the bottom.
%
%  RUN_TRACKER VIDEO
%    Allows you to select a VIDEO by its name. 'all' will run all videos
%    and show average statistics. 'choose' will select one interactively.
%
%  RUN_TRACKER(VIDEO, SHOW_VISUALIZATION, SHOW_PLOTS)
%    Decide whether to show the scrollable figure, and the precision plot.

function [precision, fps] = run_tracker(video,show_visualization, show_plots)

	%path to the videos (you'll be able to choose one with the GUI).
	base_path = 'sequences/';

	%default settings
	if nargin < 1, video = 'Human7'; end
	if nargin < 2, show_visualization = ~strcmp(video, 'all'); end
	if nargin < 3, show_plots = ~strcmp(video, 'all'); end

    %default settings
    kernel.type =  'linear';

    padding = 2;  %extra area surrounding the target
    lambda1 = 1e-4;     %regularization
    lambda2 = 25;
    interp_factor = 0.015;  %linear interpolation factor for adaptation
    output_sigma_factor = 0.1; %spatial bandwidth (proportional to target)

    features.gray = false;
    features.hog = true;
    features.hog_orientations = 9;

    cell_size = 4;

	switch video
	case 'choose',
		%ask the user for the video, then call self with that video name.
		video = choose_video(base_path);
		if ~isempty(video),
			[precision, fps] = run_tracker(video,show_visualization, show_plots);

			if nargout == 0,  %don't output precision as an argument
				clear precision
			end
		end

	case 'all',
		%all videos, call self with each video name.

		%only keep valid directory names
		dirs = dir(base_path);
		videos = {dirs.name};
		videos(strcmp('.', videos) | strcmp('..', videos) | ...
			strcmp('anno', videos) | ~[dirs.isdir]) = [];

		%the 'Jogging' sequence has 2 targets, create one entry for each.
		%we could make this more general if multiple targets per video
		%becomes a common occurence.
		videos(strcmpi('Jogging', videos)) = [];
		videos(end+1:end+2) = {'Jogging.1', 'Jogging.2'};

		all_precisions = zeros(numel(videos),1);  %to compute averages
		all_fps = zeros(numel(videos),1);

		if ~exist('matlabpool', 'file'),
			%no parallel toolbox, use a simple 'for' to iterate
			for k = 1:numel(videos),
				[all_precisions(k), all_fps(k)] = run_tracker(videos{k}, show_visualization, show_plots);
			end
		else
			%evaluate trackers for all videos in parallel
			if matlabpool('size') == 0,
				matlabpool open;
			end
			parfor k = 1:numel(videos),
				[all_precisions(k), all_fps(k)] = run_tracker(videos{k}, show_visualization, show_plots);
			end
		end

		%compute average precision at 20px, and FPS
		mean_precision = mean(all_precisions);
		fps = mean(all_fps);
		fprintf('\nAverage precision (20px):% 1.3f, Average FPS:% 4.2f\n\n', mean_precision, fps)
		if nargout > 0,
			precision = mean_precision;
		end

	case 'benchmark',
		%running in benchmark mode - this is meant to interface easily
		%with the benchmark's code.

		%get information (image file names, initial position, etc) from
		%the benchmark's workspace variables
		seq = evalin('base', 'subS');
		target_sz = seq.init_rect(1,[4,3]);
		pos = seq.init_rect(1,[2,1]) + floor(target_sz/2);
		img_files = seq.s_frames;
		video_path = [];

		%call tracker function with all the relevant parameters
		positions = tracker(video_path, img_files, pos, target_sz, ...
			padding, kernel, lambda, output_sigma_factor, interp_factor, ...
			cell_size, features, false);

		%return results to benchmark, in a workspace variable
		rects = [positions(:,2) - target_sz(2)/2, positions(:,1) - target_sz(1)/2];
		rects(:,3) = target_sz(2);
		rects(:,4) = target_sz(1);
		res.type = 'rect';
		res.res = rects;
		assignin('base', 'res', res);

	otherwise
		%we were given the name of a single video to process.

		%get image file names, initial state, and ground truth for evaluation
		[img_files, pos, target_sz, ground_truth, video_path] = load_video_info(base_path, video);

		%call tracker function with all the relevant parameters
		[positions, time] = tracker(video_path, img_files, pos, target_sz, ...
			padding, kernel, lambda1, lambda2, output_sigma_factor, interp_factor, ...
			cell_size, features, show_visualization);

		%calculate and show precision plot, as well as frames-per-second
		precisions = precision_plot(positions, ground_truth, video, show_plots);
		fps = numel(img_files) / time;

		fprintf('%12s - Precision (20px):% 1.3f, FPS:% 4.2f\n', video, precisions(20), fps)

		if nargout > 0,
			%return precisions at a 20 pixels threshold
			precision = precisions(20);
		end

	end
end


% run_simPressShaped.m
% Dana Goerzen and Jamie Near, McGill University 2021.
%
% USAGE:
% This script is run simply by editing the input parameters and then
% clicking "Run".
%
% DESCRIPTION:
% This script simulates a PRESS experiment with fully shaped refocusing
% pulses. Coherence order filtering is employed to only simulate desired signals
% This results in a 4x speed up compared to phase cycling (see deprecated run_simPressShaped_phCyc.m)
% Furthermore, simulations are run at various locations in space to account for the
% within-voxel spatial variation of the metabolite signal.  Summation
% across spatial positions is performed. The MATLAB parallel computing toolbox
% (parfor loop) was used to accelerate the simulations.  Acceleration
% is currently performed in the direction of the slice selective pulse along
% the x-direction, but this can be changed.  Up to a factor of 12 acceleration
% can be achieved using this approach.  To enable the use of the MATLAB
% parallel computing toolbox, initialize the multiple worked nodes using
% "matlabpool size X" where "X" is the number of available processing
% nodes.  If the parallel processing toolbox is not available, then replace
% the "parfor" loop with a "for" loop.
%
% INPUTS:
% To run this script, edit the parameters below as desired and then click
% "run":
% refocWaveform     = name of refocusing pulse waveform.
% refTp             = duration of refocusing pulses[ms]
% Bfield            = Magnetic field strength in [T]
% Npts              = number of spectral points
% sw                = spectral width [Hz]
% Bfield            = magnetic field strength [Tesla]
% lw                = linewidth of the output spectrum [Hz]
% thkX              = slice thickness of x refocusing pulse [cm]
% thkY              = slice thickness of y refocusing pulse [cm]
% fovX              = full simulation FOV in the x direction [cm]
% fovY              = full simulation FOV in the y direction [cm]
% nX                = number of spatial grid points to simulate in x-direction
% nY                = number of spatial grid points to simulate in y-direction
% taus              = vector of pulse sequence timings  [ms]
% spinSys           = spin system to simulate
%
% OUTPUTS:
% out_posxy         = Simulation results, spatially resolved.
% out               = Simulation results, summed over all space.

% ************INPUT PARAMETERS**********************************
refocWaveform='sampleRefocPulse.pta'; %name of refocusing pulse waveform.
refTp=5; %duration of refocusing pulses[ms]
Npts=2048; %number of spectral points
sw=2000; %spectral width [Hz]
Bfield=3; %magnetic field strength [Tesla]
lw=2; %linewidth of the output spectrum [Hz]
thkX=1.66; %slice thickness of x refocusing pulse [cm]
thkY=1.66; %slice thickness of y refocusing pulse [cm]
fovX=4; %size of the full simulation Field of View in the x-direction [cm]
fovY=4; %size of the full simulation Field of View in the y-direction [cm]
nX=16; %Number of grid points to simulate in the x-direction
nY=16; %Number of grid points to simulate in the y-direction
tau1=6; %TE1 for first spin echo [ms]
tau2=6; %TE2 for second spin echo [ms]
spinSys='Lac'; %spin system to simulate
flipAngle=180; %Refocusing pulse flip angle [degrees]
centreFreq=1.3; %Centre frequency of refocusing pulses [ppm]
% ************END OF INPUT PARAMETERS**********************************

%set up spatial grid
x=linspace(-fovX/2,fovX/2,nX); %X positions to simulate [cm]
y=linspace(-fovY/2,fovY/2,nY); %y positions to simulate [cm]

%Load RF waveform
refRF=io_loadRFwaveform(refocWaveform,'ref',0);

gamma=42577000; %gyromagnetic ratio

%Load spin systems
load spinSystems
sys=eval(['sys' spinSys]);

%Resample refocusing RF pulse from 400 pts to 100 pts to reduce
%computational workload
refRF=rf_resample(refRF,100);

Gx=(refRF.tbw/(refTp/1000))/(gamma*thkX/10000); %[G/cm]
Gy=(refRF.tbw/(refTp/1000))/(gamma*thkY/10000); %[G/cm]

%Initialize structures:
out_posxy=cell(length(x),length(y));
out=struct([]);

%loop through space: Don't forget to initialize the parallel processing
%toolbox workers using 'matlabpool open N' (for N workers, 12 max).

%for X=1:length(x);
parfor X=1:length(x)
    for Y=1:length(y)
                disp(['Executing X-position ' num2str(X) ' of ' num2str(length(x)) ', '...
                    'Y-position ' num2str(Y) ' of ' num2str(length(y))])
                out_posxy{X}{Y}=sim_press_shaped(Npts,sw,Bfield,lw,sys,tau1,tau2,...
                    refRF,refTp,x(X),y(Y),Gx,Gy,flipAngle,centreFreq);

        out=op_addScans(out,out_posxy{X}{Y});

    end %end of spatial loop (parfor) in y direction.
end %end of spatial loop (parfor) in x direction.

%For consistent scaling across different shaped simulations, we need to :
%1.  Scale down by the total number of simulations run (since these were
%    all added together.
numSims=(nX*nY);
out=op_ampScale(out,1/numSims);

%2.  Scale by the total size of the simulated region, relative to the size
%    of the voxel.
voxRatio=(thkX*thkY)/(fovX*fovY);
out=op_ampScale(out,1/voxRatio);

%Uncomment this part to view the results of the spatially resolved simulation:
 if length(x)>1 && length(y)>1
     ppmmin=1.0;
     ppmmax=1.6;
     sim_make2DSimPlot(out_posxy,ppmmin,ppmmax);
 else
     plot(out.ppm,out.specs);
 end
op_plotspec(out)


function view = er_voxRMap(view, roi, scans, dt, conditions, subsets);
%
% view = er_voxRMap(<view=cur view>,  <roi=selected>, <scans=scan group>, ...
%                          <dt=cur dt>, <conditions=all>, <subsets=even odd>);
%
% Export a map of "voxel reliability": for each voxel, the correlation
% coefficient R between response amplitudes across conditions for two
% subsets. By default, these subsets are even and odd runs in the scan
% group.
%
% If 'gray' is provided as the ROI, will step through gray matter computing
% the map in a memory-efficient manner.
%
% subsets: 2x1 cell, e.g. {[1 3 5 7] [2 4 6 8]}, showing which subsets of
% runs to compare. By default, will compare even and odd runs across the
% selected scans.
%
% ras, 05/01/06.
if notDefined('view'), view = getCurView;               end
if notDefined('roi'),  roi = view.selectedROI;          end
if notDefined('scans'), scans = er_getScanGroup(view);  end
if notDefined('dt'), dt = view.curDataType;              end
if notDefined('conditions'),
    trials = er_concatParfiles(view);
    conditions = trials.condNums(trials.condNums>0);
end
if notDefined('subsets'), % {odd even}
    subsets = {scans(1:2:end) scans(2:2:end)};
end

if ~isequal(roi, 'gray')
    % for an ROI: call mv_exportMap
    mv = mv_init(view, roi, scans, dt);
    mv_exportMap(mv, 'voxel reliability', 1);
    return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% If we got here, we're doing a memory-efficient gray matter computation %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
roi = getGrayRoi(view);
roi.coords = roiSubCoords(view, roi.coords); % remove redundant voxels
nVoxels = size(roi.coords, 2);

hwait = mrvWaitbar(0, 'Computing Voxel Reliability Across Gray Matter...');
set(hwait, 'Position', get(hwait,'Position')+[0 100 0 0]);
for a = 1:2000:nVoxels
    b = min(nVoxels, a+1999);
    subRoi = roi;
    subRoi.coords = roi.coords(:,a:b);
    subRoi.name = 'ROI1'; % will prevent lengthy caching of each sub-ROI

    mv = mv_init(view, subRoi);

    mv.params.selConds = conditions;
    mv = mv_reliability(mv, 'plotFlag', 0);

    voxR(a:b) = mv.wta.voxR;

    mrvWaitbar(b/nVoxels, hwait);
end
close(hwait);

% plug in the values to the map volume:
mapdims = viewGet(view,'dataSize');
nScans = viewGet(view,'numScans');
mapvol = zeros(mapdims);
scan = scans(1);
ind = roiIndices(view, roi.coords);
mapvol(ind) = voxR;

%%%%%set in view
map = cell(1,nScans);
mapName = sprintf('VoxR_%s', roi.name);
map{scan} = mapvol;
view = setParameterMap(view, map, mapName);
saveParameterMap(view, [], 1);
disp('Finished computing gray matter voxel reliability map.')

return
% /------------------------------------------------------------------/ %

% /------------------------------------------------------------------/ %
function roi = getGrayRoi(view);
% roi = getGrayRoi(view);
% find, load, or make a gray ROI for the view.

% try finding a loaded ROI
if ~isempty(view.ROIs)
    existingRois = {view.ROIs.name};
    N = cellfind(existingRois, 'gray');
    if ~isempty(N), roi = view.ROIs(N); return; end
end

% try loading a saved ROI
w = what(roiDir(view));
savedRois = w.mat';
if ~isempty(savedRois)
    N = cellfind(savedRois, 'gray.mat');
    if ~isempty(N)
        load(fullfile(roiDir(view), 'gray.mat'), 'ROI');
        roi = ROI;
        return
    end
end

% got here: need to make it
try
    view = makeGrayROI(view);
    roi = view.ROIs(end);
    saveROI(view, roi);
catch
    disp('Couldn''t make a gray ROI. Segmentation installed?')
    roi = [];
end

return


% Re-select te corners after calibration

if ~exist('n_ima')|~exist('fc'),
   fprintf(1,'No calibration data available.\n');
   return;
end;

check_active_images;

flag = 0;
for kk = ind_active,
   if ~exist(['y_' num2str(kk)]),
      flag = 1;
   else
      eval(['ykk = y_' num2str(kk) ';']);
      if isnan(ykk(1,1)),
	 flag = 1;
      end;
   end;
end;

if flag,
   fprintf(1,'Need to calibrate once before before recomputing image corners. Maybe need to load Calib_Results.mat file.\n');
   return;
end;

if n_ima == 0,
    fprintf(1,'No image data available\n');
    return;
end

%if ~exist(['I_' num2str(ind_active(1))]),
%   n_ima_save = n_ima;
%   active_images_save = active_images;
%   ima_read_calib;
%   n_ima = n_ima_save;
%   active_images = active_images_save;
%   check_active_images;
%   if no_image_file,
%      disp('Cannot extract corners without images');
%      return;
%   end;
%end;

fprintf(1,'\nRe-extraction of the grid corners on the images (after first calibration)\n');

if ~dont_ask,
    disp('Window size for corner finder (wintx and winty):');
    wintx = input('wintx ([] = 20) = ');
    if isempty(wintx), wintx = 20; end;
    wintx = round(wintx);
    winty = input('winty ([] = 20) = ');
    if isempty(winty), winty = 20; end;
    winty = round(winty);
else
    wintx = 20;
    winty = 20;
end;

fprintf(1,'Window size = %dx%d\n',2*wintx+1,2*winty+1);

if ~dont_ask,
    ima_numbers = input('Number(s) of image(s) to process ([] = all images) = ');
else
    ima_numbers = [];
end;

if isempty(ima_numbers),
   ima_proc = 1:n_ima;
else
   ima_proc = ima_numbers;
end;

if ~dont_ask,
    q_auto = input('Use the projection of 3D grid or manual click ([]=auto, other=manual): ','s');
else
    q_auto = [];
end;

fprintf(1,'Processing image ');

for kk = ima_proc;
    if active_images(kk),
        fprintf(1,'%d...',kk);

        if ~type_numbering,
            number_ext =  num2str(image_numbers(kk));
        else
            number_ext = sprintf(['%.' num2str(N_slots) 'd'],image_numbers(kk));
        end;
        ima_name = [calib_name  number_ext '.' format_image];

        if exist(ima_name),
            if format_image(1) == 'p';
                if format_image(2) == 'p',
                    I = double(loadppm(ima_name));
                else
                    I = double(loadpgm(ima_name));
                end;
            else
                if format_image(1) == 'r',
                    I = readras(ima_name);
                else
                    I = double(imread(ima_name));
                end;
            end;
            if size(I,3)>1,
                I = 0.299 * I(:,:,1) + 0.5870 * I(:,:,2) + 0.114 * I(:,:,3);
            end;
            [ny,nx,junk] = size(I);
            if isempty(q_auto),
                eval(['y = y_' num2str(kk) ';']);
                xc = cornerfinder(y+1,I,winty,wintx); % the four corners
                eval(['wintx_' num2str(kk) ' = wintx;']);
                eval(['winty_' num2str(kk) ' = winty;']);
                eval(['x_' num2str(kk) '= xc - 1;']);
            else
                fprintf(1,'\n');
                fprintf(1,'\nProcessing image %d...\n',kk);
                click_calib_fisheye_no_read;
            end;
        else
            fprintf(1,'Image %s not found!!!...',ima_name);
        end;
    else
        if ~exist(['omc_' num2str(kk)]),
            eval(['dX_' num2str(kk) ' = NaN;']);
            eval(['dY_' num2str(kk) ' = NaN;']);
            eval(['wintx_' num2str(kk) ' = NaN;']);
            eval(['winty_' num2str(kk) ' = NaN;']);
            eval(['x_' num2str(kk) ' = NaN*ones(2,1);']);
            eval(['X_' num2str(kk) ' = NaN*ones(3,1);']);
            eval(['n_sq_x_' num2str(kk) ' = NaN;']);
            eval(['n_sq_y_' num2str(kk) ' = NaN;']);
        end;
    end;
end;

% Recompute the error:
comp_error_calib_fisheye;
fprintf(1,'\ndone\n');


function [ result ] = infer_events_stove(result, events, times, threshold)

    appliance_name = 'Stove';
    phases = length(events);
    % check events that could be created by the stove of phase 1
    could_be_stove = abs(events{1}(:,1)) > threshold;
    times_could_be_stove = times{1}(could_be_stove);
    events_could_be_stove = events{1}(could_be_stove,1);
    for phase = 2:phases
        % check events that could be created by the stove of phase
        % "phase"
        could_be_stove = abs(events{phase}(:,1)) > threshold;
        times_phase = times{phase}(could_be_stove);
        % for each possible event on phase check if time lies within event on
        % old phase
        tmp = arrayfun(@(t) any(times_phase > t-5 & times_phase < t+5), times_could_be_stove);
        times_could_be_stove = times_could_be_stove(tmp);
        events_could_be_stove = events_could_be_stove(tmp);
    end

    result.appliance_names = {appliance_name};

    % events inferred from algorithm
    % col1: event time
    % col2: appliance id
    % col3: delta
    num_events = length(times_could_be_stove);
    result.events = [times_could_be_stove, ones(num_events,1), events_could_be_stove];
end


%% Face and Eyes Detection
%
% In this demo, we will learn the basics of face detection using Haar
% Feature-based Cascade Classifiers, and how the same extends for eye
% detection, etc.
%
% This program demonstrates the use of |cv.CascadeClassifier| class to detect
% objects (face + eyes). You can use Haar or LBP features. This classifier can
% detect many kinds of rigid objects, once the appropriate classifier is
% trained. It's most known use is for faces.
%
% Sources:
%
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/facedetect.cpp>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/tapi/ufacedetect.cpp>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/gpu/cascadeclassifier.cpp>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/python/facedetect.py>
% * <https://docs.opencv.org/3.2.0/db/d28/tutorial_cascade_classifier.html>
% * <https://docs.opencv.org/3.2.0/d7/d8b/tutorial_py_face_detection.html>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp>
%

%% Theory
%
% Object Detection using Haar feature-based cascade classifiers is an
% effective object detection method proposed by Paul Viola and Michael Jones
% in their paper, "Rapid Object Detection using a Boosted Cascade of Simple
% Features" in 2001. It is a machine learning based approach where a cascade
% function is trained from a lot of positive and negative images. It is then
% used to detect objects in other images.
%
% Here we will work with face detection. Initially, the algorithm needs a lot
% of positive images (images of faces) and negative images (images without
% faces) to train the classifier. Then we need to extract features from it.
% For this, haar features shown in the below image are used. They are just like
% our convolutional kernel. Each feature is a single value obtained by
% subtracting sum of pixels under the white rectangle from sum of pixels under
% the black rectangle.
%
% <<https://docs.opencv.org/3.4.0/haar_features.jpg>>
%
% Now all possible sizes and locations of each kernel are used to calculate
% lots of features. (Just imagine how much computation it needs? Even a
% 24x24 window results over 160000 features). For each feature calculation, we
% need to find the sum of the pixels under white and black rectangles. To
% solve this, they introduced the integral image. However large your image, it
% reduces the calculations for a given pixels, to an operation involving just
% four pixels. Nice, isn't it? It makes things super-fast.
%
% But among all these features we calculated, most of them are irrelevant. For
% example, consider the image below. The top row shows two good features. The
% first feature selected seems to focus on the property that the region of the
% eyes is often darker than the region of the nose and cheeks. The second
% feature selected relies on the property that the eyes are darker than the
% bridge of the nose. But the same windows applied to cheeks or any other
% place is irrelevant. So how do we select the best features out of 160000+
% features? It is achieved by *Adaboost*.
%
% <<https://docs.opencv.org/3.4.0/haar.png>>
%
% For this, we apply each and every feature on all the training images. For
% each feature, it finds the best threshold which will classify the faces to
% positive and negative. Obviously, there will be errors or misclassifications.
% We select the features with minimum error rate, which means they are the
% features that most accurately classify the face and non-face images. (The
% process is not as simple as this. Each image is given an equal weight in the
% beginning. After each classification, weights of misclassified images are
% increased. Then the same process is done. New error rates are calculated.
% Also new weights. The process is continued until the required accuracy or
% error rate is achieved or the required number of features are found).
%
% The final classifier is a weighted sum of these weak classifiers. It is
% called weak because it alone can't classify the image, but together with
% others forms a strong classifier. The paper says even 200 features provide
% detection with 95% accuracy. Their final setup had around 6000 features.
% (Imagine a reduction from 160000+ features to 6000 features. That is a big
% gain).
%
% So now you take an image. Take each 24x24 window. Apply 6000 features to it.
% Check if it is face or not. Wow.. Isn't it a little inefficient and time
% consuming? Yes, it is. The authors have a good solution for that.
%
% In an image, most of the image is non-face region. So it is a better
% idea to have a simple method to check if a window is not a face region. If
% it is not, discard it in a single shot, and don't process it again. Instead,
% focus on regions where there can be a face. This way, we spend more time
% checking a possible face region.
%
% For this they introduced the concept of *Cascade of Classifiers*. Instead of
% applying all 6000 features on a window, the features are grouped into
% different stages of classifiers and applied one-by-one. (Normally the first
% few stages will contain very many fewer features). If a window fails the
% first stage, discard it. We don't consider the remaining features on it. If
% it passes, apply the second stage of features and continue the process. The
% window which passes all stages is a face region. How is that plan!
%
% The authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25
% and 50 features in the first five stages. (The two features in the above
% image are actually obtained as the best two features from Adaboost).
% According to the authors, on average, 10 features out of 6000+ are evaluated
% per sub-window.
%
% So this is a simple intuitive explanation of how Viola-Jones face detection
% works. Read the paper for more details or check out the following references:
%
% * Video Lecture on
%   <http://www.youtube.com/watch?v=WfdYYNamHZ8 Face Detection and Tracking>
% * An interesting interview regarding Face Detection by
%   <http://www.makematics.com/research/viola-jones/ Adam Harvey>
%
% OpenCV comes with a trainer as well as detector. If you want to train your
% own classifier for any object like car, planes etc. you can use OpenCV to
% create one. See the OpenCV docs for full details on Cascade Classifier
% Training.
%
% Here we will deal with detection. OpenCV already contains many pre-trained
% classifiers for face, eyes, smiles, etc. Those XML files are stored in
% the |opencv/data/haarcascades/| folder.
%

%% Code
%
% In this example, we will create a face and eyes detector with OpenCV:
%
% * First we need to load the required XML classifiers.
% * Then load our input image (or video) in grayscale mode.
% * Now we find the faces in the image. If faces are found, it returns the
%   positions of each detected faces as a rectangle |[x,y,w,h]|. Once we get
%   these locations, we can create a ROI for the face and apply eye detection
%   on this ROI (since eyes are always on the face!).
%

%% Options

% this is the primary trained classifier such as frontal face
cascadeName = fullfile(mexopencv.root(),'test','haarcascade_frontalface_alt.xml');
% this an optional secondary classifier such as eyes
nestedCascadeName = fullfile(mexopencv.root(),'test','haarcascade_eye_tree_eyeglasses.xml');
% image scale greater or equal to 1, try 1.3 for example
scale = 1.0;
% attempts detection of flipped image as well
tryflip = false;

%% Initialization

% download XML files if missing
download_classifier_xml(cascadeName);
download_classifier_xml(nestedCascadeName);

% load cacade classifiers
cascade = cv.CascadeClassifier(cascadeName);
assert(~cascade.empty(), 'Could not load classifier cascade');
nestedCascade = cv.CascadeClassifier();
if ~nestedCascade.load(nestedCascadeName)
    disp('Could not load classifier cascade for nested objects');
end
scale = max(scale, 1.0);

%% Main loop
% (either video feed or a still image)
if false
    % read an image
    frame = cv.imread(fullfile(mexopencv.root(),'test','lena.jpg'), 'Color',true);
    % detect faces/eyes and draw detections
    frame = detectAndDraw(frame, cascade, nestedCascade, scale, tryflip);
    imshow(frame);
else
    % prepare video input
    cap = cv.VideoCapture();
    pause(1);
    assert(cap.isOpened());

    % prepare figure
    frame = cap.read();
    assert(~isempty(frame));
    hImg = imshow(frame);

    % video feed
    while ishghandle(hImg)
        % read frame
        frame = cap.read();
        if isempty(frame), break; end

        % detect faces/eyes and draw detections
        frame = detectAndDraw(frame, cascade, nestedCascade, scale, tryflip);

        % update
        set(hImg, 'CData',frame);
        drawnow;
    end
    cap.release();
end

%% Processing function

function img = detectAndDraw(img, cascadeF, cascadeE, scale, tryflip)
    % downscale image and preprocess it
    fx = 1/scale;
    gray = cv.cvtColor(img, 'RGB2GRAY');
    gray = cv.resize(gray, fx, fx);
    gray = cv.equalizeHist(gray);
    [h,w] = size(gray);

    % detection options
    detectOpts = {
        'ScaleFactor',1.1, ...
        'MinNeighbors',2, ...
        ... 'FindBiggestObject',true, ...
        ... 'DoRoughSearch',true, ...
        'ScaleImage',true, ...
        'MinSize',[30 30]
    };

    % detect faces
    tic
    faces = cascadeF.detect(gray, detectOpts{:});
    if tryflip
        faces2 = cascadeF.detect(cv.flip(gray, 1), detectOpts{:});
        faces2 = cellfun(@(r) [w-r(1)-r(3) r(2:4)], faces2, 'UniformOutput',false);
        faces = [faces(:); faces2(:)];
    end
    toc

    % draw
    clrs = uint8(255 * lines(7));
    for i=1:numel(faces)
        r = faces{i};
        ii = mod(i-1, size(clrs,1)) + 1;
        drawOpts = {'Color',clrs(ii,:), 'Thickness',3};

        % draw faces
        aspect_ratio = r(3)/r(4);
        if 0.75 < aspect_ratio && aspect_ratio < 1.3
            center = round((r(1:2) + r(3:4)*0.5) * scale);
            radius = round((r(3) + r(4)) * 0.25*scale);
            img = cv.circle(img, center, radius, drawOpts{:});
        else
            pt1 = round(r(1:2) * scale);
            pt2 = round((r(1:2) + r(3:4) - 1) * scale);
            img = cv.rectangle(img, pt1, pt2, drawOpts{:});
        end

        if ~cascadeE.empty()
            % detect nested objects (eyes)
            if false && mexopencv.require('images')
                grayROI = imcrop(gray, [r(1:2)+1 r(3:4)]);
            else
                grayROI = cv.Rect.crop(gray, r);
            end
            nestedObjs = cascadeE.detect(grayROI, detectOpts{:});

            % draw eyes
            for j=1:numel(nestedObjs)
                nr = nestedObjs{j};
                center = round((r(1:2) + nr(1:2) + nr(3:4)*0.5) * scale);
                radius = round((nr(3) + nr(4)) * 0.25*scale);
                img = cv.circle(img, center, radius, drawOpts{:});
            end
        end
    end
end

%% Helper function

function download_classifier_xml(fname)
    if exist(fname, 'file') ~= 2
        % attempt to download trained Haar/LBP/HOG classifier from Github
        url = 'https://cdn.rawgit.com/opencv/opencv/3.4.0/data/';
        [~, f, ext] = fileparts(fname);
        if strncmpi(f, 'haarcascade_', length('haarcascade_'))
            url = [url, 'haarcascades/'];
        elseif strncmpi(f, 'lbpcascade_', length('lbpcascade_'))
            url = [url, 'lbpcascades/'];
        elseif strncmpi(f, 'hogcascade_', length('hogcascade_'))
            url = [url, 'hogcascades/'];
        else
            error('File not found');
        end
        fprintf('Downloading cascade classifier "%s"...\n', [f ext]);
        url = [url f ext];
        urlwrite(url, fname);
    end
end


function [identified]=irf_disp_IV(n,endo,IRFperiods,IRFt,irf_estimates,D_estimates,gamma_estimates,pref,signreslabels,strctident)

%determine number of identified shocks
if IRFt==4||IRFt==6
Index=find(~contains(signreslabels,'shock'));
identified=min(Index)-1;
identified=n-numel(Index);
elseif IRFt==5
identified=1;
signreslabels{1,1} = strcat('Shock identified by IV (',strctident.Instrument,')');
else
identified = n;
end

count=1;
namecount=1;
irf_estimates = irf_estimates';
hf = figure;
   if IRFt==1
   irfname='impulse response functions (no structural identifcation)';
   elseif IRFt==2
   irfname='impulse response functions (structural identification by Cholesky ordering)';
   elseif IRFt==3
   irfname='impulse response functions (structural identification by triangular factorisation)';
   elseif IRFt==4
   irfname=['impulse response functions (structural identification by ',strctident.hbartext_signres,strctident.hbartext_zerores,strctident.hbartext_magnres,strctident.hbartext_relmagnres,strctident.hbartext_FEVDres,strctident.hbartext_CorrelInstrumentShock,':::',' restrictions)'];
   irfname=erase(irfname,', :::'); % delete the last ,
   elseif IRFt==5
   irfname=['impulse response functions (structural identification by IV ',strctident.Instrument,')'];
   elseif IRFt==6
   irfname_temp=[strctident.hbartext_signres,strctident.hbartext_zerores,strctident.hbartext_magnres,strctident.hbartext_relmagnres,strctident.hbartext_FEVDres,strctident.hbartext_CorrelInstrumentShock,':::',' restrictions)'];
   irfname_temp=erase(irfname_temp,', :::'); % delete the last ,
   irfname=['impulse response functions (structural identification by IV ',strctident.Instrument,' & ',irfname_temp];
   end
   set(hf,'name',irfname);
set(hf,'name',irfname);
set(hf,'Color',[0.9 0.9 0.9]);
%get(0,'ScreenSize');
set(hf,'Units','normalized');
% unitsperplot=0.2*identified*n/6;
% if unitsperplot>1
% set(hf,'position',[0,0,1,1])
% else
% set(hf,'position',[0,0,0.2*identified,0.2*identified])
% end

%%%%% set(hf,'position',[250,0,1800,1200])
%set(hf, 'Color', [1,1,1]);
%fontsize=ceil(18*(6/n)); %if n=6 fontsize=18;
fontsize=11;

for jj=1:identified
    for ii=1:n
        count;
        subplot(n,identified,jj+identified*(ii-1));
        hold on
Xpatch=[(1:IRFperiods) (IRFperiods:-1:1)];
Ypatch=[irf_estimates{jj,ii}(1,:) fliplr(irf_estimates{jj,ii}(3,:))];
IRFpatch=patch(Xpatch,Ypatch,[1 0.5 0]);
set(IRFpatch,'facealpha',0.9);
set(IRFpatch,'edgecolor','none');
plot(irf_estimates{jj,ii}(2,:),'Color',[1 0 0],'LineWidth',3);
plot([1,IRFperiods],[0 0],'k--');
hold off
minband=min(irf_estimates{jj,ii}(1,:));
maxband=max(irf_estimates{jj,ii}(3,:));
space=maxband-minband;
Ymin=minband-0.2*space;
Ymax=maxband+0.2*space;
set(gca,'XLim',[1 IRFperiods],'YLim',[Ymin Ymax],'FontName','Times New Roman','Fontsize',fontsize);
% top labels
subplotcolumn=jj+identified*(ii-1);
if subplotcolumn <= identified
title(signreslabels{subplotcolumn,1},'FontWeight','normal','Interpreter','none','Fontsize',fontsize);
end
if count<=n
   ylabel(endo{namecount,1},'FontWeight','normal','Interpreter','none','Fontsize',fontsize);
   namecount=namecount+1;
end
count=count+1;
end
end
% top supertitle
ax=axes('Units','Normal','Position',[.11 .075 .85 .88],'Visible','off');
set(get(ax,'Title'),'Visible','on')
%%%%% title('Shock:','FontSize',11,'FontName','Times New Roman','FontWeight','normal');
% side supertitle
%%%%% ylabel('Response of:','FontSize',16,'FontName','Times New Roman','FontWeight','normal');
set(get(ax,'Ylabel'),'Visible','on')
    set(gcf,'PaperPositionMode','Auto')
    %fname=strcat(pref.datapath, '\results\');
    %saveas(gcf,[fname,PrintName],'epsc')
    %saveas(gcf,'IRFs','png');
% then display the results for D and gamma, if a structural decomposition was selected

if IRFt==2 || IRFt==3 || IRFt==4 || IRFt==5 || IRFt==6

filelocation=fullfile(pref.results_path, [pref.results_sub '.txt']);
fid=fopen(filelocation,'at');

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

svarinfo1=['D (structural decomposition matrix): posterior estimates'];
fprintf('%s\n',svarinfo1);
fprintf(fid,'%s\n',svarinfo1);

% recover D
D=reshape(D_estimates,n,n);
% calculate the (integer) length of the largest number in D, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(D))))));
% add a separator, a potential minus sign and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(D(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

svarinfo2=['gamma (structural disturbances covariance matrix): posterior estimates'];
fprintf('%s\n',svarinfo2);
fprintf(fid,'%s\n',svarinfo2);

% recover gamma
gamma=reshape(gamma_estimates,n,n);
% calculate the (integer) length of the largest number in D, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(gamma))))));
% add a separator, a potential minus sign and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(gamma(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

fclose(fid);
end

% finally, record results in excel
% retranspose the cell of records
irf_estimates=irf_estimates';
bear.data.excelrecord4fcn(identified, IRFperiods, IRFt, endo, strctident, irf_estimates, n, pref)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Model/simulation parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sim=1;
OS_RATE = 8;
SNR = 1;
fc = 10e3/20e6; % sample rate is 20 MHz, top is 10 kHz offset
muFOC = floor(.01*2^12)/2^12;
muTOC = floor(.01*8*2^12)/2^12;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialize LUTs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
make_srrc_lut;
make_train_lut;
make_trig_lut;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (sim)
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Emulate microprocessor packet creation
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % data payload creation
    messageASCII = 'Hello World';
    message = double(unicode2native(messageASCII));
    % add on length of message to the front with four bytes
    msgLength = length(message);
    messageWithNumBytes =[ ...
        mod(msgLength,2^8) ...
        mod(floor(msgLength/2^8),2^8) ...
        mod(floor(msgLength/2^16),2^8) ...
        1 ... % message ID
        message];
    % add two bytes at the end, which is a CRC
    messageWithCRC = CreateAppend16BitCRC(messageWithNumBytes);
    ml = length(messageWithCRC);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % FPGA radio transmit core
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    data_in = 0;
    empty_in = 1;
    tx_en_in = 0;
    numBytesFromFifo = 0;
    num_samp = ml*8*2*2*3;
    x = zeros(1,num_samp);
    CORE_LATENCY = 4;
    data_buf = zeros(1,CORE_LATENCY);
    empty_buf = ones(1,CORE_LATENCY);
    clear_buf = zeros(1,CORE_LATENCY);
    tx_en_buf = zeros(1,CORE_LATENCY);
    for i1 = 1:num_samp
        % first thing the processor does is clear the internal tx fifo
        if i1 == 1
            clear_fifo_in = 1;
        else
            clear_fifo_in = 0;
        end

        if i1 == 5 % wait a little bit then begin to load the fifo
            empty_in = 0;
            numBytesFromFifo = 0;
        end

        data_buf = [data_buf(2:end) data_in];
        empty_buf = [empty_buf(2:end) empty_in];
        clear_buf = [clear_buf(2:end) clear_fifo_in];
        tx_en_buf = [tx_en_buf(2:end) tx_en_in];
        [i_out, q_out, re_byte_out, tx_done_out, d1, d2, d3] = ...
            qpsk_tx(data_buf(1),empty_buf(1),clear_buf(1),tx_en_buf(1));
        x_out = complex(i_out,q_out)/2^11;
        x(i1) = x_out;

        %%% Emulate read FIFO AXI interface
        if re_byte_out == 1 && numBytesFromFifo < length(messageWithCRC)
            data_in = messageWithCRC(numBytesFromFifo+1);
            numBytesFromFifo = numBytesFromFifo + 1;
        end
        % processor loaded all bytes into FIFO so begin transmitting
        if numBytesFromFifo == length(messageWithCRC)
            empty_in = 1;
            tx_en_in = 1;
        end
    end

    index = find(abs(x) > sum(SRRC))+24*8; % constant is pad bits
    offset = index(1)+6+length(TB_i)*OS_RATE;
    idx = offset:8:(offset+8*ml*4-1);
    y = x(idx); % four symbos per byte of data
    sc = zeros(1,(msgLength+6)*8);
    sc(1:2:end) = real(y);
    sc(2:2:end) = imag(y);
    sh = sign(sc);
    sb = (sh+1)/2;
    d = zeros(1,ml);
    for i1 = 1:ml
        si = sb(1+(i1-1)*8:i1*8);
        d(i1) = bi2de(si);
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Emulate channel
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % pad on either side with zeros
    p = complex(zeros(1,100),zeros(1,100));
    xp = [p x p]; % pad

    % Apply frequency offset and receive/over-the-air AWGN
    y = xp.*exp(1i*2*pi*fc*(0:length(xp)-1));
    rC = y/max(abs(y))*.1*2^11; % this controls receive gain
    r = awgn(rC,SNR,0,1);
    r1 = rC;
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load Chipscope samples
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (~sim)
    fid = fopen('rx.prn');
    M = textscan(fid,'%d %d %d %d','Headerlines',1);
    fclose(fid);
    is = double(M{3});
    qs = double(M{4});
    r = complex(is,qs);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Main receiver core
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
r_out = zeros(1,length(r));
s_f = zeros(1,length(r));
s_t = zeros(1,length(r));
s_c = zeros(1,length(r));
f_est = zeros(1,length(r));
t_est = zeros(1,length(r));
s_p = zeros(1,length(r));
s_o = zeros(1,length(r));
byte_count = 0;
if (sim)
    bytes = zeros(1,ml);
end
for i1 = 1:length(r)+200
    if i1 > length(r)
        r_in = 0;
    else
        r_in = r(i1);
    end
    i_in = round(real(r_in));
    q_in = round(imag(r_in));
    [r_out(i1), s_f(i1), s_c(i1), s_t(i1), t_est(i1), f_est(i1), ...
        byte, en, s_p(i1), s_o(i1)] = ...
        qpsk_rx(i_in, q_in, floor(muFOC*2^12), floor(muTOC*2^12));

    if en == 1
        byte_count = byte_count + 1;
        bytes(byte_count) = byte;
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure(2)
subplot(2,2,1)
scatter(real(r),imag(r))
title('Pre FOC Signal');
subplot(2,2,3)
plot(real(r_out));
title('Pre FOC Signal (real part)');
subplot(2,2,2)
scatter(real(s_t),imag(s_t))
title('Post TOC Signal');
subplot(2,2,4)
plot(real(s_p));
title('Message bits');

figure(3)
axis([0 length(s_p) -1.25 1.25]);
plot(s_o);
title('Correlation magnitude');

numRecBytes = bytes(1)+bytes(2)+bytes(3);
msgBytes = bytes((1+4):(numRecBytes+4));

if (sim)
    if sum(msgBytes-message) == 0
        disp('Received message correctly');
    else
        disp('Received message incorrectly');
    end
    native2unicode(bytes);
    native2unicode(msgBytes)
end

if (~sim)
    native2unicode(msgBytes)
end


classdef nme_bus_nld_acp_node_test < mp.nme_bus_acp

%   MATPOWER
%   Copyright (c) 2021-2022, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%     properties
%     end

    methods
        function name = name(obj)
            name = 'bus_nld';
        end

        function obj = add_vvars(obj, nm, dm, idx)
            dme = obj.data_model_element(dm);
            nb = obj.nk;

            %% prepare angle bounds for ref buses
            va_lb = -Inf(nb, 1);
            va_ub =  Inf(nb, 1);
            k = find(dme.type == mp.NODE_TYPE.REF);
            va_lb(k) = dme.va_start(k);
            va_ub(k) = dme.va_start(k);

            nm.add_var('va', ['va_' obj.name], nb, dme.va_start, va_lb, va_ub);
            nm.add_var('vm', ['vm_' obj.name], nb, dme.vm_start, dme.vm_lb, dme.vm_ub);
        end
    end     %% methods
end         %% classdef


function value = ch_to_rot13 ( ch )

%*****************************************************************************80
%
%% CH_TO_ROT13 converts a character to its ROT13 equivalent.
%
%  Discussion:
%
%    Two applications of CH_TO_ROT13 to a character will return the original.!
%
%    As a further scrambling, digits are similarly rotated using
%    a "ROT5" scheme.
%
%  Example:
%
%    Input:  Output:
%
%    a       n
%    C       P
%    J       W
%    1       6
%    5       0
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 April 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character CH, the character to be converted.
%
%    Output, character VALUE, the ROT13 equivalent of the character.
%

%
%  [0:4] -> [5:9]
%
  if ( 48 <= ch && ch <= 52 )
    value = ch + 5;
%
%  [5:9] -> [0:4]
%
  elseif ( 53 <= ch && ch <= 57 )
    value = ch - 5;
%
%  [A:M] -> [N:Z]
%
  elseif ( 65 <= ch && ch <= 77 )
    value = ch + 13;
%
%  [N:Z] -> [A:M]
%
  elseif ( 78 <= ch && ch <= 90 )
    value = ch - 13;
%
%  [a:m] -> [n:z]
%
  elseif ( 97 <= ch && ch <= 109 )
    value = ch + 13;
%
%  [n:z] -> [a:m]
%
  elseif ( 110 <= ch && ch <= 122 )
    value = ch - 13;
  else
    value = ch;
  end

  value = char ( value );

  return
end


function [nx, cx, s] = pne_callback_nose(k, nx, cx, px, s, opt)
%PNE_CALLBACK_NOSE  Callback to handle NOSE events
%   [NX, CX, S] = PNE_CALLBACK_NOSE(K, NX, CX, PX, S, OPT)
%
%   Callback to handle NOSE events, triggered by event function PNE_EVENT_NOSE
%   to indicate the limit (nose point) of the continuation curve has been
%   reached.
%
%   This function sets the msg field of the event when the nose point has
%   been found, raises the S.done flag and sets S.done_msg.
%
%   See PNE_CALLBACK_DEFAULT for details of the input and output arguments.

%   MP-Opt-Model
%   Copyright (c) 2016-2021, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%   and Shrirang Abhyankar, Argonne National Laboratory
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

%% skip if initialize, finalize or done
if k <= 0 || s.done
    return;
end

%% handle event
if ~s.rollback || nx.step == 0
    ev = pne_detected_event(s.events, 'NOSE', 1);   %% zero only
    if ~isempty(ev)
        if nx.step == 0
            msg = sprintf('Nose point eliminated by limit induced bifurcation at %d continuation steps, lambda = %.4g.', k, nx.x(end));
        else
            msg = sprintf('Reached limit in %d continuation steps, lambda = %.4g.', k, nx.x(end));
        end

        %% the following conditional is only necessary if we also allow
        %% finding the location of the nose-point without terminating
        if ischar(opt.stop_at) && strcmp(opt.stop_at, 'NOSE')
            s.done = 1;
            s.done_msg = msg;
        end
    end
end


function histogram_old_95(vari1,stri2)
    %histogram_old_95.m                               A.Allmann
    %plots histogram in cumulative number window
    %vari1 depends on input parameter
    %
    %Last modification 6/95
    global mess  ccum freq_field histo hisvar strii1 strii2
    stri1='Histogram';
    strii1=stri1;
    strii2=stri2;
    hisvar=vari1;
    tm1=[];
    % Find out of figure already exists
    %
    [existFlag,figNumber]=figure_exists('Histogram',1);
    newHistoFlag=existFlag;
    if newHistoFlag
        figure_w_normalized_uicontrolunits(histo)
        cla
        cla
        delete(gca)
    else
        histo= figure_w_normalized_uicontrolunits( ...
            'NumberTitle','off','Name',stri1,...
            'MenuBar','none', ...
            'NextPlot','new', ...
            'Visible','off')

        %Menuline for options
        %
        %matdraw

        op1 = uimenu('Label','Display');
        uimenu(op1,'Label','Bin Number','Callback','inpubin(1);');
        uimenu(op1,'Label','Bin Vector','Callback','inpubin(2);');
        uimenu(op1,'Label','Default','Callback','histogram(hisvar);');

        callbackStr= ...
            ['newcat=a;f1=gcf; f2=gpf; set(f1,''Visible'',''off'');', ...
            'if f1~=f2, figure_w_normalized_uicontrolunits(f2); end'];

        uicontrol('Units','normal',...
            'Position',[.0  .83 .08 .06],'String','Close ',...
             'Callback','close;done')

        uicontrol('Units','normal',...
            'Position',[.0  .93 .08 .06],'String','Print ',...
             'Callback','myprint')

    end

    orient tall
    rect = [0.25,  0.18, 0.60, 0.70];
    axes('position',rect)
    hold on

    histogram(vari1,50);
    title2([stri2,stri1],'FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m,'Color','k')
    set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
        'FontWeight','bold','LineWidth',1.5,'Box','on')

    xlabel(stri2,'FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
    ylabel('  Number ','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
    set(gcf,'Visible','on')


function [imageVol, lastfile] = GE_readVolume(startDir, passnum, volSize, depth, im_offset)
%
%GE_readVolume
%
% [imageVol, lastfile] = GE_readVolume(startDir, passnum, [nX nY nZ], depth, im_offset)
%
% reads the volume for passnum from the series which is stored
% starting in startDir and returns the name of the last file read
%
% Souheil J. Inati
% Dartmouth College
% May 2000
% souheil.inati@dartmouth.edu
%

% initialize some variables
nX = volSize(1);
nY = volSize(2);
nZ = volSize(3);
sliceSize = nX*nY;
imageVol = zeros(nX, nY, nZ);
[path_stem, path_start] = fileparts(startDir);

for i = 1:nZ
        % Make the filename
        filenum = (passnum-1)*nZ + i;   % file no.
        filep = ceil(filenum/999) - 1;
        filen = filenum - 999*filep;
        path_num = str2num(path_start) + 20*filep;
        path_now = sprintf('00%d',path_num);
        disp(['DEBUD: ',path_now]);
        path_now = path_now(length(path_now)-2:length(path_now));
        path = fullfile(path_stem, path_now);
	stub = sprintf('00%d',filen);
	stub = stub(length(stub)-2:length(stub));
        imageFile = fullfile(path,['I.' stub]);

        % Open the file
	[fid,message] = fopen(imageFile,'r','b');
	if (fid == -1)
          fprintf('Cannot Open %s.\n',imageFile);
          passnum
	  break
	end

	% Skip to the data
	fseek(fid,im_offset,-1);
	% Read the slice
	buffer = fread(fid,sliceSize,sprintf('int%d',depth));
	% append the slice to the imageSet
	imageVol(:,:,i) = reshape(buffer, nX, nY);

        % Close the file
	status = fclose(fid);

        % Set the lastfile
        lastfile = imageFile;
end

return


classdef IN1KMOP8 < EvoXBenchProblem
% <multi> <real> <large/none> <expensive/none>

%------------------------------- Reference --------------------------------
% Z. Lu, R. Cheng, Y. Jin, K. C. Tan, and K. Deb, Neural architecture
% search as multiobjective optimization benchmarks: Problem formulation and
% performance assessment, IEEE Transactions on Evolutionary Computation,
% 2023.
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            config.name = 'mnv3';
            config.args.objs = 'err&params&flops';
            config.args.normalized_objectives = false;
            obj.Setting@EvoXBenchProblem(config);
        end
    end
end


%clear all
global planC

directoryname = uigetdir;
dirdata = dir(directoryname);
files={dirdata.name};
ln=length(files);
files=files(3:ln); ln=ln-2;

structNum_roi=1;
structNum_40p=2;
M=[];
Thresholds=[40:10:80];
for i=20:20
    name=files{i}
    load([directoryname,'\',name]);
    %     roiVol = getStructureVol(structNum_40p);
    %    [Dx, Vx(i,:), mean_suv_40p, max_suv_40p, min_suv_40p, slope_ivh_40p(i)]=analyze_ivh1(structNum_40p, 1, 0);
    %slope(i) = calc_slope_grigsby(structNum_roi,Thresholds);
    [energy_40p,contrast_40p,Entropy_40p,Homogeneity_40p,standard_dev_40p,Ph_40p] = getHaralicParams(structNum_40p);
    %     [Eccentricity_40p,EulerNumber_40p,Solidity_40p,Extent_40p]=getShapeParams(structNum_40p);
    %     row=[roiVol, mean_suv_40p, standard_dev_40p, max_suv_40p, min_suv_40p, slope_ivh_40p, Dx, Vx,energy_40p,contrast_40p,Entropy_40p,Homogeneity_40p,...
    %         Eccentricity_40p,EulerNumber_40p,Solidity_40p,Extent_40p];
    %     M=[M;row];
end
%xlswrite('pet_hetro_cervix_grigsby.xls',M)

% clear PlanC
% save pet_hetro_cervix


%CODEGENERATOR.GENFDYN Generate code for forward dynamics
%
% Iqdd = cGen.genfdyn() is a symbolic vector (1xN) of joint inertial
% reaction forces/torques.
%
% Notes::
% - Side effects of execution depends on the cGen flags:
%   - saveresult: the symbolic expressions are saved to
%     disk in the directory specified by cGen.sympath
%   - genmfun: ready to use m-functions are generated and
%     provided via a subclass of SerialLink stored in cGen.robjpath
%   - genslblock: a Simulink block is generated and stored in a
%     robot specific block library cGen.slib in the directory
%     cGen.basepath
%   - genccode: generates C-functions and -headers in the directory
%     specified by the ccodepath property of the CodeGenerator object.
%   - mex: generates robot specific MEX-functions as replacement for the
%     m-functions mentioned above. Access is provided by the SerialLink
%     subclass. The MEX files rely on the C code generated before.
%
% Author::
%  Joern Malzahn, (joern.malzahn@tu-dortmund.de)
%
% See also CodeGenerator.CodeGenerator, CodeGenerator.geninertia, CodeGenerator.genfkine.

% Copyright (C) 2012-2014, by Joern Malzahn
%
% 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
%
% The code generation module emerged during the work on a project funded by
% the German Research Foundation (DFG, BE1569/7-1). The authors gratefully
% acknowledge the financial support.

function [Iqdd] = genfdyn(CGen)
[q,qd] = CGen.rob.gencoords;
tau = CGen.rob.genforces;
nJoints = CGen.rob.n;

CGen.logmsg([datestr(now),'\tLoading required symbolic expressions\n']);

%% Inertia matrix
CGen.logmsg([datestr(now),'\tLoading inertia matrix row by row']);

I = sym(zeros(nJoints));
for kJoints = 1:nJoints
    CGen.logmsg(' %s ',num2str(kJoints));
    symname = ['inertia_row_',num2str(kJoints)];
    fname = fullfile(CGen.sympath,[symname,'.mat']);

    if ~exist(fname,'file')
        CGen.logmsg(['\n',datestr(now),'\t Symbolics not found, generating...\n']);
        CGen.geninertia;
    end
    tmpstruct = load(fname);
    I(kJoints,:)=tmpstruct.(symname);

end
CGen.logmsg('\t%s\n',' done!');

%% Matrix of centrifugal and Coriolis forces/torques matrix
CGen.logmsg([datestr(now),'\t\tCoriolis matrix by row']);

C = sym(zeros(nJoints));
for kJoints = 1:nJoints
    CGen.logmsg(' %s ',num2str(kJoints));
    symname = ['coriolis_row_',num2str(kJoints)];
    fname = fullfile(CGen.sympath,[symname,'.mat']);

    if ~exist(fname,'file')
        CGen.logmsg(['\n',datestr(now),'\t Symbolics not found, generating...\n']);
        CGen.gencoriolis;
    end
    tmpstruct = load(fname);
    C(kJoints,:)=tmpstruct.(symname);

end
CGen.logmsg('\t%s\n',' done!');

%% Vector of gravitational load
CGen.logmsg([datestr(now),'\t\tvector of gravitational forces/torques']);
symname = 'gravload';
fname = fullfile(CGen.sympath,[symname,'.mat']);

if ~exist(fname,'file')
    CGen.logmsg(['\n',datestr(now),'\t Symbolics not found, generating...\n']);
    CGen.gengravload;
end
tmpstruct = load(fname);
G = tmpstruct.(symname);

CGen.logmsg('\t%s\n',' done!');

%% Joint friction
CGen.logmsg([datestr(now),'\t\tjoint friction vector']);
symname = 'friction';
fname = fullfile(CGen.sympath,[symname,'.mat']);

if ~exist(fname,'file')
    CGen.logmsg(['\n',datestr(now),'\t Symbolics not found, generating...\n']);
    CGen.genfriction;
end
tmpstruct = load(fname);
F = tmpstruct.(symname);

CGen.logmsg('\t%s\n',' done!');

% Full inverse dynamics
CGen.logmsg([datestr(now),'\tGenerating symbolic inertial reaction forces/torques expression\n']);
Iqdd = tau.'-C*qd.' -G.' +F.';
Iqdd = Iqdd.';

%% Save symbolic expressions
if CGen.saveresult
    CGen.logmsg([datestr(now),'\tSaving symbolic inertial reaction forces/torques expression']);

    CGen.savesym(Iqdd,'Iqdd','Iqdd.mat')

    CGen.logmsg('\t%s\n',' done!');
end

%% M-Functions
if CGen.genmfun
    CGen.genmfunfdyn;
end

%% Embedded Matlab Function Simulink blocks
if CGen.genslblock
    CGen.genslblockfdyn;
end

%% C-Code
if CGen.genccode
    CGen.genccodefdyn;
end

%% MEX
if CGen.genmex
    CGen.genmexfdyn;
end

end


function parsed_all = detect_all_by_featmap( featmap, scale, param, caffe_solver, thres )
    scale = 2.^(scale(end:-1:1)-5);
    parsed = [];
    for s = 1:numel(featmap)
        caffe_solver.reshape_as_input({{featmap{s}}});
        caffe_solver.set_input_data({{featmap{s}}});
        caffe_solver.forward_prefilled();
        parsed_t = convert_output_to_struct( param, caffe_solver, 1, thres);
        for j = 1 : length(parsed_t)
            parsed_t(j).box = round(parsed_t(j).box / scale(s));
            parsed_t(j).point = round(parsed_t(j).point / scale(s));
            parsed_t(j).box(:, end+1) = parsed_t(j).cls_score;
        end
        if s == 1
            parsed = parsed_t;
        else
            for j = 1 : length(param.gpu_id)
                parsed(j).cls_score = cat(1, parsed(j).cls_score, parsed_t(j).cls_score);
                %parsed(j).active = cat(1, parsed(j).cls_score, parsed_t.cls_score);
                parsed(j).box = cat(1, parsed(j).box, parsed_t(j).box);
                parsed(j).point = cat(1, parsed(j).point, parsed_t(j).point);
            end
        end
    end
    parsed_all = parsed;
end


function [us,optimState] = searchHedge(searchFcns,u,gpstruct,LB,UB,optimState,options)
%SEARCHWCM Weighted covariance matrix search step (inspired by CMA-ES).

if nargin < 2 || isempty(u) || isempty(gpstruct)
    try
        us = feval(searchFcns{optimState.hedge.chosen}{:});
    catch
        us = 'hedge';
    end
    return;
end

% SUMRULE not specified, all arguments shifted by one
if nargin < 7
    options = optimState;
    optimState = UB;
    UB = LB;
    LB = gpstruct;
    gpstruct = u;
    u = sumrule;
    sumrule = [];
end

hedge = optimState.hedge;

nh = numel(searchFcns);

% Initialize hedge struct
if isempty(hedge)
    hedge.g = zeros(1,nh);
    hedge.g(1) = 10;
    for i = 1:nh; hedge.str{i} = feval(searchFcns{i}{:}); end
    hedge.n = numel(hedge.g);
    hedge.count = 0;
    hedge.gamma = options.HedgeGamma;
    hedge.beta = options.HedgeBeta;
    hedge.decay = options.HedgeDecay;
    % hedge.string = {'mpi','mei'};
end

hedge.count = hedge.count + 1;
% gammaHedge = min(1/nHedge, sqrt(log(nHedge)/(nHedge*hedge.count)));

hedge.p = exp(hedge.beta*(hedge.g - max(hedge.g)))./sum(exp(hedge.beta*(hedge.g - max(hedge.g))));
hedge.p = hedge.p*(1-hedge.n*hedge.gamma) + hedge.gamma;
% hedge.p
hedge.chosen = find(rand() < cumsum(hedge.p),1);
if isempty(hedge.chosen)
    hedge.chosen = randi(nh);
    if options.gpWarnings
        warning('bads:searchHedgeFail', ['Cannot determine best search function in SEARCHHEDGE (P=' numarray2str(hedge.p) '). Attempting to continue.']);
    end
end
if hedge.gamma == 0
    hedge.phat = ones(size(hedge.g));
else
    hedge.phat = Inf(size(hedge.p));
    hedge.phat(hedge.chosen) = hedge.p(hedge.chosen);
end

us = feval(searchFcns{hedge.chosen}{:}, ...
    u, ...
    gpstruct, ...
    LB, ...
    UB, ...
    optimState, ...
    options);

optimState.hedge = hedge;

end


%function Main_CNN_ImageNet_minimal()
% Minimalistic demonstration of how to run an ImageNet CNN model

% setup toolbox
addpath(genpath('../CoreModules'))
% download a pre-trained CNN from the web
if ~exist('imagenet-vgg-f.mat', 'file')
  fprintf('Downloading a model ... this may take a while\n') ;
  urlwrite('http://www.vlfeat.org/matconvnet/models/imagenet-vgg-f.mat', ...
    'imagenet-vgg-f.mat') ;
end
net = load('imagenet-vgg-f.mat') ;

% obtain and preprocess an image
im = imread('test_im.JPG') ;
im_ = single(im) ; % note: 255 range
im_ = imresize(im_, net.meta.normalization.imageSize(1:2)) ;
im_ = im_ - net.meta.normalization.averageImage ;

% run the CNN
opts=[];
opts.use_gpu=0;%unless you have a good gpu
opts.use_nntoolbox=0; %Requires Neural Network Toolbox to use it.

opts.training=0;
opts.use_corr=1;
res(1).x=im_;

if opts.use_gpu
    net=SwitchProcessor(net,'gpu');
end
tic;
[ net,res,opts ] = net_ff( net,res,opts );
toc;
% show the classification result
scores = squeeze(gather(res(end).x)) ;
[bestScore, best] = max(scores) ;
figure(1) ; clf ; imagesc(im) ;
title(sprintf('%s (%d), score %.3f',...
   net.meta.classes.description{best}, best, bestScore)) ;
drawnow;


function [] = fix_pos(blocka,blockb,r,t)

% fix the height distance between 2 blocks
% blocka acts as the origin of coordinates
% blockb is the one move around the blocka
% t is for the down, r is for the left

Pos = get_param(blocka, 'Position');
Posb = get_param(blockb, 'Position');
B = Posb(3)-Posb(1);
H = Posb(4)-Posb(2);
pos1 = Pos(1)+r;
pos3 = pos1+B;
pos2 = Pos(4)+t;
pos4 = pos2+H;
set_param(blockb, 'Position',[pos1 pos2 pos3 pos4]);


function [net, info] = cnn_imagenet(varargin)
%CNN_IMAGENET   Demonstrates training a CNN on ImageNet
%  This demo demonstrates training the AlexNet, VGG-F, VGG-S, VGG-M,
%  VGG-VD-16, and VGG-VD-19 architectures on ImageNet data.

run(fullfile(fileparts(mfilename('fullpath')), ...
  '..', '..', 'matlab', 'vl_setupnn.m')) ;

% opts.dataDir = fullfile(vl_rootnn, 'data','ILSVRC2012') ;
opts.dataDir = fullfile('/data','jiangqy','ImageNet');
opts.modelType = 'alexnet' ;
opts.networkType = 'simplenn' ;
opts.batchNormalization = false ;
opts.weightInitMethod = 'gaussian' ;
[opts, varargin] = vl_argparse(opts, varargin) ;

sfx = opts.modelType ;
if opts.batchNormalization, sfx = [sfx '-bnorm'] ; end
sfx = [sfx '-' opts.networkType] ;
% opts.expDir = fullfile(vl_rootnn, 'data', ['imagenet12-' sfx]) ;
opts.expDir = fullfile('/data','jiangqy','ImageNet');
[opts, varargin] = vl_argparse(opts, varargin) ;

opts.numFetchThreads = 12 ;
opts.lite = false ;
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');
opts.train = struct() ;
opts = vl_argparse(opts, varargin) ;
if ~isfield(opts.train, 'gpus'), opts.train.gpus = [12]; end;

% -------------------------------------------------------------------------
%                                                             Prepare model
% -------------------------------------------------------------------------

net = cnn_imagenet_init('model', opts.modelType, ...
                        'batchNormalization', opts.batchNormalization, ...
                        'weightInitMethod', opts.weightInitMethod, ...
                        'networkType', opts.networkType) ;

% -------------------------------------------------------------------------
%                                                              Prepare data
% -------------------------------------------------------------------------

if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
else
  imdb = cnn_imagenet_setup_data('dataDir', opts.dataDir, 'lite', opts.lite) ;
  mkdir(opts.expDir) ;
  save(opts.imdbPath, '-struct', 'imdb') ;
end

% Set the class names in the network
net.meta.classes.name = imdb.classes.name ;
net.meta.classes.description = imdb.classes.description ;

% Compute image statistics (mean, RGB covariances, etc.)
imageStatsPath = fullfile(opts.expDir, 'imageStats.mat') ;
if exist(imageStatsPath)
  load(imageStatsPath, 'averageImage', 'rgbMean', 'rgbCovariance') ;
else
  [averageImage, rgbMean, rgbCovariance] = getImageStats(opts, net.meta, imdb) ;
  save(imageStatsPath, 'averageImage', 'rgbMean', 'rgbCovariance') ;
end

% Set the image average (use either an image or a color)
%net.meta.normalization.averageImage = averageImage ;
net.meta.normalization.averageImage = rgbMean ;

% Set data augmentation statistics
[v,d] = eig(rgbCovariance) ;
net.meta.augmentation.rgbVariance = 0.1*sqrt(d)*v' ;
clear v d ;

% -------------------------------------------------------------------------
%                                                                     Learn
% -------------------------------------------------------------------------

% switch opts.networkType
%   case 'simplenn', trainFn = @cnn_train ;
%   case 'dagnn', trainFn = @cnn_train_dag ;
% end

[net, info] = cnn_train(net, imdb, getBatchFn(opts, net.meta), ...
                      'expDir', opts.expDir, ...
                      net.meta.trainOpts, ...
                      opts.train) ;

% -------------------------------------------------------------------------
%                                                                    Deploy
% -------------------------------------------------------------------------

net = cnn_imagenet_deploy(net) ;
modelPath = fullfile(opts.expDir, 'net-deployed.mat')

switch opts.networkType
  case 'simplenn'
    save(modelPath, '-struct', 'net') ;
  case 'dagnn'
    net_ = net.saveobj() ;
    save(modelPath, '-struct', 'net_') ;
    clear net_ ;
end

% -------------------------------------------------------------------------
function fn = getBatchFn(opts, meta)
% -------------------------------------------------------------------------
useGpu = numel(opts.train.gpus) > 0 ;

bopts.numThreads = opts.numFetchThreads ;
bopts.imageSize = meta.normalization.imageSize ;
bopts.border = meta.normalization.border ;
bopts.averageImage = meta.normalization.averageImage ;
bopts.rgbVariance = meta.augmentation.rgbVariance ;
bopts.transformation = meta.augmentation.transformation ;

switch lower(opts.networkType)
  case 'simplenn'
    fn = @(x,y) getSimpleNNBatch(bopts,x,y) ;
  case 'dagnn'
    fn = @(x,y) getDagNNBatch(bopts,useGpu,x,y) ;
end

% -------------------------------------------------------------------------
function [im,labels] = getSimpleNNBatch(opts, imdb, batch)
% -------------------------------------------------------------------------
images = strcat([imdb.imageDir filesep], imdb.images.name(batch)) ;
isVal = ~isempty(batch) && imdb.images.set(batch(1)) ~= 1 ;

if ~isVal
  % training
  im = cnn_imagenet_get_batch(images, opts, ...
                              'prefetch', nargout == 0) ;
else
  % validation: disable data augmentation
  im = cnn_imagenet_get_batch(images, opts, ...
                              'prefetch', nargout == 0, ...
                              'transformation', 'none') ;
end

if nargout > 0
  labels = imdb.images.label(batch) ;
end

% -------------------------------------------------------------------------
function inputs = getDagNNBatch(opts, useGpu, imdb, batch)
% -------------------------------------------------------------------------
images = strcat([imdb.imageDir filesep], imdb.images.name(batch)) ;
isVal = ~isempty(batch) && imdb.images.set(batch(1)) ~= 1 ;

if ~isVal
  % training
  im = cnn_imagenet_get_batch(images, opts, ...
                              'prefetch', nargout == 0) ;
else
  % validation: disable data augmentation
  im = cnn_imagenet_get_batch(images, opts, ...
                              'prefetch', nargout == 0, ...
                              'transformation', 'none') ;
end

if nargout > 0
  if useGpu
    im = gpuArray(im) ;
  end
  labels = imdb.images.label(batch) ;
  inputs = {'input', im, 'label', labels} ;
end

% -------------------------------------------------------------------------
function [averageImage, rgbMean, rgbCovariance] = getImageStats(opts, meta, imdb)
% -------------------------------------------------------------------------
train = find(imdb.images.set == 1) ;
train = train(1: 101: end);
bs = 256 ;
opts.networkType = 'simplenn' ;
fn = getBatchFn(opts, meta) ;
avg = {}; rgbm1 = {}; rgbm2 = {};

for t=1:bs:numel(train)
  batch_time = tic ;
  batch = train(t:min(t+bs-1, numel(train))) ;
  fprintf('collecting image stats: batch starting with image %d ...', batch(1)) ;
  temp = fn(imdb, batch) ;
  z = reshape(permute(temp,[3 1 2 4]),3,[]) ;
  n = size(z,2) ;
  avg{end+1} = mean(temp, 4) ;
  rgbm1{end+1} = sum(z,2)/n ;
  rgbm2{end+1} = z*z'/n ;
  batch_time = toc(batch_time) ;
  fprintf(' %.2f s (%.1f images/s)\n', batch_time, numel(batch)/ batch_time) ;
end
averageImage = mean(cat(4,avg{:}),4) ;
rgbm1 = mean(cat(2,rgbm1{:}),2) ;
rgbm2 = mean(cat(3,rgbm2{:}),3) ;
rgbMean = rgbm1 ;
rgbCovariance = rgbm2 - rgbm1*rgbm1' ;


function val=soft_threshodr(groups,nc,w,mu)
%soft_threshodr
%
val=w/(1+mu);
end


function [outdic,f,ci,ce,cs,g,ai,ae] = sqplab_simul(indic,x,lm,v)

switch indic
    case 0
    case 1
        outdic = 0;
    case 2
        [f,g] = sqplab_fun(x);
        [ci,ce,ai,ae] = sqplab_con(x);
         outdic = 0;
    case 3
        [f,g] = sqplab_fun(x);
        [ci,ce,ai,ae] = sqplab_con(x);
         outdic = 0;
    case 4
        [f,g] = sqplab_fun(x);
        [ci,ce,ai,ae] = sqplab_con(x);
     %   ci = -ci;
        ai = -ai;
        ai = reshape(ai,[],length(g));
        ae = reshape(ae,[],length(g));
        cs = [];
        outdic = 0;
end


function lab = rgb2lab(rgb_im)

    if ~isa(rgb_im,'uint8'),
        rgb_im = im2uint8(rgb_im);
    end

    cform = makecform('srgb2lab');
    lab = applycform(rgb_im,cform);

end


function out = feval(N, varargin)
%FEVAL   Evaluate the operator of the CHEBOP at a CHEBFUN or CHEBMATRIX.
%   OUT = FEVAL(N, U) for a CHEBFUN or CHEBMATRIX U applies the CHEBOP N to U,
%   i.e., it returns N(U). Here, N.OP should be of the form @(u) diff(u,2) + ...
%   If N.op is of the form @(x, u) diff(u,2) + ... then an x variable is
%   instantiated internally and included automatically, however, this is not
%   the preferred syntax and may not be supported in future releases.
%
%   OUT = FEVAL(N, X, U) for the CHEBFUN X and CHEBFUN or CHEBMATRIX U applies
%   the CHEBOP N to X and  U, i.e., it returns N(X, U) where N.OP has the form
%   @(x, u) diff(u,2) + .... Here, X should be the dependent variable on
%   N.DOMAIN.
%
%   OUT = FEVAL(N, X, U1, U2, ..., UM) for a CHEBFUN X and CHEBFUN or CHEMBATRIX
%   objects U1, ..., UM applies the CHEBOP N to the functions Uk; i.e., it
%   returns N(X, U1, U2, ..., UM) where N.OP has the form @(x, u1, u2, ..., um).
%   Note that for systems of equations, X _must_ be included in N.OP.
%
%   OUT = FEVAL(N, X, U) where U is a CHEBMATRIX of M entries and N.OP has the
%   form @(X, U1, U2, ..., UM) is equivalent FEVAL(N, X, U{1}, ..., U{M}).
%   Again, OUT = FEVAL(N, U) will also work in this situation, but this is not
%   the preferred syntax.
%
%   OUT = FEVAL(N, DIM) returns an DIM-point discretization of the linear
%   operator N. If N is not linear an error is thrown. OUT = FEVAL(N, DIM,
%   'oldschool') uses boundary bordering to deal wiuth the boundary conditions,
%   rather than the rectangular projection approach of hale and Driscoll. Note
%   that this syntax exists only the support ATAP and doesn't necessarily give a
%   clear picture of the discretizations now being used in the Chebfun release.
%   CHEBOP/MATRIX, which is the preferred syntax for this functionality,
%   provides further details
%
% See also CHEBOP/SUBSREF, LINOP/MTIMES, CHEBOP/MATRIX.

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

% Support for calling a linear CHEBOP with a numerical input to get its
% discretization. This is deprecated
if ( (nargin == 2) && isnumeric(varargin{1}) )
    warning('CHEBFUN:CHEBOP:feval:deprecated', ...
        ['FEVAL(N, DIM) or N(DIM) exists only to provide backwards\n', ...
        'compatibility with ATAP. The preferred method for visualizing a\n', ...
        'discretization of a linear CHEBOP is MATRIX(N, DIM). Note, however,\n', ...
        'that these may not give the same result due to changes in how\n', ...
        'CHEBOP discretizes differential operators.'])
    warning('off', 'CHEBFUN:CHEBOP:feval:deprecated');

    % We cannot support boundary conditions in this way.
    throwBCwarning = false;
    if ( ~isempty(N.lbc) )
        N.lbc = [];
        throwBCwarning = true;
    end
    if ( ~isempty(N.rbc) )
        N.rbc = [];
        throwBCwarning = true;
    end
    if ( ~isempty(N.bc) )
        N.bc = [];
        throwBCwarning = true;
    end
    if ( throwBCwarning )
        warning('CHEBFUN:CHEBOP:feval:BCs', ...
            'Boundary conditions are not supported in FEVAL(N, DIM).')
    end

    % Because the native V5 matrix is rectangular, we have to do some resizing
    % to recapture V4 behavior. Note: this may break for systems, piecewise
    % cases.
    n = varargin{1};
    L = linop(N);
    pref = cheboppref();
    disc = pref.discretization;
    if ( isa(disc, 'char') && strcmpi(disc, 'values') )
        pref.discretization = @chebcolloc2;
    elseif ( isa(disc, 'function_handle') && ~isequal(disc, @chebcolloc2) )
        % We only support CHEBCOLLOC2 discretizations!
        error('CHEBFUN:CHEBOP:feval:notColloc2', ...
            ['FEVAL(N, DIM) only supports CHEBCOLLOC2 discretizations.\n', ...
             'Use MATRIX(N, DIM) or change the discretization in CHEBOPPREF.']);
    end
    A = matrix(L, n, pref); % has n rows but maybe more columns

    % We want an n by n result. We have that A is (n-d) x n where d =
    % L.diffOrder. Also, the output of A is at 1st kind points. We need to do:
    %  (map from n 1st kind to n 2nd kind) * A * (map from n 2nd kind to
    %  n+d 2nd kind).

    % Note that we don't have to translate/scale to the domain for barymat
    % matrices that go between grids.
    d = L.diffOrder;
    [x1,~,w1] = chebtech1.chebpts( n );
    x2 = chebtech2.chebpts( n );
    x3 = chebtech2.chebpts( n + d );

    out = barymat(x2, x1, w1) * A * barymat(x3, x2);
    return

elseif ((nargin == 3) && ischar(varargin{2}) ...
        && strcmpi(varargin{2}, 'oldschool'))

    % TODO: Is this still correct?
    out = matrix(N, varargin{:});
    return
end

% We must expand CHEBMATRIX entries out to a cell for {:} to work below.
isChebMat = cellfun(@(u) isa(u, 'chebmatrix'), varargin);
if ( any(isChebMat) )
    args = {};
    for k = 1:numel(varargin)
        % Append variables from the kth input:
        if ( isChebMat(k) )
            args = [args , varargin{k}.blocks.']; %#ok<AGROW>
        else
            args = [args , varargin(k)];          %#ok<AGROW>
        end
    end
else
    args = varargin;
end

% How many input arguments are there to N.op?
numberOfInputs = nargin(N);

% If no arguments, return empty:
if ( numberOfInputs == 0 )
    out = [];
    return
end

if ( numberOfInputs == 1)
    % If N has one input arguments, either we have a scalar problem, or the
    % problem is specified on chebmatrix format, e.g.,
    %   N.op = @(u) [ diff(u{1},2) + u{2}; u{1} + diff(u{2}];
    % Here, importantly, x does not appear in the argument list for N.op.
    u = varargin{1};

    % If we have a scalar problem, but U is still a CHEBMATRIX, we need to
    % extract the BLOCK of U in order to be evaluate N. If on the other hand, U
    % has more than one block, but NUMBEROFINPUTS is still equal to 1 (which got
    % us here in the first place), we must be dealing with a CHEBOP N, whose OP
    % is specified on CHEBMATRIX format, e.g.
    %   N.op = @(u) [diff(u{1}) + u{2}; u{1} + diff(u{2})];
    if ( isa(u, 'chebmatrix') && max(size(u)) == 1 )
        u = u.blocks{1};
    end

    out = N.op(u);

elseif ( numberOfInputs == 2 )
    % If N has two input arguments, either we have a scalar problem, or the
    % problem is specified on chebmatrix format, e.g.,
    %   N.op = @(x, u) [ diff(u{1},2) + u{2}; u{1} + diff(u{2}];
    % Here, importantly, x must appear in the argument list for N.op.

    % Did we not get the x variable passed in as argument?
    if ( numel(varargin) == 1 )
        u = varargin{1};

        % Construct the independent variable X.
        x = chebfun(@(x) x, N.domain);
        % If the CHEBFUN U passed in is a quasimatrix, we need to tile the
        % independent variable X to have the same dimensions as U:
        x = repmat(x, 1, size(u,2));

    elseif ( numel(varargin) == numberOfInputs )
        % Got passed both X and U.
        x = varargin{1};
        u = varargin{2};

    else
        error('CHEBFUN:CHEBOP:feval:numInputs', ...
            'Unexpected number of input arguments.')
    end

    % If we have a scalar problem, but U is still a CHEBMATRIX, we need to
    % extract the BLOCK of U in order to be evaluate N. If on the other
    % hand, U has more than one block, but NUMBEROFINPUTS is still less than
    % or equal to 2 (which got us here in the first place), we must be
    % dealing with a CHEBOP N, whose OP is specified on CHEBMATRIX format,
    % e.g.,
    %   N.op = @(x,u) [diff(u{1}) + u{2}; u{1} + diff(u{2})];
    if ( isa(u, 'chebmatrix') && max(size(u)) == 1 )
        u = u.blocks{1};
    end

    % Evaluate the operator!
    out = N.op(x, u);

else
    % The operator is specified on the form
    %   N.op = @(x, u, v) = [diff(u,2) + v; u + diff(v)]

    % Count the number of RHSs:
    numCols = max(max(cellfun(@(v) size(v, 2), varargin)));

    % We must expand CHEBMATRIX entries out to a cell for {:} to work below.
    isChebMat = cellfun(@(u) isa(u, 'chebmatrix'), varargin);
    if ( any(isChebMat) )
        args = {};
        for k = 1:numel(varargin)
            % Append variables from the kth input:
            if ( isChebMat(k) )
                args = [args , varargin{k}.blocks.']; %#ok<AGROW>
            else
                args = [args , varargin(k)];          %#ok<AGROW>
            end
        end
        % ARGS need to be vertically concatenated for operator to be evaluated
        % correctly.
        args = args.';
    else
        % ARGS need to be vertically concatenated for operator to be evaluated
        % correctly.
        args = varargin.';
    end

    if ( numCols > 1 )
        % Deal with multiple RHS
        out = cell(1, numCols);
        for k = 1:numCols
            out{k} = doEval(N, args(:,k));
        end
        out = horzcat(out{:});
    else
        out = doEval(N, args);
    end

end

% If the operator is written in a function file or nested function, then it
% is natural for it to be returned in cell form. Convert it to a chebmatrix:
if ( iscell(out) )
    out = vertcat(out{:}); % TODO: is this correct for multiple RHSs?
end

end

function out = doEval(N, args)

    numberOfInputs = nargin(N);
    if ( numel(args) == numberOfInputs - 1 )
        % Check if we need to include an x (independent variable):
        x = chebfun(@(x) x, N.domain);
        args = [ {x} ; args ];
    end
    % Evaluate the operator:
    out = N.op(args{:});

end


function logProb = vargplvmProbabilityCompute(model, y, display, iters)

% VARGPLVMPROBABILITYCOMPUTE description

% VARGPLVM

% Takes an input a trained vargplvm and a test data point (with possibly missing values)
% Computes the probability density in the test data point

% Indices of missing dimension
indexMissing = isnan(y);
indexPresent = ~indexMissing;
nTestSamples = size(y,1);
logProb = zeros(nTestSamples,1);

% if ~matlabpool('size')
%     if display, fprintf('vargplvmProbabilityCompute.m: line 17 -- Starting up MatLab pool for parallel computing.'); end
%     matlabpool
% end
try
    nWorkers = matlabpool('size');
catch e
    nWorkers = 1;
end
if nWorkers==0 % If matlabpool has not started, don't try to use it.
    nWorkers = 1;
end

% compute the variational lower without the new data point
Fold = vargplvmLogLikelihood(model);

if all(all(repmat(indexMissing(1,:), [nTestSamples, 1]) == indexMissing))
    % Faster option:
    if display,
        fprintf('Optimisation will be done all at once as the missing variables are always the same (or if there is no missing variable).\n');
        fprintf('Initialising the latent point using the nearest neighbour from the training data.\n');
    end
    dst = dist2(y(:,indexPresent(1,:)), model.y(:,indexPresent(1,:)));
    [~, mini] = min(dst,[],2);

    if display, fprintf('Creating the variational distribtion for the test latent point.\n'); end
    vardistx = vardistCreate(model.vardist.means(mini,:), model.q, 'gaussian');

    if display, fprintf('Optimising over the latent points.\n'); end
    model.vardistx = vardistx;
    [X, varX] = vargplvmOptimisePoint(model, vardistx, y, display, iters);

    if display, fprintf('Computing the variational lower with the new data points included.\n'); end
    vardistx.means = X;
    vardistx.covars = varX;

    if display, fprintf('Generating results for each sample separately (so optimisation is done only once for all test samples).\n'); end
    parfor t = 1:nTestSamples,
        vardistxTmp = vardistx;
        vardistxTmp.numData = 1;
        % if display, fprintf('Testing sample %d/%d\n', t, nTestSamples);
        vardistxTmp.means = vardistx.means(t,:);
        vardistxTmp.covars = vardistx.covars(t,:) ;
        Fnew = vargplvmPointLogLikelihood(model, vardistxTmp, y(t,:));

        % compute the probability
        logProb(t) = Fnew - Fold;
    end

else % This version is slower, but also uses multithreading:
    c = clock;
    tmpDir = sprintf('/tmp/%s/%d_%d_%d_%d_%d', getenv('USER'), c(1), c(2), c(3), c(4), c(5));
    if display,
        fprintf('There are missing variables but they are not consistent. Optimising for each test point separately.\n');
        fprintf('In order to reduce the memory usage by each worker, I will use temporary files in %s\n', tmpDir);
    end
    if ~exist(tmpDir,'dir')
        mkdir(tmpDir);
    end

    logProbCells = cell(nWorkers,1);
    for w=1:nWorkers
        tmpFile = sprintf('%s/Ytest_cpu%02d.mat', tmpDir, w);
        if ~exist(tmpFile,'file')
            currSamplesBegin = 1 + (w-1)*floor(nTestSamples/nWorkers);
            currSamplesEnd = w*floor(nTestSamples/nWorkers);
            if w==nWorkers
                currSamplesEnd = nTestSamples;
            end
            sampleIndices = [currSamplesBegin currSamplesEnd];
            if display, fprintf('Writing samples for worker %d/%d: from %d to %d...', w, nWorkers, currSamplesBegin, currSamplesEnd); end
            currY = y(currSamplesBegin:currSamplesEnd,:);
            currIndexPresent = indexPresent(currSamplesBegin:currSamplesEnd,:);
            save(tmpFile, 'currY', 'currIndexPresent', 'sampleIndices');
            if display, fprintf(' done!\n'); end
        end
    end
    clear y;
    clear indexPresent;

    parfor w=1:nWorkers,
      tmpFile = sprintf('%s/Ytest_cpu%02d.mat', tmpDir, w);
      if display, fprintf('Loading %s...', tmpFile); end
      testData = load(tmpFile);
      if display, fprintf(' done!\n'); end

      currSamples = (testData.sampleIndices(1):testData.sampleIndices(end))';
      currLogProb = zeros(currSamples(end)-currSamples(1)+1,1);

      for tIdx=1:length(currSamples),
        modelCopy = model;
        t = currSamples(tIdx);
        if display, fprintf('-----\nvargplvmProbabilityCompute(): evaluating sample %d of %d\n', t, nTestSamples); end;

        dst = dist2(testData.currY(tIdx,testData.currIndexPresent(tIdx,:)), modelCopy.y(:,testData.currIndexPresent(tIdx,:)));
        [~, mini] = min(dst);

        % create the variational distribtion for the test latent point
        vardistx = vardistCreate(modelCopy.vardist.means(mini,:), modelCopy.q, 'gaussian');

        % optimize over the latent point
        modelCopy.vardistx = vardistx;
        [X, varX] = vargplvmOptimisePoint(modelCopy, vardistx, testData.currY(tIdx,:), display, iters);

        % compute the variational lower with the new data point included
        vardistx.means = X;
        vardistx.covars = varX;

        % Old way:
        Fnew = vargplvmPointLogLikelihood(modelCopy, vardistx, testData.currY(tIdx,:));

        % compute the probability
        currLogProb(tIdx) = Fnew - Fold;
      end
      logProbCells{w} = currLogProb;
    end

    % Concatenating the results of all workers:
    for w=1:nWorkers
      currSamples = ((1 + (w-1)*floor(nTestSamples/nWorkers)) : w*floor(nTestSamples/nWorkers))';
      if w==nWorkers && (currSamples(end) < nTestSamples),
          currSamples = [currSamples; ((currSamples(end)+1):nTestSamples)'];
      end
      logProb(currSamples) = logProbCells{w};
    end
end
end


function vw = addROIsinglePoint(vw,sgn)
%
% vw = addROIsinglePoint(vw,[sgn])
%
% AUTHOR:  Wandell
% DATE:   07.26.00
% PURPOSE:
%   The user clicks on a point and all of the gray matter within
% a distance, d, is selected for an ROI.  The calculation of the
% disk is managed by mrManifoldDistance.
%
% We find gray matter that is within some distance of the selected point.
% This is always done using gray matter graph in the VOLUME and coords data set
% via the routine mrManifoldDistance.  It appears that the proper nodes and
% edges are in Gray/coords.mat
%
% Hence, we have to
%   (a) make sure the gray graph is loaded,
%   (b) find the selected point in the gray matter,
%   (c) compute the disk around the point
%       return the corresponding values in whatever view we are in.
% If sgn~=0, the routine adds user-specified disk to the selected ROI in
% current slice. If sgn==0, the disk is removed from the current ROI.
%
% Follows logic from:  djh, 7/98
%
% If you change this function make parallel changes in:
%   all addROI*.m functions

% error if no current ROI.  This is usually created by the
% callback, so it should be here.
if vw.selectedROI == 0
  myErrorDlg('No current ROI');
  return
end

% Default is to add the data to the current ROI
if ~exist('sgn','var')
  sgn = 1;
end

% Get current ROI coords
curCoords = getCurROIcoords(vw);

% Save prevSelpts for undo
vw.prevCoords = curCoords;

% Get curSlice
curSlice = viewGet(vw, 'Current Slice');

% Get a single point from the user.  We leave the designation
% rgn, rather than pnt, for now.
% (rgn is short for region)
figure(vw.ui.figNum);
rgn = round(ginput(1));

% Note: ginput hands them back in x, y order (1st col is x and
% 2nd col is y).  But we use them in the opposite order (row,col), so that
% we want (y,x).  So we flip 'em. Hmmm....BW, but, but ...
%
rgn = fliplr(rgn);

% Check if outside image
dims=size(vw.ui.image);
if (min(rgn(:,1))< 1 | max(rgn(:,1))>dims(1) | ...
      min(rgn(:,2))< 1 | max(rgn(:,2))>dims(2))
  myWarnDlg('Selected point is outside image boundaries');
  return;
end

% Compute new coordinates
newCoords(1,:) = rgn(1);
newCoords(2,:) = rgn(2);
newCoords(3,:) = curSlice;

% Convert coords to canonical frame of reference
% Do an (inverse) rotation if necessary
if (strcmp(vw.viewType,'Flat'))
    newCoords=(rotateCoords(vw,newCoords,1));
end

% for VOLUME vw.  It does nothing for other views.
newCoords = curOri2CanOri(vw,newCoords);

% Merge/remove coordinates
if sgn
  coords = mergeCoords(curCoords,newCoords);
else
  coords = removeCoords(newCoords,curCoords);
end
vw.ROIs(vw.selectedROI).coords = coords;

return;


% gray image denoising

% @inproceedings{zhang2017learning,
%   title={Learning Deep CNN Denoiser Prior for Image Restoration},
%   author={Zhang, Kai and Zuo, Wangmeng and Gu, Shuhang and Zhang, Lei},
%   booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
%   year={2017}
% }

% If you have any question, please feel free to contact with me.
% Kai Zhang (e-mail: cskaizhang@gmail.com)

% clear; clc;
addpath('utilities');
imageSets     = {'BSD68','Set12'}; %%% testing dataset
folderTest    = 'testsets';
folderModel   = 'models';
folderResult  = 'results';
taskTestCur   = 'Denoising';
if ~exist(folderResult,'file')
    mkdir(folderResult);
end

setTestCur    = imageSets{1};
imageSigmaS   = [15,25,50];
modelSigmaS   = [15,25,50];
showResult    = 1;
saveResult    = 0;
useGPU        = 1;
pauseTime     = 1;

%%% folder to store results
folderResultCur = fullfile(folderResult, [taskTestCur,'_',setTestCur]);
if ~exist(folderResultCur,'file')
    mkdir(folderResultCur);
end

%%% read images
ext         =  {'*.jpg','*.png','*.bmp'};
filePaths   =  [];
folderTestCur = fullfile(folderTest,setTestCur);
for i = 1 : length(ext)
    filePaths = cat(1,filePaths, dir(fullfile(folderTestCur,ext{i})));
end

%%% PSNR and SSIM
PSNRs = zeros(length(modelSigmaS),length(filePaths));
SSIMs = zeros(length(modelSigmaS),length(filePaths));

load(fullfile(folderModel,'modelgray.mat'));

for i = 1:length(modelSigmaS)

    disp([i,length(modelSigmaS)]);
    net = loadmodel(modelSigmaS(i),CNNdenoiser);
    net = vl_simplenn_tidy(net);
    % for i = 1:size(net.layers,2)
    %     net.layers{i}.precious = 1;
    % end
    %%% move to gpu
    if useGPU
        net = vl_simplenn_move(net, 'gpu');
    end

    for j = 1:length(filePaths)

        %%% read images
        label = imread(fullfile(folderTestCur,filePaths(j).name));
        [~,imageName,extCur] = fileparts(filePaths(j).name);
        label = im2double(label);
        randn('seed',0);
        input = single(label + imageSigmaS(i)/255*randn(size(label)));

        %%% convert to GPU
        if useGPU
            input = gpuArray(input);
        end
        res    = vl_simplenn(net,input,[],[],'conserveMemory',true,'mode','test');
        output = input - res(end).x;

        %%% convert to CPU
        if useGPU
            output = gather(output);
            input  = gather(input);
        end

        %%% calculate PSNR and SSIM
        [PSNRCur, SSIMCur] = Cal_PSNRSSIM(im2uint8(label),im2uint8(output),0,0);
        if showResult
            imshow(cat(2,im2uint8(label),im2uint8(input),im2uint8(output)));
            title([filePaths(j).name,'    ',num2str(PSNRCur,'%2.2f'),'dB','    ',num2str(SSIMCur,'%2.4f')])
            drawnow;
            if saveResult
                imwrite(im2uint8(output),fullfile(folderResultCur,[imageName,'_',num2str(imageSigmaS(i)),'_',num2str(modelSigmaS(i)),'_',num2str(PSNRCur,'%2.2f'),'.png']));
            end
            pause(pauseTime)
        end
        PSNRs(i,j) = PSNRCur;
        SSIMs(i,j) = SSIMCur;

    end
end

%%% save PSNR and SSIM metrics
save(fullfile(folderResultCur,['PSNR_',taskTestCur,'_',setTestCur,'.mat']),'PSNRs')
save(fullfile(folderResultCur,['SSIM_',taskTestCur,'_',setTestCur,'.mat']),'SSIMs')

disp([mean(PSNRs,2),mean(SSIMs,2)]);