defineGoodSegs sets the segments to good, bad and 3n set by the watershed algorithm "Good" segments (segs_good) are the ones that lie along a real cellular boundary, "bad" segments, lie along spurious boundaries within single cells. 3n_segs are the fixed segments. Note that we assume (safely) that the watershed always over-rather than under-segment the image. That is, the set of all real segments is contained with the set of all segments produced by the watershed algorithm. INPUT : data : data segmentation frame file ws : watersehd image phaseNorm : normalized phase image C2phaseThresh : c2 (curvature) calculated image mask_bg : background mask A : scoring coefficients CONST : segmentation parameters caclScores : boolean to calculate scores OUTPUT : data : updated data segmentation frame file. Copyright (C) 2016 Wiggins Lab Written by Paul Wiggins & Stella Stylianidou. University of Washington, 2016 This file is part of SuperSegger. SuperSegger 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. SuperSegger 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 SuperSegger. If not, see <http://www.gnu.org/licenses/>.
0001 function [data] = defineGoodSegs(data, ws, phaseNorm, C2phaseThresh, ... 0002 mask_bg, A, CONST, calcScores) 0003 % defineGoodSegs sets the segments to good, bad and 3n set by the watershed algorithm 0004 % "Good" segments (segs_good) are the ones that lie along a real cellular 0005 % boundary, "bad" segments, lie along spurious boundaries 0006 % within single cells. 3n_segs are the fixed segments. 0007 % Note that we assume (safely) that the watershed always over-rather 0008 % than under-segment the image. That is, the set of all real segments is 0009 % contained with the set of all segments produced by the watershed algorithm. 0010 % 0011 % INPUT : 0012 % data : data segmentation frame file 0013 % ws : watersehd image 0014 % phaseNorm : normalized phase image 0015 % C2phaseThresh : c2 (curvature) calculated image 0016 % mask_bg : background mask 0017 % A : scoring coefficients 0018 % CONST : segmentation parameters 0019 % caclScores : boolean to calculate scores 0020 % OUTPUT : 0021 % data : updated data segmentation frame file. 0022 % 0023 % Copyright (C) 2016 Wiggins Lab 0024 % Written by Paul Wiggins & Stella Stylianidou. 0025 % University of Washington, 2016 0026 % This file is part of SuperSegger. 0027 % 0028 % SuperSegger is free software: you can redistribute it and/or modify 0029 % it under the terms of the GNU General Public License as published by 0030 % the Free Software Foundation, either version 3 of the License, or 0031 % (at your option) any later version. 0032 % 0033 % SuperSegger is distributed in the hope that it will be useful, 0034 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0035 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0036 % GNU General Public License for more details. 0037 % 0038 % You should have received a copy of the GNU General Public License 0039 % along with SuperSegger. If not, see <http://www.gnu.org/licenses/>. 0040 0041 0042 0043 sim = size( phaseNorm ); 0044 0045 % Create labeled image of the segments 0046 %here we obtain the cell-background boundary, which we know is correct. 0047 disk1 = strel('disk',1); 0048 outer_bound = xor(bwmorph(mask_bg,'dilate'),mask_bg); 0049 0050 % label the connected regions in the mask with an id 0051 % and calculate the properties 0052 regs_label = bwlabel( ~ws, 8); 0053 regs_prop = regionprops( regs_label,... 0054 {'BoundingBox','MinorAxisLength','MajorAxisLength','Area'}); 0055 0056 % calculate the connectivity of each pixel in the segments 0057 ws = double(ws.*mask_bg); 0058 ws_cc = compConn( ws+outer_bound, 4 ); 0059 0060 % segs_3n are the non-negotiable segments. They are on no matter what. 0061 % this includes the outer boundary of the clumps (outer_bound), as well as the 0062 % intersections between seg lines (pixels with connectivity_4 > 2). 0063 segs_3n = double(((ws_cc > 2)+outer_bound)>0); 0064 0065 % segs are the guys that divide cells in the clumps that may or may not be 0066 % on. Since we have removed all the intersections, we can label these and 0067 % calculate their properties. 0068 segs = ws-segs_3n.*ws; 0069 0070 %turn on all the segs smaller than MIN_SEGS_SIZE 0071 MIN_SEGS_SIZE = 2; 0072 cc = bwconncomp( segs, 4 ); 0073 segs_props = regionprops(cc, 'Area'); 0074 logmask = [segs_props.Area] < MIN_SEGS_SIZE; 0075 0076 idx = find(logmask); 0077 segs_3n = segs_3n + ismember(labelmatrix(cc), idx); 0078 idx = find(~logmask); 0079 segs = ismember(labelmatrix(cc), idx); 0080 0081 % redefine segs after eliminating the small segs and calculate all the 0082 % region properties we will need. 0083 % here we create coordinates to crop around each segment. This decreases the time 0084 % required to process each segment 0085 segs_label = bwlabel( segs,4); 0086 numSegs = max( segs_label(:) ); 0087 segs_props = regionprops(segs_label, {'Area', 'BoundingBox','MinorAxisLength',... 0088 'MajorAxisLength', 'Orientation', 'Centroid' } ); 0089 0090 [~, ~, ~, ~, ~, G, C1, C2, f_xx, f_yy, f_xy] = curveFilter (double(phaseNorm),1.5); 0091 G_ = G; 0092 G_(G_>0) = 0; 0093 0094 0095 segs_props_tmp = regionprops(segs_label, G, 'MeanIntensity' ); 0096 0097 [segs_props(:).G] = deal (segs_props_tmp.MeanIntensity); 0098 0099 segs_props_tmp = regionprops(segs_label, G_, 'MeanIntensity' ); 0100 [segs_props(:).G_] = deal (segs_props_tmp.MeanIntensity); 0101 0102 segs_props_tmp = regionprops(segs_label, C1, 'MeanIntensity' ); 0103 [segs_props(:).C1] = deal (segs_props_tmp.MeanIntensity); 0104 0105 segs_props_tmp = regionprops(segs_label, C2, 'MeanIntensity' ); 0106 [segs_props(:).C2] = deal (segs_props_tmp.MeanIntensity); 0107 0108 segs_props_tmp = regionprops(segs_label, f_xx, 'MeanIntensity' ); 0109 [segs_props(:).f_xx] = deal (segs_props_tmp.MeanIntensity); 0110 0111 segs_props_tmp = regionprops(segs_label, f_yy, 'MeanIntensity' ); 0112 [segs_props(:).f_yy] = deal (segs_props_tmp.MeanIntensity); 0113 0114 segs_props_tmp = regionprops(segs_label, f_xy, 'MeanIntensity' ); 0115 [segs_props(:).f_xy] = deal (segs_props_tmp.MeanIntensity); 0116 0117 0118 % segs_good is the im created by the segments that will be on 0119 % segs_bad is the im created by the rejected segs 0120 segs_good = false(sim); 0121 segs_bad = false(sim); 0122 0123 % these define the size of the image for use in crop sub regions in the 0124 % loop--basically used to reduced the computation time. 0125 xmin = 1; 0126 ymin = 1; 0127 xmax = sim(2); 0128 ymax = sim(1); 0129 0130 % Make the segs_info: 0131 num_info = CONST.superSeggerOpti.NUM_INFO; 0132 seg_info = nan(numSegs,num_info); 0133 0134 % score is a binary include (1)/exclude (0) flag generated 0135 % by a vector multiplcation of A with seg_info. 0136 score = zeros(numSegs,1); 0137 scoreRaw = zeros(numSegs,1); 0138 0139 % Loop through all segments to decide which are good and which are 0140 % bad. 0141 for ii = 1:numSegs 0142 0143 % Crop around each segment with two pixels of padding in x and y 0144 [xx,yy] = getBBpad( segs_props(ii).BoundingBox, sim, 2 ); 0145 0146 0147 % here we get the cropped segment mask and corresponding phase image 0148 segs_props_tmp = []; 0149 0150 segs_props_tmp.mask = logical(segs_label(yy, xx) == ii); 0151 segs_props_tmp.phase = phaseNorm(yy, xx); 0152 segs_props_tmp.phaseC2 = C2phaseThresh(yy,xx); 0153 segs_props_tmp.regs_label = regs_label(yy,xx); 0154 segs_props_tmp.sim = sim; 0155 0156 seg_info(ii,:) = CONST.seg.segScoreInfo( segs_props(ii),segs_props_tmp,... 0157 regs_prop,regs_label,disk1); 0158 0159 if calcScores 0160 % Calculate the score to determine if the seg will be included. 0161 % if score is less than 0 set the segment off 0162 [scoreRaw(ii)] = CONST.seg.segmentScoreFun( seg_info(ii,:), A ); 0163 score(ii) = double( 0 < scoreRaw (ii)); 0164 0165 % update the good and bad segs images. 0166 0167 if score(ii) 0168 segs_good(yy,xx) = or(segs_good(yy, xx), segs_props_tmp.mask); 0169 else 0170 segs_bad(yy,xx) = or(segs_bad(yy, xx), segs_props_tmp.mask); 0171 end 0172 end 0173 0174 end 0175 data.segs.phaseC2 = C2phaseThresh; 0176 data.segs.phaseNorm = phaseNorm; 0177 data.mask_bg = mask_bg; 0178 data.segs.segs_good = segs_good; 0179 data.segs.segs_bad = segs_bad; 0180 data.segs.segs_3n = segs_3n; 0181 data.segs.info = seg_info; 0182 data.segs.segs_label = segs_label; 0183 data.segs.score = score; 0184 data.segs.scoreRaw = scoreRaw; 0185 data.segs.props = segs_props; 0186 0187 %intShowSegScore( data, reshape([drill(segs_props,'.Centroid(1)'),... 0188 % drill(segs_props,'.Centroid(2)')],[numel(segs_props),2]) , 21 ); 0189 0190 end 0191 0192 0193 %% Debugging tool not called for visualizing scores 0194 function intShowSegScore( data, cen, ind ) 0195 0196 figure(101); 0197 clf; 0198 0199 nseg = numel( data.segs.score); 0200 0201 backer = 0.8*ag(data.phase); 0202 0203 segs_good = 0.4*ag(data.segs.segs_good); 0204 segs_bad = 0.4*ag(data.segs.segs_bad); 0205 segs_3n = 0.4*ag(data.segs.segs_3n); 0206 0207 imshow(cat(3,segs_good+backer+segs_3n,... 0208 0.5*segs_good+backer,... 0209 segs_bad+backer)); 0210 0211 hold on; 0212 0213 for ii = 1:nseg 0214 0215 text( cen(ii,1), cen(ii,2), num2str( data.segs2.info(ii,ind),'%1.2g' ),'Color', 'w'); 0216 end 0217 0218 0219 end