Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
671 lines (619 sloc) 28.5 KB
function [FreezingEpisodes] = SignX(InputFiles)
%%SignX - A GUI to perform freezing detection.
%
% Uses the motion output from the tracking GUI and the original movie
% to extract freezing episodes and display the results. Parameters can
% then be adjusted to give the best results. The same parameters are
% usually usable for different animals in the same conditions.
%
% - Uses a motion threshold to detect freezing episodes
% - Allows to merge episodes closer than a defined gap
% - Defines a minimum freezing duration
% - Allows manual editing/removal of single episodes
% (e.g. sometimes to remove grooming detected as freezing)
%
% Output: a new variable in the .mat tracking file with the start/end
% times of each freezing episode
%
% The current version has not been tested for compatibility and
% dependencies; in particular, it might not run under MATLAB versions
% older than R2018a. Also, unlike the tracking GUI, it needs the frames
% timestamps, that are currently either retrieved from the tracking
% file or a file generated by our acquisition system. This will soon be
% expanded to accommodate different systems.
%
% Future implementations/changes:
% - Expand the manual
% - Switch from function to class for more robustness and ease of
% use on successive files
% - Make the overall code less dependent on the recording system
% - Use the calibration option from the tracking GUI to get an even
% more absolute freezing threshold (here it is influenced by the
% real pixel size, that depends on the camera distance)
% - Take into account potential differences in screen
% resolutions/sizes
% - Add inputs checking
% - Adjust some parameters to get a smooth browsing (some movies
% have ridiculous FPS and resolution that are too heavy to handle
% like this)
% - Add the possibility to compute a "moving" background
%
% Copyright (C) 2019 Jérémy Signoret-Genest, DefenseCircuitsLab
%
% 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
% (at your option) 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 <https://www.gnu.org/licenses/>.
if nargin == 0,
[FileName,FilePath] = uigetfile({'*.avi;*.mp4;*.m4v;*.mpg;*.mkv;*.wmv;*.mov'}); % Precise path here for more convenience
if isempty(FileName),
return
end
InputFiles = fullfile(FilePath,FileName);
else
% Check inputs
end
if ~iscell(InputFiles),
InputFiles = {InputFiles};
end
for ir = 1 : numel(InputFiles),
OnlineReading = true;
MergeThreshold = 0.2;
FreezingMinTime = 2;
ThresholdMM = 1.5;
SmoothMM = 3;
[PathFile,FileName,~] = fileparts(InputFiles{ir});
if contains(InputFiles{ir},'_IR'),
MovieType = 'Thermal';
FileName = FileName(1:end-3);
AviName = [PathFile,'\',FileName,'_IR.avi'];
else
MovieType = 'RGB';
AviName = [PathFile,'\',FileName,'.avi'];
end
%% Retrieve data
disp(['Processing file ' num2str(ir) ' out of ' num2str(numel(InputFiles)) '...'])
TrackingLog = [PathFile,'\',FileName,'_Tracking'];
Tracking = load(TrackingLog);
% numFrames = Tracking.(MovieType).FramesNum;
Contour = Tracking.(MovieType).Contour;
Center_GF = Tracking.(MovieType).Center;
if ~isfield(Tracking.(MovieType),'Times')
if strcmpi(MovieType,'RGB'),
MM_File = [PathFile '\' FileName '.DVT'];
DVTRead = csvread(MM_File);
Times = DVTRead(:,2);
else
error('No time information found.');
end
else
Times = Tracking.(MovieType).Times;
end
if strcmpi(MovieType,'Thermal'),
Times = (round(Times-Times(1))/10)/100;
end
Frame0 = VideoReader(AviName);
FrameTimes = (1/Frame0.FrameRate : 1/Frame0.FrameRate : Frame0.Duration)-1/Frame0.FrameRate;
% if ~OnlineReading,
% disp(newline)
% disp('Retrieving all frames...')
% Frames = cell(numFrames,1);
% parfor F = 1 : numFrames-1,
% FrameF = Frame0;
% FrameF.CurrentTime = FrameTimes(F);
% Frames{F} = FrameF.readFrame;
% end
% end
% Get freezing events
MotionMeasure = Tracking.(MovieType).MotionMeasure;
MotionMeasure(isnan(MotionMeasure)) = 0;
Contour(isinf(MotionMeasure)) = {[NaN;NaN]};
Contour(cellfun('isempty', Contour)) = {[NaN;NaN]};
MotionMeasure(isinf(MotionMeasure)) = 100;
LoadedFE = false;
if isfield(Tracking.(MovieType),'Freezing'),
if isfield(Tracking.(MovieType).Freezing,'Ranges'),
if ~isempty(Tracking.(MovieType).Freezing.Ranges),
FreezingEpisodes = Tracking.(MovieType).Freezing.Ranges;
ThresholdMM = Tracking.(MovieType).Freezing.MotionMeasureThreshold;
MergeThreshold = Tracking.(MovieType).Freezing.MergingThreshold;
FreezingMinTime = Tracking.(MovieType).Freezing.Duration;
SmoothMM = Tracking.(MovieType).Freezing.Smoothing;
LoadedFE = true;
end
end
end
if ~LoadedFE
FindIndex = find(Smooth(MotionMeasure,SmoothMM)<ThresholdMM);
FreezingEpisodes = FindContinuousRange(FindIndex);
FreezingEpisodes = FindIndex(FreezingEpisodes(:,[1 2]));
FreezingEpisodes = Times(FreezingEpisodes);
% Merging
for KF = 2 : numel(FreezingEpisodes(:,1))
if (FreezingEpisodes(KF,1)-FreezingEpisodes(KF-1,2))<MergeThreshold,
FreezingEpisodes(KF-1,2) = FreezingEpisodes(KF,2);
FreezingEpisodes(KF,1) = FreezingEpisodes(KF-1,1);
end
end
FreezingEpisodesLength = (FreezingEpisodes(:,2)-FreezingEpisodes(:,1));
FreezingEpisodes(FreezingEpisodesLength<=FreezingMinTime,:) = [];
[~,FreezingEpisodesIndex] = unique(FreezingEpisodes(:,1));
FreezingEpisodes = FreezingEpisodes(FreezingEpisodesIndex,:);
end
OriginalEpisodes = FreezingEpisodes;
%% Prepare figure and UI
Scrsz = get(0,'ScreenSize');
Fig = figure('Position',[Scrsz(3)/10 50 4/5*Scrsz(3) Scrsz(4)-150]);
SubMovie = subplot('Position',[0.075 0.4290 0.4167 0.5161]);
SubMM = subplot('Position',[0.075 2*(1-0.9451) 1-0.0449-0.075 1-4*(1-0.9451)-0.5161]);
SubFreezing = subplot('Position',[SubMM.Position(1) SubMM.Position(2)+SubMM.Position(4) SubMM.Position(3) 0.5*(1-0.9451)]);
MouseID = uicontrol('Style','text','String',FileName,'FontSize',14,'FontName','Arial','FontWeight','bold',...
'Units','Normalized','Position',[0.075 0.95 0.2 0.025],'HorizontalAlignment','left');
LockedZoom = uicontrol('Style','checkbox','String',' Lock Y-Axis','Value',true,'FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@YZoom,'Units','Normalized','Position',[0.8 0.6 0.15 0.025]);
CancelAdjustment = uicontrol('Style','pushbutton','String','Cancel last adjustment','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@RevertLastAdjustment,'Units','Normalized','Position',[0.55 0.525 0.175 0.05]);
CancelDeletion = uicontrol('Style','pushbutton','String','Cancel last deletion','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@CancelLastDeletion,'Units','Normalized','Position',[0.55 0.585 0.175 0.05]);
Delete = uicontrol('Style','pushbutton','String','Delete selected episode','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@DeleteEpisode,'Units','Normalized','Position',[0.55 0.645 0.175 0.05]);
PlayButton = uicontrol('Style','pushbutton','String','Play','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@SetPlay,'Units','Normalized','Position',[0.62 0.45 0.07 0.05]);
PauseButton = uicontrol('Style','pushbutton','String','Pause','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@PauseMovie,'Units','Normalized','Position',[0.69 0.45 0.07 0.05]);
DecreaseRateButton = uicontrol('Style','pushbutton','String','Slower','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@DecreaseFrameRate,'Units','Normalized','Position',[0.55 0.45 0.07 0.05]);
IncreaseRateButton = uicontrol('Style','pushbutton','String','Faster','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@IncreaseFrameRate,'Units','Normalized','Position',[0.76 0.45 0.07 0.05]);
ThresholdEdit = uicontrol('Style','edit','String',num2str(ThresholdMM),'FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@EditThreshold,'Units','Normalized','Position',[0.55 0.80 0.05 0.04]);
ThresholdLegend = uicontrol('Style','text','String','Freezing threshold','FontSize',14,'FontName','Arial','FontWeight','bold',...
'Units','Normalized','Position',[0.55 0.85 0.15 0.03],'HorizontalAlignment','left');
ThresholdDrag = uicontrol('Style','pushbutton','String','Drag','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@DragThreshold,'Units','Normalized','Position',[0.55 0.75 0.05 0.04],'HorizontalAlignment','left');
ThresholdEditSet = uicontrol('Style','pushbutton','String','Set','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@EditThresholdSet,'Units','Normalized','Position',[0.6005 0.80 0.05 0.04],'HorizontalAlignment','left');
MergeThresholdEdit = uicontrol('Style','edit','String',num2str(MergeThreshold),'FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@MergeEditThreshold,'Units','Normalized','Position',[0.7 0.80 0.05 0.04]);
MergeThresholdLegend = uicontrol('Style','text','String','Merging threshold (s)','FontSize',14,'FontName','Arial','FontWeight','bold',...
'Units','Normalized','Position',[0.7 0.85 0.15 0.03],'HorizontalAlignment','left');
MergeThresholdEditSet = uicontrol('Style','pushbutton','String','Set','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@MergeEditThresholdSet,'Units','Normalized','Position',[0.7505 0.80 0.05 0.04],'HorizontalAlignment','left');
MinEpisodeLegend = uicontrol('Style','text','String','Minimum (s)','FontSize',14,'FontName','Arial','FontWeight','bold',...
'Units','Normalized','Position',[0.85 0.85 0.15 0.03],'HorizontalAlignment','left');
MinEpisodeEdit = uicontrol('Style','edit','String',num2str(FreezingMinTime),'FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@EditMinEpisode,'Units','Normalized','Position',[0.85 0.80 0.05 0.04]);
MinEpisodeEditSet = uicontrol('Style','pushbutton','String','Set','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@EditMinEpisodeSet,'Units','Normalized','Position',[0.9005 0.80 0.05 0.04],'HorizontalAlignment','left');
ValidateButton = uicontrol('Style','pushbutton','String','Validate','FontSize',16,'FontName','Arial','FontWeight','bold',...
'Callback',@Exit,'Units','Normalized','Position',[0.8850 0.01 0.0700 0.0500],'HorizontalAlignment','left');
%% Initialize
% if ~OnlineReading,
% ImFrame = image(Frames{1},'Parent',SubMovie);
% else
if strcmpi(MovieType,'Thermal'),
ImFrame = imagesc(rgb2gray(Frame0.readFrame),'Parent',SubMovie);
HW = load('HotWhite');
SubMovie.Colormap = HW.HotWhite;
SubMovie.CLim = [25 175];
else
ImFrame = image(Frame0.readFrame,'Parent',SubMovie);
end
% end
hold(SubMovie,'on')
drawnow
ContourPlot = plot(Contour{1}(1,:),Contour{1}(2,:),'k','LineWidth',2.5,'Parent',SubMovie);
uistack(ContourPlot,'top')
CenterPlot = plot(Center_GF(1,1),Center_GF(1,2),'+k','LineWidth',2.5,'MarkerSize',5,'Parent',SubMovie);
uistack(CenterPlot,'top')
SpeedText = text(0.9*Frame0.Width,0.95*Frame0.Height,'x1','FontSize',22,'FontName','Arial','FontWeight','bold','Color','k','Parent',SubMovie);
uistack(SpeedText,'top')
if OnlineReading,
TimeText = text(0.05*Frame0.Width,0.95*Frame0.Height,'0','FontSize',22,'FontName','Arial','FontWeight','bold','Color','k','Parent',SubMovie);
end
uistack(TimeText,'top')
hold(SubMovie,'off')
SubMovie.XColor = 'none';
SubMovie.YColor = 'none';
plot(Times(2:end),Smooth(MotionMeasure,SmoothMM),'LineWidth',1.5,'Parent',SubMM);
hold(SubMM,'on')
drawnow
YlimMM = SubMM.YLim;
% Prepare a hidden plot for the threshold
ThresholdLine = plot(Times([2 end]),[1 1],'Color','none','LineWidth',1.5,'Parent',SubMM);
PimpAxis(SubMM,'xlabel','Time(s)','ylabel','Motion Measure')
SubMM.XLim = [-5 Times(end)];
LineCurrentTime = plot([0 0],[0 500],'LineWidth',2.5,'Parent',SubMM,'ButtonDownFcn',@TimeLine);
SubMM.YLim = YlimMM;
linkaxes([SubMM SubFreezing],'x')
hold(SubFreezing,'on');
FreezingHandles = arrayfun(@(x) plot([FreezingEpisodes(x,1) FreezingEpisodes(x,2)],[0 0],'k','LineWidth',3,'Parent',SubFreezing,'Tag',num2str(x),'ButtonDownFcn',@FreezingEdit),1:numel(FreezingEpisodes(:,1)));
SubFreezing.XColor = 'none';
SubFreezing.YColor = 'none';
SubFreezing.YLim = [-0.5 0.5];
drawnow
ZoomHandleSubFreezing = zoom(SubFreezing);
ZoomHandleSubFreezing.Motion = 'horizontal';
ZoomHandleSubFreezing.ActionPostCallback = @EvaluateWindow;
ZoomHandleSubMM = zoom(SubMM);
ZoomHandleSubMM.Motion = 'horizontal';
ZoomHandleSubMM.ActionPostCallback = @EvaluateWindow;
Edition = false;
DeletionIndex = [];
SelectedEpisode = [];
LeftLimit = [];
RightLimit = [];
Dragging = false;
AdjustedRanges = [];
CurrentTime = 0;
Play = false;
PrePlayState = [];
FrameRate = Frame0.FrameRate;
ShiftTimeLine = 0.2;
drawnow
ReProcessFreezing;
waitfor(Fig);
end
function YZoom(src,~)
if src.Value==0,
ZoomHandleSubMM.Motion = 'both';
else
ZoomHandleSubMM.Motion = 'horizontal';
end
end
function IncreaseFrameRate(~,~)
FrameRate = FrameRate*2;
SpeedText.String = ['x' num2str(round(FrameRate/Frame0.FrameRate*10)/10)];
uistack(SpeedText,'top')
drawnow
end
function SetPlay(~,~)
Play = true;
PlayMovie;
end
function DecreaseFrameRate(~,~)
FrameRate = FrameRate/2;
SpeedText.String = ['x' num2str(round(FrameRate/Frame0.FrameRate*10)/10)];
uistack(SpeedText,'top')
drawnow
end
function FreezingEdit(src,~)
% Check if an episode is being edited
if ~Edition
% Make sure the playing has stopped
PrePlayState = Play;
Play = false;
% Get episode index
SelectedEpisode = str2double(src.Tag);
% Change line appearence
src.LineWidth = 2.5;
src.Color = [0.85,0.33,0.10];
% Change callback
src.ButtonDownFcn = @FreezingEndEdit;
% Draw bars on limits
LeftLimit = plot([FreezingEpisodes(SelectedEpisode,1) FreezingEpisodes(SelectedEpisode,1)],[-0.25 0.25],'k','LineWidth',2,'ButtonDownFcn',@DragLimitLeft);
RightLimit = plot([FreezingEpisodes(SelectedEpisode,2) FreezingEpisodes(SelectedEpisode,2)],[-0.25 0.25],'k','LineWidth',2,'ButtonDownFcn',@DragLimitRight);
% Set status
Edition = true;
end
end
function DragLimitLeft(~,~)
if ~Dragging,
Dragging = true;
Fig.WindowButtonMotionFcn = @MovingCursorLeft;
Fig.WindowButtonUpFcn = @DragLimitLeft;
else
Dragging = false;
Fig.WindowButtonMotionFcn = [];
Fig.WindowButtonUpFcn = [];
AdjustedRanges = [AdjustedRanges;SelectedEpisode];
FreezingEpisodes(SelectedEpisode,1) = LeftLimit.XData(1);
end
end
function MovingCursorLeft(~,~)
CurrentCursor = SubFreezing.CurrentPoint;
if CurrentCursor(1)<FreezingEpisodes(SelectedEpisode,2),
LeftLimit.XData = [CurrentCursor(1) CurrentCursor(1)];
FreezingHandles(SelectedEpisode).XData(1) = CurrentCursor(1);
end
end
function DragLimitRight(~,~)
if ~Dragging,
Dragging = true;
Fig.WindowButtonMotionFcn = @MovingCursorRight;
Fig.WindowButtonUpFcn = @DragLimitRight;
else
Dragging = false;
Fig.WindowButtonMotionFcn = [];
Fig.WindowButtonUpFcn = [];
FreezingEpisodes(SelectedEpisode,2) = RightLimit.XData(1);
end
end
function MovingCursorRight(~,~)
CurrentCursor = SubFreezing.CurrentPoint;
if CurrentCursor(1)>FreezingEpisodes(SelectedEpisode,1),
RightLimit.XData = [CurrentCursor(1) CurrentCursor(1)];
FreezingHandles(SelectedEpisode).XData(2) = CurrentCursor(1);
end
end
function RevertLastAdjustment(~,~)
if ~isempty(AdjustedRanges),
FreezingEpisodes(AdjustedRanges(end),:) = OriginalEpisodes(AdjustedRanges(end),:);
FreezingHandles(AdjustedRanges(end)).XData = OriginalEpisodes(AdjustedRanges(end),:);
AdjustedRanges(end) = [];
end
end
function FreezingEndEdit(src,~)
% Revert appearence
src.LineWidth = 3;
src.Color = 'k';
% Set status
Edition = false;
AdjustedRanges = [AdjustedRanges;SelectedEpisode];
FreezingEpisodes(SelectedEpisode,1) = LeftLimit.XData(1);
FreezingEpisodes(SelectedEpisode,2) = RightLimit.XData(1);
SelectedEpisode = [];
% Remove bars on limits
delete(LeftLimit)
delete(RightLimit)
% Change callback
src.ButtonDownFcn = @FreezingEdit;
% Restore playing state
Play = PrePlayState;
end
function DeleteEpisode(~,~)
if ~isempty(SelectedEpisode),
% Remove bars on limits
delete(LeftLimit)
delete(RightLimit)
FreezingHandles(SelectedEpisode).LineWidth = 3;
FreezingHandles(SelectedEpisode).ButtonDownFcn = [];
FreezingHandles(SelectedEpisode).Color = 'none';
DeletionIndex = [DeletionIndex,SelectedEpisode];
% Set status
Edition = false;
SelectedEpisode = [];
% Restore playing state
Play = PrePlayState;
end
end
function CancelLastDeletion(~,~)
if ~isempty(DeletionIndex),
FreezingHandles(DeletionIndex(end)).Color = 'k';
FreezingHandles(DeletionIndex(end)).ButtonDownFcn = @FreezingEdit;
DeletionIndex(end) = [];
end
end
function TimeLine(~,~)
if ~Dragging,
PrePlayState = Play;
Play = false;
Dragging = true;
Fig.WindowButtonMotionFcn = @MovingTimeLine;
Fig.WindowButtonUpFcn = @TimeLine;
else
Dragging = false;
Fig.WindowButtonMotionFcn = [];
Fig.WindowButtonUpFcn = [];
Play = PrePlayState;
PlayMovie;
end
end
function MovingTimeLine(~,~)
CurrentCursor = SubMM.CurrentPoint;
if CurrentCursor(1)>=0 && CurrentCursor(1)<=Times(end),
if CurrentCursor(1) >= SubMM.XLim(2),
NewY = SubMM.XLim(2) + 0.025*diff(SubMM.XLim);
if NewY<=Times(end),
SubMM.XLim = SubMM.XLim + 0.025*diff(SubMM.XLim);
else
SubMM.XLim = SubMM.XLim+(Times(end)-SubMM.XLim(2));
end
CurrentTime = SubMM.XLim(2);
elseif CurrentCursor(1) <= SubMM.XLim(1),
NewY = SubMM.XLim(1) - 0.025*diff(SubMM.XLim);
if NewY<=Times(end),
SubMM.XLim = SubMM.XLim - 0.025*diff(SubMM.XLim);
else
SubMM.XLim = SubMM.XLim - (SubMM.XLim(1));
end
CurrentTime = SubMM.XLim(1);
else
CurrentTime = CurrentCursor(1);
end
end
LineCurrentTime.XData = [CurrentTime CurrentTime];
FrameUpdate;
end
function FrameUpdate(~,~)
NewIndex = FindInInterval(Times,[CurrentTime CurrentTime]);
% if ~OnlineReading,
% ImFrame.CData = Frames{NewIndex(1)};
% else
ContourPlot.XData = Contour{NewIndex(1)}(1,:);
ContourPlot.YData = Contour{NewIndex(1)}(2,:);
CenterPlot.XData = Center_GF(NewIndex(1),1);
CenterPlot.YData = Center_GF(NewIndex(1),2);
Frame0.CurrentTime = FrameTimes(NewIndex(1));
if strcmpi(MovieType,'Thermal'),
ImFrame.CData = rgb2gray(Frame0.readFrame);
else
ImFrame.CData = (Frame0.readFrame);
end
TimeText.String = num2str(Times(NewIndex(1)));
% end
uistack(SpeedText,'top')
drawnow
end
function EvaluateWindow(~,~)
PrePlayState = Play;
Play = false;
if SubMM.XLim(1)<0,
SubMM.XLim(1) = 0;
elseif SubMM.XLim(2)>Times(end),
SubMM.XLim(2) = Times(end);
end
if CurrentTime<SubMM.XLim(1) || CurrentTime>SubMM.XLim(2),
CurrentTime = SubMM.XLim(1) + 0.5*diff(SubMM.XLim);
LineCurrentTime.XData = [CurrentTime CurrentTime];
FrameUpdate;
end
Play = PrePlayState;
PlayMovie;
end
function PlayMovie(~,~)
if Play
% Only approximate framerate (for faster plotting)
CurrentTime = CurrentTime+1/FrameRate;
CurrentIndex = FindInInterval(Times,[CurrentTime CurrentTime]);
% Plot once to get a starting value for the delay
tic
% if ~OnlineReading,
% ImFrame.CData = Frames{CurrentIndex(1)};
% else
CurrentIndex = FindInInterval(Times,[CurrentTime CurrentTime]);
ContourPlot.XData = Contour{CurrentIndex(1)}(1,:);
ContourPlot.YData = Contour{CurrentIndex(1)}(2,:);
CenterPlot.XData = Center_GF(CurrentIndex(1),1);
CenterPlot.YData = Center_GF(CurrentIndex(1),2);
Frame0.CurrentTime = FrameTimes(CurrentIndex(1));
if strcmpi(MovieType,'Thermal'),
ImFrame.CData = rgb2gray(Frame0.readFrame);
else
ImFrame.CData = (Frame0.readFrame);
end
TimeText.String = num2str(Times(CurrentIndex(1)));
% end
uistack(SpeedText,'top')
LineCurrentTime.XData = [Times(CurrentIndex(1)) Times(CurrentIndex(1))];
drawnow
end
while Play
TocT = toc;
EstimatedShift = TocT*FrameRate;
if EstimatedShift>1
tic;
CurrentIndex = CurrentIndex + round(EstimatedShift);
CurrentTime = Times(CurrentIndex(1));
% if ~OnlineReading,
% ImFrame.CData = Frames{CurrentIndex(1)};
% else
ContourPlot.XData = Contour{CurrentIndex(1)}(1,:);
ContourPlot.YData = Contour{CurrentIndex(1)}(2,:);
CenterPlot.XData = Center_GF(CurrentIndex(1),1);
CenterPlot.YData = Center_GF(CurrentIndex(1),2);
Frame0.CurrentTime = FrameTimes(CurrentIndex(1));
if strcmpi(MovieType,'Thermal'),
ImFrame.CData = rgb2gray(Frame0.readFrame);
else
ImFrame.CData = (Frame0.readFrame);
end
TimeText.String = num2str(Times(CurrentIndex(1)));
% end
uistack(SpeedText,'top')
LineCurrentTime.XData = [CurrentTime CurrentTime];
if CurrentTime>=(SubMM.XLim(2)-ShiftTimeLine*diff(SubMM.XLim)),
SubMM.XLim = SubMM.XLim + CurrentTime-SubMM.XLim(2)+ShiftTimeLine*diff(SubMM.XLim);
end
drawnow
end
end
end
function PauseMovie(~,~)
Play = false;
end
function EditThreshold(src,~)
end
function EditThresholdSet(~,~)
if str2double(ThresholdEdit.String)>0,
ThresholdMM = str2double(ThresholdEdit.String);
ThresholdLine.Color = 'none';
ThresholdLine.ButtonDownFcn = [];
ReProcessFreezing;
end
end
function DragThreshold(~,~)
ThresholdLine.Color = [0.85,0.33,0.10];
ThresholdLine.ButtonDownFcn = @StartDragThreshold;
uistack(ThresholdLine,'top')
Play = false;
Dragging = false;
end
function StartDragThreshold(~,~)
if ~Dragging,
Fig.WindowButtonMotionFcn = @MovingThresholdLine;
Fig.WindowButtonUpFcn = @StartDragThreshold;
Dragging = true;
else
Dragging = false;
Fig.WindowButtonMotionFcn = [];
Fig.WindowButtonUpFcn = [];
end
end
function MovingThresholdLine(~,~)
CurrentCursor = SubMM.CurrentPoint;
if CurrentCursor(1,2)>=0 && CurrentCursor(1,2)<=SubMM.YLim(2),
ThresholdLine.YData = [CurrentCursor(1,2) CurrentCursor(1,2)];
ThresholdEdit.String = num2str(CurrentCursor(1,2));
drawnow;
end
end
function MergeEditThreshold(~,~)
end
function MergeEditThresholdSet(~,~)
if str2double(MergeThresholdEdit.String)>=0,
MergeThreshold = str2double(MergeThresholdEdit.String);
ReProcessFreezing;
end
end
function EditMinEpisode(~,~)
end
function EditMinEpisodeSet(~,~)
if str2double(MinEpisodeEdit.String)>0,
FreezingMinTime = str2double(MinEpisodeEdit.String);
ReProcessFreezing;
end
end
function ReProcessFreezing(~,~)
FindIndex = find(Smooth(MotionMeasure,SmoothMM)<ThresholdMM);
FreezingEpisodes = FindContinuousRange(FindIndex);
FreezingEpisodes = FindIndex(FreezingEpisodes(:,[1 2]));
FreezingEpisodes = Times(FreezingEpisodes);
% Merging
for KFS = 2 : numel(FreezingEpisodes(:,1))
if (FreezingEpisodes(KFS,1)-FreezingEpisodes(KFS-1,2))<MergeThreshold,
FreezingEpisodes(KFS,1) = FreezingEpisodes(KFS-1,1);
FreezingEpisodes(KFS-1,:) = NaN(1,2);
end
end
FreezingEpisodes = FreezingEpisodes(~isnan(FreezingEpisodes(:,1)),:);
FreezingEpisodesLength = (FreezingEpisodes(:,2)-FreezingEpisodes(:,1));
FreezingEpisodes(FreezingEpisodesLength<=FreezingMinTime,:) = [];
OriginalEpisodes = FreezingEpisodes;
delete(FreezingHandles(:));
FreezingHandles = arrayfun(@(x) plot([FreezingEpisodes(x,1) FreezingEpisodes(x,2)],[0 0],'k','LineWidth',3,'Parent',SubFreezing,'Tag',num2str(x),'ButtonDownFcn',@FreezingEdit),1:numel(FreezingEpisodes(:,1)));
SubFreezing.XColor = 'none';
SubFreezing.YColor = 'none';
SubFreezing.YLim = [-0.5 0.5];
end
function Exit(~,~)
Play = false;
FreezingEpisodes(DeletionIndex,:) = [];
% Add to logfile
Tracking.(MovieType).Freezing.MotionMeasureThreshold = ThresholdMM;
Tracking.(MovieType).Freezing.MergingThreshold = MergeThreshold;
Tracking.(MovieType).Freezing.Duration = FreezingMinTime;
Tracking.(MovieType).Freezing.Smoothing = SmoothMM;
Tracking.(MovieType).Freezing.Ranges = FreezingEpisodes;
save(TrackingLog,'-struct','Tracking')
close(Fig)
end
end
You can’t perform that action at this time.