function varargout = MotionAnalyst2D(varargin)
%MOTIONANALYST2D M-file for MotionAnalyst2D.fig
% Author:	Robb Colbrunn, Cleveland Clinic BioRobotics and Mechanical Testing Core
% Date:		2-10-10
% Last change:  3-24-11
% Version:	1.3
% See documentation for complete change history
% Date     Author      Comment
% 3-24-11  R.Colbrunn  Added "Select Assist" option to improve detection of
%                      marker centroids when markers can be encompassed by
%                      target area.  Do not use when using edges as markers.
%                      Added auto-increment of marker selection.  Can break
%                      out of auto-select by right clicking, clicking off
%                      the image, or pressing ESC key.  Matlab bug prevents
%                      ESC key from working before the first marker is
%                      selected.
                    
%License
%     Copyright (C) 2010  Colbrunn
% 
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     any later version.
% 
%     This program 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 General Public License for more details.
% 
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.

%      MOTIONANALYST2D, by itself, creates a new MOTIONANALYST2D or raises the existing
%      singleton*.
%
%      H = MOTIONANALYST2D returns the handle to a new MOTIONANALYST2D or the handle to
%      the existing singleton*.
%
%      MOTIONANALYST2D('Property','Value',...) creates a new MOTIONANALYST2D using the
%      given property value pairs. Unrecognized properties are passed via
%      varargin to MotionAnalyst2D_OpeningFcn.  This calling syntax produces a
%      warning when there is an existing singleton*.
%
%      MOTIONANALYST2D('CALLBACK') and MOTIONANALYST2D('CALLBACK',hObject,...) call the
%      local function named CALLBACK in MOTIONANALYST2D.M with the given input
%      arguments.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help MotionAnalyst2D

% Last Modified by GUIDE v2.5 24-Mar-2011 12:39:57

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @MotionAnalyst2D_OpeningFcn, ...
                   'gui_OutputFcn',  @MotionAnalyst2D_OutputFcn, ...
                   'gui_LayoutFcn',  [], ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
   gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before MotionAnalyst2D is made visible.
function MotionAnalyst2D_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   unrecognized PropertyName/PropertyValue pairs from the
%            command line (see VARARGIN)

% Choose default command line output for MotionAnalyst2D
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);
%initialize all gui default settings
axes(handles.analysticon);
imshow('analyst.png');
table = [1 0 0];
set(handles.mrktable,'Data', table);
set(handles.SelectAssist,'Value',0);  
set(handles.AssistRadius,'Visible','off');
set(handles.AssistRadiusLbl,'Visible','off'); 

% UIWAIT makes MotionAnalyst2D wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = MotionAnalyst2D_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

function NumMarkers_Callback(hObject, eventdata, handles)
% hObject    handle to NumMarkers (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
table = get(handles.mrktable,'Data');
numold = get(hObject,'UserData'); %old value stored in UserData
numstr = get(hObject, 'String');
numnew = str2double(numstr);
set(hObject,'UserData', numnew); %store new value as old value
%update table depending on new size.  Keep old values
if numnew == numold
    return;
elseif numnew < numold
    for i = numnew+1:numold
        table(numnew+1,:) = [];
    end
elseif numnew > numold
    for i = numold+1:numnew
        table(i,:) = [i 0 0];
    end
end
set(handles.mrktable,'Data', table);

% --- Executes during object creation, after setting all properties.
function NumMarkers_CreateFcn(hObject, eventdata, handles)
% hObject    handle to NumMarkers (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');

end

function TargetRad_Callback(hObject, eventdata, handles)
% hObject    handle to TargetRad (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
ImageProp = getappdata(handles.axes1, 'PropData');
drawmrkrs(ImageProp.Data, handles);


% --- Executes during object creation, after setting all properties.
function TargetRad_CreateFcn(hObject, eventdata, handles)
% hObject    handle to TargetRad (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function SearchRad_Callback(hObject, eventdata, handles)
% hObject    handle to SearchRad (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
ImageProp = getappdata(handles.axes1, 'PropData');
drawmrkrs(ImageProp.Data, handles);


% --- Executes during object creation, after setting all properties.
function SearchRad_CreateFcn(hObject, eventdata, handles)
% hObject    handle to SearchRad (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function NumFrames_Callback(hObject, eventdata, handles)
% hObject    handle to NumFrames (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --- Executes during object creation, after setting all properties.
function NumFrames_CreateFcn(hObject, eventdata, handles)
% hObject    handle to NumFrames (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in Interpolate.
function Interpolate_Callback(hObject, eventdata, handles)
% hObject    handle to Interpolate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% Hint: get(hObject,'Value') returns toggle state of Interpolate


% --- Executes during object creation, after setting all properties.
function analysticon_CreateFcn(hObject, eventdata, handles)
% hObject    handle to analysticon (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% Hint: place code in OpeningFcn to populate analysticon

% --------------------------------------------------------------------
function FileMenu_Callback(hObject, eventdata, handles)
% hObject    handle to FileMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function OpenMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to OpenMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function PrintMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to PrintMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function CloseMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to CloseMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

function path_Callback(hObject, eventdata, handles)
% hObject    handle to path (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --- Executes during object creation, after setting all properties.
function path_CreateFcn(hObject, eventdata, handles)
% hObject    handle to path (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in browsebutton.
function browsebutton_Callback(hObject, eventdata, handles)
% hObject    handle to browsebutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global filename datafolder;
[fname,pname] = uigetfile('*.*','Enter data file');
if (fname ~= 0)
pathname = sprintf('%s%s',pname,fname);
%filename = fname;
filename = pathname;  % remove later
datafolder = [pname '/'];
else
    return
end
axes(handles.axes1);
set(handles.axes1, 'Visible', 'on');
Imagraw = imread(pathname);
imagedims = size(Imagraw);
if max(size(size(Imagraw)))==2 % if it is greyscale (2 dimensional array)
    for i=1:3
    Imagraw = im2uint8(Imagraw);%ensure images are converted to 8-bit.
    Imagrgb(:,:,i) = Imagraw; %convert to rgb by making all colors the same
    end
elseif imagedims(3)==4 % if it contains alpha channel (4 dimensional array)
    Imagraw = im2uint8(Imagraw);%ensure images are converted to 8-bit.
    Imagraw(:,:,4) = []; %remove alpha channel
    Imagrgb = Imagraw; %convert to rgb by making all colors the same
else
    Imagrgb = Imagraw;
end
Imagesize = size(Imagrgb);
ImageProp = struct('Data', Imagrgb, 'Xdim', Imagesize(2), 'Ydim', Imagesize(1));
setappdata(handles.axes1, 'PropData', ImageProp);
imshow(pathname);
set(handles.path,'String', pathname);

%Find number of images in folder
    % include only those files that match the image_type
[pathstr, name, ext, versn] = fileparts(pathname);
imgpath = [pathstr '\*' ext];
dir_info = dir(imgpath);
number_of_files = num2str(length(dir_info));
set(handles.NumFrames, 'String',number_of_files);

%set slider parameters
set(handles.slider1, 'Value',1);
set(handles.slider1, 'Min',1);
set(handles.slider1, 'Max',str2num(number_of_files));

%store files paths in slider1 UserData
for i=1:str2num(number_of_files)
files{i} = strcat(pathstr, '\', dir_info(i).name);
end
set(handles.slider1,'UserData',files);

  

    %===========================================================
function [Imageout] = addxhairs(Image, cntrpnt, radius, colors)
% add cross hairs to an image

%find maximum size of image
Imagesize = size(Image);
Xmax = Imagesize(2);
Ymax = Imagesize(1);

Imageout = Image;%set out = in
if (cntrpnt(1)==0)||(cntrpnt(1)==0) % if marker locations have not been filled, don't draw
    return
end

for i = (-radius):radius
    Imageout(cntrpnt(2),bound(cntrpnt(1)+i, Xmax, 1),:) = colors; %draw x line.  bound to within image
end
for j = (-radius):radius
    Imageout(bound(cntrpnt(2)+j, Ymax, 1),cntrpnt(1),:) = colors; %draw y line
end

    %===========================================================
function [Imageout] = addsquare(Image, cntrpnt, radius, colors)
% add square to an image

%find maximum size of image
Imagesize = size(Image);
Xmax = Imagesize(2);
Ymax = Imagesize(1);

Imageout = Image;%set out = in
if (cntrpnt(1)==0)||(cntrpnt(1)==0) % if marker locations have not been filled, don't draw
    return
end

for i = (-radius):radius
    Imageout(bound(cntrpnt(2)+radius, Ymax, 1),bound(cntrpnt(1)+i, Xmax, 1),:) = colors; %draw top x line.  bound to within image
    Imageout(bound(cntrpnt(2)-radius, Ymax, 1),bound(cntrpnt(1)+i, Xmax, 1),:) = colors; %draw bottom x line.  bound to within image
end
for j = (-radius):radius
    Imageout(bound(cntrpnt(2)+j, Ymax, 1),bound(cntrpnt(1)+radius, Xmax, 1),:) = colors; %draw right y line
    Imageout(bound(cntrpnt(2)+j, Ymax, 1),bound(cntrpnt(1)-radius, Xmax, 1),:) = colors; %draw left y line
end

    %===========================================================
function [Imageout] = addcircle(Image, cntrpnt, radius, colors)
% add circle to an image

%find maximum size of image
Imagesize = size(Image);
Xmax = Imagesize(2);
Ymax = Imagesize(1);


Imageout = Image;
if (cntrpnt(1)==0)||(cntrpnt(1)==0)
    return
end
% % Draw a circle in a matrix using the integer midpoint circle algorithm
% % Does not miss or repeat pixels
% % Created by : Peter Bone
% % Created : 19th March 2007
xc = cntrpnt(2);
yc = cntrpnt(1);
xc = int16(xc);
yc = int16(yc);

x = int16(0);
y = int16(radius);
d = int16(1 - radius);

Imageout(xc, bound(yc+y,Xmax,1), :) = colors;
Imageout(xc, bound(yc-y,Xmax,1), :) = colors;
Imageout(bound(xc+y,Ymax,1), yc, :) = colors;
Imageout(bound(xc-y,Ymax,1), yc, :) = colors;

while ( x < y - 1 )
    x = x + 1;
    if ( d < 0 ) 
        d = d + x + x + 1;
    else 
        y = y - 1;
        a = x - y + 1;
        d = d + a + a;
    end
    Imageout( bound( x+xc,Ymax,1),  bound( y+yc,Xmax,1), :) = colors;
    Imageout( bound( y+xc,Ymax,1),  bound( x+yc,Xmax,1), :) = colors;
    Imageout( bound( y+xc,Ymax,1),  bound(-x+yc,Xmax,1), :) = colors;
    Imageout( bound( x+xc,Ymax,1),  bound(-y+yc,Xmax,1), :) = colors;
    Imageout( bound(-x+xc,Ymax,1),  bound(-y+yc,Xmax,1), :) = colors;
    Imageout( bound(-y+xc,Ymax,1),  bound(-x+yc,Xmax,1), :) = colors;
    Imageout( bound(-y+xc,Ymax,1),  bound( x+yc,Xmax,1), :) = colors;
    Imageout( bound(-x+xc,Ymax,1),  bound( y+yc,Xmax,1), :) = colors;    

end
    %===========================================================
function addlabel(Image, cntrpnt, markernum, handles)
% add marker labels to an image
if (cntrpnt(1)==0)||(cntrpnt(1)==0)
    return
end
%find maximum size of image
Imagesize = size(Image);
Xmax = Imagesize(2);
Ymax = Imagesize(1);

offset = 10; % offset location for label
axes(handles.axes1);
text('Position',[bound(cntrpnt(1)+offset,Xmax,1), bound(cntrpnt(2)+offset,Ymax,1)],'String', num2str(markernum), 'FontSize', 8, 'Color', 'Red')

    %===========================================================
function [Imageout] = drawmrkrs(Image, handles)
% add cross hairs and circles to an image
Imageout = Image;

table = get(handles.mrktable,'Data'); % get marker data from table
tableSize = size(table);
nummark = tableSize(1);

%set colors
xhaircolor = 255 * get(handles.MarkerColor,'BackgroundColor');
targcirccolor = 255 * get(handles.TargetColor,'BackgroundColor');
srchcirccolor = 255 * get(handles.SearchColor,'BackgroundColor');

%set radii for texture and search circles
targradius = round((str2double(get(handles.TargetRad,'String')))/1);% divide by 2 to treat as diameter instead
srchradius = round((str2double(get(handles.SearchRad,'String')))/1);% divide by 2 to treat as diameter instead

    for i = 1:nummark
        Imageout = addxhairs(Imageout, [table(i,2),table(i,3)],5,xhaircolor);
        Imageout = addsquare(Imageout, [table(i,2),table(i,3)],targradius,targcirccolor);
        Imageout = addsquare(Imageout, [table(i,2),table(i,3)],srchradius,srchcirccolor);
        %Imageout = addcircle(Imageout, [table(i,2),table(i,3)],targradius,targcirccolor);
        %Imageout = addcircle(Imageout, [table(i,2),table(i,3)],srchradius,srchcirccolor);      
    end
imshow(Imageout);
for i = 1:nummark
        addlabel(Imageout,[table(i,2),table(i,3)], i, handles);        
end

%===========================================================
function [data] = bound(data, uplim, lolim)
% add cross hairs and circles to an image
if data >= uplim
    data = uplim;
elseif data <= lolim
    data = lolim;
else
    data = data;
end
    
% --- Executes on button press in LoadMarkers.
function LoadMarkers_Callback(hObject, eventdata, handles)
% hObject    handle to LoadMarkers (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

%build path to control file
path = get(handles.path,'String');
[pathstr, name, ext, versn] = fileparts(path);
% Read control file (*.csv)
csvpath = [pathstr '\*.csv'];
[control_filename,control_pathname] = uigetfile(csvpath,'Select Control File');
if (control_filename == 0)
return
end
fprintf(1,'Reading control file...');
fid = fopen(strcat(control_pathname,control_filename),'rt');
line = fgets(fid);
row = 0;
while (line ~= -1)
    keyword = line(1:findstr(line,',')-1);
    line = line(findstr(line,',')+1:length(line));
    switch lower(keyword)
        case 'directory'
            directory(1,:) = line(1:findstr(line,',')-1);
        case 'imagetype'
            image_type(1,:) = lower(line(1:findstr(line,',')-1));           
        case 'initialxypoints'
            if ~isempty(strfind(line,',,'))
                line = line(1:findstr(line,',,')-1);
            end;
            xy_points_temp = str2num(line);
            number_of_points(1) = length(xy_points_temp) / 2;
            xy_points(1,1:length(xy_points_temp)) = xy_points_temp;
            clear xy_points_temp;
        case 'targetwidth'
            target_width(1) = str2num(line(1:findstr(line,',')-1));
        case 'searchwidth'
            search_width(1) = str2num(line(1:findstr(line,',')-1));
        case 'interpolate'
            interp(1) = str2num(line(1:findstr(line,',')-1));
        case 'numframestodisplay'
            display(1) = str2num(line(1:findstr(line,',')-1));
        otherwise
            fprintf(1,'Unknown keyword encountered in parameters file. \n');
    end;      
    line = fgets(fid);
end;
fclose(fid);

    %get all data required from control file
    set(handles.TargetRad, 'String', num2str(target_width(1)));
    set(handles.SearchRad, 'String', num2str(search_width(1)));
    set(handles.NumFrames, 'String', num2str(display(1)));
    set(handles.Interpolate, 'Value', interp(1));
    set(handles.NumMarkers, 'String', num2str(number_of_points(1)));
    
    %format marker positions to add to table
    nums = numel(xy_points);
    data = (reshape(xy_points,2,(nums/2)))';
    table = [];
    for i = 1:number_of_points(1)
        for j=1:2
            table(i,1) = i;
            table(i,j+1) = data(i,j);
        end
    end
    set(handles.mrktable,'Data', table);
    
    %draw markers on image
    ImageProp = getappdata(handles.axes1, 'PropData');
    Imageout = drawmrkrs(ImageProp.Data, handles);

% old functions for the load button
% % this pulls up a listbox of the workspace variables and loads one of them
% % into the data.  This functionality was replaced with choosing a file to
% % load.
% % mrkrsetname = lb;
% % xypoints = evalin('base',['round(' mrkrsetname ')']);



% --- Executes during object creation, after setting all properties.
function mrktable_CreateFcn(hObject, eventdata, handles)
% hObject    handle to mrktable (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called


% --- Executes when selected cell(s) is changed in mrktable.
function mrktable_CellSelectionCallback(hObject, eventdata, handles)
% hObject    handle to mrktable (see GCBO)
% eventdata  structure with the following fields (see UITABLE)
%	Indices: row and column indices of the cell(s) currently selecteds
% handles    structure with handles and user data (see GUIDATA)
set(hObject,'Interruptible','off'); %This prevents an unintended reentrance into collection loop.
ImageProp = getappdata(handles.axes1, 'PropData');
sel = eventdata.Indices;
if (numel(sel) == 0)||(sel(2)~= 1)%only go on if first column is selected
    return
end
 numstr = get(handles.NumMarkers, 'String');
 nummarks = round(str2double(numstr));

for i=sel(1):nummarks
ActiveMarker = i;
axes(handles.axes1);

% reset image, slider, and path to first one in sequence
Imageout = drawmrkrs(ImageProp.Data, handles);
files = get(handles.slider1,'UserData');
file = char(files(1));
set(handles.path,'String', file);
set(handles.slider1,'Value', 1);

%prompt to pick point
prompt = strcat('Select Marker #',num2str(ActiveMarker));
set(text(10,32,prompt), 'FontSize', 14, 'Color', 'Red')
[x,y,button] = ginput(1); % get marker location

if button==3 %right click
    BadData=1;
elseif button==27 %ESC key
    BadData=1;
elseif (x<0)||(y<0)||(x>ImageProp.Xdim)||(y>ImageProp.Ydim)%bound to be within figure limits
    BadData=1;
else
    BadData=0;
end
% clean up screen before returning
if BadData==1
    Imageout = drawmrkrs(ImageProp.Data, handles);
    table = get(hObject,'Data');
    set(hObject,'Data', table);
    return
end
%determine if select assist is enabled and if so, modify selection point
assist = get(handles.SelectAssist, 'Value');
if assist == 1 %centroid calculation on circular markers
    %targradius = round(str2double(get(handles.AssistRadius,'String')));% divide by 2 to treat as diameter instead
    centers = find_cents(ImageProp.Data,x,y,round(str2double(get(handles.AssistRadius,'String')))); %run centroid calc
    x=centers(1); %replace x and y
    y=centers(2);
end

table = get(hObject,'Data');
table(ActiveMarker,2) = round(x);
table(ActiveMarker,3) = round(y);
set(hObject,'Data', table);
Imageout = drawmrkrs(ImageProp.Data, handles);
end



% --- Executes on button press in help.
function help_Callback(hObject, eventdata, handles)
% hObject    handle to help (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
open('MotionAnalyst2D_help.pdf');


% --- Executes on button press in BegTrack.
function BegTrack_Callback(hObject, eventdata, handles)
% hObject    handle to BegTrack (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% write control file to current directory
writedata('control file.csv', handles);

%build path to control file and get file type 
    path = get(handles.path,'String');
    [pathstr, name, ext, versn] = fileparts(path);

% run texture coorelation software    
MotionAnalyst_tc_multi_points (pathstr);

% --- Executes when user attempts to close figure1.
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% Hint: delete(hObject) closes the figure
if isequal(get(hObject, 'waitstatus'), 'waiting')
    % The GUI is still in UIWAIT, use UIRESUME and return
    uiresume(hObject);
else
    % The GUI is no longer waiting, so destroy it now.
    delete(hObject);
end


% --- Executes when entered data in editable cell(s) in mrktable.
function mrktable_CellEditCallback(hObject, eventdata, handles)
% hObject    handle to mrktable (see GCBO)
% eventdata  structure with the following fields (see UITABLE)
%	Indices: row and column indices of the cell(s) edited
%	PreviousData: previous data for the cell(s) edited
%	EditData: string(s) entered by the user
%	NewData: EditData or its converted form set on the Data property. Empty if Data was not changed
%	Error: error string when failed to convert EditData to appropriate value for Data
% handles    structure with handles and user data (see GUIDATA)
ImageProp = getappdata(handles.axes1, 'PropData');
sel = eventdata.Indices;
if (numel(sel) == 0)||(sel(2)== 1)%only go on if first column is not selected
    return
end

% reset image, slider, and path to first one in sequence
files = get(handles.slider1,'UserData');
file = char(files(1));
set(handles.path,'String', file);
set(handles.slider1,'Value', 1);

% check which column it is and cap the data at the image size
if sel(2)==2
    newval = bound(str2double(eventdata.EditData),ImageProp.Xdim,1);
elseif sel(2)==3
    newval = bound(str2double(eventdata.EditData),ImageProp.Ydim,1);
end
table = get(hObject,'Data');
table(sel(1),sel(2)) = newval;
set(hObject,'Data', table);

drawmrkrs(ImageProp.Data, handles);


% --- Executes on button press in SaveMarkers.
function SaveMarkers_Callback(hObject, eventdata, handles)
% hObject    handle to SaveMarkers (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

[fname,pname] = uiputfile('*.csv','Enter data file');
if (fname ~= 0)
writedata(fname, handles);
end


% --- Executes on button press in SearchColor.
function SearchColor_Callback(hObject, eventdata, handles)
% hObject    handle to SearchColor (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
color = uisetcolor;
set(hObject,'BackgroundColor',color);
ImageProp = getappdata(handles.axes1, 'PropData');
drawmrkrs(ImageProp.Data, handles);

% --- Executes on button press in TargetColor.
function TargetColor_Callback(hObject, eventdata, handles)
% hObject    handle to TargetColor (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
color = uisetcolor;
set(hObject,'BackgroundColor',color);
ImageProp = getappdata(handles.axes1, 'PropData');
drawmrkrs(ImageProp.Data, handles);

% --- Executes on button press in MarkerColor.
function MarkerColor_Callback(hObject, eventdata, handles)
% hObject    handle to MarkerColor (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
color = uisetcolor;
set(hObject,'BackgroundColor',color);
ImageProp = getappdata(handles.axes1, 'PropData');
drawmrkrs(ImageProp.Data, handles);

%===========================================================
function writedata(filename, handles);
	% write the data to the control file
    
    %get all data required for control file
    nummark = get(handles.NumMarkers, 'String');
    targetrad = get(handles.TargetRad, 'String');
    srchrad = get(handles.SearchRad, 'String');
    numframes = get(handles.NumFrames, 'String');
    interp = get(handles.Interpolate, 'Value');
    
    %format marker positions to write to file
    table = get(handles.mrktable,'Data');
    for i=1:2
    data(:,i) = table(:,i+1);
    end
    sizedata = size(data);
    nums = sizedata(1)*sizedata(2);
    data = reshape(data',1,nums);
    datapnts = '';
    commas = '';
    for i = 1:nums
        commas = strcat(commas,',');
        datapnts = strcat(datapnts,',',num2str(data(i)));
    end
    
    %build path to control file and get file type 
    path = get(handles.path,'String');
    [pathstr, name, ext, versn] = fileparts(path);
    controlfile = [pathstr '\' filename];
    imtype = strrep(ext, '.', '');
    
	fid = fopen(controlfile, 'w');
	if (fid ~= -1)
        fprintf(fid, 'Directory,%s%s\n', pathstr, commas);
        fprintf(fid, 'ImageType,%s%s\n', imtype, commas);
        fprintf(fid, 'InitialXYPoints,%s\n', datapnts);
        fprintf(fid, 'TargetWidth,%s%s\n',targetrad, commas);
        fprintf(fid, 'SearchWidth,%s%s\n', srchrad, commas);
        fprintf(fid, 'Interpolate,%s%s\n', num2str(interp), commas);
        fprintf(fid, 'NumFramesToDisplay,%s%s\n', numframes, commas);
		fclose(fid);
	else
		fprintf('Error: cannot write points to %s\n', controlfile);
    end	
    


% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of
%        slider
try 
ImageProp = getappdata(handles.axes1, 'PropData');
Imagesize = size(ImageProp.Data);
catch ME1   %only go on if an image is displayed
    set(hObject,'Value', 0);
    return
end

slidevalue = round(get(hObject,'Value'));
files = get(hObject,'UserData');
file = char(files(slidevalue));
Imagraw = imread(file);
imagedims = size(Imagraw);
if max(size(size(Imagraw)))==2 % if it is greyscale (2 dimensional array)
    for i=1:3
    Imagraw = im2uint8(Imagraw);%ensure images are converted to 8-bit.
    Imagrgb(:,:,i) = Imagraw; %convert to rgb by making all colors the same
    end
elseif imagedims(3)==4 % if it contains alpha channel (4 dimensional array)
    Imagraw = im2uint8(Imagraw);%ensure images are converted to 8-bit.
    Imagraw(:,:,4) = []; %remove alpha channel
    Imagrgb = Imagraw; %convert to rgb by making all colors the same
else
    Imagrgb = Imagraw;
end
drawmrkrs(Imagrgb, handles);
set(handles.path,'String', file);

% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% This function uses a "center of mass" technique to refine a marker
% selection point to be a centroid of the object that was roughly selected
% written by Scott Sibole.  Cleveland Clinic CoBi Core. March 2011
function [centers] = find_cents(img,x,y,offset)
    centers = zeros(length(x),2);
    for i = 1:length(x)
        % make a box around picked point with side lengths of 2x offset
        % and extract subimage in box
        dmy = img(round(y(i)-offset):round(y(i)+offset),round(x(i)-offset):round(x(i)+offset),1:3);
        
        % convert RGB tiff data to greyscale
        dmy = rgb2gray(dmy);
        
        % get maximum and minimum greyscale intensities
        maxI = max(max(dmy));
        minI = min(min(dmy));
        
        % 1D array to get mean and standard deviation
        dmy2 = reshape(dmy,numel(dmy),1);
        
        % get mean and standard deviations of image intensities
        meanI = mean(dmy2);
        stdI = std(double(dmy2));
        
        % pixels more than 1 standard deviation less than the mean are set
        % to minimum intensity
        dmy(dmy<double(meanI)-stdI) = minI;
        
        % pixels more than e standard deviations more than the mean are set
        % to maximum intensity
        dmy(dmy>double(meanI)+exp(1)*stdI) = minI;
        
        % all pixels not included in last 2 ranges set to maximum inensity
        dmy(dmy~=minI) = maxI;
        
        % get threshold of greyscale data
        threshold = graythresh(dmy);
        % convert greyscale to logical black and white based on threshold
        dmy = im2bw(dmy,threshold);
        % invert the logical matrix
        dmy = ~ dmy;
        % fill any holes in markers
        dmy = imfill(dmy,'holes');
        

        CoMn = [0,0]; %numerator in center of mass equation
        CoMd = 0; %denominator in center of mass equation
        
        
        %tmp = -(double(dmy) - 255*ones(size(dmy)));
        for j = 1:size(dmy,1)
            for k = 1:size(dmy,2)
                CoMn = CoMn + double(dmy(j,k))*[j,k]; %sum in numerator
                CoMd = CoMd + double(dmy(j,k)); %sum in denominator
            end
        end
        
        %debug plotting
        %figure(i)
        %tmp = cast(tmp,'uint8');
        %imshow(dmy);

        % calculate center of mass
        dmy = CoMn/CoMd + double([y(i)-offset,x(i)-offset]);

        % swap indices and save to centers array
        centers(i,1) = dmy(1,2);
        centers(i,2) = dmy(1,1);
    end


% --- Executes on button press in SelectAssist.
function SelectAssist_Callback(hObject, eventdata, handles)
% hObject    handle to SelectAssist (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of SelectAssist
% 1=checked, 0=unchecked

 assist = get(hObject,'Value');
 if assist == 1
    set(handles.AssistRadius,'Visible','on');
    set(handles.AssistRadiusLbl,'Visible','on'); 
 else
    set(handles.AssistRadius,'Visible','off');
    set(handles.AssistRadiusLbl,'Visible','off'); 
 end

function AssistRadius_Callback(hObject, eventdata, handles)
% hObject    handle to AssistRadius (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AssistRadius as text
%        str2double(get(hObject,'String')) returns contents of AssistRadius as a double


% --- Executes during object creation, after setting all properties.
function AssistRadius_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AssistRadius (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
