diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2229ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +emove autosaves generated by the Matlab editor +## We have git for backups! +##--------------------------------------------------- + +# Windows default autosave extension +*.asv + +# OSX / *nix default autosave extension +*.m~ + diff --git a/batch/BatchSuperSeggerOpti.m~ b/batch/BatchSuperSeggerOpti.m~ deleted file mode 100644 index dbc396f..0000000 --- a/batch/BatchSuperSeggerOpti.m~ +++ /dev/null @@ -1,347 +0,0 @@ -function BatchSuperSeggerOpti(dirname_,skip,clean_flag,res,startEnd,showWarnings) -% BatchSuperSeggerOpti : runs everything from start to finish, -% including alignment, building the directory structure, -%single image segmentation, error resolution, cell linking, -% fluorescence analysis, and cell files. -% -% Processes a raw data set by -% (1) Aligning and cropping time series -% (2) Organizing files into directories -% xy points are put in their own dir's -% phase, fluor files put in their own dir's -% makes seg and cell directories -% (3) Segmenting the frames into cell regions -% (4) Linking the regions between time steps -% (5) finding loci and calculating fluor statistics -% (6) Putting complete cells into the cell dir. -% -% INPUT : -% dirname_ : dir containing raw tif files -% skip : The segmentation is performed every skip files -% : this skip is very useful for high frequency timelapse where -% : cells would switch back and forth between one and two -% : segments leading to errors that are difficult to resolve. -% : This segments every skip files, then copies the segments into -% : the intermediate frames. -% clean_flag : Set this to be true to start from scratch and reseg all the -% : files regardless of whether any seg files exist. If this -% : flag is false, use existing segments, if they exist and -% : new segs if they don't yet exist. -% res : is a string that is passed to loadConstants(Mine).m to load -% : the right constants for processing. -% SEGMENT_FLAG : to segment cells -% ONLY_SEG : if true it does not run trackOpti (does only the segmentation) -% showWarnings : Set to 0 to mute warnings -% startEnd : array of two values to indicate where to start and where to -% stop the program. 1, alignment, 2, segmentation, 3, stripping, 4 linking, -% 5, cell marker, 6, cellA structrues, 7, clist, 8 cell files. -% -% 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 . - -% Init - -if (nargin < 1) || isempty( dirname_ ) || strcmp(dirname_ ,'.') - dirname_ = pwd; -end -dirname_ = fixDir(dirname_); - -if nargin < 2 || isempty( skip ) - skip = 1; % default : don't skip frames -end - -if nargin < 3 || isempty( clean_flag ) - clean_flag = 0; % default : don't resegment frames if segmented. -end - -if nargin < 4 || isempty( res ) - res = []; -end - - -if ~exist( 'startEnd', 'var' ) || isempty( startEnd ) - startEnd = [NaN NaN]; -end - -if ~exist( 'showWarnings', 'var' ) || isempty( showWarnings ) - showWarnings = 1; -end - -%if you pass a res value, write over CONST values. If it isn't passed, -% use existing values, if they exist. If not, load the default values. -if isstruct(res) - CONST = res; -else - disp (['BatchSuperSeggerOpti : Loading constants file ', res]); - if exist('loadConstantsMine','file'); - CONST = loadConstantsMine(res); - else - CONST = loadConstants(res,0); - end -end - - -if clean_flag && SEGMENT_FLAG && showWarnings - try - disp ('Clean flag is set to true.') - answer=input('Do you want to continue, Y/N [Y]:','s'); - if lower(answer) ~='y' - disp ('Exiting BatchSuperSegger. Reset clean flag and rerun'); - return - end - catch - % can not use input - in eval mode - end -end - -% align frames -if exist( dirname_, 'dir' ) && startEnd(1) <=1 - if exist( [dirname_,filesep,'raw_im'] ,'dir') && ... - (numel(dir ([dirname_,filesep,'raw_im',filesep,'*.tif'])) || ... - exist([dirname_,filesep,'raw_im',filesep,'cropbox.mat'],'file')) - disp('BatchSuperSeggerOpti : images already aligned'); - if exist([dirname_,filesep,'raw_im',filesep,'cropbox.mat'],'file') - tmp = load( [dirname_,filesep,'raw_im',filesep,'cropbox.mat'] ); - crop_box_array = tmp.crop_box_array; - else - crop_box_array = cell(1,10000); - end - elseif numel(dir ([dirname_,filesep,'*.tif'])) - % check naming convention - if ~isRightNameFormat(dirname_) - disp('Images in incorrect naming format. Using convertImageNames to convert names.') - convertImageNames(dirname_) - end - - mkdir( [dirname_,filesep,'raw_im'] ); - if CONST.align.ALIGN_FLAG - crop_box_array = trackOptiAlignPad( dirname_,... - CONST.parallel.parallel_pool_num, CONST); - movefile( [dirname_,filesep,'*.tif'], [dirname_,filesep,'raw_im'] ) % moves images to raw_im - movefile( [dirname_,'align',filesep,'*.tif'], [dirname_,filesep]); % moves aligned back to main folder - rmdir( [dirname_,'align'] ); % removes _align directory - else - crop_box_array = cell(1,10000); - end - else - error('No images found'); - end -else - error(['BatchSuperSeggerOpti : Can''t find directory ''',dirname_,'''. Exiting.'] ); -end - - -% setups the dir structure for analysis. -trackOptiPD(dirname_, CONST); -save( [dirname_,'CONST.mat'],'-STRUCT', 'CONST' ); % Saves CONST set you used. -save( [dirname_,'raw_im',filesep,'cropbox.mat'], 'crop_box_array' ); - -% Loop through xy directories -% Reset n values in case directories have already been made. -% setup nxy values -contents = dir([dirname_,'xy*']); - -if isempty(contents) - disp('BSSO: No xy directories were found.'); -else - num_dir_tmp = numel(contents); - nxy = []; - num_xy = 0; - - for i = 1:num_dir_tmp - if (contents(i).isdir) && (numel(contents(i).name) > 2) - num_xy = num_xy+1; - nxy = [nxy, str2num(contents(i).name(3:end))]; - dirname_list{i} = [dirname_,contents(i).name,filesep]; - end - end - - % set values for nc (array of channels (phase and fluorescent)) - contents = dir([dirname_list{1},'fluor*']); - num_dir_tmp = numel(contents); - nc = 1; - num_c = 1; - - for i = 1:num_dir_tmp - if (contents(i).isdir) && (numel(contents(i).name) > numel('fluor')) - num_c = num_c+1; - nc = [nc, str2num(contents(i).name(numel('fluor')+1:end))+1]; - end - end - - - % Set up parallel loop for each xy point if more than one xy position - % exists. If not more than one xy, we will parallelize inner loops - if (num_xy>1) && (CONST.parallel.parallel_pool_num>0) - workers = CONST.parallel.parallel_pool_num; - CONST.parallel.parallel_pool_num = 0; - else - workers=0; - end - - if workers || ~CONST.parallel.show_status - h = []; - else - h = waitbar( 0, ['Data segmentation xy: 0/',num2str(num_xy)] ); - cleanup = onCleanup( @()( delete( h ) ) ); - end - - parfor(j = 1:num_xy,workers) - %for j = 1:num_xy - - dirname_xy = dirname_list{j}; - intProcessXY( dirname_xy, skip, nc, num_c, clean_flag, ... - CONST, startEnd, crop_box_array{j}) - - if workers || ~CONST.parallel.show_status - disp( ['BatchSuperSeggerOpti: No status bar. xy ',num2str(j), ... - ' of ', num2str(num_xy),'.']); - else - if isvalid(h) - waitbar( j/num_xy,h,... - ['Data segmentation xy: ',num2str(j),... - '/',num2str(num_xy)]); - end - end - end - - if workers % shutting down parallel pool - poolobj = gcp('nocreate'); - delete(poolobj); - end - - - if ~workers - close(h); - end - -end - -% done! -end - -function intProcessXY( dirname_xy, skip, nc, num_c, clean_flag, ... - CONST, startEnd, crop_box) -% intProcessXY : the details of running the code in parallel. -% Essentially for parallel processing to work, you have to hand each -% processor all the information it needs to process the images. - -% Initialization -file_filter = '*.tif'; -verbose = CONST.parallel.verbose; - -% get header to show xy position -tmp1 = strfind( dirname_xy, 'xy'); -tmp2 = strfind( dirname_xy,[filesep]); - -if ~isempty(tmp1) && ~isempty(tmp2) - header = [dirname_xy(tmp1(end):(tmp2(end)-1)),': ']; -else - header = [dirname_xy]; -end - -% reset nz values -contents=dir([dirname_xy,'phase',filesep,file_filter]); -num_im = numel(contents); - -nz = []; % array of numbers of z frames -nt = []; % array of frame numbers - -for i = 1:num_im; - nameInfo = ReadFileName( contents(i).name ); - nt = [nt, nameInfo.npos(1,1)]; - nz = [nz, nameInfo.npos(4,1)]; -end - -nt = sort(unique(nt)); -nz = sort(unique(nz)); - -num_t = numel(nt); -num_z = numel(nz); - -if isempty(nz) || nz(1)==-1 % no z frames - nz = 1; -end - - -disp([header 'BatchSuperSeggerOpti : Segmenting Cells']); - -if (CONST.parallel.parallel_pool_num>0) - workers = CONST.parallel.parallel_pool_num; % number of workers -else - workers=0; -end - -if ~CONST.parallel.show_status - h = []; -else - h = waitbar( 0, ['BatchSuperSeggerOpti : Frame 0/',num2str(num_t)] ); - cleanup = onCleanup( @()( delete( h ) ) ); -end - -stamp_name = [dirname_xy,'seg',filesep,'.doSegFull']; - -if clean_flag - if exist(stamp_name,'file') - delete(stamp_name) - end - delete([dirname_xy,'seg',filesep,'*seg.mat*']); -end - - -% does the segmentations for all the frames in parallel -if startEnd(1) <= 2 && ~exist( stamp_name, 'file' ) - parfor(i=1:num_t,workers) % through all frames - %for i = 1:num_t - - if isempty( crop_box ) - crop_box_tmp = []; - else - crop_box_tmp = crop_box(i,:); - end - - doSeg(i, nameInfo, nc, nz, nt, num_z, num_c, dirname_xy, ... - skip, CONST, [header,'t',num2str(i),': '], crop_box_tmp); - - if ~CONST.parallel.show_status - if verbose - disp( [header, 'BatchSuperSeggerOpti : Segment. Frame ',num2str(i), ... - ' of ', num2str(num_t),'.']); - end - else - waitbar( i/num_t, h,... - ['Data segmentation t: ',num2str(i),'/',num2str(num_t)]); - end - end - time_stamp = clock; %#ok saved below - save( stamp_name, 'time_stamp'); % saves that xydir was full segmented -end -if CONST.parallel.show_status - if isvalid(h) - close(h); - end -end - -% trackOpti has all the rest of things : Linking, Cell files, Fluorescence calculation etc -if ~ONLY_SEG - trackOpti(dirname_xy,skip,CONST, clean_flag, header); -else - disp ('Only segmentation was set to true - Linking and cell files were not made'); -end -end - diff --git a/batch/processExp.m~ b/batch/processExp.m~ deleted file mode 100644 index c833edf..0000000 --- a/batch/processExp.m~ +++ /dev/null @@ -1,117 +0,0 @@ -function processExp( dirname ) -% processExp : main function for running the segmentation software. -% Used to choose the appropriate settings, and converting the images -% filenames before running BatchSuperSeggerOpti. -% Images need to have the NIS-Elements Format, or they can be converted -% using convertImageNames. -% -% the naming convention of the image files must be of the following format -% time, xy-positions, fluorescence channel, where c1 is bright field -% and c2,c3 etc are different fluorescent channels -% Example of two time points, two xy positions and one fluorescent channel -% filename_t001xy1c1.tif -% filename_t001xy1c2.tif -% filename_t001xy2c1.tif -% filename_t001xy2c2.tif -% filename_t002xy1c1.tif -% filename_t002xy1c2.tif -% filename_t002xy2c1.tif -% filename_t002xy2c2.tif -% -% INPUT : -% dirname : folder that contains .tif images in NIS elements format. -% -% -% Copyright (C) 2016 Wiggins Lab -% Written by Paul Wiggins, Nathan Kuwada, 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 . - -%% Converting other microscopes files -% For example if you are using MicroManager and the file format is the -% followin : date-strain_00000000t_BF.tif, date-strain_00000000t_GFP.tif, -% you can run convertImageNames(dirname, 'whatever_name_you_want', '', 't', -% '','', {'BF','GFP'} ) - -basename = 'date-strain'; -timeFilterBefore ='t'; -timeFilterAfter = '_' ; -xyFilterBefore='_x'; -xyFilterAfter='_'; -channelNames = {'BF','GFP'}; - -convertImageNames(dirname, basename, timeFilterBefore, ... - timeFilterAfter, xyFilterBefore,xyFilterAfter, channelNames ) - -%% Set the segmentations constants for your bacteria and micrscope resolution -% Using correct resolution ensures correct pixel size and segmentation constants -% if you do not know which constants to use you can run -% tryDifferentConstants(dirname) with a phase image to choose. - -% for E. coli we mainly use : -% '60XEc' : loadConstants 60X Ecoli -% '100XEc': loadConstants 100X Ecoli - -% other possible constants are : -% '100XPa' : 100X Pseudemonas -% '60XPa' : 60X Pseudemonas -%' 60XA' : 60X E.coli Aska -% '60XEcLB' : E.coli LB -% '60XPaM','60XPaM2' : for 60X, Pseudomonas Minimal -% '60XBthai' : 60X Thailandensis - -res = '60XEcLB'; - -%% Paralell Processing Mode -% to run code in parallel mode must have the parallel processing toolbox, -% for convenience default is false (non-parallel) - -parallel_flag = true; - -%% Load Constants -CONST = loadConstants(res,parallel_flag) ; - -%% Calculation Options -% after you load the constants you can modify them according to your needs -% for more options, looks at the loadConstants file. - -CONST.trackLoci.numSpots = [0 0]; % Max number of foci to fit in each fluorescence channel (default = [0 0]) -CONST.trackLoci.fluorFlag = false ; % compute integrated fluorescence (default = true) -CONST.trackOpti.NEIGHBOR_FLAG = false; % calculate number of neighbors (default = false) -CONST.imAlign.AlignChannel = 1; % change this if you want the images to be aligned to fluorescence channel - - -%% Skip Frames for Segmentation -% For fast time-lapse or slow growth you can skip phase image frames -% during segmentation to increase processing speed. Fluorescence images -% will not be skipped. - -skip = 1; % segment every frame -%skip = 5; % segment every fifth phase image - -%% Clean previous segmented data -% If set to true, will begin processing on aligned images; if false, will -% try to restart processing at last successful function (default = false) - -cleanflag = false; - - -%% Start running segmentation - -BatchSuperSeggerOpti( dirname, skip, cleanflag, CONST); - - -end diff --git a/batch/superSeggerGui.fig b/batch/superSeggerGui.fig index dacc5f1..5d546c5 100644 Binary files a/batch/superSeggerGui.fig and b/batch/superSeggerGui.fig differ diff --git a/batch/superSeggerGui.m b/batch/superSeggerGui.m index 5e61d2d..53fde85 100644 --- a/batch/superSeggerGui.m +++ b/batch/superSeggerGui.m @@ -59,6 +59,31 @@ function load_listbox(handles) function imageFolder_ClickedCallback(hObject, eventdata, handles) handles.directory.String = uigetdir; + + +function help_ClickedCallback(hObject, eventdata, handles) +msgbox('Examples for image conversion : ') + +function convert_names_help_Callback(hObject, eventdata, handles) + +Opt.Interpreter = 'tex'; +Opt.WindowStyle = 'normal'; +msgbox({'NAMING CONVERSION:', + '', + 'Our naming convention is : basename_t001xy1c1.tif, where t is the prefix for time, xy the prefix for position number and c the prefix for channel number.', + '', + 'The convert script accepts the prefix and suffix characters you use to indicate the frame and position numbers.' , + '', + 'For example if your naming convetion is \bfname-pos1-p-t001.tif\rm, you can use for channel names : \bf-p-\rm, position prefix : \bfpos\rm, time suffix : \bf.tif\rm.', +'If your naming convetion is \bfname{\_}00000000t{\_}BF.tif\rm and \bfname{\_}00000000t{\_}GFP.tif\rm, you can use for channel names : \bfBF,GFP\rm, time prefix : \bf{\_}\rm and time suffix : \bft{\_}\rm.' +}, 'Title','none',Opt); + + +function convert_names_help_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + function directory_Callback(hObject, eventdata, handles) function directory_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) @@ -200,4 +225,4 @@ function constants_list_Callback(hObject, eventdata, handles) function constants_list_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); -end \ No newline at end of file +end diff --git a/frameLink/errorRez.m~ b/frameLink/errorRez.m~ deleted file mode 100644 index e4e8095..0000000 --- a/frameLink/errorRez.m~ +++ /dev/null @@ -1,465 +0,0 @@ -function [data_c, data_r, cell_count,resetRegions] = errorRez (time, ... - data_c, data_r, data_f, CONST, cell_count, header, ignoreError, debug_flag) -% errorRez : links cells from the frame before to the current and attempts to -% resolve segmentation errors if the linking is inconsistent. -% -% INPUT : -% time : current frame number -% data_c : current time frame data (seg/err) file. -% data_r : reverse time frame data (seg/err) file. -% data_f : forward time frame data (seg/err) file. -% CONST : segmentation parameters. -% cell_count : last cell id used. -% header : last cell id used. -% debug_flag : 1 to display figures for debugging -% -% OUTPUT : -% data_c : updated current time frame data (seg/err) file. -% data_r : updated reverse time frame data (seg/err) file. -% cell_count : last cell id used. -% resetRegions : if true, regions were modified and this frame needs to -% be relinked. -% -% -% Copyright (C) 2016 Wiggins Lab -% Written by 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 . - - -global REMOVE_STRAY -global header_string -global regToDelete -header_string = header; -verbose = CONST.parallel.verbose; -MIN_LENGTH = 10; -REMOVE_STRAY = CONST.trackOpti.REMOVE_STRAY; -DA_MIN = CONST.trackOpti.DA_MIN; -DA_MAX = CONST.trackOpti.DA_MAX; -regToDelete = []; -resetRegions = false; -minAreaToMerge = 55; - - -% set all ids to 0 -cArea = [data_c.regs.props.Area]; -data_c.regs.ID = zeros(1,data_c.regs.num_regs); -modRegions = []; -for regNum = 1 : data_c.regs.num_regs; - - - if regNum == 34 - keyboard; - end - - if data_c.regs.ID(regNum) ~= 0 - disp ([header, 'ErRes: Frame: ', num2str(time), ' already has an id ',num2str(regNum)]); - elseif ismember (regNum,modRegions) - disp ([header, 'ErRes: Frame: ', num2str(time), ' already modified ',num2str(regNum)]); - else - rCellsFromC = data_c.regs.map.r{regNum}; % where regNum maps in reverse - - if ~isempty(rCellsFromC) - cCellsFromR = data_r.regs.map.f{rCellsFromC}; - cCellsTransp = data_c.regs.revmap.r{rCellsFromC}; - else - cCellsFromR = []; - cCellsTransp = []; - end - - - %%% maps to 0 - if numel(rCellsFromC) == 0 % maps to 0 in the previous frame - stray - - % think whether this is useful : numel(mapRC) == 0 - if (time ~= 1) && (hasNoFwMapping(data_c,regNum) && REMOVE_STRAY) - % deletes the regions not appearing at time = 1 that do not map to anything - % or if remove_stray flag is set to true. - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time), ... - ', reg: ', num2str(regNum), '. is a stray region - Deleted.']; - if verbose - disp([header, 'ErRes: ',data_c.regs.error.label{regNum}] ); - end - regToDelete = [regToDelete;regNum]; - resetRegions = true; - else % maps to a region in the next frame, or time is 1 - if time~=1 - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time), ... - ', reg: ', num2str(regNum), '. is a stray region.']; - if verbose - disp([header, 'ErRes: ',data_c.regs.error.label{regNum}] ); - end - end - [data_c,cell_count] = createNewCell (data_c, regNum, time, cell_count); - end - - elseif numel(rCellsFromC) == 1 && numel (cCellsTransp) == 1 && all(cCellsFromR == regNum) - % MAPS TO ONE AND AGREES - % sets cell ID from mapped reg, updates death in data_r - errorStat = (data_c.regs.error.r(regNum)>0); - [data_c, data_r] = continueCellLine( data_c, regNum, data_r, rCellsFromC, time, errorStat); - - elseif numel(rCellsFromC) == 1 && numel (cCellsTransp) == 1 && ~all(cCellsFromR == regNum) - % MAPS TO ONE AND DISAGREES - % map with an error flag... - errorStat = (data_c.regs.error.r(regNum)>0); - [data_c, data_r] = continueCellLine( data_c, regNum, data_r, rCellsFromC, time, errorStat); - - - - elseif numel(rCellsFromC) == 1 && numel(cCellsFromR) == 1 && numel (cCellsTransp) == 2 - % regNum and another cell map to one in reverse - % but one in reverse only maps to one forward - - sister1 = regNum; - sister2 = cCellsTransp (cCellsTransp~=regNum); - mapRC = cCellsTransp; - mother = rCellsFromC; - - if debug_flag - % red in c maps to blue in r, blue in r maps to green in c - imshow(cat(3,0.5*ag(data_c.phase) + 0.5*ag(data_c.regs.regs_label==sister1),... - ag(data_r.regs.regs_label == mother),ag(data_c.regs.regs_label==sister2))); - end - - totAreaC = data_c.regs.props(sister1).Area + data_c.regs.props(sister2).Area; - totAreaR = data_r.regs.props(mother).Area; - AreaChange = (totAreaC-totAreaR)/totAreaC; - goodAreaChange = (AreaChange > DA_MIN && AreaChange < DA_MAX); - haveNoMatch = (isempty(data_c.regs.map.f{sister1}) || isempty(data_c.regs.map.f{sister2})); - matchToTheSame = ~haveNoMatch && all(ismember(data_c.regs.map.f{sister1}, data_c.regs.map.f{sister2})); - oneIsSmall = (cArea(sister1) < minAreaToMerge) || (cArea(sister2) < minAreaToMerge); - if goodAreaChange && ~ignoreError && ~isempty(data_f) && (haveNoMatch || matchToTheSame || oneIsSmall) - % r: one has no forward mapping, or both map to the same in fw, or one small - % wrong division merge cells - [data_c,mergeReset] = merge2Regions (data_c, [sister1, sister2], CONST); - modRegions = [modRegions;sister1;sister2]; - resetRegions = (resetRegions || mergeReset); - elseif goodAreaChange - [data_c, data_r, cell_count] = createDivision (data_c,data_r,mother,sister1,sister2, cell_count, time,header, verbose); - modRegions = [modRegions;sister1;sister2]; - else - % map to best, remove mapping from second - [data_c,data_r,cell_count,reset_tmp,modids_tmp] = mapBestOfTwo (data_c, mapRC, data_r, rCellsFromC, time, verbose, cell_count,header); - resetRegions = or(reset_tmp,resetRegions); - modRegions = [modRegions;modids_tmp]; - end - - elseif numel(rCellsFromC) == 1 && numel(cCellsFromR) == 2 - % the 1 in reverse maps to two in current : possible splitting event - mother = rCellsFromC; - sister1 = regNum; - mapRC = data_r.regs.map.f{mother}; - sister2 = mapRC (mapRC~=regNum); - sister2Mapping = data_c.regs.map.r{sister2}; - - if numel(sister2) == 1 && any(mapRC==regNum) && ~isempty(sister2Mapping) && all(sister2Mapping == mother) - - - - totAreaC = data_c.regs.props(sister1).Area + data_c.regs.props(sister2).Area; - totAreaR = data_r.regs.props(mother).Area; - AreaChange = (totAreaC-totAreaR)/totAreaC; - goodAreaChange = (AreaChange > DA_MIN && AreaChange < DA_MAX); - haveNoMatch = (isempty(data_c.regs.map.f{sister1}) || isempty(data_c.regs.map.f{sister2})); - matchToTheSame = ~haveNoMatch && all(ismember(data_c.regs.map.f{sister1}, data_c.regs.map.f{sister2})); - oneIsSmall = (cArea(sister1) < minAreaToMerge) || (cArea(sister2) < minAreaToMerge); - if goodAreaChange && ~ignoreError && (haveNoMatch || matchToTheSame || oneIsSmall) - - - - % wrong division merge cells - if ~ignoreError - [data_c,reset_tmp] = merge2Regions (data_c, [sister1, sister2], CONST); - modRegions = [modRegions;sister1;sister2]; - else - [data_c,data_r,cell_count,reset_tmp,modids_tmp] = mapBestOfTwo (data_c, mapRC, data_r, rCellsFromC, time, verbose, cell_count,header); - modRegions = [modRegions;modids_tmp]; - end - resetRegions = or(reset_tmp,resetRegions); - else - [data_c, data_r, cell_count] = createDivision (data_c,data_r,mother,sister1,sister2, cell_count, time,header, verbose); - modRegions = [modRegions;sister1;sister2]; - end - elseif numel(sister2) == 1 && any(mapRC==regNum) && any(data_c.regs.map.r{sister2} ~= mother) - % map the one-to-one to mother - errorStat = (data_c.regs.error.r(regNum)>0); - [data_c, data_r] = continueCellLine( data_c, regNum, data_r, rCellsFromC, time, errorStat); - - elseif ~any(mapRC==regNum) - % ERROR NOT FIXED : mapCR maps to mother. but mother maps to - % two other cells.. - % OTHER POSSIBLE RESOLUTIONS.. : - % 1 : merging missing, cell divided but piece fell out - check - % if all three should be mapped - % 2 : get the best two couples of the three - - % force mapping - sister1 = regNum; - sister2 = mapRC(1); - sister3 = mapRC(2); - - % make a new cell for regNum with error... - [data_c,cell_count] = createNewCell (data_c, regNum, time, cell_count); - data_c.regs.error.r(regNum) = 1; - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time),... - ', reg: ', num2str(regNum),'. Incorrect Mapping 1 to 2 - making a new cell']; - - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{regNum}]); - end - % red : regNum, green : ones mother maps to, blue : mother - if debug_flag - imshow(cat(3,0.5*ag(data_c.phase) + 0.5*ag(data_c.regs.regs_label==regNum), ... - ag((data_c.regs.regs_label == mapRC(1)) + ... - (data_c.regs.regs_label==mapRC(2))),ag(data_r.regs.regs_label==mother))); - end - else - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time),... - ', reg: ', num2str(regNum),'. Error not fixed - two to 1 but don''t know what to do.']; - - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{regNum}]); - end - - end - elseif numel(rCellsFromC) > 1 - % 1 in current maps to two in reverse - % try to find a segment that should be turned on in current - % frame, exit regNum loop, make time - 1 and relink - - % The two in reverse map to regNum only - % twoInRMapToCOnly = numel(data_r.regs.map.f{rCellsFromC(1)}) == 1 && data_r.regs.map.f{rCellsFromC(1)}==regNum && ... - % numel(data_r.regs.map.f{rCellsFromC(2)}) == 1 && data_r.regs.map.f{rCellsFromC(2)}==regNum; - - if debug_flag - imshow(cat(3,0.5*ag(data_c.phase), 0.7*ag(data_c.regs.regs_label==regNum),... - ag((data_r.regs.regs_label==rCellsFromC(1)) + (data_r.regs.regs_label==rCellsFromC(2))))); - end - - - if ~ignoreError %& twoInRMapToCOnly - [data_c,success] = missingSeg2to1 (data_c,regNum,data_r,rCellsFromC,CONST); - else - success = false; - end - - if success % segment found - data_c.regs.error.r(regNum) = 0; - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time),... - ', reg: ', num2str(regNum),'. Segment added to fix 2 to 1 error']; - - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{regNum}]); - end - if debug_flag - imshow(cat(3,ag(data_c.regs.regs_label == regNum)+0.5*ag(data_c.phase),... - ag(data_r.regs.regs_label == rCellsFromC(1)),... - ag(data_r.regs.regs_label == rCellsFromC(2)))); - end - resetRegions = true; - else - % ERROR NOT FIXED : link to the one with the best score - [data_c,data_r] = mapToBestOfTwo (data_c, regNum, data_r, rCellsFromC, time, verbose,header); - end - - - elseif numel(rCellsFromC) == 1 && numel(cCellsFromR) > 2 - - haveNoMatch = any(isempty({data_c.regs.map.f{cCellsFromR}})); - forwMap = [data_c.regs.map.f{cCellsFromR}]; - forwardMap = unique(forwMap); - occur = histc(forwMap,forwardMap); - matchToTheSame = ~haveNoMatch && numel(forwardMap)==1; - someMatchToSame = ~haveNoMatch && any(occur>1); - % r: one has no forward mapping, or both map to the same in fw - if ~isempty(data_f) && (haveNoMatch || matchToTheSame) - % wrong division merge cells - if ~ignoreError - [data_c,reset_tmp] = merge2Regions (data_c, cCellsFromR, CONST); - modRegions = [modRegions;cCellsFromR']; - else - [data_c,data_r,cell_count,reset_tmp,modids_tmp] = mapBestOfTwo (data_c, cCellsTransp, data_r, rCellsFromC, time, verbose, cell_count,header); - modRegions = [modRegions;modids_tmp]; - end - resetRegions = or(reset_tmp,resetRegions); - elseif ~isempty(data_f) && (someMatchToSame) - indFwMap = find(occur>1); - valueFw = forwardMap(indFwMap); - cellsToMerge = []; - for i = 1 : numel(cCellsFromR) - cur_cell = cCellsFromR(i); - if any(data_c.regs.map.f{cur_cell} == valueFw) - cellsToMerge = [cellsToMerge ;cur_cell]; - end - - end - [data_c,reset_tmp] = merge2Regions (data_c, cellsToMerge, CONST); - modRegions = [modRegions;cellsToMerge]; - end - else - - data_c.regs.error.label{regNum} = ['Frame: ', num2str(time),... - ', reg: ', num2str(regNum),'. Error not fixed']; - - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{regNum}]); - end - if debug_flag - intDisplay (data_r,rCellsFromC,data_c,regNum); - - end - - end - - end -end -%intDisplay (data_c,regToDelete,data_f,[]); -[data_c] = deleteRegions( data_c,regToDelete); - -end - - - -function intDisplay (data_c,regC,data_f,regF) -% intDisplay : displays linking -% reg : maskF -% green : maskC -% blue : all cell masks in c - - -maskC = data_c.regs.regs_label*0; -for c = 1 : numel(regC) - if ~isnan(regC(c)) - maskC = maskC + (data_c.regs.regs_label == regC(c))>0; - end -end - -if ~isempty (data_f) - maskF = data_f.regs.regs_label*0; - if isempty(regF) - disp('nothing') - imshow (cat(3,0*ag(maskF),ag(maskC),ag(data_c.mask_cell))); - else - for f = 1 : numel(regF) - if ~isnan(regF(f)) - maskF = maskF + (data_f.regs.regs_label == regF(f))>0; - end - end - imshow (cat(3,ag(maskF),ag(maskC),ag(data_c.mask_cell))); - end -end -end - - - - -function [ data_c, data_r, cell_count ] = createDivision (data_c,data_r,mother,sister1,sister2, cell_count, time, header, verbose) - -data_c.regs.error.label{sister1} = (['Frame: ', num2str(time),... - ', reg: ', num2str(sister1),' and ', num2str(sister2),' . cell division from mother reg', num2str(mother),'. [L1,L2,Sc] = [',... - num2str(data_c.regs.L1(sister1),2),', ',num2str(data_c.regs.L2(sister1),2),... - ', ',num2str(data_c.regs.scoreRaw(sister1),2),'].']); -if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{sister1}] ); -end -data_r.regs.error.r(mother) = 0; -data_c.regs.error.r(sister1) = 0; -data_c.regs.error.r(sister2) = 0; -[data_c, data_r, cell_count] = markDivisionEvent( ... - data_c, sister1, data_r, mother, time, 0, sister2, cell_count); - -end - - -function result = hasNoFwMapping (data_c,regNum) -result = isempty(data_c.regs.map.f{regNum}); -end - - -function [data_c,data_r] = mapToBestOfTwo (data_c, regNum, data_r, mapCR, time, verbose,header) -% maps to best from two forward - - -flaggerC = (data_c.regs.idsC.r(1,:) == regNum) & isnan(data_c.regs.idsC.r(2,:)); -flaggerR1 = (data_c.regs.idsR.r(1,:) == mapCR(1)) & isnan(data_c.regs.idsR.r(2,:)); -flaggerR2 = (data_c.regs.idsR.r(1,:) == mapCR(2)) & isnan(data_c.regs.idsR.r(2,:)); - -loc1 = find(flaggerC&flaggerR1); -loc2 = find(flaggerC&flaggerR2); -cost1 = data_c.regs.cost.r(loc1); -cost2 = data_c.regs.cost.r(loc2); - -if isempty(cost2) || cost10); -[data_c, data_r] = continueCellLine( data_c, keeper, data_r, mapCR, time, errorStat); -data_c.regs.revmap.r{mapCR} = keeper; - - -data_c.regs.error.r(remove) = 1; -idsOfModRegions = [remove;keeper]; -if REMOVE_STRAY && hasNoFwMapping(data_c,remove) - data_c.regs.error.label{remove} = (['Frame: ', num2str(time),... - ', reg: ', num2str(remove),' was not the best match for ', num2str(mapCR),' and was deleted.' num2str(keeper) , ' was.']); - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{remove}] ); - end - regToDelete = [regToDelete;remove]; - resetRegions = true; -else - [data_c,cell_count] = createNewCell (data_c, remove, time, cell_count); - data_c.regs.error.label{remove} = (['Frame: ', num2str(time),... - ', reg: ', num2str(remove),' was not the best match for ', num2str(mapCR),' made into a new cell.']); - if verbose - disp([header, 'ErRes: ', data_c.regs.error.label{remove}] ); - end -end -end \ No newline at end of file diff --git a/frameLink/trackOptiStripSmall.m~ b/frameLink/trackOptiStripSmall.m~ deleted file mode 100644 index 156c944..0000000 --- a/frameLink/trackOptiStripSmall.m~ +++ /dev/null @@ -1,136 +0,0 @@ -function trackOptiStripSmall(dirname, CONST, disp_flag) -% trackOptiStripSmall : removes small regions and fills holes in the regions. -% It removes regions anything with area below CONST.trackOpti.MIN_AREA -% that are probably not real, typically bubbles, dust, or minicells. -% It then creates a new cell mask and new region fields and resaves the seg -% file. -% -% INPUT : -% dirname : seg folder eg. maindirectory/xy1/seg -% CONST : Constants file -% -% 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 . - - -VERY_SMALL_AREA = CONST.trackOpti.MIN_AREA; % smaller that this is stripped -MIN_AREA = CONST.trackOpti.MIN_AREA; % smaller that this is stripped if no neighbors -dirname = fixDir(dirname); -contents=dir([dirname '*_seg.mat']); -num_im = length(contents); - -if ~exist('disp_flag','var') || isempty(disp_flag) - disp_flag = 0; -end - - -if CONST.parallel.show_status - h = waitbar( 0, 'Strip small cells.'); - cleanup = onCleanup( @()( delete( h ) ) ); -else - h = []; -end -SE = strel('disk',3); - -for i = 1:num_im; - - if CONST.parallel.show_status - waitbar((num_im-i)/num_im,h,['Strip small cells--Frame: ',num2str(i),'/',num2str(num_im)]); - end - - data_c = loaderInternal([dirname,contents(i).name]); % load data - - % remove small area regions - regs_label = bwlabel(data_c.mask_cell); - props = regionprops( regs_label, 'Area' ); - area_props = [props(:).Area]; - small = find(area_props<=MIN_AREA); - - small_new = []; - % only if they can not connect to other cells - for j = 1 : numel(small) - id = small(j); - mask = imdilate(regs_label == id,SE); - neighbors = unique(regs_label(mask)); - neighbors = neighbors(neighbors~=id); - neighbors = neighbors(neighbors~=0); - if isempty(neighbors) || (area_props(id) < VERY_SMALL_AREA) - small_new = [small_new,id]; - end - end - - - % remove the small from the mask - cellmask_small= ismember( regs_label,small_new ); - cellmask_nosmall = data_c.mask_cell ; - cellmask_nosmall (cellmask_small) = 0; - - data_c.mask_bg (cellmask_small) =0; - - % remove segments in small regions - dilatedMask = imdilate(cellmask_nosmall, strel('square',4)); - data_c.segs.segs_3n(~dilatedMask) = 0; - data_c.segs.segs_good(~dilatedMask) = 0; - data_c.segs.segs_bad(~dilatedMask) = 0; - - - % filling the holes in each region separetely - ss = size( data_c.phase ); - regs_label = bwlabel( cellmask_nosmall ); - props = regionprops( regs_label, {'Area','BoundingBox'} ); - num_props = numel(props); - mask_new = false(ss); - - for ii = 1:num_props - [xx,yy] = getBBpad(props(ii).BoundingBox, ss,1); - mask = (regs_label(yy,xx)==ii); - mask__ = bwmorph(bwmorph( mask, 'dilate'), 'erode' ); - mask__ = imfill(mask__,'holes'); - mask_tmp = mask_new(yy,xx); - mask_tmp(mask__) = true; - mask_new(yy,xx) = mask_tmp; - end - - - if disp_flag - imshow(cat(3,ag( data_c.mask_cell),ag(mask_new),ag(mask_new))); - pause; - end - - data_c.mask_cell = mask_new; - - % remake the regions - data_c = intMakeRegs( data_c, CONST); - - % save the updated *seg.mat file - dataname=[dirname,contents(i).name]; - save(dataname,'-STRUCT','data_c'); - - -end - -if CONST.parallel.show_status - close(h); -end - -end - - -function data = loaderInternal( filename ) -data = load( filename ); -end \ No newline at end of file diff --git a/settings/loadConstants.m b/settings/loadConstants.m index 2516564..fe24951 100644 --- a/settings/loadConstants.m +++ b/settings/loadConstants.m @@ -34,8 +34,13 @@ % You should have received a copy of the GNU General Public License % along with SuperSegger. If not, see . +% gets the list of all possible constants in the settings folder +[possibleConstants, list, filepath] = getConstantsList(); + +CONST = []; if nargin < 1 || isempty( res ) - disp ('No constant chosen'); + disp ('No constant chosen. Possible constants are : '); + disp(list'); return; end @@ -47,8 +52,7 @@ dispText = true; end -% gets the list of all possible constants in the settings folder -[possibleConstants, ~, filepath] = getConstantsList(); + % default values for numbers resFlag = []; @@ -186,7 +190,10 @@ ConstLoaded = load(res); CONST.ResFlag = res; else - errordlg('loadConstants: Constants not loaded : no match found. Aborting.'); + errordlg('loadConstants: Constants not loaded : no match found. Aborting. '); + disp(['Possible constants']); + disp(list'); + CONST = []; return; end diff --git a/viz/superSeggerViewerGui.fig b/viz/superSeggerViewerGui.fig index 0ba4add..4da48f3 100644 Binary files a/viz/superSeggerViewerGui.fig and b/viz/superSeggerViewerGui.fig differ diff --git a/viz/superSeggerViewerGui.m b/viz/superSeggerViewerGui.m index 1ea3648..d1b12fa 100644 --- a/viz/superSeggerViewerGui.m +++ b/viz/superSeggerViewerGui.m @@ -337,12 +337,7 @@ function initImage(hObject, handles) % Not updated showSeggerImage(handles.data_c, handles.data_r, handles.data_f, forcedFlags, handles.clist, handles.CONST, handles.axes1); try save(handles.filename_flags, 'FLAGS', 'nn', 'dirnum' ); - clist = handles.clist; - if ~isempty(clist) - save( [handles.dirname0,handles.contents_xy(handles.dirnum).name,filesep,'clist.mat'],'-STRUCT','clist'); - end catch - disp('Error saving.' ); end end @@ -1501,3 +1496,18 @@ function cell_no_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end + + +% --- Executes on button press in save_clist. +function save_clist_Callback(hObject, eventdata, handles) +% hObject handle to save_clist (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) +try + clist = handles.clist; + if ~isempty(clist) + save( [handles.dirname0,handles.contents_xy(handles.dirnum).name,filesep,'clist.mat'],'-STRUCT','clist'); + end +catch + disp('Error saving.' ); +end