Home > SuperSegger > segmentation > superSeggerOpti.m

superSeggerOpti

PURPOSE ^

superSeggerOpti generates the initial segmentation of rod-shaped cells.

SYNOPSIS ^

function [data,A] = superSeggerOpti(phaseOrData, mask, disp_flag, CONST, adapt_flag, header, crop_box)

DESCRIPTION ^

 superSeggerOpti generates the initial segmentation of rod-shaped cells.
 It uses a local minimum filter (similar to a median filter) to enhance
 contrast and then uses Matlab's WATERSHED command to generate
 cell boundaries. The spurious boundaries (i.e., those that lie in the
 cell interiors) are removed by an intensity thresholding routine
 on each boundary. Any real boundaries incorrectly removed
 by this thresholding are added back by an iterative algorithm that
 uses knowledge of cell shape to determine which regions are missing
 boundaries.

 INPUT :
       phaseOrData : phase image or data file to be used
       mask : cell mask, given externally or calculated with band-pass filter
       disp_flag : display flag
       CONST : segmentation constants
       adapt_flag : break up regions that are too big to be cells
       header : string displayed with infromation
       crop_box : information about alignement of the image

 OUTPUT :
       data.segs : defined below
       data.mask_bg : a binary image in which all background (non-cell) pixels are masked
       data.mask_cell : cell mask, a binary image the same size as phase in
       which each cell is masked by a connected region of white pixels
       data.phase : Original phase image
       A : scoring vector optimized for different cells and imaging conditions

   segs.
     phaseMagic: % phase image processed with magicContrast only
      segs_good: % on segments, image of the boundaries between cells that the program
      has determined are correct (i.e., not spurious).
       segs_bad: % off segments, image of program-determined spurious boundaries between cells
        segs_3n: % an image of all of boundary intersections, segments that cannot be switched off
           info: % segment parameters that are used to generate the raw
           score, looke below
     segs_label: % bwlabel of good and bad segs.
          score: % cell scores for regions
       scoreRaw: % raw scores for segments
          props: % segement properties for segments


         seg.info(:,1) : the minimum phase intensity on the seg
         seg.info(:,2) : the mean phase intensity on the seg
         seg.info(:,3) : area of the seg
         seg.info(:,4) : the mean second d of the phase normal to the seg
         seg.info(:,5) : second d of the phase normal to the seg at the min pixel
         seg.info(:,6) : second d of the phase parallel to the seg at the min pixel
         seg.info(:,7) and seg_info(:,8) : min and max area of neighboring regions
         seg.info(:,9) and seg_info(:,10) : min and max lengths of the minor axis of the neighboring regions
         seg.info(:,11) and seg_info(:,12) : min and max lengths of the major axis of the neighboring regions
         seg.info(:,11) : length of minor axis
         seg.info(:,12) : length of major axis
         seg.info(:,13) : square of length of major axis
         seg.info(:,16) : max length of region projected onto the major axis
         segment
         seg.info(:,17) : min length of region projected onto the major axis
         segment
         seg.info(:,18) : max length of region projected onto the minor axis
         segment
         seg.info(:,19) : min length of region projected onto the minor axis
         segment

 The output images are related by
 mask_cell = mask_bg .* (~segs_good) .* (~segs_3n);

 Copyright (C) 2016 Wiggins Lab
 Written by Stella Stylianidou & Paul Wiggins.
 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/>.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [data,A]  = superSeggerOpti(phaseOrData, mask, disp_flag, CONST, adapt_flag, header, crop_box)
0002 % superSeggerOpti generates the initial segmentation of rod-shaped cells.
0003 % It uses a local minimum filter (similar to a median filter) to enhance
0004 % contrast and then uses Matlab's WATERSHED command to generate
0005 % cell boundaries. The spurious boundaries (i.e., those that lie in the
0006 % cell interiors) are removed by an intensity thresholding routine
0007 % on each boundary. Any real boundaries incorrectly removed
0008 % by this thresholding are added back by an iterative algorithm that
0009 % uses knowledge of cell shape to determine which regions are missing
0010 % boundaries.
0011 %
0012 % INPUT :
0013 %       phaseOrData : phase image or data file to be used
0014 %       mask : cell mask, given externally or calculated with band-pass filter
0015 %       disp_flag : display flag
0016 %       CONST : segmentation constants
0017 %       adapt_flag : break up regions that are too big to be cells
0018 %       header : string displayed with infromation
0019 %       crop_box : information about alignement of the image
0020 %
0021 % OUTPUT :
0022 %       data.segs : defined below
0023 %       data.mask_bg : a binary image in which all background (non-cell) pixels are masked
0024 %       data.mask_cell : cell mask, a binary image the same size as phase in
0025 %       which each cell is masked by a connected region of white pixels
0026 %       data.phase : Original phase image
0027 %       A : scoring vector optimized for different cells and imaging conditions
0028 %
0029 %   segs.
0030 %     phaseMagic: % phase image processed with magicContrast only
0031 %      segs_good: % on segments, image of the boundaries between cells that the program
0032 %      has determined are correct (i.e., not spurious).
0033 %       segs_bad: % off segments, image of program-determined spurious boundaries between cells
0034 %        segs_3n: % an image of all of boundary intersections, segments that cannot be switched off
0035 %           info: % segment parameters that are used to generate the raw
0036 %           score, looke below
0037 %     segs_label: % bwlabel of good and bad segs.
0038 %          score: % cell scores for regions
0039 %       scoreRaw: % raw scores for segments
0040 %          props: % segement properties for segments
0041 %
0042 %
0043 %         seg.info(:,1) : the minimum phase intensity on the seg
0044 %         seg.info(:,2) : the mean phase intensity on the seg
0045 %         seg.info(:,3) : area of the seg
0046 %         seg.info(:,4) : the mean second d of the phase normal to the seg
0047 %         seg.info(:,5) : second d of the phase normal to the seg at the min pixel
0048 %         seg.info(:,6) : second d of the phase parallel to the seg at the min pixel
0049 %         seg.info(:,7) and seg_info(:,8) : min and max area of neighboring regions
0050 %         seg.info(:,9) and seg_info(:,10) : min and max lengths of the minor axis of the neighboring regions
0051 %         seg.info(:,11) and seg_info(:,12) : min and max lengths of the major axis of the neighboring regions
0052 %         seg.info(:,11) : length of minor axis
0053 %         seg.info(:,12) : length of major axis
0054 %         seg.info(:,13) : square of length of major axis
0055 %         seg.info(:,16) : max length of region projected onto the major axis
0056 %         segment
0057 %         seg.info(:,17) : min length of region projected onto the major axis
0058 %         segment
0059 %         seg.info(:,18) : max length of region projected onto the minor axis
0060 %         segment
0061 %         seg.info(:,19) : min length of region projected onto the minor axis
0062 %         segment
0063 %
0064 % The output images are related by
0065 % mask_cell = mask_bg .* (~segs_good) .* (~segs_3n);
0066 %
0067 % Copyright (C) 2016 Wiggins Lab
0068 % Written by Stella Stylianidou & Paul Wiggins.
0069 % University of Washington, 2016
0070 % This file is part of SuperSegger.
0071 %
0072 % SuperSegger is free software: you can redistribute it and/or modify
0073 % it under the terms of the GNU General Public License as published by
0074 % the Free Software Foundation, either version 3 of the License, or
0075 % (at your option) any later version.
0076 %
0077 % SuperSegger is distributed in the hope that it will be useful,
0078 % but WITHOUT ANY WARRANTY; without even the implied warranty of
0079 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0080 % GNU General Public License for more details.
0081 %
0082 % You should have received a copy of the GNU General Public License
0083 % along with SuperSegger.  If not, see <http://www.gnu.org/licenses/>.
0084 
0085 % Load the constants from the package settings file
0086 
0087 MIN_BG_AREA     = CONST.superSeggerOpti.MIN_BG_AREA;
0088 MAGIC_RADIUS    = CONST.superSeggerOpti.MAGIC_RADIUS;
0089 MAGIC_THRESHOLD = CONST.superSeggerOpti.MAGIC_THRESHOLD;
0090 CUT_INT         = CONST.superSeggerOpti.CUT_INT;
0091 SMOOTH_WIDTH    = CONST.superSeggerOpti.SMOOTH_WIDTH;
0092 MAX_WIDTH       = CONST.superSeggerOpti.MAX_WIDTH;
0093 A               = CONST.superSeggerOpti.A;
0094 verbose = CONST.parallel.verbose;
0095 
0096 
0097 if ~isfield( CONST.seg, 'segScoreInfo' )
0098     CONST.seg.segScoreInfo = @segInfoL2;
0099 end
0100 
0101 if ~exist('header','var')
0102     header = [];
0103 end
0104 
0105 if ~exist('crop_box','var')
0106     crop_box = [];
0107 end
0108 
0109 if ~exist('adapt_flag','var')
0110     adapt_flag = 1;
0111 end
0112 
0113 if ~exist('mask','var')
0114     mask = [];
0115 end
0116 
0117 mask_colonies = [];
0118 
0119 % If data structure is passed, rescue the phase image and mask
0120 if isstruct( phaseOrData )
0121     data      = phaseOrData;
0122     phaseOrig = data.phase;
0123     dataFlag  = true;
0124     segs_old = data.segs;
0125         
0126     % Copy the mask from data into mask if it is empty
0127     if isempty( mask )
0128         mask      = data.mask_bg;
0129     end
0130 else
0131     phaseOrig = phaseOrData;
0132     dataFlag  = false;
0133     data       = [];
0134     data.phase = phaseOrig;
0135 end
0136 
0137 
0138 
0139 
0140 % Initial image smoothing
0141 %this step is necessary to reduce the camera and read noise in the raw
0142 %phase image. Without it, the watershed algorithm will over-segment the
0143 %image.
0144 if all(ismember('100X',CONST.ResFlag))
0145     phaseNorm = imfilter(phaseOrig,fspecial('disk',1),'replicate');
0146 else
0147     phaseNorm = phaseOrig;
0148 end
0149 
0150 
0151 % fix the range, set the max and min value of the phase image
0152 mult_max = 2.5;
0153 mult_min = 0.3;
0154 mean_phase = mean(phaseNorm(:));
0155 phaseNorm(phaseNorm > (mult_max*mean_phase)) = mult_max*mean_phase;
0156 phaseNorm(phaseNorm < (mult_min*mean_phase)) = mult_min*mean_phase;
0157 
0158 
0159 % if the size of the meditatrix is even, we get a half pixel shift in the
0160 % position of the mask which turns out to be a probablem later.
0161 f = fspecial('gaussian', 11, SMOOTH_WIDTH);
0162 phaseNormFilt = imfilter(phaseNorm, f,'replicate');
0163 
0164 
0165 % Minimum constrast filter to enhance inter-cellular image contrast
0166 [phaseNormFilt,imin,imax] = ag(phaseNormFilt);
0167 magicPhase = magicContrast(phaseNormFilt, MAGIC_RADIUS);
0168 
0169 phaseNormUnfilt = (double(phaseOrig)-imin)/(imax-imin);
0170 
0171 % C2phase is the Principal curvature 2 of the image without negative values
0172 % it also enhances subcellular contrast. We subtract the magic threshold
0173 % to remove the variation in intesnity within a cell region.
0174 [~,~,~,C2phase] = curveFilter (double(phaseNormFilt),1);
0175 C2phaseThresh = double(uint16(C2phase-MAGIC_THRESHOLD));
0176 
0177 
0178 % creates initial background mask by globally thresholding the band-pass
0179 % filtered phase image. We determine the thresholds empirically.
0180 % We use one threshold to remove the background, and another to remove
0181 % the smaller background regions between cells.
0182 if isempty(mask)
0183     % no background making mask
0184     filt_3 = fspecial('gaussian',25, 15);
0185     filt_4 = fspecial('gaussian',5, 1/2);
0186     mask_colonies = makeBgMask(phaseNormFilt, filt_3, filt_4, MIN_BG_AREA, CONST, crop_box);
0187     
0188     [~,~,~,~,~,K,~,~] = curveFilter(phaseNormUnfilt, 3 );
0189     aK = abs(K);
0190     
0191     if CONST.superSeggerOpti.remove_debris
0192         mask_colonies = removeDebris(mask_colonies, phaseNormUnfilt, aK, CONST);
0193     end
0194     
0195     % remove bright halos from the mask
0196     mask_halos = (magicPhase>CUT_INT);
0197     mask_bg = logical((mask_colonies-mask_halos)>0);
0198     
0199     % removes micro-colonies with background level outline intensity - not bright enough
0200     
0201     if CONST.superSeggerOpti.remove_microcolonies
0202         mask_bg = intRemoveFalseMicroCol(mask_bg, phaseOrig, CONST);
0203     end
0204     
0205 else
0206     mask_bg = mask;
0207 end
0208 
0209 if nargin < 3 || isempty(disp_flag)
0210     disp_flag=1;
0211 end
0212 
0213 if nargin < 5 || isempty(adapt_flag)
0214     adapt_flag=1;
0215 end
0216 
0217 %% Split up the micro colonies into watershed regions to assemble cells
0218 % if data exists, reconstruct ws
0219 if dataFlag
0220     ws = logical(~data.mask_bg+data.segs.segs_3n+data.segs.segs_bad+data.segs.segs_good);
0221 else
0222     % watershed just the cell mask to identify segments
0223     phaseMask = uint8(agd(C2phaseThresh) + 255*(1-(mask_bg)));
0224     ws = 1-(1-double(~watershed(phaseMask,8))).*mask_bg;
0225     
0226     
0227     if adapt_flag
0228         % If the adapt_flag is set to true (on by default) it watersheds the C2phase
0229         % without using the thershold to identify more segments. It atempts to
0230         % breaks regions that are too big to be cells. This function slows the
0231         % code down, AND slows down the regionOpti code.
0232         
0233         wsc = 1- ws;
0234         regs_label = bwlabel( wsc );
0235         props = regionprops( regs_label, 'BoundingBox','Orientation','MajorAxisLength','MinorAxisLength');
0236         L2 = [props.MinorAxisLength];
0237         wide_regions = find(L2 > MAX_WIDTH);
0238         
0239         for ii = wide_regions
0240             [xx,yy] = getBB( props(ii).BoundingBox );
0241             mask_reg = (regs_label(yy,xx)==ii);
0242             
0243             c2PhaseReg = double(C2phase(yy,xx)).*mask_reg;
0244             invC2PhaseReg = 1-mask_reg;
0245             ppp = c2PhaseReg+max(c2PhaseReg(:))*invC2PhaseReg;
0246             wsl = double(watershed(ppp)>0);
0247             wsl = (1-wsl).*mask_reg;
0248             
0249             % prune added segs by adding just enough to fix the cell width problem
0250             wsl_cc = compConn( wsl, 4 );
0251             wsl_3n = double(wsl_cc>2);
0252             wsl_segs = wsl-wsl_3n;
0253             wsl_label = bwlabel(wsl_segs,4);
0254             num_wsl_label = max(wsl_label(:));
0255             wsl_mins = zeros(1,num_wsl_label);
0256             
0257             debug_flag = 0;
0258             if debug_flag
0259                 backer = 0.5*ag(ppp);
0260                 imshow(cat(3,backer,backer,backer + ag(wsl_segs)),[]);
0261                 keyboard;
0262             end
0263             
0264             for ff = 1:num_wsl_label
0265                 wsl_mins(ff) = min(c2PhaseReg(ff==wsl_label));
0266             end
0267             [wsl_mins, sort_ord] = sort(wsl_mins,'descend');
0268             
0269             wsl_segs_good = wsl_3n;
0270             
0271             for ff = sort_ord;
0272                 wsl_segs_good = wsl_segs_good + double(wsl_label==ff);
0273                 mask_reg_tmp = mask_reg-wsl_segs_good;
0274                 if maxMinAxis(mask_reg_tmp) < MAX_WIDTH
0275                     break
0276                 end
0277             end
0278             ws(yy,xx) = double(0<(ws(yy,xx) + wsl_segs_good));
0279         end
0280     end
0281 end
0282 
0283 %% Remake the data structure
0284 
0285 % Determine the "good" and "bad" segments
0286 data = defineGoodSegs(data,ws,phaseNormUnfilt,C2phaseThresh,mask_bg, A,CONST, ~dataFlag );
0287 data.mask_colonies = mask_colonies;
0288 % copy the existing score into the data structure
0289 if dataFlag
0290     
0291     data.segs.score = nan( [size(data.segs.info,1),1] );
0292     % map the regions
0293     props_tmp = regionprops( data.segs.segs_label, segs_old.segs_label, {'MinIntensity','MaxIntensity'} );
0294     tmp_min = [props_tmp.MinIntensity];
0295     tmp_max = [props_tmp.MaxIntensity];
0296     
0297     [y,x] = hist( tmp_max, 0:max(tmp_max));
0298     good_club = x(y==1);
0299     flagger = and( ismember( tmp_max,good_club), and(tmp_min==tmp_max,tmp_min>0));
0300     
0301     data.segs.score( flagger ) = segs_old.score(  tmp_max(flagger) );
0302     data.segs.score( ~flagger )  = nan;
0303     
0304     data.segs.segs_good = segs_old.segs_good;
0305     data.segs.segs_bad  = segs_old.segs_bad;
0306     data.segs.segs_3n   = segs_old.segs_3n;
0307     
0308     %disp( ['New segments lost: ',num2str(sum( ~flagger))] );
0309     %disp( ['Old segments lost: ',num2str(    sum(~ismember(unique(segs_old.segs_label(:)),tmp_max(flagger))))] );
0310 
0311 end
0312 
0313 % Calculate and return the final cell mask
0314 data.mask_cell = double((mask_bg - data.segs.segs_good - data.segs.segs_3n)>0);
0315 
0316 
0317 if disp_flag
0318     figure(1)
0319     clf;
0320     showSegDataPhase(data);
0321     drawnow;
0322 end
0323 
0324 
0325 
0326 
0327 end
0328 
0329 function Lmax = maxMinAxis(mask)
0330 % maxMinAxis : calculates maximum minor axis length of the regions in the mask.
0331 mask_label = bwlabel(mask);
0332 props = regionprops( mask_label, 'Orientation', 'MinorAxisLength' );
0333 Lmax =  max([props.MinorAxisLength]);
0334 end
0335

Generated on Thu 19-Jan-2017 13:55:21 by m2html © 2005