0001 function varargout = FTrack(varargin)
0002
0003
0004
0005
0006
0007
0008 gui_Singleton = 1;
0009 gui_State = struct('gui_Name', mfilename, ...
0010 'gui_Singleton', gui_Singleton, ...
0011 'gui_OpeningFcn', @FTrack_OpeningFcn, ...
0012 'gui_OutputFcn', @FTrack_OutputFcn, ...
0013 'gui_LayoutFcn', [] , ...
0014 'gui_Callback', []);
0015 if nargin && ischar(varargin{1})
0016 gui_State.gui_Callback = str2func(varargin{1});
0017 end
0018
0019 if nargout
0020 [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
0021 else
0022 gui_mainfcn(gui_State, varargin{:});
0023 end
0024
0025
0026
0027
0028 function FTrack_OpeningFcn(hObject, eventdata, handles, varargin)
0029
0030
0031
0032
0033
0034
0035
0036 handles.output = hObject;
0037
0038
0039 guidata(hObject, handles);
0040 disp('Welcome to FTrack!')
0041 warning off all
0042
0043
0044
0045
0046
0047
0048
0049 function varargout = FTrack_OutputFcn(hObject, eventdata, handles)
0050
0051
0052
0053
0054
0055
0056 varargout{1} = handles.output;
0057
0058
0059
0060 function load_video_Callback(hObject, eventdata, handles)
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 [filename, pathname] = uigetfile({'*.avi;*.mpg;*.mp2','Video Files (*.avi,*.mpg,*.mp2)'}, 'Pick a video', 'MultiSelect','on');
0071 if iscell(filename)
0072 NFiles = length(filename);
0073 else
0074 NFiles = 1;
0075 filename = {filename};
0076 end
0077
0078 if isequal(filename,0) || isequal(pathname,0)
0079 disp('File select canceled')
0080 else
0081 for i = 1:NFiles
0082 disp(['Video selected: ', fullfile(pathname, filename{i})])
0083 handles.filename{i} = fullfile(pathname, filename{i});
0084 end
0085 end
0086
0087 guidata(gcbo,handles);
0088
0089
0090
0091
0092 function viewframe_Callback(hObject, eventdata, handles)
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 filename = handles.filename;
0104 if iscell(filename)
0105 NFiles = length(filename);
0106 else
0107 NFiles = 1;
0108 filename = {filename};
0109 end
0110
0111 for i = 1:NFiles
0112 video = videoReader(filename{i});
0113 seek(video,1);
0114 info = getinfo(video);
0115 img = getframe(video);
0116 figure
0117 imagesc(img)
0118 title(filename{i})
0119 disp(['Video name:',filename{i}])
0120 disp(['Video dimensions [Width, Height]: [', num2str(info.width),' , ' num2str(info.height),']'])
0121 disp(['Number of frames: ',num2str(info.numFrames)])
0122 disp(['Frame rate: ',num2str(info.fps),' frames/s'])
0123
0124 handles.VideoInfo(i) = info;
0125 end
0126
0127 disp('Frame Viewer Finished')
0128 guidata(gcbo, handles);
0129
0130
0131
0132 function arena_dims_Callback(hObject, eventdata, handles)
0133
0134
0135
0136
0137 filename = handles.filename;
0138 if iscell(filename)
0139 NFiles = length(filename);
0140 else
0141 NFiles = 1;
0142 filename = {filename};
0143 end
0144
0145 p = [];
0146 q = [];
0147 for i = 1:NFiles
0148 video = videoReader(filename{i});
0149 info = getinfo(video);
0150 seek(video,1);
0151 img = getframe(video);
0152 sz = size(img);
0153 figure
0154 colormap gray
0155 imagesc(img)
0156 axis image
0157 title({filename{i}; 'Left click to select points on boundary of arena. Press return when done.'})
0158
0159
0160 [p q] = ginput;
0161
0162
0163
0164 ellipse = fit_ellipse(p',q','y');
0165 semiminor = min(ellipse.a,ellipse.b);
0166 semimajor = max(ellipse.a,ellipse.b);
0167 ellipse.epsilon = sqrt(1-semiminor^2/semimajor^2);
0168 ellipse.psi = asin(ellipse.epsilon);
0169 ellipse.semiminor = semiminor;
0170 ellipse.semimajor = semimajor;
0171
0172 rotated_ellipse = ellipse.rotated_ellipse;
0173 ellipse.points_selected = [p q];
0174 title('Arena w/ Boundary')
0175 ellipse.boundaries = [ rotated_ellipse(1,:)', info.height-rotated_ellipse(2,:)'];
0176
0177 info = handles.VideoInfo(i);
0178 figure
0179 title('Masking arena. Please wait...')
0180 drawnow
0181 disp('Masking arena...')
0182 mask = zeros(info.height, info.width);
0183 for k=1:info.height
0184 for j=1:info.width
0185 rot = inv(ellipse.R)*[j;k];
0186 testpoint = (rot(1)-ellipse.X0).^2/(ellipse.a).^2+(rot(2)-ellipse.Y0).^2/(ellipse.b).^2;
0187 if (testpoint <= 1.01)
0188 mask(k,j) = 1;
0189 end
0190 end
0191 end
0192 ellipse.mask = double(mask);
0193 handles.arena{i} = ellipse;
0194
0195 imagesc(double(img(:,:,1)).*double(mask))
0196 axis image
0197 colormap gray
0198 title('Portion to be tracked')
0199
0200 end
0201
0202
0203
0204 disp('Arena Dimensions Calculated')
0205 disp(ellipse)
0206 guidata(gcbo, handles);
0207
0208
0209
0210 function input_params_Callback(hObject, eventdata, handles)
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220 filename = handles.filename;
0221 if iscell(filename)
0222 NFiles = length(filename);
0223 else
0224 Nfiles = 1;
0225 filename = {filename};
0226 end
0227 UserIn = [];
0228
0229 for i = 1:NFiles
0230 first = strvcat(filename{i}, ' ','Output directory');
0231 prompt = {first,'Start Frame (Remember that first frame is indexed 0)','End Frame:', 'Initial background size:', 'Arena radius (cm)', 'Bounding box half-size (in pixels)','Background weight (0.9 < a < 1)'};
0232 dlg_title = ['Input Paramters'];
0233 num_lines = 1;
0234 defaults = {'C:\Documents and Settings\liam\My Documents\LabVIEW Data\FTrack output','0','999', '100','7.5','10','0.9'};
0235 options.Resize='on';
0236 options.WindowStyle='normal';
0237 answer = inputdlg(prompt,dlg_title,num_lines,defaults, options);
0238 UserIn = [UserIn answer];
0239 disp(['Input parameters have been entered for ', filename{i}])
0240
0241 InputData(i).OutputPath = UserIn{1,i};
0242 InputData(i).StartFrame = str2double(UserIn(2,i));
0243 InputData(i).EndFrame = str2double(UserIn(3,i));
0244 InputData(i).NBackFrames = str2double(UserIn(4,i));
0245 InputData(i).ArenaRadius = str2double(UserIn(5,i));
0246 InputData(i).sqrsize = str2double(UserIn(6,i));
0247 InputData(i).alpha = str2double(UserIn(7,i));
0248
0249 end
0250
0251 handles.InputData = InputData;
0252
0253 guidata(gcbo, handles);
0254
0255
0256
0257
0258
0259 function find_opt_CreateFcn(hObject, eventdata, handles)
0260
0261
0262
0263
0264
0265
0266 function find_opt_SelectionChangeFcn(hObject, eventdata, handles)
0267
0268
0269
0270
0271
0272
0273
0274
0275 function neg_opt_CreateFcn(hObject, eventdata, handles)
0276
0277
0278
0279
0280
0281 function neg_opt_SelectionChangeFcn(hObject, eventdata, handles)
0282
0283
0284
0285
0286
0287
0288
0289 function TrackStart_Callback(hObject, eventdata, handles)
0290
0291
0292
0293
0294
0295
0296
0297 filename = handles.filename;
0298 InputData = handles.InputData;
0299
0300 if iscell(filename)
0301 NVideos = length(filename);
0302 else
0303 NVideos = 1;
0304 filename = {filename};
0305 end
0306
0307 neg_opt = get(get(handles.neg_opt,'SelectedObject'), 'Tag');
0308
0309
0310 for i=1:NVideos
0311
0312
0313 info = handles.VideoInfo(i);
0314 FrameRate = info.fps;
0315 FrameRange = [InputData(i).StartFrame:InputData(i).EndFrame];
0316
0317
0318 [x, y, orientation] = FlyTracker(filename{i}, FrameRange,...
0319 InputData(i).NBackFrames, neg_opt, InputData(i).sqrsize,...
0320 InputData(i).alpha, handles.arena{i});
0321
0322
0323 if (info.numFrames == InputData(i).EndFrame)
0324 InputData(i).EndFrame = InputData(i).EndFrame-1;
0325 elseif (info.numFrames < InputData(i).EndFrame)
0326 InputData(i).EndFrame = info.numFrames-1;
0327 end
0328
0329 t = [InputData(i).StartFrame:InputData.EndFrame(i)]/FrameRate;
0330
0331
0332 handles.x = x;
0333 handles.y = y;
0334 handles.orientation = orientation;
0335 handles.t = t;
0336
0337 guidata(gcbo, handles);
0338
0339
0340
0341 out = SaveFiles(i,handles);
0342
0343 end
0344 disp('Tracking Complete.')
0345
0346
0347
0348
0349
0350 function view_traj_Callback(hObject, eventdata, handles)
0351
0352
0353
0354
0355 [filename, pathname] = ...
0356 uigetfile({'*.mat'},'Select Raw Trajectory Data');
0357
0358 if isequal(filename,0) || isequal(pathname,0)
0359 disp('File select canceled')
0360 return;
0361 else
0362 fullname = fullfile(pathname, filename);
0363 end
0364
0365
0366 load(fullname)
0367 figure
0368 set(gcf,'Name',fullname)
0369 subplot(2,2,1)
0370 plot(t,x)
0371 xlim([0 t(end)])
0372 xlabel('Time (s)')
0373 ylabel('cm')
0374 title('Raw x data')
0375 subplot(2,2,3)
0376 plot(t,y)
0377 xlim([0 t(end)])
0378 xlabel('Time (s)')
0379 ylabel('cm')
0380 title('Raw y data')
0381 subplot(2,2,[2 4])
0382 plot(x,y)
0383 xlabel('x position (cm)')
0384 ylabel('y position (cm)')
0385 title('Raw Trajectory')
0386 axis equal
0387
0388 handles.filename = filename;
0389 handles.x = x;
0390 handles.y = y;
0391 handles.orientation = orientation;
0392 handles.t = t;
0393 handles.VideoInfo = VideoInfo;
0394 handles.InputData = InputData;
0395 handles.arena{1} = arena;
0396
0397 guidata(gcbo, handles);
0398
0399
0400
0401
0402
0403 function clean_x_Callback(hObject, eventdata, handles)
0404
0405
0406
0407
0408 x = handles.x;
0409 filename = handles.filename;
0410
0411
0412 figure
0413 plot(x)
0414 title('Zoom in if necessary. Press any key to continue.')
0415 xlabel('Frame')
0416 ylabel('cm')
0417 pause
0418
0419
0420
0421
0422
0423 while(1)
0424 title('Define region of data to clean: left, right, baseline, threshold. Hit Return to exit.')
0425 [p q] = ginput(4);
0426 if isempty(p)
0427 close;
0428 disp('X data has been cleaned.')
0429 out = SaveFiles(1,handles);
0430 return;
0431 else
0432 rnge = floor(p(1)):floor(p(2));
0433 end
0434
0435 if (q(3) > q(4))
0436 choice = 'below';
0437 elseif (q(3) < q(4));
0438 choice = 'above';
0439 end
0440 epsilon = q(4);
0441
0442 x = CleanData(x, rnge, choice, epsilon);
0443 handles.x = x;
0444 guidata(gcbo, handles)
0445 ax = gca;
0446 xlim_temp = get(ax, 'XLim');
0447 ylim_temp = get(ax, 'YLim');
0448
0449
0450 figure
0451 plot(x)
0452 xlim(xlim_temp);
0453 ylim(ylim_temp);
0454 xlabel('Frame')
0455 ylabel('cm')
0456 title('Zoom in if necessary. Press any key to continue.')
0457 pause
0458 end
0459
0460
0461
0462
0463 function clean_y_Callback(hObject, eventdata, handles)
0464
0465
0466
0467
0468 y = handles.y;
0469 filename = handles.filename;
0470
0471 figure(2)
0472 plot(y)
0473 xlabel('Frame')
0474 ylabel('cm')
0475 title('Zoom in if necessary. Press any key to continue.')
0476 pause
0477
0478
0479
0480
0481
0482 while(1)
0483 title('Define region of data to clean: left, right, baseline, threshold. Hit Return to exit.')
0484 [p q] = ginput(4);
0485 if isempty(p)
0486 close;
0487 disp('Y data has been cleaned.')
0488 out = SaveFiles(1,handles);
0489 return;
0490 else
0491 rnge = floor(p(1)):floor(p(2));
0492 end
0493
0494 if (q(3) > q(4))
0495 choice = 'below';
0496 elseif (q(3) < q(4));
0497 choice = 'above';
0498 end
0499 epsilon = q(4);
0500
0501 y = CleanData(y, rnge, choice, epsilon);
0502 handles.y = y;
0503 guidata(gcbo, handles)
0504 ax = gca;
0505 xlim_temp = get(ax, 'XLim');
0506 ylim_temp = get(ax, 'YLim');
0507
0508
0509 figure(2)
0510 plot(y)
0511 xlim(xlim_temp);
0512 ylim(ylim_temp);
0513 xlabel('Frame')
0514 ylabel('cm')
0515 title('Zoom in if necessary. Press any key to continue.')
0516 pause
0517 end
0518
0519 return;
0520
0521 function out = SaveFiles(i,handles)
0522
0523 if iscell(handles.filename)
0524 filename = handles.filename{i};
0525 else
0526 filename = handles.filename;
0527 end
0528
0529 OutputPath = handles.InputData(i).OutputPath;
0530 x = handles.x;
0531 y = handles.y;
0532 t = handles.t;
0533 orientation = handles.orientation;
0534 InputData = handles.InputData(i);
0535 VideoInfo = handles.VideoInfo(i);
0536 arena = handles.arena{i};
0537
0538 [temp, name, ext, versn] = fileparts(filename);
0539
0540 name_mat = strcat(name,'.mat');
0541 name_xy=strcat(name,'.xy');
0542 name_ori=strcat(name,'.ori');
0543 save_filename = fullfile(OutputPath,name);
0544 save_filename_xy = fullfile(OutputPath,name_xy);
0545 save_filename_ori = fullfile(OutputPath,name_ori);
0546 ori=handles.orientation(1,:)';
0547 xy=[handles.x' handles.y'];
0548 save(save_filename,'x','y','t','orientation','InputData', 'VideoInfo','arena')
0549 disp(['Saved ',save_filename])
0550 save(save_filename_xy,'xy','-ascii','-tabs');
0551 disp(['Saved ',save_filename_xy])
0552 save(save_filename_ori,'ori','-ascii','-tabs');
0553 disp(['Saved ',save_filename_ori])
0554 out = 1;
0555
0556 return;
0557
0558
0559
0560 function tilt_correct_Callback(hObject, eventdata, handles)
0561
0562
0563
0564
0565
0566
0567
0568
0569 x = handles.x;
0570 y = handles.y;
0571 t = handles.t;
0572 ellipse = handles.arena{1};
0573 radius_in_cm = handles.InputData.ArenaRadius;
0574 video = videoReader(handles.VideoInfo.url);
0575 info = getinfo(video);
0576 height = info.height;
0577
0578 psi = ellipse.psi;
0579 phi = ellipse.phi;
0580
0581
0582 rotated_ellipse(:,1) = ellipse.boundaries(:,1)-ellipse.X0_in;
0583 rotated_ellipse(:,2) = ellipse.boundaries(:,2)-(height-ellipse.Y0_in);
0584
0585 M = [cos(phi) sin(phi);-sin(phi) cos(phi)];
0586
0587
0588 if (ellipse.a > ellipse.b)
0589 L = [1 0; 0 ellipse.a/ellipse.b];
0590 else
0591 L = [ellipse.b/ellipse.a 0; 0 1];
0592 end
0593
0594 T = L*M;
0595
0596 disp('Correcting for camera tilt. This may take a few minutes, so be patient!')
0597
0598 z = zeros(1,length(rotated_ellipse(:,1)));
0599
0600
0601 for j = 1:length(rotated_ellipse(:,1))
0602 temp = T*[rotated_ellipse(j,1); rotated_ellipse(j,2)];
0603 xe(j) = temp(1);
0604 ye(j) = temp(2);
0605 end
0606
0607
0608 z = zeros(1,length(x));
0609 new_ellipse = fit_ellipse(xe',ye','n');
0610
0611 semiminor = min(new_ellipse.a,new_ellipse.b);
0612 semimajor = max(new_ellipse.a,new_ellipse.b);
0613 new_ellipse.epsilon = sqrt(1-semiminor^2/semimajor^2);
0614 new_ellipse.psi = asin(new_ellipse.epsilon);
0615 new_ellipse.semiminor = semiminor;
0616 new_ellipse.semimajor = semimajor;
0617 new_ellipse.boundaries = [xe' ye'];
0618
0619
0620 for j = 1:length(x)
0621 temp = T*[x(j)-ellipse.X0_in; y(j)-(height-ellipse.Y0_in)];
0622 xp(j) = temp(1);
0623 yp(j) = temp(2);
0624 end
0625
0626
0627 if (abs(new_ellipse.b-new_ellipse.a) <= 2)
0628 disp('Tilt corrected')
0629 pixels_in_cm = semimajor/radius_in_cm;
0630
0631 x = (xp)/pixels_in_cm;
0632 y = (yp)/pixels_in_cm;
0633
0634 figure
0635 plot(x,y,new_ellipse.boundaries(:,1)/pixels_in_cm,new_ellipse.boundaries(:,2)/pixels_in_cm,'r')
0636 title('Transformed trajectory with boundary')
0637
0638 handles.arena{1}=new_ellipse;
0639 handles.x = x;
0640 handles.y = y;
0641 handles.InputData.pixels_in_cm = pixels_in_cm;
0642 out = SaveFiles(1,handles);
0643 else
0644 disp('Something went wrong. Arena is still an ellipse. ')
0645 end
0646
0647
0648 guidata(gcbo, handles)
0649
0650
0651
0652
0653
0654
0655