diff --git a/src/MATLAB/AddNewSegmentHull.m b/src/MATLAB/AddNewSegmentHull.m new file mode 100644 index 0000000000000000000000000000000000000000..c0533b1419c8bd2f138cffd9fd9cd2bde1871333 --- /dev/null +++ b/src/MATLAB/AddNewSegmentHull.m @@ -0,0 +1,29 @@ +function newTrackID = AddNewSegmentHull(clickPt) + global CONSTANTS CellHulls CellFamilies Figures + + fileName = [CONSTANTS.rootImageFolder CONSTANTS.datasetName '_t' num2str(Figures.time,'%03d') '.TIF']; + [img colrMap] = imread(fileName); + img = mat2gray(img); + + newObj = PartialImageSegment(img, clickPt, 200, 1.0); + + newHull = struct('time', [], 'points', [], 'centerOfMass', [], 'indexPixels', [], 'deleted', 0); + + if ( isempty(newObj) ) + % Add a point hull since we couldn't find a segmentation containing the click + newHull.time = Figures.time; + newHull.points = round(clickPt); + newHull.centerOfMass = [clickPt(2) clickPt(1)]; + newHull.indexPixels = sub2ind(size(img), clickPt(2), clickPt(1)); + else + newHull.time = Figures.time; + newHull.points = newObj.points; + newHull.centerOfMass = newObj.centerOfMass; + newHull.indexPixels = newObj.indexPixels; + end + + CellHulls(end+1) = newHull; + newFamilyIDs = NewCellFamily(length(CellHulls), newHull.time); + + newTrackID = [CellFamilies(newFamilyIDs).rootTrackID]; +end \ No newline at end of file diff --git a/src/MATLAB/AddSingleHullToTrack.m b/src/MATLAB/AddSingleHullToTrack.m index 161ddcbc1152d172581a6823ef594af74b2c397a..d78790265720bedc83bcb8441a12990c74b624cd 100644 --- a/src/MATLAB/AddSingleHullToTrack.m +++ b/src/MATLAB/AddSingleHullToTrack.m @@ -16,17 +16,20 @@ if(~isempty(CellTracks(oldTrackID).parentTrack) && ... error([num2str(oldTrackID) ' is not a single hull track or has a parent/child']); end -if(CellTracks(oldTrackID).startTime<CellTracks(newTrackID).startTime) +if(~any([CellTracks(CellTracks(newTrackID).childrenTracks).endTime]<CellTracks(oldTrackID).startTime)) + RemoveChildren(newTrackID); + AddHullToTrack(CellTracks(oldTrackID).hulls(1),newTrackID,[]); +elseif(CellTracks(oldTrackID).startTime<CellTracks(newTrackID).startTime) %old before new if(~isempty(CellTracks(newTrackID).parentTrack)) - moveMitosisUp(CellTracks(oldTrackID).startTime,... + MoveMitosisUp(CellTracks(oldTrackID).startTime,... CellTracks(newTrackID).siblingTrack); end AddHullToTrack(CellTracks(oldTrackID).hulls(1),newTrackID,[]); elseif(CellTracks(oldTrackID).startTime>CellTracks(newTrackID).endTime) %new before old if(~isempty(CellTracks(newTrackID).childrenTracks)) - moveMitosisDown(CellTracks(oldTrackID).startTime,newTrackID); + MoveMitosisDown(CellTracks(oldTrackID).startTime,newTrackID); end AddHullToTrack(CellTracks(oldTrackID).hulls(1),newTrackID,[]); else @@ -54,49 +57,3 @@ CellTracks(oldTrackID).endTime = []; CellTracks(oldTrackID).timeOfDeath = []; CellTracks(oldTrackID).color = []; end - -function moveMitosisUp(time,siblingTrackID) -global CellTracks - -%remove hulls from parent -hash = time - CellTracks(CellTracks(siblingTrackID).parentTrack).startTime + 1; -hulls = CellTracks(CellTracks(siblingTrackID).parentTrack).hulls(hash:end); -CellTracks(CellTracks(siblingTrackID).parentTrack).hulls(hash:end) = 0; -RehashCellTracks(CellTracks(siblingTrackID).parentTrack,CellTracks(CellTracks(siblingTrackID).parentTrack).startTime); - -%add hulls to sibling -for i=1:length(hulls) - AddHullToTrack(hulls(i),siblingTrackID,[]); -end -end - -function moveMitosisDown(time,trackID) -global CellTracks CellFamilies - -remove = 0; -children = {}; - -for i=1:length(CellTracks(trackID).childrenTracks) - if(CellTracks(CellTracks(trackID).childrenTracks(i)).endTime <= time) - remove = 1; - break - end - hash = time - CellTracks(CellTracks(trackID).childrenTracks(i)).startTime + 1; - if(0<hash) - children(i).startTime = CellTracks(CellTracks(trackID).childrenTracks(i)).startTime; - children(i).hulls = CellTracks(CellTracks(trackID).childrenTracks(i)).hulls(1:hash); - end -end - -if(remove) - RemoveChildren(trackID); -else - for i=1:length(children) - familyID = NewCellFamily(children(i).hulls(1),children(i).startTime); - newTrackID = CellFamilies(familyID).rootTrackID; - for j=2:length(children(i).hulls) - AddHullToTrack(children(i).hulls(j),newTrackID,[]); - end - end -end -end diff --git a/src/MATLAB/CHullContainsPoint.m b/src/MATLAB/CHullContainsPoint.m new file mode 100644 index 0000000000000000000000000000000000000000..7292d5cbf87edf195d64f18ee7af20f95b452f2d --- /dev/null +++ b/src/MATLAB/CHullContainsPoint.m @@ -0,0 +1,23 @@ +function bInHull = CHullContainsPoint(pt, hulls) + bInHull = boolean(zeros(length(hulls),1)); + + for i=1:length(hulls) + + if ( size(hulls(i).points,1) <= 1 ) + continue; + end + + cvpts = hulls(i).points; + hullvec = diff(cvpts); + + outnrm = [-hullvec(:,2) hullvec(:,1)]; + %outnrm = outnrm ./ sqrt(sum(outnrm.^2,2)); + + ptvec = cvpts(1:end-1,:) - ones(size(outnrm,1),1)*pt; + %ptvec = ptvec ./ sqrt(sum(ptvec.^2,2)); + + chkIn = sign(sum(outnrm .* ptvec,2)); + + bInHull(i) = all(chkIn >= 0); + end +end \ No newline at end of file diff --git a/src/MATLAB/ChangeLabel.m b/src/MATLAB/ChangeLabel.m index 20f00ee6043df61f363ef905da045958c46fe565..c5b4a3329baf97c5ecb847a387ed5d42abb9670b 100644 --- a/src/MATLAB/ChangeLabel.m +++ b/src/MATLAB/ChangeLabel.m @@ -123,9 +123,10 @@ else %the old track still exists in some fasion end moveChildren(oldTrackID,newTrackID); end - elseif(isempty(find(CellTracks(oldTrackID).hulls==lastOldHull, 1)) &&... - CellHulls(lastOldHull).time>CellTracks(newTrackID).endTime &&... - ~isempty(CellTracks(newTrackID).childrenTracks)) + elseif(~isempty(CellTracks(newTrackID).childrenTracks) && ... + (((isempty(find(CellTracks(oldTrackID).hulls==lastOldHull, 1)) &&... + CellHulls(lastOldHull).time>CellTracks(newTrackID).endTime)) || ... + any([CellTracks(CellTracks(newTrackID).childrenTracks).startTime]<CellTracks(newTrackID).endTime))) RemoveChildren(newTrackID); end end diff --git a/src/MATLAB/ContextChangeLabel.m b/src/MATLAB/ContextChangeLabel.m index bf4e3f479133034a4b552520517d5471e37afe81..dcec450f790c8713f527b268d6a47bd7b061b7db 100644 --- a/src/MATLAB/ContextChangeLabel.m +++ b/src/MATLAB/ContextChangeLabel.m @@ -55,6 +55,14 @@ elseif(isempty(CellTracks(trackID).parentTrack) && isempty(CellTracks(trackID).c AddSingleHullToTrack(trackID,newTrackID); History('Push'); LogAction('Added hull to track',hullID,newTrackID); +elseif(~isempty(CellTracks(trackID).parentTrack) && CellTracks(trackID).parentTrack==newTrackID) + MoveMitosisUp(time,trackID) + History('Push'); + LogAction('Moved Mitosis Up',trackID,newTrackID); +elseif(~isempty(CellTracks(newTrackID).parentTrack) &&CellTracks(newTrackID).parentTrack==trackID) + MoveMitosisUp(time,newTrackID) + History('Push'); + LogAction('Moved Mitosis Up',newTrackID,trackID); else ChangeLabel(time,trackID,newTrackID); History('Push'); diff --git a/src/MATLAB/CreateContextMenuCells.m b/src/MATLAB/CreateContextMenuCells.m index 18f532b42b3e3ded87c4edf820d54a9990580cf8..43d7e4649882b5be58eef90e43aff905c5420ba8 100644 --- a/src/MATLAB/CreateContextMenuCells.m +++ b/src/MATLAB/CreateContextMenuCells.m @@ -272,23 +272,45 @@ end %% Helper functions function addHull(num) -global Figures +global Figures CellHulls -[hullID trackID] = getClosestCell(); -if(isempty(trackID)),return,end +[hullID trackID] = getClosestCell(num<2); +clickPt = get(gca,'CurrentPoint'); -newTracks = SplitHull(hullID,num+1);%adding one to the number so that the original hull is accounted for +if ( ~CHullContainsPoint(clickPt(1,1:2), CellHulls(hullID)) ) + trackID = []; +end + +if(~isempty(trackID)) + % Try to split the existing hull + 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]); +elseif ( num<2 ) + % Try to run local segmentation and find a hull we missed or place a + % point-hull at least + newTrack = AddNewSegmentHull(clickPt(1,1:2)); + + History('Push'); + LogAction('Added cell',[],newTrack); +else + return; +end -History('Push'); -LogAction('Split cell',trackID,[trackID newTracks]); DrawTree(Figures.tree.familyID); DrawCells(); end -function [hullID trackID] = getClosestCell() +function [hullID trackID] = getClosestCell(bAllowEmpty) hullID = FindHull(get(gca,'CurrentPoint')); if(0>=hullID) - warndlg('Please click closer to the center of the desired cell','Unknown Cell'); + if ( bAllowEmpty ) + hullID = []; + else + warndlg('Please click closer to the center of the desired cell','Unknown Cell'); + end + trackID = []; return end diff --git a/src/MATLAB/CreateMenuBar.m b/src/MATLAB/CreateMenuBar.m index 4e0e9cd071a28e88baa2de3474a40c70b96295fe..3e5af67f05ca8713c02a085ef2f45b4f60ace873 100644 --- a/src/MATLAB/CreateMenuBar.m +++ b/src/MATLAB/CreateMenuBar.m @@ -233,6 +233,8 @@ global CellTracks answer = inputdlg('Enter Tree Containing Cell:','Display Tree',1); answer = str2double(answer); +if(isempty(answer)),return,end + if(0>=answer || isempty(CellTracks(answer).hulls)) msgbox([num2str(answer) ' is not a valid cell'],'Not Valid','error'); return diff --git a/src/MATLAB/MoveMitosisDown.m b/src/MATLAB/MoveMitosisDown.m new file mode 100644 index 0000000000000000000000000000000000000000..c4a327b0039c412a930a8e7ad12d561648a07074 --- /dev/null +++ b/src/MATLAB/MoveMitosisDown.m @@ -0,0 +1,38 @@ +function MoveMitosisDown(time,trackID) +% MoveMitosisDown(time,trackID) will move the Mitosis even down the track +% to the given time. The hulls from the children between parent mitosis +% and the given time are broken off into thier own tracks. + +%--Eric Wait + +global CellTracks CellFamilies + +remove = 0; +children = {}; + +for i=1:length(CellTracks(trackID).childrenTracks) + if(CellTracks(CellTracks(trackID).childrenTracks(i)).endTime <= time) + remove = 1; + break + end + hash = time - CellTracks(CellTracks(trackID).childrenTracks(i)).startTime + 1; + if(0<hash) + children(i).startTime = CellTracks(CellTracks(trackID).childrenTracks(i)).startTime; + children(i).hulls = CellTracks(CellTracks(trackID).childrenTracks(i)).hulls(1:hash); + end +end + +if(remove) + RemoveChildren(trackID); +else + for i=1:length(children) + familyID = NewCellFamily(children(i).hulls(1),children(i).startTime); + newTrackID = CellFamilies(familyID).rootTrackID; + for j=2:length(children(i).hulls) + if(children(i).hulls(j)~=0) + AddHullToTrack(children(i).hulls(j),newTrackID,[]); + end + end + end +end +end \ No newline at end of file diff --git a/src/MATLAB/MoveMitosisUp.m b/src/MATLAB/MoveMitosisUp.m new file mode 100644 index 0000000000000000000000000000000000000000..c5531c44c2f39d47c33f2b779661e9d668eba2f8 --- /dev/null +++ b/src/MATLAB/MoveMitosisUp.m @@ -0,0 +1,20 @@ +function MoveMitosisUp(time,siblingTrackID) +% MoveMitosisUp(time,siblingTrackID) will move the Mitosis event up the +% tree. This function takes the hulls from the parent between the old +% mitosis time and the given time and attaches them to the given track. + +%--Eric Wait + +global CellTracks + +%remove hulls from parent +hash = time - CellTracks(CellTracks(siblingTrackID).parentTrack).startTime + 1; +hulls = CellTracks(CellTracks(siblingTrackID).parentTrack).hulls(hash:end); +CellTracks(CellTracks(siblingTrackID).parentTrack).hulls(hash:end) = 0; +RehashCellTracks(CellTracks(siblingTrackID).parentTrack,CellTracks(CellTracks(siblingTrackID).parentTrack).startTime); + +%add hulls to sibling +for i=1:length(hulls) + AddHullToTrack(hulls(i),siblingTrackID,[]); +end +end \ No newline at end of file diff --git a/src/MATLAB/PartialImageSegment.m b/src/MATLAB/PartialImageSegment.m new file mode 100644 index 0000000000000000000000000000000000000000..010ad7970ae4562f38bc6297e11b2b8486ff033f --- /dev/null +++ b/src/MATLAB/PartialImageSegment.m @@ -0,0 +1,180 @@ +function hull = PartialImageSegment(img, centerPt, subSize, alpha) + + if ( length(subSize) < 2 ) + subSize = [subSize(1) subSize(1)]; + end + + imSize = size(img); + + coordMin = floor([centerPt(1)-subSize(1)/2 centerPt(2)-subSize(2)/2]); + coordMin(coordMin < 1) = 1; + + coordMax = ceil([centerPt(1)+subSize(1)/2 centerPt(2)+subSize(2)/2]); + if ( coordMax(1) > imSize(2) ) + coordMax(1) = imSize(2); + end + if ( coordMax(2) > imSize(1) ) + coordMax(2) = imSize(1); + end + + % Build the subimage to be segmented + subImg = img(coordMin(2):coordMax(2), coordMin(1):coordMax(1)); + +% hold off;figure;imagesc(subImg);colormap(gray);hold on; + + objs = []; + + se=strel('square',3); + + bwDark=0*subImg; + level=alpha*graythresh(subImg); + bwHalo=im2bw(subImg,level); + + l2=graythresh(subImg); + pix=subImg(subImg<l2); + lDark=graythresh(pix); + bwDark(subImg<lDark)=1; + + bwNorm=0*bwDark; + + gd=imdilate(subImg,se); + ge=imerode(subImg,se); + ig=gd-ge; + lig=graythresh(ig); + bwig=im2bw(ig,lig); + seBig=strel('square',19); + bwmask=imclose(bwig,seBig); + + bwDarkCenters=(bwDark & bwmask ); + d=bwdist(~bwDarkCenters); + bwDarkCenters(d<2)=0; + + bwHaloMask=imdilate(bwHalo,seBig); + + bwHaloHoles=imfill(bwHalo ,8,'holes') & ~bwHalo; + bwDarkHoles=imfill(bwDarkCenters ,8,'holes') & ~bwDarkCenters; + bwgHoles=bwmorph(bwig | bwDarkCenters,'close',1) ; + bwgHoles=imfill( bwgHoles ,8,'holes') & ~(bwig |bwDarkCenters); + + bwHoles=bwHaloHoles |bwDarkHoles|bwgHoles; + + CC = bwconncomp(bwHoles,8); + LHoles = labelmatrix(CC); + stats = regionprops(CC, 'Area'); + idx = find([stats.Area] < 500); + bwHoles = ismember(LHoles, idx); + + bwCells=bwDarkCenters| bwHoles|bwNorm; + bwCells(~bwHaloMask)=0; + + + CC = bwconncomp(bwHalo,8); + LCells = labelmatrix(CC); + + bwCells(bwig)=0; + + bwTails=bwDarkCenters; + bwTails(bwHalo)=0; + CC = bwconncomp(bwTails,8); + LTails = labelmatrix(CC); + + CC = bwconncomp(bwCells,8); + LCenters = labelmatrix(CC); + stats=regionprops(CC,'eccentricity'); + d=bwdist(~bwCells); + +% [tr,tc] = find(LCenters>0); +% plot(tc,tr,'.r'); + + num=max(LCenters(:)); + for n=1:num + pix=find(LCenters==n); + if length(pix)<50 + bwCells(pix)=0; + continue + end + + bwPoly=logical(0*subImg); + bwPoly(pix)=1; + bwPoly=bwmorph(bwPoly,'dilate',1); + p=bwperim(bwPoly); + + igRat=length(find(p & bwig))/length(find(p)); + + HaloRat=length(find(p & bwHalo))/length(find(p)); + + [r c]=ind2sub(imSize,pix); + ch=convhull(r,c); + + bwDarkInterior=bwDarkCenters&bwPoly; + DarkRat=length(find(bwDarkInterior))/length(find(bwPoly)); +% if HaloRat>0.5 || igRat<.1 ||(DarkRat<.5 && igRat<.5 && length(pix)<175) +% bwCells(pix)=0; +% continue +% end + dmax=max(d(pix)); + if dmax>4 + bwCells(pix(d(pix)<2))=0; + end + end + + bwCellFG=0*bwCells; + + CC = bwconncomp(bwCells,8); + LCenters = labelmatrix(CC); + +% [tr,tc] = find(LCenters>0); +% plot(tc,tr,'og'); + +% hold off;figure;imagesc(subImg);colormap(gray);hold on; + + stats=regionprops(CC,'area','Eccentricity'); + idx = find([stats.Area] >=25); + for i=1:length(idx) + pix=find(LCenters==idx(i)); + if length(pix)<20 + continue + end + [r c]=ind2sub(size(subImg),pix); + bwPoly=roipoly(subImg,c,r); + if bwarea(bwPoly)<1 + continue + end + + ch=convhull(r,c); + % one last check for parasites + if length(find(subImg(pix)>lDark))/length(pix)> 0.5 + continue + end + % it's a keeper! + bwCellFG(pix)=1; + +% plot(c(ch),r(ch),'-r','linewidth',1.5) + + glc = c + coordMin(1); + glr = r + coordMin(2); + + no=[]; + no.points=[glc(ch),glr(ch)]; + no.centerOfMass = mean([glr glc]); + + %no.indPixels=pix; + no.indexPixels = sub2ind(imSize,[glr glc]); + no.imagePixels=img(no.indexPixels); + % surround completely by Halo? + if all(bwHaloHoles(pix)) + no.BrightInterior=1; + else + no.BrightInterior=0; + end + + no.ID=-1; + no.Eccentricity=stats(idx(i)).Eccentricity; + objs = [objs no]; + end + + bInHull = CHullContainsPoint(centerPt, objs); + + hull = objs(bInHull); +end +