diff --git a/+agg/seg.m b/+agg/seg.m index d8d631c..1b9b7eb 100644 --- a/+agg/seg.m +++ b/+agg/seg.m @@ -181,11 +181,11 @@ moreaggs = 0; % default, returned if 'Yes' is chosen if strcmp(choice,'Yes, but refine') choice2 = questdlg('How do you want to refine aggregate detection?',... - 'agg detection','More particles or add to existing particles', ... + 'agg detection','Interactive tool to adjust thresholding', ... 'Remove particles','More particles or add to existing particles'); % If more particles, set moreaggs = 1, which will skip ahead to Line 131 - if strcmp(choice2, 'More particles or add to existing particles') + if strcmp(choice2, 'Interactive tool to adjust thresholding') moreaggs = 1; % If particles to remove, use the bwselect utility. diff --git a/+agg/ui_slider2.mlapp b/+agg/ui_slider2.mlapp index cd7a6cf..aaea22b 100644 Binary files a/+agg/ui_slider2.mlapp and b/+agg/ui_slider2.mlapp differ diff --git a/+tools/load_imgs.m b/+tools/load_imgs.m index 52d6473..d0605d9 100644 --- a/+tools/load_imgs.m +++ b/+tools/load_imgs.m @@ -10,7 +10,7 @@ % the input string, FD. For example, the sample images can be loaded using % IMGS = load_imgs('images'). % -% IMGS = load_imgs(FD,N) loads the images specified by array N. By +% IMGS = load_imgs(FD, N) loads the images specified by array N. By % default, N spans 1 to the number of images in the given folder. For % example, the 2nd and 3rd images can be loaded using N = [2,3]. This % allows for partial loading of larger data sets for batch processing. @@ -95,13 +95,18 @@ %-- Get file information -------------------------------------------------% while flag == 0 - dir_start = 'images'; % initial directory to look for images + dir_start = 'images'; % initial directory to look for images % Browse or get file information. - if isempty(fd) % if no folder, user browses for images (tif,jpg) + if isempty(fd) % if no folder, user browses for images (tif,jpg) [fname, folder] = uigetfile({'*.tif;*.jpg;*.png', 'TEM image (*.tif;*.jpg)'}, ... 'Select Images', dir_start, 'MultiSelect', 'on'); - else % if folder is given, get all tif files in the folder + + elseif isfile(fd) % then a single filename is given + [folder, fname, ext] = fileparts(fd); + fname = [fname, ext]; + + else % if folder is given, get all tif files in the folder t0 = [ ... % pattern to match filenames dir(fullfile(fd,'*.tif')), ... % get TIF dir(fullfile(fd,'*.png')), ... % get PNG @@ -111,15 +116,15 @@ end % Format file information for output - if iscell(fname) % handle a cell array of files + if iscell(fname) % handle a cell array of files flag = 1; for ii=length(fname):-1:1 Imgs(ii).fname = fname{ii}; Imgs(ii).folder = [folder, filesep]; end - elseif Imgs.fname==0 % handle when no image was selected + elseif Imgs.fname==0 % handle when no image was selected error('No image selected.'); - else % handle when only one image is selected + else % handle when only one image is selected Imgs.fname = fname; Imgs.folder = [folder, filesep]; flag = 1; diff --git a/+tools/write_json.m b/+tools/write_json.m index f0f2852..9eec52a 100644 --- a/+tools/write_json.m +++ b/+tools/write_json.m @@ -1,9 +1,20 @@ +% WRITE_JSON Used to write structures for JSON files. +% NOTE: Saving large aggregate structures can be slow. +% +% AUTHOR: Timothy Sipkens function [t2,t0] = write_json(var, fname) fid = fopen(fname,'wt'); % open file, overwriting previous text +% Binary field of Aggs structure is sparse logical. +% Convert of logical, as sparse structure cannot be stored. +if isfield(var, 'binary') + for ii=1:length(var) + var(ii).binary = full(var(ii).binary); + end +end %-- Encode json ----------------------------------------------------------% t0 = jsonencode(var); % generate json text using built-in function diff --git a/.circleci/config.yml b/.circleci/config.yml index 2a6c09a..4556ffa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ jobs: build: machine: - image: 'ubuntu-2004:202201-02' + image: default steps: - checkout - matlab/install diff --git a/README.md b/README.md index 20d35a3..4b7d72c 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,13 @@ This code also includes a set of utility functions in the **+tools** package and # A. Dependencies -This software was tested using MATLAB 2020a (though most functions have been validated against older versions) and depends on the following MATLAB toolboxes: +This software was tested using MATLAB 2022a (though most functions have been validated against older versions). The current code depends on the following MATLAB toolboxes: 1. the curve fitting toolbox, 2. the financial toolbox, 3. the image toolbox, 4. the optimization toolbox, and -6. the video and image blockset (in the computer vision toolbox, which is used for OCR). +5. the video and image blockset (in the computer vision toolbox, which is used for OCR). If not already installed, these packages can be added to MATLAB via the instructions available on [MATLAB's website](https://www.mathworks.com/help/matlab/matlab_env/get-add-ons.html). @@ -62,7 +62,9 @@ git submodule init The submodule is not necessary for any of the scripts or methods included with this code. -Additional dependencies are required for use of the **[carboseg](https://github.com/tsipkens/atems/tree/master/carboseg)** or convolutional neureal network component of this program, including a copy of Python. See the appropriate [section below](#+-carboseg-and-cnn-segmentation) for more information. +Additional dependencies are required for use of the **[carboseg](https://github.com/tsipkens/atems/tree/master/carboseg)** or convolutional neural network component of this program, including a copy of Python. See the appropriate [section below](#+-carboseg-and-cnn-segmentation) for more information. + +This code has been tested on Windows 10+. Linux users may have some issues with loading images when supplying a string to `tools.load_imgs(...)` (for example, because of differences in file separator). macOS users may encounter similar issues, including in writing aggregate structures to JSON files and in certain plotting functions. # B. Getting started @@ -115,7 +117,7 @@ on the MATLAB command line for more information on that function. The next step is to evaluate binary masks that separate the image into pixels that are part of the background and pixels that are part of aggregates. This is done using the functions in the **+agg** package. For example, a *k*-means classifier can be used by calling: ```Matlab -imgs_binary = agg.seg_kmeans(imgs, pixsizes, opts); +imgs_binary = agg.seg_kmeans(imgs, pixsizes); % segment aggregates ``` @@ -175,7 +177,7 @@ Code associated with this example is given in the script **main_b.m**. The outpu # C. Components -This section provides details of the overall structure of this codebase and the methods available for characterization of soot aggregates in TEM images. +This section provides details of the overall structure of this codebase and the methods available for the characterization of soot aggregates in TEM images. ## 1. MAIN SCRIPTS (main_\*): Testing the codebase @@ -232,17 +234,17 @@ This `seg_carboseg(...)` function employs Python to implement a convolutional ne Details on the setup and use of this component are given in the [README](carboseg/README.md) in the **carboseg** subfolder. Two options exist for interacting with the Python code: (1) initializing an instance of Python directly in MATLAB or (2) a multi-step procedure of exporting and reimporting images. -### + **seg_otsu_rb\*** / Otsu thresholding +### + **seg_otsu\*** / Otsu thresholding These automated methods apply Otsu thresholding followed by a rolling ball transformation. Two versions of this function are included. -**A.** The `agg.seg_otsu_rb_orig(...)` function remains more true to the original code of [Dastanpour et al. (2016)][dastanpour2016]. For the sample images, this often results in fragmented segmentations, e.g., +**A.** The `agg.seg_otsu_orig(...)` function remains more true to the original code of [Dastanpour et al. (2016)][dastanpour2016]. For the sample images, this often results in fragmented segmentations, e.g., ![rb_orig](docs/otsu_rb_orig.png) As the technique may be insufficient on its own, this implementation can be complimented with `agg.seg_slider(...)`, described [below](#-seg_slider_orig--gui-based-slider-method), to fill in the gaps between the aggregates and add missing aggregates. -**B.** Stemming from the deficiencies of the above function, the `agg.seg_otsu_rb(...)` function updates the above implementation by (*i*) not immediately removing boundary aggregates, (*ii*) adding a background subtraction step using the `agg.bg_subtract(...)` function, and (*iii*) adding a bilateral denoising step. This results in the following segmentations. +**B.** Stemming from the deficiencies of the above function, the `agg.seg_otsu(...)` function updates the above implementation by (*i*) not immediately removing boundary aggregates, (*ii*) adding a background subtraction step using the `agg.bg_subtract(...)` function, and (*iii*) adding a bilateral denoising step. This results in the following segmentations. ![otsu_rb](docs/otsu_rb.png) @@ -292,11 +294,11 @@ Among the changes to the original EDM-SBS code, this implementation also applies ### + **kook\*** / Hough transform -Two `pp.kook*(...)` functions are included with this program, which fit circles to features in the image using the Hough transform and the pre-processing steps described by [Kook et al. (2015)][kook]. +Two `pp.hough_kook**(...)` functions are included with this program, which fit circles to features in the image using the Hough transform and the pre-processing steps described by [Kook et al. (2015)][kook]. -The first function, `pp.kook(...)`, contains a copy of the code provided by [Kook et al. (2015)][kook], with minor modifications to match the input/output of some of the other packages — namely to take a single image, `img`, and a pixel size, `pixsize` — and to output a `Pp` structure, which contains information for each circle. Note that the original function acts on images without trying to assign primary particles to an aggregate, something resolved in the second function below. This causes some compatibility issues in terms of comparing the output from this function to the other methods contained in this program. +The first function, `pp.hough_kook*(...)`, contains a copy of the code provided by [Kook et al. (2015)][kook], with minor modifications to match the input/output of some of the other packages — namely to take a single image, `img`, and a pixel size, `pixsize` — and to output a `Pp` structure, which contains information for each circle. Note that the original function acts on images without trying to assign primary particles to an aggregate, something resolved in the second function below. This causes some compatibility issues in terms of comparing the output from this function to the other methods contained in this program. -The `pp.kook2(...)` function contains a modified version of the method proposed by [Kook et al. (2015)][kook] that excludes circles in the background and assigns primary particles to aggregates. This is done rather simply: by checking if the center of the circles from the preceding procedure lie within the binary for a given aggregate. A sample output is as follows. +The `pp.hough_kook2(...)` function contains a modified version of the method proposed by [Kook et al. (2015)][kook] that excludes circles in the background and assigns primary particles to aggregates. This is done rather simply: by checking if the center of the circles from the preceding procedure lie within the binary for a given aggregate. A sample output is as follows. ![kook2](docs/kook2.png) diff --git a/docs/paper/paper.md b/docs/paper/paper.md index 13f1d58..252cb0d 100644 --- a/docs/paper/paper.md +++ b/docs/paper/paper.md @@ -67,9 +67,9 @@ This code has been used in a number of studies in the literature. This code was # Acknowledgements -We wish to acknowledge related code released in association with some of the cited work. These including Matlab code provided in @kook2016 and [SciLab code](https://www.coria.fr/en/edm-sbs-automated-analysis-of-tem-images/) released in association with @bescond2014. The code from @altenhoff2020 was provided by the authors and adapted to the present format. +We wish to acknowledge related code released in association with some of the cited work. These include Matlab code provided in @kook2016 and [SciLab code](https://www.coria.fr/en/edm-sbs-automated-analysis-of-tem-images/) released in association with @bescond2014. The code from @altenhoff2020 was provided by the authors and adapted to the present format. We also wish to acknowledge funding by the Canadian Council of the Arts (Killam Fellowship), the Natural Sciences and Engineering Research Council of Canada (NSERC), and Transport Canada. -# References \ No newline at end of file +# References