From 9dba44f6d5be4841fb8ae8fb76e46bd63e2ffd41 Mon Sep 17 00:00:00 2001 From: Eric Wait <eric@waitphoto.com> Date: Fri, 8 Apr 2011 22:16:19 -0500 Subject: [PATCH] LEVer 3.2 --- src/MATLAB/AddHashedCell.m | 2 + src/MATLAB/AddHullToTrack.m | 2 +- src/MATLAB/ChangeLabel.m | 82 +++++--- src/MATLAB/ChangeTrackAndChildrensFamily.m | 19 +- src/MATLAB/ChangeTrackParent.m | 10 +- src/MATLAB/CloseFigure.m | 4 + src/MATLAB/CombineTrackWithParent.m | 3 + src/MATLAB/ContextChangeLabel.m | 5 +- src/MATLAB/ContextChangeParent.m | 11 +- src/MATLAB/ContextProperties.m | 2 + src/MATLAB/ContextRemoveFromTree.m | 5 +- src/MATLAB/ConvertTrackingData.m | 8 +- src/MATLAB/CreateColors.m | 2 + src/MATLAB/CreateContextMenuCells.m | 128 +++++++++--- src/MATLAB/CreateContextMenuTree.m | 6 +- src/MATLAB/CreateMenuBar.m | 25 +++ src/MATLAB/DeleteHullFromTrack.m | 2 + src/MATLAB/DrawCells.m | 5 +- src/MATLAB/DrawTree.m | 12 +- src/MATLAB/ExportImage.m | 2 + src/MATLAB/FindHull.m | 2 + src/MATLAB/GetNextColor.m | 2 + src/MATLAB/GetTrackID.m | 2 + src/MATLAB/GrayOutColor.m | 4 +- src/MATLAB/History.m | 231 ++++++++++++--------- src/MATLAB/InSubTree.m | 42 ++++ src/MATLAB/InitializeFigures.m | 2 + src/MATLAB/LEVer.m | 4 + src/MATLAB/LogAction.m | 2 + src/MATLAB/NewCellFamily.m | 5 + src/MATLAB/NewCellTrack.m | 5 + src/MATLAB/OpenData.m | 4 +- src/MATLAB/ProcessNewborns.m | 2 + src/MATLAB/RehashCellTracks.m | 15 +- src/MATLAB/RemoveFromTree.m | 37 +++- src/MATLAB/RemoveHull.m | 28 +++ src/MATLAB/RemoveTrackFromFamily.m | 28 +++ src/MATLAB/ResegmentHull.m | 48 +++++ src/MATLAB/SaveData.m | 17 +- src/MATLAB/SaveDataAs.m | 4 + src/MATLAB/SiblingDistance.m | 7 +- src/MATLAB/SplitHull.m | 25 +++ src/MATLAB/SplitTrack.m | 2 + src/MATLAB/SwapTrackLabels.m | 2 + src/MATLAB/TimeChange.m | 2 + src/MATLAB/TogglePlay.m | 5 + src/MATLAB/UpdateHashedCellsTrackID.m | 8 +- src/MATLAB/UpdateTimeIndicatorLine.m | 2 + src/MATLAB/driver.m | 65 ------ 49 files changed, 666 insertions(+), 271 deletions(-) create mode 100644 src/MATLAB/RemoveHull.m create mode 100644 src/MATLAB/RemoveTrackFromFamily.m create mode 100644 src/MATLAB/ResegmentHull.m create mode 100644 src/MATLAB/SplitHull.m delete mode 100644 src/MATLAB/driver.m diff --git a/src/MATLAB/AddHashedCell.m b/src/MATLAB/AddHashedCell.m index a6c71dd9..a0260fd9 100644 --- a/src/MATLAB/AddHashedCell.m +++ b/src/MATLAB/AddHashedCell.m @@ -2,6 +2,8 @@ function AddHashedCell(t,cellHullID,cellTrackID) %This will either add an entry to HashedHulls or update an entry based on %cellHullID +%--Eric Wait + global HashedCells if(isempty(HashedCells)) diff --git a/src/MATLAB/AddHullToTrack.m b/src/MATLAB/AddHullToTrack.m index ae8d4b5d..1b72f845 100644 --- a/src/MATLAB/AddHullToTrack.m +++ b/src/MATLAB/AddHullToTrack.m @@ -8,6 +8,7 @@ function AddHullToTrack(hullID,trackID,previousHullID) %previousHullID at previousTime exists in that track. Also, it has been %removed from any previous track assosiation. +%--Eric Wait global HashedCells CellTracks CellFamilies CellHulls @@ -37,7 +38,6 @@ if(0 >= hash) end end CellTracks(curTrackID).hulls(hash) = hullID; -% CellTracks(curTrackID).hulls(hash).time = time; if(CellTracks(curTrackID).endTime < time) CellTracks(curTrackID).endTime = time; diff --git a/src/MATLAB/ChangeLabel.m b/src/MATLAB/ChangeLabel.m index 3fe1b834..4d8109b0 100644 --- a/src/MATLAB/ChangeLabel.m +++ b/src/MATLAB/ChangeLabel.m @@ -1,4 +1,5 @@ function ChangeLabel(time,oldTrackID,newTrackID) +%ChangLabel(time,oldTrackID,newTrackID) %This will attempt to change the trackID from a given time until the end of %the track. However, the trackID will only be changed up to the point that %the newTrackID does not exist. If when moving hulls from the oldTrack to @@ -14,6 +15,8 @@ function ChangeLabel(time,oldTrackID,newTrackID) %The only time that the subtree would not move with the change would be as %stated above. +%--Eric Wait + global CellTracks CellFamilies CellHulls bothHaveChildren = 0;%flag to deal with conflicting children @@ -51,70 +54,91 @@ else RehashCellTracks(oldTrackID,CellHulls(firstHull).time); end -%Handle children if(oldEmptied) - %update parent and sibling - if(~isempty(CellTracks(oldTrackID).siblingTrack)) - CombineTrackWithParent(CellTracks(oldTrackID).siblingTrack); - index = CellTracks(CellTracks(oldTrackID).parentTrack).childrenTracks == oldTrackID; - CellTracks(CellTracks(oldTrackID).parentTrack).childrenTracks(index) = []; - end - - %update family - index = [CellFamilies(CellTracks(oldTrackID).familyID).tracks]==oldTrackID; - CellFamilies(CellTracks(oldTrackID).familyID).tracks(index) = []; - - %clean up other fields - CellTracks(oldTrackID).parentTrack = []; - CellTracks(oldTrackID).siblingTrack = []; - CellTracks(oldTrackID).startTime = []; - CellTracks(oldTrackID).endTime = []; - CellTracks(oldTrackID).color = []; - - %deal with any children if(oldBeforeNew) + %deal with any children if(~isempty(CellTracks(oldTrackID).childrenTracks)) - dropChildren(CellTracks(oldTrackID).childrenTracks); + dropChildren(oldTrackID); + end + if(~isempty(CellTracks(newTrackID).siblingTrack) && ... + isempty(find(CellTracks(oldTrackID).childrenTracks==CellTracks(newTrackID).siblingTrack, 1))) + CombineTrackWithParent(CellTracks(newTrackID).siblingTrack); end + CellTracks(newTrackID).parentTrack = CellTracks(oldTrackID).parentTrack; + index = CellTracks(CellTracks(newTrackID).parentTrack).childrenTracks==oldTrackID; + CellTracks(CellTracks(newTrackID).parentTrack).childrenTracks(index) = newTrackID; + CellTracks(newTrackID).siblingTrack = CellTracks(oldTrackID).siblingTrack; + CellTracks(newTrackID).familyID = CellTracks(oldTrackID).familyID; elseif(newBeforeOld) + %deal with any children if(bothHaveChildren) - dropChildren(CellTracks(newTrackID).childrenTracks); + index = CellTracks(newTrackID).childrenTracks==oldTrackID; + if(~isempty(find(index, 1))) + RemoveFromTree(CellTracks(CellTracks(newTrackID).childrenTracks(~index)).startTime,... + CellTracks(newTrackID).childrenTracks(~index),'no'); + CellTracks(newTrackID).childrenTracks = []; + CellTracks(oldTrackID).siblingTrack = []; + else + dropChildren(newTrackID); + end moveChildren(oldTrackID,newTrackID); elseif(~isempty(CellTracks(newTrackID).childrenTracks)) - dropChildren(CellTracks(newTrackID).childrenTracks); + index = CellTracks(newTrackID).childrenTracks==oldTrackID; + if(~isempty(find(index, 1))) + RemoveFromTree(CellTracks(CellTracks(newTrackID).childrenTracks(~index)).startTime,... + CellTracks(newTrackID).childrenTracks(~index),'no'); + CellTracks(newTrackID).childrenTracks = []; + CellTracks(oldTrackID).siblingTrack = []; + else + dropChildren(newTrackID); + end elseif(~isempty(CellTracks(oldTrackID).childrenTracks)) moveChildren(oldTrackID,newTrackID); end + if(~isempty(CellTracks(oldTrackID).siblingTrack) && ... + isempty(find(CellTracks(newTrackID).childrenTracks==CellTracks(oldTrackID).siblingTrack, 1))) + CombineTrackWithParent(CellTracks(oldTrackID).siblingTrack); + end end + + %clean up other fields + RemoveTrackFromFamily(oldTrackID); + CellTracks(oldTrackID).parentTrack = []; + CellTracks(oldTrackID).siblingTrack = []; + CellTracks(oldTrackID).startTime = []; + CellTracks(oldTrackID).endTime = []; + CellTracks(oldTrackID).color = []; else %the old track still exists in some fasion if(isempty(find(CellTracks(oldTrackID).hulls==lastOldHull, 1)) &&... ~isempty(CellTracks(oldTrackID).childrenTracks)) %the last hull from the old track has been moved over and had %children if(CellHulls(lastOldHull).time<CellTracks(newTrackID).endTime) - dropChildren(CellTracks(oldTrackID).childrenTracks); + dropChildren(oldTrackID); elseif(CellHulls(lastOldHull).time>=CellTracks(newTrackID).endTime) if(~isempty(CellTracks(newTrackID).childrenTracks)) - dropChildren(CellTracks(newTrackID).childrenTracks); + dropChildren(newTrackID); end moveChildren(oldTrackID,newTrackID); end elseif(isempty(find(CellTracks(oldTrackID).hulls==lastOldHull, 1)) &&... CellHulls(lastOldHull).time>CellTracks(newTrackID).endTime &&... ~isempty(CellTracks(newTrackID).childrenTracks)) - dropChildren(CellTracks(newTrackID).childrenTracks); + dropChildren(newTrackID); end end end -function dropChildren(children) +function dropChildren(trackID) %remove children from tree global CellTracks familyIDs = []; -for i=1:length(children) - familyIDs = [familyIDs RemoveFromTree(CellTracks(children(i)).startTime,children(i))]; +while ~isempty(CellTracks(trackID).childrenTracks) + familyIDs = [familyIDs RemoveFromTree(CellTracks(CellTracks(trackID).childrenTracks(1)).startTime,CellTracks(trackID).childrenTracks(1),'no')]; end + +CellTracks(trackID).childrenTracks = []; %run processNewborns on them ProcessNewborns(familyIDs); end diff --git a/src/MATLAB/ChangeTrackAndChildrensFamily.m b/src/MATLAB/ChangeTrackAndChildrensFamily.m index 227c1b91..043a07ee 100644 --- a/src/MATLAB/ChangeTrackAndChildrensFamily.m +++ b/src/MATLAB/ChangeTrackAndChildrensFamily.m @@ -4,6 +4,8 @@ function ChangeTrackAndChildrensFamily(oldFamilyID,newFamilyID,trackID) %This DOES NOT make the parent child relationship, it is just updates the %CellFamilies data structure. +%--Eric Wait + global CellFamilies CellTracks %get the full list of tracks to be updateded @@ -12,8 +14,7 @@ trackList = traverseTree(newFamilyID,trackID); %remove tracks from family for i=1:length(trackList) CellTracks(trackList(i)).familyID = newFamilyID; - index = CellFamilies(oldFamilyID).tracks == trackList(i); - CellFamilies(oldFamilyID).tracks(index) = []; +% RemoveTrackFromFamily(trackList(i)); end if(isempty(CellFamilies(oldFamilyID).tracks)) @@ -22,16 +23,8 @@ if(isempty(CellFamilies(oldFamilyID).tracks)) CellFamilies(oldFamilyID).endTime = []; else %update times - CellFamilies(oldFamilyID).startTime = CellTracks(CellFamilies(oldFamilyID).tracks(1)).startTime; - CellFamilies(oldFamilyID).endTime = CellTracks(CellFamilies(oldFamilyID).tracks(1)).endTime; - for i=2:length(CellFamilies(oldFamilyID).tracks) - if(CellTracks(CellFamilies(oldFamilyID).tracks(i)).startTime < CellFamilies(oldFamilyID).startTime) - CellFamilies(oldFamilyID).startTime = CellTracks(CellFamilies(oldFamilyID).tracks(i)).startTime; - end - if(CellTracks(CellFamilies(oldFamilyID).tracks(i)).endTime > CellFamilies(oldFamilyID).endTime) - CellFamilies(oldFamilyID).endTime = CellTracks(CellFamilies(oldFamilyID).tracks(i)).endTime; - end - end + CellFamilies(oldFamilyID).startTime = min([CellTracks(CellFamilies(oldFamilyID).tracks).startTime]); + CellFamilies(oldFamilyID).endTime = max([CellTracks(CellFamilies(oldFamilyID).tracks).endTime]); end end @@ -57,4 +50,6 @@ if(~isempty(CellTracks(trackID).childrenTracks)) trackList = [trackList traverseTree(newFamilyID, CellTracks(trackID).childrenTracks(i))]; end end + +RemoveTrackFromFamily(trackID); end diff --git a/src/MATLAB/ChangeTrackParent.m b/src/MATLAB/ChangeTrackParent.m index c4e4216d..fcc5aef5 100644 --- a/src/MATLAB/ChangeTrackParent.m +++ b/src/MATLAB/ChangeTrackParent.m @@ -5,7 +5,15 @@ function ChangeTrackParent(parentTrackID,time,childTrackID) %there should be a new track and the child track that are siblings with the %parent track being the parent. -global CellTracks +%--Eric Wait + +global CellTracks CellFamilies + +%see if the child exists before time +if(time > CellTracks(childTrackID).startTime) + newFamilyID = RemoveFromTree(time,childTrackID,'yes'); + childTrackID = CellFamilies(newFamilyID).rootTrackID; +end %find where the child should attach to the parent hash = time - CellTracks(parentTrackID).startTime + 1; diff --git a/src/MATLAB/CloseFigure.m b/src/MATLAB/CloseFigure.m index edb65e73..d6cc4533 100644 --- a/src/MATLAB/CloseFigure.m +++ b/src/MATLAB/CloseFigure.m @@ -1,4 +1,8 @@ function CloseFigure(varargin) +%Closes both figures and cleans up the Figures global var + +%--Eric Wait + global Figures if(strcmp(get(Figures.cells.menuHandles.saveMenu,'Enable'),'on')) choice = questdlg('Save current edits before closing?','Closing','Yes','No','Cancel','Cancel'); diff --git a/src/MATLAB/CombineTrackWithParent.m b/src/MATLAB/CombineTrackWithParent.m index 9a0556bd..b55598df 100644 --- a/src/MATLAB/CombineTrackWithParent.m +++ b/src/MATLAB/CombineTrackWithParent.m @@ -1,4 +1,5 @@ function CombineTrackWithParent(trackID) +% CombineTrackWithParent(trackID) %Combine childTrack with its parent track - in otherwords the childtrack %will be merged into the parent track making it all one edge. %Afterward all of the hulls previously associated with the given track will @@ -7,6 +8,8 @@ function CombineTrackWithParent(trackID) %***Make sure that the sibling of the given track has been delt with prior %to calling this function. IT WILL BE LOST +%--Eric Wait + global CellFamilies CellTracks CellHulls parentID = CellTracks(trackID).parentTrack; diff --git a/src/MATLAB/ContextChangeLabel.m b/src/MATLAB/ContextChangeLabel.m index 05111ec7..5ce3f145 100644 --- a/src/MATLAB/ContextChangeLabel.m +++ b/src/MATLAB/ContextChangeLabel.m @@ -1,5 +1,8 @@ function ContextChangeLabel(time,trackID) %context menu callback function + +%--Eric Wait + global CellTracks HashedCells newTrackID = inputdlg('Enter New Label','New Label',1,{num2str(trackID)}); @@ -11,7 +14,7 @@ if(newTrackID>length(CellTracks) || isempty(CellTracks(newTrackID).hulls)) switch choice case 'Yes' oldFamily = CellTracks(trackID).familyID; - RemoveFromTree(time,trackID); + RemoveFromTree(time,trackID,'yes'); History('Push'); LogAction(['Removed ' num2str(trackID) ' From Tree'], oldFamily,CellTracks(trackID).familyID); case 'Cancel' diff --git a/src/MATLAB/ContextChangeParent.m b/src/MATLAB/ContextChangeParent.m index 82714593..2172cf5f 100644 --- a/src/MATLAB/ContextChangeParent.m +++ b/src/MATLAB/ContextChangeParent.m @@ -1,12 +1,15 @@ -function ContextChangeParent(trackID) +function ContextChangeParent(trackID,time) %Function for context menu call back + +%--Eric Wait + global CellTracks newParentID = inputdlg('Enter New Parent','New Parent',1,{num2str(CellTracks(trackID).parentTrack)}); if(isempty(newParentID)),return,end; newParentID = str2double(newParentID(1)); -if(CellTracks(newParentID).startTime > CellTracks(trackID).startTime) +if(CellTracks(newParentID).startTime > time) msgbox(['Parent ' num2str(newParentID) ' comes after ' num2str(trackID) ' consider a different edit.'],'Parent Change','warn'); return elseif(CellTracks(trackID).endTime < CellTracks(newParentID).startTime) @@ -15,11 +18,11 @@ elseif(CellTracks(trackID).endTime < CellTracks(newParentID).startTime) end oldParent = CellTracks(trackID).parentTrack; -ChangeTrackParent(newParentID,CellTracks(trackID).startTime,trackID); +ChangeTrackParent(newParentID,time,trackID); History('Push'); LogAction(['Changed parent of ' num2str(trackID)],oldParent,newParentID); -DrawTree(CellTracks(trackID).familyID); +DrawTree(CellTracks(newParentID).familyID); DrawCells(); end diff --git a/src/MATLAB/ContextProperties.m b/src/MATLAB/ContextProperties.m index a528f090..7e007c8f 100644 --- a/src/MATLAB/ContextProperties.m +++ b/src/MATLAB/ContextProperties.m @@ -1,6 +1,8 @@ function ContextProperties(hullID,trackID) %context menu callback function +%--Eric Wait + global CellTracks Figures %collect all the data that will be passed to the properties UI diff --git a/src/MATLAB/ContextRemoveFromTree.m b/src/MATLAB/ContextRemoveFromTree.m index c32bad1c..fc187c9f 100644 --- a/src/MATLAB/ContextRemoveFromTree.m +++ b/src/MATLAB/ContextRemoveFromTree.m @@ -1,10 +1,13 @@ function ContextRemoveFromTree(time,trackID) %context menu callback function + +%--Eric Wait + global CellTracks oldFamilyID = CellTracks(trackID).familyID; -newFamilyID = RemoveFromTree(time, trackID); +newFamilyID = RemoveFromTree(time, trackID,'yes'); History('Push'); LogAction(['Removed part or all of ' num2str(trackID) ' from tree'],oldFamilyID,newFamilyID); diff --git a/src/MATLAB/ConvertTrackingData.m b/src/MATLAB/ConvertTrackingData.m index 8141d4eb..bad774e2 100644 --- a/src/MATLAB/ConvertTrackingData.m +++ b/src/MATLAB/ConvertTrackingData.m @@ -2,10 +2,12 @@ function ConvertTrackingData(objHulls,gConnect) %Takes the data structure from the tracking data and creates LEVer's data %scheme +%--Eric Wait + global CONSTANTS Costs HashedCells CellHulls CellFamilies %Initialize CONSTANTS -CONSTANTS.ImageSize = unique([objHulls(:).imSize]); +CONSTANTS.imageSize = unique([objHulls(:).imSize]); CONSTANTS.maxPixelDistance = 40; CONSTANTS.maxCenterOfMassDistance = 80; CONSTANTS.minParentCandidateTimeFrame = 5; @@ -23,7 +25,8 @@ CellHulls = struct(... 'time', {objHulls(1).t},... 'points', {objHulls(1).pts},... 'centerOfMass', {objHulls(1).COM},... - 'indexPixels', {objHulls(1).indPixels}); + 'indexPixels', {objHulls(1).indPixels},... + 'deleted', {0}); if objHulls(1).inID == 0 NewCellFamily(1,objHulls(1).t); @@ -37,6 +40,7 @@ for i=2:length(objHulls) CellHulls(i).points = objHulls(i).pts; CellHulls(i).centerOfMass = objHulls(i).COM; CellHulls(i).indexPixels = objHulls(i).indPixels; + CellHulls(i).deleted = 0; if objHulls(i).inID == 0 NewCellFamily(i,objHulls(i).t); diff --git a/src/MATLAB/CreateColors.m b/src/MATLAB/CreateColors.m index 7a41b7fe..04f7f8a0 100644 --- a/src/MATLAB/CreateColors.m +++ b/src/MATLAB/CreateColors.m @@ -4,6 +4,8 @@ function colors = CreateColors() %the text is typicaly white or black depending on the darkness of the %background +%--Eric Wait + colors = [1,0,0,0,0,0,0.4,0.15,0.15;... 1,0.5,0,0,0,0,0.4,0.2,0.15;... 1,1,0,0,0,0,0.4,0.4,0.15;... diff --git a/src/MATLAB/CreateContextMenuCells.m b/src/MATLAB/CreateContextMenuCells.m index 7fc174a8..544d213a 100644 --- a/src/MATLAB/CreateContextMenuCells.m +++ b/src/MATLAB/CreateContextMenuCells.m @@ -2,6 +2,8 @@ function CreateContextMenuCells() %creates the context menu for the figure that displays the image data and %the subsequent function calls +%--Eric Wait + global Figures figure(Figures.cells.handle); @@ -15,16 +17,38 @@ uimenu(Figures.cells.contextMenuHandle,... 'Label', 'Change Parent',... 'CallBack', @changeParent); -uimenu(Figures.cells.contextMenuHandle,... +addHull = uimenu(Figures.cells.contextMenuHandle,... 'Label', 'Add Hull',... - 'CallBack', @addHull,... + 'Separator', 'on'); + +uimenu(addHull,... + 'Label', 'Number of Hulls to add'); + +uimenu(addHull,... + 'Label', '1',... 'Separator', 'on',... - 'Enable', 'off'); + 'CallBack', @addHull1); + +uimenu(addHull,... + 'Label', '2',... + 'CallBack', @addHull2); + +uimenu(addHull,... + 'Label', '3',... + 'CallBack', @addHull3); + +uimenu(addHull,... + 'Label', '4',... + 'CallBack', @addHull4); + +uimenu(addHull,... + 'Label', 'Other',... + 'Separator', 'on',... + 'CallBack', @addHullOther); uimenu(Figures.cells.contextMenuHandle,... 'Label', 'Remove Hull',... - 'CallBack', @removeHull,... - 'Enable', 'off'); + 'CallBack', @removeHull); uimenu(Figures.cells.contextMenuHandle,... 'Label', 'Mark Death',... @@ -43,37 +67,63 @@ end %% Callback functions function changeLabel(src,evnt) -global Figures HashedCells +global Figures -hullID = FindHull(get(gca,'CurrentPoint')); -tempIndex = [HashedCells{Figures.time}.hullID]==hullID; -trackID = HashedCells{Figures.time}(tempIndex).trackID; +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end ContextChangeLabel(Figures.time,trackID); end function changeParent(src,evnt) -global Figures HashedCells +global Figures +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end -hullID = FindHull(get(gca,'CurrentPoint')); -tempIndex = [HashedCells{Figures.time}.hullID]==hullID; -trackID = HashedCells{Figures.time}(tempIndex).trackID; +ContextChangeParent(trackID,Figures.time); +end + +function addHull1(src,evnt) +addHull(1); +end -ContextChangeParent(trackID); +function addHull2(src,evnt) +addHull(2); end -function addHull(src,evnt) +function addHull3(src,evnt) +addHull(3); +end + +function addHull4(src,evnt) +addHull(4); +end + +function addHullOther(src,evnt) +num = inputdlg('Enter Number of Hulls to Add','Add Hulls',1,{1}); +if(isempty(num)),return,end; +num = str2double(num(1)); +addHull(num); end function removeHull(src,evnt) +global Figures + +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end + +RemoveHull(hullID); +History('Push'); +LogAction(['Removed hull from track ' num2str(trackID)],hullID,[]); +DrawTree(Figures.tree.familyID); +DrawCells(); end function markDeath(src,evnt) -global Figures HashedCells CellTracks +global Figures CellTracks -hullID = FindHull(get(gca,'CurrentPoint')); -tempIndex = [HashedCells{Figures.time}.hullID]==hullID; -trackID = HashedCells{Figures.time}(tempIndex).trackID; +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end CellTracks(trackID).timeOfDeath = Figures.time; @@ -83,7 +133,7 @@ if(~isempty(CellTracks(trackID).childrenTracks)) for i=1:length(CellTracks(trackID).childrenTracks) familyIDs = [familyIDs ... RemoveFromTree(CellTracks(CellTracks(trackID).childrenTracks(i)).startTime,... - CellTracks(trackID).childrenTracks(i))]; + CellTracks(trackID).childrenTracks(i),'yes')]; end CellTracks(trackID).childrenTracks = []; ProcessNewborns(familyIDs); @@ -97,20 +147,42 @@ DrawCells(); end function removeFromTree(src,evnt) -global Figures HashedCells +global Figures -hullID = FindHull(get(gca,'CurrentPoint')); -tempIndex = [HashedCells{Figures.time}.hullID]==hullID; -trackID = HashedCells{Figures.time}(tempIndex).trackID; +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end ContextRemoveFromTree(Figures.time,trackID); end function properties(src,evnt) -global Figures HashedCells +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end -hullID = FindHull(get(gca,'CurrentPoint')); -tempIndex = [HashedCells{Figures.time}.hullID]==hullID; -trackID = HashedCells{Figures.time}(tempIndex).trackID; ContextProperties(hullID,trackID); end + +%% Helper functions +function addHull(num) +global Figures + +[hullID trackID] = getClosestCell(); +if(isempty(trackID)),return,end + +newTracks = SplitHull(hullID,num+1);%adding one to the number so that the original hull is accounted for + +History('Push'); +LogAction('Split cell',trackID,[trackID newTracks]); +DrawTree(Figures.tree.familyID); +DrawCells(); +end + +function [hullID trackID] = getClosestCell() +hullID = FindHull(get(gca,'CurrentPoint')); +if(0>=hullID) + warndlg('Please click closer to the center of the desired cell','Unknown Cell'); + trackID = []; + return +end +trackID = GetTrackID(hullID); +end diff --git a/src/MATLAB/CreateContextMenuTree.m b/src/MATLAB/CreateContextMenuTree.m index 70472b08..ac1a048c 100644 --- a/src/MATLAB/CreateContextMenuTree.m +++ b/src/MATLAB/CreateContextMenuTree.m @@ -2,6 +2,8 @@ function CreateContextMenuTree() %creates the context menu for the figure that displays the tree data and %the subsequent function calls +%--Eric Wait + global Figures figure(Figures.tree.handle); @@ -33,8 +35,9 @@ ContextChangeLabel(CellTracks(trackID).startTime,trackID); end function changeParent(src,evnt) +global CellTracks trackID = get(gco,'UserData'); -ContextChangeParent(trackID); +ContextChangeParent(trackID,CellTracks(trackID).startTime); end function removeFromTree(src,evnt) @@ -45,7 +48,6 @@ end function properties(src,evnt) global CellTracks - trackID = get(gco,'UserData'); ContextProperties(CellTracks(trackID).hulls(1),trackID); end diff --git a/src/MATLAB/CreateMenuBar.m b/src/MATLAB/CreateMenuBar.m index 4a4f530a..2f456f05 100644 --- a/src/MATLAB/CreateMenuBar.m +++ b/src/MATLAB/CreateMenuBar.m @@ -1,6 +1,8 @@ function CreateMenuBar(handle) %This sets up the custom menu bar for the given figure handle +%--Eric Wait + global Figures fileMenu = uimenu(... @@ -98,6 +100,13 @@ uimenu(... 'Callback', @timeJump,... 'Accelerator', 't'); +uimenu(... + 'Parent', viewMenu,... + 'Label', 'Display Largest Tree',... + 'HandleVisibility', 'callback',... + 'Callback', @largestTree,... + 'Separator', 'on'); + if(strcmp(get(handle,'Tag'),'cells')) Figures.cells.menuHandles.saveMenu = saveMenu; @@ -174,3 +183,19 @@ end UpdateTimeIndicatorLine(); DrawCells(); end + +function largestTree(src,evnt) +global CellFamilies Figures + +maxID = 1; +for i=2:length(CellFamilies) + if(length(CellFamilies(maxID).tracks) < length(CellFamilies(i).tracks)) + maxID = i; + end +end +if(Figures.tree.familyID == maxID),return,end + +Figures.tree.familyID = maxID; +DrawTree(maxID); +DrawCells(); +end diff --git a/src/MATLAB/DeleteHullFromTrack.m b/src/MATLAB/DeleteHullFromTrack.m index 67f2a5ca..e48f2f18 100644 --- a/src/MATLAB/DeleteHullFromTrack.m +++ b/src/MATLAB/DeleteHullFromTrack.m @@ -6,4 +6,6 @@ function DeleteHullFromTrack(hullID,trackID) %It is intended that AddHullToTrack will be run after this function, %otherwise this hull will cease to exist in any family or track +%--Eric Wait + end diff --git a/src/MATLAB/DrawCells.m b/src/MATLAB/DrawCells.m index ec170ab9..301da85c 100644 --- a/src/MATLAB/DrawCells.m +++ b/src/MATLAB/DrawCells.m @@ -5,6 +5,8 @@ function DrawCells() %will be more boldly colored, others will be with square labels and be %slightly grayed out +%--Eric Wait + global CellFamilies CellTracks CellHulls HashedCells Figures CONSTANTS if(isempty(CellFamilies(Figures.tree.familyID).tracks)),return,end @@ -20,7 +22,8 @@ yl=ylim; %adjust the image display hold off; -imagesc(img); +im = imagesc(img); +set(im,'uicontextmenu',Figures.cells.contextMenuHandle); set(gca,'Position',[.01 .01 .98 .98],'uicontextmenu',Figures.cells.contextMenuHandle); axis off; if xl(1)~=0 && xl(2)~=1 diff --git a/src/MATLAB/DrawTree.m b/src/MATLAB/DrawTree.m index bf464e40..9afd693d 100644 --- a/src/MATLAB/DrawTree.m +++ b/src/MATLAB/DrawTree.m @@ -1,10 +1,16 @@ function DrawTree(familyID) -%This will draw the family tree of the given family. Assumes binary tree +%This will draw the family tree of the given family. + +%--Eric Wait global CellFamilies HashedCells Figures if(isempty(CellFamilies(familyID).tracks)),return,end +%let the user know that this might take a while +set(Figures.tree.handle,'Pointer','watch'); +set(Figures.cells.handle,'Pointer','watch'); + Figures.tree.familyID = familyID; trackID = CellFamilies(familyID).tracks(1); @@ -27,6 +33,10 @@ set(gca,... Figures.tree.axesHandle = gca; hold off UpdateTimeIndicatorLine(); + +%let the user know that the drawing is done +set(Figures.tree.handle,'Pointer','arrow'); +set(Figures.cells.handle,'Pointer','arrow'); end function [xMin xCenter xMax] = traverseTree(trackID,initXmin) diff --git a/src/MATLAB/ExportImage.m b/src/MATLAB/ExportImage.m index fc07b4d7..247a888f 100644 --- a/src/MATLAB/ExportImage.m +++ b/src/MATLAB/ExportImage.m @@ -2,6 +2,8 @@ function ExportImage(figureHandle) %this function is intended to create a high resolution file of the given %figure for printing or sharing +%--Eric Wait + global Figures if(figureHandle == Figures.cells.handle) diff --git a/src/MATLAB/FindHull.m b/src/MATLAB/FindHull.m index cb4556ed..aab17521 100644 --- a/src/MATLAB/FindHull.m +++ b/src/MATLAB/FindHull.m @@ -2,6 +2,8 @@ function hullID = FindHull(curPoint) %This function will find the closest hull to the given point and return the %hullID if it is within CONSTANTS.clickMargin +%--Eric Wait + global CONSTANTS CellHulls HashedCells Figures centerOfMasses = reshape([CellHulls([HashedCells{Figures.time}(:).hullID]).centerOfMass]',2,[])'; diff --git a/src/MATLAB/GetNextColor.m b/src/MATLAB/GetNextColor.m index ddc3f5a5..63d7ab1d 100644 --- a/src/MATLAB/GetNextColor.m +++ b/src/MATLAB/GetNextColor.m @@ -2,6 +2,8 @@ function color = GetNextColor() %Takes the global Colors list and selects the next in the list and returns %it +%--Eric Wait + global Colors persistent index diff --git a/src/MATLAB/GetTrackID.m b/src/MATLAB/GetTrackID.m index aeac1249..856b576c 100644 --- a/src/MATLAB/GetTrackID.m +++ b/src/MATLAB/GetTrackID.m @@ -1,6 +1,8 @@ function trackID = GetTrackID(hullID) %Given a hull ID a track ID will be returned +%--Eric Wait + global CellHulls HashedCells hullTime = CellHulls(hullID).time; diff --git a/src/MATLAB/GrayOutColor.m b/src/MATLAB/GrayOutColor.m index 8529fe2a..1972f7b2 100644 --- a/src/MATLAB/GrayOutColor.m +++ b/src/MATLAB/GrayOutColor.m @@ -1,7 +1,9 @@ function grayedColor = GrayOutColor(color) -%this will take the given color and give back a grayed out color of similar +%This will take the given color and give back a grayed out color of similar %hue +%--Eric Wait + grayedColor = [0 0 0]; parfor i=1:3 if(0==color(i)) diff --git a/src/MATLAB/History.m b/src/MATLAB/History.m index cc2aad32..ed2d84e5 100644 --- a/src/MATLAB/History.m +++ b/src/MATLAB/History.m @@ -1,5 +1,6 @@ function History(action) -%This will keep track of any state changes. +%This will keep track of any state changes. Call this function once the +%new state is established. After the changes take place. %Possible actions are: %History('Push') = save current state to the stack %History('Pop') = retrive the last state @@ -10,158 +11,194 @@ function History(action) %All of the data structures are saved on the stack, so do not set this %value too high or you might run out of working memory +%--Eric Wait + global CellFamilies CellTracks HashedCells CONSTANTS Figures CellHulls -persistent hist; -persistent top; -persistent bottom; -persistent redo; -persistent empty; -persistent full; +persistent hist; %stack +persistent current; %points to the last state saved on the stack +persistent bottom; %points to the oldest or bottom most valid history +persistent top; %points to the youngest or top most valid history +persistent empty; %flag will be "empty" if only the original opened state is on the stack +persistent full; %flag +persistent exceededLimit; %flag to denote if CONSTANTS.historySize has ever been reached if (isempty(hist)) - top = 1;%points to next place to push or is one greater than the current history - bottom = 0;%points to the oldest or bottom most valid history - redo = 0;%points to the youngest or top most valid history - empty = 1;%flag will be "empty" if only the original opened state is on the stack - full = 0;%flag + current = 1; + bottom = 0; + top = 0; + empty = 1; + full = 0; + exceededLimit = 0; end switch action case 'Push' - set(Figures.cells.menuHandles.undoMenu,'Enable','on'); - set(Figures.cells.menuHandles.saveMenu,'Enable','on'); - set(Figures.tree.menuHandles.undoMenu,'Enable','on'); - set(Figures.tree.menuHandles.saveMenu,'Enable','on'); if (empty) empty = 0; bottom = 1; elseif (full) %drop oldest history + exceededLimit = 1; if (bottom < CONSTANTS.historySize) bottom = bottom + 1; else bottom = 1; end end - - hist(top).CellFamilies = CellFamilies; - hist(top).CellTracks = CellTracks; - hist(top).HashedCells = HashedCells; - hist(top).CellHulls = CellHulls; - hist(top).Figures.tree.familyID = Figures.tree.familyID; - - redo = top; - top = top + 1; - if (top > CONSTANTS.historySize) - top = 1; + current = current + 1; + if (current > CONSTANTS.historySize) + current = 1; end - if (top==bottom) + top = current; + + hist(current).CellFamilies = CellFamilies; + hist(current).CellTracks = CellTracks; + hist(current).HashedCells = HashedCells; + hist(current).CellHulls = CellHulls; + hist(current).Figures.tree.familyID = Figures.tree.familyID; + + if (current==bottom) full = 1; empty = 0; end - - %"Disable" redo - set(Figures.cells.menuHandles.redoMenu,'Enable','off'); - set(Figures.tree.menuHandles.redoMenu,'Enable','off'); - + setMenus(); case 'Pop' if (~empty) - if(redo < top) - top = top - 2; - else - top = top - 1; - end - if (top == 0) - top = CONSTANTS.historySize; + current = current - 1; + if (current == 0) + current = CONSTANTS.historySize; end full = 0; - if (top==bottom) + if (current==bottom) empty = 1; - set(Figures.cells.menuHandles.undoMenu,'Enable','off'); - set(Figures.cells.menuHandles.saveMenu,'Enable','off'); - set(Figures.tree.menuHandles.undoMenu,'Enable','off'); - set(Figures.tree.menuHandles.saveMenu,'Enable','off'); - else - set(Figures.cells.menuHandles.saveMenu,'Enable','on'); - set(Figures.tree.menuHandles.saveMenu,'Enable','on'); - end - - CellFamilies = hist(top).CellFamilies; - CellTracks = hist(top).CellTracks; - HashedCells = hist(top).HashedCells; - CellHulls = hist(top).CellHulls; - Figures.tree.familyID = hist(top).Figures.tree.familyID; - - %increment again so that top is always the next available place - top = top + 1; - if (top > CONSTANTS.historySize) - top = 1; end - set(Figures.cells.menuHandles.redoMenu,'Enable','on'); - set(Figures.tree.menuHandles.redoMenu,'Enable','on'); + CellFamilies = hist(current).CellFamilies; + CellTracks = hist(current).CellTracks; + HashedCells = hist(current).HashedCells; + CellHulls = hist(current).CellHulls; + Figures.tree.familyID = hist(current).Figures.tree.familyID; %Update displays DrawTree(Figures.tree.familyID); DrawCells(); - + setMenus(); LogAction('Undo',[],[]); - else - set(Figures.cells.menuHandles.redoMenu,'Enable','off'); - set(Figures.tree.menuHandles.redoMenu,'Enable','off'); end - case 'Redo' - if (redo>=top || (top<bottom && redo<top)) + if (top>current || (bottom>top && top~=current)) %redo possible - - CellFamilies = hist(top).CellFamilies; - CellTracks = hist(top).CellTracks; - HashedCells = hist(top).HashedCells; - CellHulls = hist(top).CellHulls; - Figures.tree.familyID = hist(top).Figures.tree.familyID; - - %increment again so that top is always the next available place - top = top + 1; - if (top > CONSTANTS.historySize) - top = 1; + current = current + 1; + if (current > CONSTANTS.historySize) + current = 1; end + CellFamilies = hist(current).CellFamilies; + CellTracks = hist(current).CellTracks; + HashedCells = hist(current).HashedCells; + CellHulls = hist(current).CellHulls; + Figures.tree.familyID = hist(current).Figures.tree.familyID; + empty = 0; - if(top==bottom) + if(current==bottom) full = 1; end %Update displays DrawTree(Figures.tree.familyID); DrawCells(); - - if (top>redo) + setMenus(); + LogAction('Redo',[],[]); + end + case 'Init' + current = 1; + bottom = 1; + top = 1; + empty = 0; + full = 0; + exceededLimit = 0; + hist(current).CellFamilies = CellFamilies; + hist(current).CellTracks = CellTracks; + hist(current).HashedCells = HashedCells; + hist(current).CellHulls = CellHulls; + hist(current).Figures.tree.familyID = Figures.tree.familyID; + set(Figures.cells.menuHandles.redoMenu,'Enable','off'); + set(Figures.tree.menuHandles.redoMenu,'Enable','off'); + set(Figures.cells.menuHandles.undoMenu,'Enable','off'); + set(Figures.tree.menuHandles.undoMenu,'Enable','off'); + set(Figures.cells.menuHandles.saveMenu,'Enable','off'); + set(Figures.tree.menuHandles.saveMenu,'Enable','off'); +end + + function setMenus() + if(top>bottom) + %not "rolled over" + if(current<top) + %redo possible + set(Figures.cells.menuHandles.redoMenu,'Enable','on'); + set(Figures.tree.menuHandles.redoMenu,'Enable','on'); + else set(Figures.cells.menuHandles.redoMenu,'Enable','off'); - set(Figures.cells.menuHandles.undoMenu,'Enable','on'); set(Figures.tree.menuHandles.redoMenu,'Enable','off'); + end + if(current>bottom) + %undo possible + set(Figures.cells.menuHandles.undoMenu,'Enable','on'); + set(Figures.tree.menuHandles.undoMenu,'Enable','on'); + else + set(Figures.cells.menuHandles.undoMenu,'Enable','off'); + set(Figures.tree.menuHandles.undoMenu,'Enable','off'); + end + elseif(top==bottom && ~empty) + if(current~=top) + %redo and undo possible + set(Figures.cells.menuHandles.redoMenu,'Enable','on'); + set(Figures.tree.menuHandles.redoMenu,'Enable','on'); + set(Figures.cells.menuHandles.undoMenu,'Enable','on'); set(Figures.tree.menuHandles.undoMenu,'Enable','on'); + else + set(Figures.cells.menuHandles.redoMenu,'Enable','off'); + set(Figures.tree.menuHandles.redoMenu,'Enable','off'); + set(Figures.cells.menuHandles.undoMenu,'Enable','off'); + set(Figures.tree.menuHandles.undoMenu,'Enable','off'); end + else + %"rolled over" + if(current>=bottom || current<top) + %redo possible + set(Figures.cells.menuHandles.redoMenu,'Enable','on'); + set(Figures.tree.menuHandles.redoMenu,'Enable','on'); + else + set(Figures.cells.menuHandles.redoMenu,'Enable','off'); + set(Figures.tree.menuHandles.redoMenu,'Enable','off'); + end + if(current>bottom || current<=top) + %undo possible + set(Figures.cells.menuHandles.undoMenu,'Enable','on'); + set(Figures.tree.menuHandles.undoMenu,'Enable','on'); + else + set(Figures.cells.menuHandles.undoMenu,'Enable','off'); + set(Figures.tree.menuHandles.undoMenu,'Enable','off'); + end + end + + %check to see if we are at the original state from the .mat file + if(exceededLimit) set(Figures.cells.menuHandles.saveMenu,'Enable','on'); set(Figures.tree.menuHandles.saveMenu,'Enable','on'); - LogAction('Redo',[],[]); + else + if(empty) + set(Figures.cells.menuHandles.saveMenu,'Enable','off'); + set(Figures.tree.menuHandles.saveMenu,'Enable','off'); + else + set(Figures.cells.menuHandles.saveMenu,'Enable','on'); + set(Figures.tree.menuHandles.saveMenu,'Enable','on'); + end end - case 'Init' - top = 1; - bottom = 1; - redo = 1; - empty = 0; - full = 0; - hist(top).CellFamilies = CellFamilies; - hist(top).CellTracks = CellTracks; - hist(top).HashedCells = HashedCells; - hist(top).CellHulls = CellHulls; - hist(top).Figures.tree.familyID = Figures.tree.familyID; - top = 2; -end + end %setMenu end diff --git a/src/MATLAB/InSubTree.m b/src/MATLAB/InSubTree.m index e69de29b..10d43adb 100644 --- a/src/MATLAB/InSubTree.m +++ b/src/MATLAB/InSubTree.m @@ -0,0 +1,42 @@ +function bool = InSubTree(rootTrack,questionTrack) +% InSubTree(rootTrack,questionTrack) will return a flag which represents +% whether or not the questionTrack falls within the subtree rooted at +% rootTrack + +%--Eric Wait + +global CellTracks +bool = 0; + +%check if they are in the same family +if(CellTracks(rootTrack).familyID ~= CellTracks(questionTrack).familyID),return,end + +%check if the track in question exists after the root +if(CellTracks(rootTrack).endTime > CellTracks(questionTrack).startTime),return,end + +bool = traverse(rootTrack,questionTrack); +end + +function bool = traverse(rootTrack,questionTrack) +%modified depth first search wich does not go passed the time of the +%questionTrack + +global CellTracks + +bool = 0; + +if (rootTrack == questionTrack) + bool = 1; + return +elseif (CellTracks(rootTrack).endTime > CellTracks(questionTrack).startTime) + return +end + +for i=1:length(CellTracks(rootTrack).childrenTracks) + bool = traverse(CellTracks(rootTrack).childrenTracks(i),questionTrack); + %once found, return + if(bool) + return + end +end +end diff --git a/src/MATLAB/InitializeFigures.m b/src/MATLAB/InitializeFigures.m index 16e63ce6..6fbebddf 100644 --- a/src/MATLAB/InitializeFigures.m +++ b/src/MATLAB/InitializeFigures.m @@ -4,6 +4,8 @@ function InitializeFigures() %Figures will have all the menus, button actions, and context menus set up %here +%--Eric Wait + global Figures CONSTANTS Figures.time = 1; diff --git a/src/MATLAB/LEVer.m b/src/MATLAB/LEVer.m index 8c121922..4752b1f6 100644 --- a/src/MATLAB/LEVer.m +++ b/src/MATLAB/LEVer.m @@ -1,4 +1,8 @@ function LEVer() +%Main program + +%--Eric Wait + global Figures %if LEVer is already opened, save state just in case the User cancels the diff --git a/src/MATLAB/LogAction.m b/src/MATLAB/LogAction.m index e6537f2c..fda88edd 100644 --- a/src/MATLAB/LogAction.m +++ b/src/MATLAB/LogAction.m @@ -5,6 +5,8 @@ function LogAction(action,oldValue,newValue) %oldValue and newValue are used to show what numbers are changed. Please %use the action string to denote what the values represent +%--Eric Wait + global Figures CONSTANTS time = clock;%[year month day hour minute seconds] diff --git a/src/MATLAB/NewCellFamily.m b/src/MATLAB/NewCellFamily.m index 9bae9820..a7d130f6 100644 --- a/src/MATLAB/NewCellFamily.m +++ b/src/MATLAB/NewCellFamily.m @@ -1,4 +1,9 @@ function curFamilyID = NewCellFamily(cellHullID,t) +%Create a empty Family that will contain one track that contains only one +%hull + +%--Eric Wait + global CellFamilies if(isempty(CellFamilies)) diff --git a/src/MATLAB/NewCellTrack.m b/src/MATLAB/NewCellTrack.m index 87c4a14c..6f5b3116 100644 --- a/src/MATLAB/NewCellTrack.m +++ b/src/MATLAB/NewCellTrack.m @@ -1,4 +1,9 @@ function curCellTrackID = NewCellTrack(familyID,cellHullID,t) +%Creates a new track in the Family that contains just the given hull. +%***Use this with empty Families only*** + +%--Eric Wait + global CellTracks curCellTrackID = 1; diff --git a/src/MATLAB/OpenData.m b/src/MATLAB/OpenData.m index e2b4f237..6506455d 100644 --- a/src/MATLAB/OpenData.m +++ b/src/MATLAB/OpenData.m @@ -3,9 +3,11 @@ function opened = OpenData() %results. If the latter, the data will be converted to LEVer's data scheme %and save out to a new file. +%--Eric Wait + global Figures Colors CONSTANTS CellFamilies CellHulls HashedCells Costs CellTracks if(isempty(Figures)) - fprintf('LEVer ver 3.0\n***DO NOT DISTRIBUTE***\n\n'); + fprintf('LEVer ver 3.1\n***DO NOT DISTRIBUTE***\n\n'); end if(exist('ColorScheme.mat','file')) diff --git a/src/MATLAB/ProcessNewborns.m b/src/MATLAB/ProcessNewborns.m index ee67775e..e1eee9cf 100644 --- a/src/MATLAB/ProcessNewborns.m +++ b/src/MATLAB/ProcessNewborns.m @@ -2,6 +2,8 @@ function ProcessNewborns(families) %This takes all the families with start times > 1 and attempts to attach %that families' tracks to other families that start before said family +%--Eric Wait + global CellFamilies CellTracks CellHulls Costs CONSTANTS size = length(families); for i=1:size diff --git a/src/MATLAB/RehashCellTracks.m b/src/MATLAB/RehashCellTracks.m index da278792..4e6ef608 100644 --- a/src/MATLAB/RehashCellTracks.m +++ b/src/MATLAB/RehashCellTracks.m @@ -1,25 +1,30 @@ function RehashCellTracks(trackID, newStartTime) -%This function will rearange the hulls in the given track so that the -%newTime will hash correctly +%RehashedCellTracks(trackID,newStartTime) will rearange the hulls in the +%given track so that the newTime will hash correctly. %The hulls are hashed so that the index into the cell array is time of hull %subtract start time of track. eg hash = time of hull - %CellTracks(i).startTime % +%If newStartTime == oldStartTime, only the endTime will change. Good for +%removing all of the 0's at the end of the hulls list for a given track. +% %***WARNING*** if oldStartTime < newStartTime and there are hulls within %[oldStartTime newStartTime) THEY WILL BE REMOVED FROM THE TRACK!!! +%--Eric Wait + global CellTracks CellHulls dif = CellTracks(trackID).startTime - newStartTime; -if(sign(dif)) +if(0<dif) for i=length(CellTracks(trackID).hulls):-1:1 CellTracks(trackID).hulls(i+dif) = CellTracks(trackID).hulls(i); end for i=1:dif CellTracks(trackID).hulls(i) = 0; end -else +elseif(0>dif) oldLength = length(CellTracks(trackID).hulls); for i=1-dif:length(CellTracks(trackID).hulls) CellTracks(trackID).hulls(i+dif) = CellTracks(trackID).hulls(i); @@ -35,4 +40,6 @@ if(indexOfLastHull~=length(CellTracks(trackID).hulls)) CellTracks(trackID).hulls = CellTracks(trackID).hulls(1:indexOfLastHull); CellTracks(trackID).endTime = CellHulls(CellTracks(trackID).hulls(end)).time; end + +CellTracks(trackID).startTime = newStartTime; end diff --git a/src/MATLAB/RemoveFromTree.m b/src/MATLAB/RemoveFromTree.m index 98b16353..7064453d 100644 --- a/src/MATLAB/RemoveFromTree.m +++ b/src/MATLAB/RemoveFromTree.m @@ -1,6 +1,14 @@ -function newFamilyID = RemoveFromTree(time,trackID) +function newFamilyID = RemoveFromTree(time,trackID,combineSiblingWithParent) +%newFamily = RemoveFromTree(time,trackID,dealWithSibling) %This will remove the track and any of its children from its current family %and create a new family rooted at the given track +%If you want the current track's sibling to be combined with its parent, +%pass combineSiblingWithParent='yes' otherwise 'no' +% +%***IF YOU PASS 'NO', YOU MUST DEAL WITH ANY SIBLING YOURSELF!!! OTHERWISE +%THERE WILL BE ISSUES WITH THE DATA**** + +%--Eric Wait global CellFamilies CellTracks CellHulls @@ -8,8 +16,9 @@ hash = time - CellTracks(trackID).startTime + 1; oldFamilyID = CellTracks(trackID).familyID; newFamilyID = NewCellFamily(CellTracks(trackID).hulls(hash),time); newTrackID = CellFamilies(newFamilyID).rootTrackID; +CellTracks(trackID).hulls(hash) = 0; -for i=0:length(CellTracks(trackID).hulls(hash+1:end)) +for i=1:length(CellTracks(trackID).hulls(hash:end))-1 if(CellTracks(trackID).hulls(hash+i)~=0) AddHullToTrack(CellTracks(trackID).hulls(hash+i),newTrackID,[]); end @@ -20,29 +29,37 @@ for i=1:length(CellTracks(trackID).childrenTracks) ChangeTrackAndChildrensFamily(oldFamilyID,newFamilyID,CellTracks(trackID).childrenTracks(i)); CellTracks(CellTracks(trackID).childrenTracks(i)).parentTrack = newTrackID; end -index = CellFamilies(oldFamilyID).tracks == trackID; -CellFamilies(oldFamilyID).tracks(index) = []; -CellFamilies(newFamilyID).tracks(end+1) = newTrackID; + +if(~isempty(find(CellFamilies(oldFamilyID).tracks==newTrackID, 1))) + CellFamilies(newFamilyID).tracks(end+1) = newTrackID; +end CellTracks(newTrackID).familyID = newFamilyID; CellTracks(newTrackID).childrenTracks = CellTracks(trackID).childrenTracks; +for i=1:length(CellTracks(newTrackID).childrenTracks) + CellTracks(CellTracks(newTrackID).childrenTracks(i)).parentTrack = newTrackID; +end +CellTracks(trackID).childrenTracks = []; %clean up old track if(isempty(find([CellTracks(trackID).hulls]~=0, 1))) - if(~isempty(CellTracks(trackID).siblingTrack)) - if(~isempty(CellTracks(CellTracks(trackID).parentTrack).startTime)) + if(~isempty(CellTracks(trackID).siblingTrack)&& strcmp(combineSiblingWithParent,'yes')) +% if(~isempty(CellTracks(CellTracks(trackID).parentTrack).startTime)) CombineTrackWithParent(CellTracks(trackID).siblingTrack); - end +% end + end + RemoveTrackFromFamily(trackID); + if(~isempty(CellTracks(trackID).parentTrack)) + index = CellTracks(CellTracks(trackID).parentTrack).childrenTracks==trackID; + CellTracks(CellTracks(trackID).parentTrack).childrenTracks(index) = []; end CellTracks(trackID).familyID = []; CellTracks(trackID).parentTrack = []; CellTracks(trackID).siblingTrack = []; - CellTracks(trackID).childrenTracks = []; CellTracks(trackID).hulls = []; CellTracks(trackID).startTime = []; CellTracks(trackID).endTime = []; CellTracks(trackID).color = []; else - CellTracks(trackID).childrenTracks = []; index = find([CellTracks(trackID).hulls]~=0, 1,'last'); CellTracks(trackID).endTime = CellHulls(CellTracks(trackID).hulls(index)).time; end diff --git a/src/MATLAB/RemoveHull.m b/src/MATLAB/RemoveHull.m new file mode 100644 index 00000000..91d039c4 --- /dev/null +++ b/src/MATLAB/RemoveHull.m @@ -0,0 +1,28 @@ +function RemoveHull(hullID) +% RemoveHull(hullID) will LOGICALLY remove the hull. Which means that the +% hull will have a flag set that means that it does not exist anywhere and +% should not be drawn on the cells figure + +%--Eric Wait + +global CellTracks HashedCells CellHulls + +trackID = GetTrackID(hullID); + +%remove hull from its track +index = find(CellTracks(trackID).hulls==hullID); +CellTracks(trackID).hulls(index) = 0; +if(1==index) + index = find(CellTracks(trackID).hulls,1,'first'); + RehashCellTracks(trackID,CellHulls(CellTracks(trackID).hulls(index)).time); +elseif(index==length(CellTracks(trackID).hulls)) + RehashCellTracks(trackID,CellTracks(trackID).startTime); +end + +%remove hull from HashedCells +time = CellHulls(hullID).time; +index = [HashedCells{time}.hullID]==hullID; +HashedCells{time}(index) = []; + +CellHulls(hullID).deleted = 1; +end diff --git a/src/MATLAB/RemoveTrackFromFamily.m b/src/MATLAB/RemoveTrackFromFamily.m new file mode 100644 index 00000000..cf564045 --- /dev/null +++ b/src/MATLAB/RemoveTrackFromFamily.m @@ -0,0 +1,28 @@ +function RemoveTrackFromFamily(trackID) +% RemoveTrackFromFamily(trackID) only removes the track from the tracks +% list currently assosiated in the CellFamily entery and updated the other +% CellFamily fields. +% This is not intended to change the structure, just to keep the data +% correct + +%--Eric Wait + +global CellFamilies CellTracks +familyID = CellTracks(trackID).familyID; +if(isempty(familyID)),return,end + +index = CellFamilies(familyID).tracks==trackID; + +%remove track +CellFamilies(familyID).tracks(index) = []; + +%update times +[minimum index] = min([CellTracks(CellFamilies(familyID).tracks).startTime]); +CellFamilies(familyID).startTime = minimum; +CellFamilies(familyID).endTime = max([CellTracks(CellFamilies(familyID).tracks).endTime]); + +%set new root +if(CellFamilies(familyID).rootTrackID == trackID) + CellFamilies(familyID).rootTrackID = CellFamilies(familyID).tracks(index); +end +end diff --git a/src/MATLAB/ResegmentHull.m b/src/MATLAB/ResegmentHull.m new file mode 100644 index 00000000..dc58f94a --- /dev/null +++ b/src/MATLAB/ResegmentHull.m @@ -0,0 +1,48 @@ +function newHulls = ResegmentHull(hull, k) +% Splits hull int k pieces using kmeans, returns the k split hulls or [] if +% there are errors. + +%--Mark Winter + +global CONSTANTS + +newHulls = []; + +% k-means clustering of (x,y) coordinates of cell interior +[r c] = ind2sub(CONSTANTS.imageSize, hull.indexPixels); +kIdx = kmeans([c,r], k, 'Replicates',5, 'EmptyAction','drop'); + +if ( any(isnan(kIdx)) ) + return; +end + +nh = struct('time', [], 'points', [], 'centerOfMass', [], 'indexPixels', [], 'deleted', 0); +for i=1:k + bIdxPix = (kIdx == i); + + hx = c(bIdxPix); + hy = r(bIdxPix); + + % If any sub-object is less than 15 pixels then cannot split this + % hull + if ( nnz(bIdxPix) < 15 ) + newHulls = []; + return; + end + + nh.indexPixels = hull.indexPixels(bIdxPix); + nh.centerOfMass = mean([hx hy]); + nh.time = hull.time; + + try + chIdx = convhull(hx, hy); + catch excp + newHulls = []; + return; + end + + nh.points = [hx(chIdx) hy(chIdx)]; + + newHulls = [newHulls nh]; +end +end diff --git a/src/MATLAB/SaveData.m b/src/MATLAB/SaveData.m index e4f57dfe..03269839 100644 --- a/src/MATLAB/SaveData.m +++ b/src/MATLAB/SaveData.m @@ -1,14 +1,21 @@ function SaveData() %This will save the current state back to the opened dataset -global CellFamilies CellTracks HashedCells CONSTANTS Costs CellHulls + +%--Eric Wait + +global CellFamilies CellTracks HashedCells CONSTANTS Costs CellHulls Figures if (exist('LEVerSettings.mat','file')~=0) load('LEVerSettings.mat'); else - settings.matPath = ['.\' CONSTANTS.datasetName '_v3.mat']; + settings.matPath = ['.\' CONSTANTS.datasetName '_LEVer_edits.mat']; end -save(settings.matPath,... +%let the user know that this might take a while +set(Figures.tree.handle,'Pointer','watch'); +set(Figures.cells.handle,'Pointer','watch'); + +save([settings.matFilePath CONSTANTS.datasetName '_LEVer_edits.mat'],... 'CellFamilies','CellHulls','CellTracks','HashedCells','Costs','CONSTANTS'); %no longer "dirty" @@ -16,4 +23,8 @@ set(Figures.tree.menuHandles.saveMenu,'Enable','off'); set(Figures.cells.menuHandles.saveMenu,'Enable','off'); LogAction('Saved',[],[]); + +%let the user know that the drawing is done +set(Figures.tree.handle,'Pointer','arrow'); +set(Figures.cells.handle,'Pointer','arrow'); end diff --git a/src/MATLAB/SaveDataAs.m b/src/MATLAB/SaveDataAs.m index 327c01ba..b0af3b07 100644 --- a/src/MATLAB/SaveDataAs.m +++ b/src/MATLAB/SaveDataAs.m @@ -1,4 +1,8 @@ function SaveDataAs() +%Save the current state to a user defined dir + +%--Eric Wait + global CellFamilies CellTracks HashedCells CONSTANTS Costs CellHulls Figures if (exist('LEVerSettings.mat','file')~=0) diff --git a/src/MATLAB/SiblingDistance.m b/src/MATLAB/SiblingDistance.m index 129cb9be..bc3fd117 100644 --- a/src/MATLAB/SiblingDistance.m +++ b/src/MATLAB/SiblingDistance.m @@ -4,8 +4,9 @@ function distance = SiblingDistance(cell1HullID,cell2HullID) %and maxPixelDistance. Make sure they are set in the global CONSTANTS %variable. +%--Eric Wait + global CellHulls CONSTANTS -distance = Inf; pixelsCell1 = CellHulls(cell1HullID).indexPixels; pixelsCell2 = CellHulls(cell2HullID).indexPixels; @@ -16,8 +17,8 @@ if (length(pixelsCell2) < length(pixelsCell1)) pixelsCell2 = temp; end -[yCell1 xCell1] = ind2sub(CONSTANTS.ImageSize,pixelsCell1); -[yCell2 xCell2] = ind2sub(CONSTANTS.ImageSize,pixelsCell2); +[yCell1 xCell1] = ind2sub(CONSTANTS.imageSize,pixelsCell1); +[yCell2 xCell2] = ind2sub(CONSTANTS.imageSize,pixelsCell2); minPixelDistance = Inf; diff --git a/src/MATLAB/SplitHull.m b/src/MATLAB/SplitHull.m new file mode 100644 index 00000000..7e8bebcc --- /dev/null +++ b/src/MATLAB/SplitHull.m @@ -0,0 +1,25 @@ +function newTrackIDs = SplitHull(hullID, k) +% Attempt to split hull corresponding to hullId into k pieces, and update +% associated data structures if successful. + +%--Mark Winter + +global CellHulls + +newHulls = ResegmentHull(CellHulls(hullID), k); + +if ( isempty(newHulls) ) + return; +end + +% Just arbitrarily assign clone's hull for now +CellHulls(hullID) = newHulls(1); + +newTrackIDs = [length(CellHulls)+1 length(CellHulls)+length(newHulls)]; +% Other hulls are just added off the clone +for i=2:length(newHulls) + CellHulls(end+i-1) = newHulls(i); + NewCellFamily(length(CellHulls), newHulls(i).time); +end + +end diff --git a/src/MATLAB/SplitTrack.m b/src/MATLAB/SplitTrack.m index 22f98153..944b5691 100644 --- a/src/MATLAB/SplitTrack.m +++ b/src/MATLAB/SplitTrack.m @@ -4,6 +4,8 @@ function newTrackID = SplitTrack(trackID,hullID) %given track. Returns the trackID of the new track, which is the first %child of the given track. +%--Eric Wait + global CellFamilies CellTracks %get all the hulls that come after hullID (in time that is) diff --git a/src/MATLAB/SwapTrackLabels.m b/src/MATLAB/SwapTrackLabels.m index 5d036872..63fa5fbe 100644 --- a/src/MATLAB/SwapTrackLabels.m +++ b/src/MATLAB/SwapTrackLabels.m @@ -2,6 +2,8 @@ function SwapTrackLabels(time,trackID1,trackID2) %This function will swap the hulls of the two tracks from the given time %forward. Any children will also be swaped +%--Eric Wait + global CellTracks CellHulls track1Hash = time - CellTracks(trackID1).startTime + 1; diff --git a/src/MATLAB/TimeChange.m b/src/MATLAB/TimeChange.m index 0a7bf254..05dea765 100644 --- a/src/MATLAB/TimeChange.m +++ b/src/MATLAB/TimeChange.m @@ -2,6 +2,8 @@ function TimeChange(time) %Takes the given time and changes the figures to that time or the closest %time within [1 length(HashedCells)] +%--Eric Wait + global Figures HashedCells if(time > length(HashedCells)) diff --git a/src/MATLAB/TogglePlay.m b/src/MATLAB/TogglePlay.m index b067bcc0..214b7d2e 100644 --- a/src/MATLAB/TogglePlay.m +++ b/src/MATLAB/TogglePlay.m @@ -1,5 +1,10 @@ function TogglePlay(src,evnt) +% Turn the timer on and off depending on previous state + +%--Eric Wait + global Figures + if(strcmp(Figures.advanceTimerHandle.Running,'off')) set(Figures.cells.menuHandles.playMenu, 'Checked', 'on'); start(Figures.advanceTimerHandle); diff --git a/src/MATLAB/UpdateHashedCellsTrackID.m b/src/MATLAB/UpdateHashedCellsTrackID.m index 9826e2cc..d803e733 100644 --- a/src/MATLAB/UpdateHashedCellsTrackID.m +++ b/src/MATLAB/UpdateHashedCellsTrackID.m @@ -2,13 +2,13 @@ function UpdateHashedCellsTrackID(newTrackID,hulls,startTime) %This will take the list of hulls and update their trackIDs to the given %trackID +%--Eric Wait + global HashedCells for i=1:length(hulls) if(~hulls(i)),continue,end - index = [HashedCells{startTime+i-1}(:).hullID]==hulls(i); - %if(~isempty(index)) - HashedCells{startTime+i-1}(index).trackID = newTrackID; - %end + index = [HashedCells{startTime+i-1}.hullID]==hulls(i); + HashedCells{startTime+i-1}(index).trackID = newTrackID; end end diff --git a/src/MATLAB/UpdateTimeIndicatorLine.m b/src/MATLAB/UpdateTimeIndicatorLine.m index 0b732814..19d114e3 100644 --- a/src/MATLAB/UpdateTimeIndicatorLine.m +++ b/src/MATLAB/UpdateTimeIndicatorLine.m @@ -2,6 +2,8 @@ function UpdateTimeIndicatorLine() %Changes the postition of the Red Line that indicates the current time %displayed +%--Eric Wait + global Figures if(ishandle(Figures.tree.timeIndicatorLine)) diff --git a/src/MATLAB/driver.m b/src/MATLAB/driver.m deleted file mode 100644 index 521b0154..00000000 --- a/src/MATLAB/driver.m +++ /dev/null @@ -1,65 +0,0 @@ -function convert() -%preallocate tables for speed - -global CellFamilies CellHulls HashedCells Costs CONSTANTS Figures Colors -%CONSTANTS.datasetName = 'ER81_E12pt5_0527090025_3_3AC05_07'; -CONSTANTS.datasetName = 'ER81_E12_0527090025_3_3AC03_02'; -%CONSTANTS.datasetName = 'ER81_E12pt5_0527090025_3_2AB02_05'; -data = [CONSTANTS.datasetName ' tracked_hulls.mat']; -CONSTANTS.rootFolder = ['..\..\Templetiffs\Temple Lineages\' CONSTANTS.datasetName '\']; -load(data); -load 'colors.mat' - -Colors = colors; -Costs = gConnect; - -CONSTANTS.ImageSize = unique([objHulls(:).imSize]); -CONSTANTS.maxPixelDistance = 40; -CONSTANTS.maxCenterOfMassDistance = 80; -CONSTANTS.minParentCandidateTimeFrame = 5; -CONSTANTS.minParentHistoryTimeFrame = 5; -CONSTANTS.minFamilyTimeFrame = 5; -CONSTANTS.maxFrameDifference = 1; - -HashedCells = cell(0,length(objHulls)); -i=1; - -CellHulls = struct(... - 'time', {objHulls(i).t},... - 'points', {objHulls(i).pts},... - 'centerOfMass', {objHulls(i).COM},... - 'indexPixels', {objHulls(i).indPixels}); - -if objHulls(i).inID == 0 - NewCellFamily(i,objHulls(i).t); -else - AddHullToTrack(i,[],objHulls(i).inID); -end - -for i=2:length(objHulls) - CellHulls(i).time = objHulls(i).t; - CellHulls(i).points = objHulls(i).pts; - CellHulls(i).centerOfMass = objHulls(i).COM; - CellHulls(i).indexPixels = objHulls(i).indPixels; - - if objHulls(i).inID == 0 - NewCellFamily(i,objHulls(i).t); - else - AddHullToTrack(i,[],objHulls(i).inID); - end -end - -ProcessNewborns(); -Figures.tree = figure; -Figures.cells = figure; - -% for i=1:length(CellFamilies) -% if(isempty(CellFamilies(i).tracks)),return,end -% DrawTree(i); -% DrawCells(450,i); -% pause(1); -% i -% end -DrawTree(10); -DrawCells(1,10); -end -- GitLab