Skip to content

Commit 87c8a7b

Browse files
authored
Merge pull request #43 from tsipkens/developer
Add draft JOSS paper
2 parents e4a58ed + b07f5e7 commit 87c8a7b

24 files changed

+1023
-66
lines changed

+agg/analyze_binary.m

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
%-- Step 3-2: Prepare an image of the isolated aggregate ---------%
182182
img_binary = zeros(size(img_binary));
183183
img_binary(CC.PixelIdxList{1,jj}) = 1;
184-
Aggs0(jj).binary = logical(img_binary); % store binary image
184+
Aggs0(jj).binary = sparse(logical(img_binary)); % store binary image
185185

186186
% Get a cropped version of the aggregate
187187
% 'autocrop' method included below.
@@ -194,7 +194,7 @@
194194
img_dilated = imdilate(img_binary,SE);
195195
img_edge = img_dilated - img_binary;
196196

197-
[row, col] = find(imcrop(Aggs0(jj).binary, Aggs0(jj).rect));
197+
[row, col] = find(imcrop(full(Aggs0(jj).binary), Aggs0(jj).rect));
198198
Aggs0(jj).length = max((max(row)-min(row)), (max(col)-min(col))) * pixsize(ii);
199199
Aggs0(jj).width = min((max(row)-min(row)), (max(col)-min(col))) * pixsize(ii);
200200
Aggs0(jj).aspect_ratio = Aggs0(jj).length / Aggs0(jj).width;
@@ -224,7 +224,11 @@
224224
[x, y] = find(img_binary ~= 0);
225225
Aggs0(jj).center_mass = [mean(x); mean(y)];
226226

227-
if f_plot==1; set(groot,'CurrentFigure',f0); tools.imshow_agg(Aggs0, ii, 0); title(num2str(ii)); drawnow; end
227+
if f_plot==1
228+
if mod(jj, 10) == 0 % show image after every 10 aggregates processed
229+
set(groot,'CurrentFigure',f0); tools.imshow_agg(Aggs0, ii, 0); title(num2str(ii)); drawnow;
230+
end
231+
end
228232
end
229233

230234
if f_plot==1; pause(0.05); end % pause very briefly to show overall aggregates
@@ -290,7 +294,6 @@
290294
y_top = min(max(y)+space,size_img(2));
291295
y_bottom = max(min(y)-space,1);
292296

293-
294297
img_binary = img_binary(x_bottom:x_top,y_bottom:y_top);
295298
img_cropped = img_orig(x_bottom:x_top,y_bottom:y_top);
296299
rect = [y_bottom,x_bottom,(y_top-y_bottom),(x_top-x_bottom)];

+agg/config/km.v6.1s3.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// VERSION 6.1S
2+
// AUTHOR: Timothy Sipkens, 2023-04-17
3+
{
4+
"version": "6.1s3",
5+
"lvl3": "1:0.002:1.35", // range of thresholds to build curve
6+
"lvl5": 0.1, // where to threshold on hist curve
7+
"lvlfun": "lin", // type of adjusted threshold
8+
"morphsc": 0.5, // Modify morph. parameter for rolling ball
9+
"minsize": 20 // minimum particle size to consider
10+
}

+agg/config/km.v6.1s4.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// VERSION 6.1S
2+
// AUTHOR: Timothy Sipkens, 2023-04-17
3+
{
4+
"version": "6.1s4",
5+
"lvl3": "1:0.002:1.35", // range of thresholds to build curve
6+
"lvl5": 0.1, // where to threshold on hist curve
7+
"lvlfun": "lin", // type of adjusted threshold
8+
"morphsc": 0.8, // Modify morph. parameter for rolling ball
9+
"minsize": 20 // minimum particle size to consider
10+
}

+agg/seg_kmeans.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494

9595

9696
tools.textheader('k-means');
97+
disp(['Loaded configuration: ', num2str(opts.version)]);
98+
disp(' ');
9799

98100
% Loop over images, calling seg function below on each iteration.
99101
img_binary{n} = []; % pre-allocate cells

+pp/edm_sbs.m

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@
7373

7474
counts = zeros(length(se_vec),1); % initialize counts
7575

76-
img_dist = bwdist(~img_binary); % Euclidean distance to outside of aggregate
76+
img_dist = bwdist(~full(img_binary)); % Euclidean distance to outside of aggregate
7777
for ii=1:se_max
78-
counts(ii) = nnz(img_dist>se_vec(ii));
78+
counts(ii) = nnz(img_dist > se_vec(ii));
7979
% count the number of non-zero pixels remaining
8080

8181
if counts(ii)==0 % if all of the pixels are gone, exit loop
@@ -102,12 +102,13 @@
102102
bet = 1.9658; % beta parameter in sigmoid function
103103
ome = -0.8515; % Omega parameter in sigmoid function
104104
a = 0.9966;
105-
sigmoid = @(x) a./( 1+exp(((log(x(1))-log(dp_bin))./log(x(2))-bet)./ome));
105+
sigmoid = @(x) a ./ (1 + ...
106+
exp(((log(x(1)) - log(dp_bin)) ./ log(x(2)) - bet) ./ ome));
106107
% x(1) = dpg, x(2) = spg
107108

108109
opts = optimset('Display','off');
109-
x0 = [25,1.5];
110-
x1 = lsqnonlin(@(x) (sigmoid(x) - Sa) ./ 100, x0, [], [], opts);
110+
x0 = [25, 1.05];
111+
x1 = lsqnonlin(@(x) (sigmoid(x) - Sa) ./ 100, x0, [], [100, 1.1], opts);
111112
x1 = real(x1);
112113
x1(x1<0) = NaN;
113114
Sa_fit = sigmoid(x1);

+pp/edm_ws.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080

8181

8282
%-- Compute Eucldian distance map ------------------------------------%
83-
img_edm = bwdist(~img_binary);
83+
img_edm = bwdist(~full(img_binary));
8484

8585
D = max(max(img_edm)) - img_edm; % EDM to be used for watershed
8686

+pp/hough_peng.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@
633633
cirrad(k) = 0;
634634
else
635635
cirrad(k) = SgnCv_LMPos(end);
636-
for i_radii = (length(SgnCv_LMPos) - 1) : -1 : 1,
636+
for i_radii = (length(SgnCv_LMPos) - 1) : -1 : 1
637637
circen = [ circen; circen(k,:) ];
638638
cirrad = [ cirrad; SgnCv_LMPos(i_radii) ];
639639
end
@@ -643,7 +643,7 @@
643643
% Output
644644
varargout{1} = circen;
645645
varargout{2} = cirrad;
646-
if nargout > 3,
646+
if nargout > 3
647647
varargout{3} = dbg_LMmask;
648648
end
649649

+pp/pcm.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565

6666
%== Step 1: Image preparation ========================================%
6767
pixsize = Aggs(aa).pixsize; % size of pixels in the image
68-
img_binary = imcrop(Aggs(aa).binary, Aggs(aa).rect); % get the binarized image for this aggregate
68+
img_binary = imcrop(full(Aggs(aa).binary), Aggs(aa).rect); % get the binarized image for this aggregate
6969

7070
% Get data for this aggregate
7171
data = Aggs(aa); % initialize data structure for current aggregate

+tools/imshow_agg.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
img_binary = or(img_binary,Aggs(aa).binary);
8282
end
8383

84-
[~,~,i0] = tools.imshow_binary( ...
84+
[~,~,i0] = tools.imshow_binary2( ...
8585
Aggs(idx1(1)).image, img_binary, opts);
8686

8787
% Make panels bigger.

+tools/imshow_binary.m

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,41 @@
33
% Author: Timothy Sipkens, 2019-07-24
44
%=========================================================================%
55

6-
function [h,f,i0] = imshow_binary(imgs, imgs_binary, opts)
6+
function [h, i1] = imshow_binary(img, img_binary, opts)
77

88
%-- Parse inputs ---------------------------------------------------------%
9-
% Convert images to cells, if they are not already.
10-
if ~iscell(imgs); imgs = {imgs}; end
11-
if ~iscell(imgs_binary); imgs_binary = {imgs_binary}; end
12-
13-
if length(imgs)>24 % only plot up to 24 images
14-
imgs = imgs(1:24);
15-
imgs_binary = imgs_binary(1:24);
16-
end
17-
n_imgs = length(imgs); % number of images
9+
if iscell(img); img = img{1}; end % select only first image
10+
if iscell(img_binary); img_binary = img_binary{1}; end
1811

1912
if ~exist('opts','var'); opts = struct(); end
2013
if ~isfield(opts,'cmap')
21-
opts.cmap = ones(max(max(imgs_binary{1})),1) * [0.12,0.59,0.96];
14+
opts.cmap = ones(max(max(img_binary)),1) * [0,1,1];
2215
% blue, repeated for as many labels as exist in img_binary
2316
end
2417
if ~isfield(opts,'f_outline'); opts.f_outline = 1; end
2518
if ~isfield(opts,'label_alpha'); opts.label_alpha = 0.7; end
2619
%-------------------------------------------------------------------------%
2720

2821

22+
t0 = labeloverlay(img, img_binary, ...
23+
'Transparency', opts.label_alpha,...
24+
'Colormap', opts.cmap);
2925

30-
% If more than one image, prepare to tile and maximize figure.
31-
if n_imgs>1
32-
N1 = floor(sqrt(n_imgs));
33-
N2 = ceil(n_imgs/N1);
34-
subplot(N1, N2, 1);
35-
end
36-
37-
38-
for ii=1:n_imgs % loop over images
39-
40-
if n_imgs>1
41-
subplot(N1, N2, ii);
42-
title(num2str(ii));
43-
end
44-
45-
t0 = labeloverlay(imgs{ii}, imgs_binary{ii}, ...
46-
'Transparency', opts.label_alpha,...
47-
'Colormap', opts.cmap);
48-
49-
if ~opts.f_outline
50-
i1 = t0;
51-
else % if adding an outline
52-
img_edge = edge(imgs_binary{ii},'sobel');
53-
se = strel('disk',1);
54-
img_dilated = imdilate(img_edge,se);
55-
% use dilation to strengthen the aggregate's outline
56-
i1 = uint8(~img_dilated).*t0;
57-
% adds borders to labeled regions
58-
end
59-
60-
tools.imshow(i1); % show labelled image
61-
62-
if ii==1; i0 = i1; end % store first figure panel for output
26+
if ~opts.f_outline
27+
i1 = t0;
6328

29+
else % if adding an outline
30+
img_edge = edge(img_binary,'sobel');
31+
se = strel('disk',1);
32+
img_dilated = imdilate(img_edge,se);
33+
% use dilation to strengthen the aggregate's outline
34+
i1 = uint8(~img_dilated).*t0;
35+
% adds borders to labeled regions
6436
end
6537

38+
tools.imshow(i1); % show labelled image
6639

67-
if nargout>0; h = gca; end % organize outputs
68-
if nargout>1; f = gcf; end
40+
if nargout>0; h = gca; end % organize output
6941

7042
end
7143

+tools/imshow_binary2.m

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
% INSHOW_BINARY Plot original image with binary mask overlayed
3+
% Author: Timothy Sipkens, 2019-07-24
4+
%=========================================================================%
5+
6+
function [h,f,i0] = imshow_binary2(imgs, imgs_binary, varargin)
7+
8+
%-- Parse inputs ---------------------------------------------------------%
9+
% Convert images to cells, if they are not already.
10+
if ~iscell(imgs); imgs = {imgs}; end
11+
if ~iscell(imgs_binary); imgs_binary = {imgs_binary}; end
12+
13+
if length(imgs)>24 % only plot up to 24 images
14+
imgs = imgs(1:24);
15+
imgs_binary = imgs_binary(1:24);
16+
end
17+
n_imgs = length(imgs); % number of images
18+
%-------------------------------------------------------------------------%
19+
20+
21+
22+
% If more than one image, prepare to tile and maximize figure.
23+
if n_imgs>1
24+
N1 = floor(sqrt(n_imgs));
25+
N2 = ceil(n_imgs/N1);
26+
subplot(N1, N2, 1);
27+
end
28+
29+
30+
for ii=1:n_imgs % loop over images
31+
32+
if n_imgs>1
33+
subplot(N1, N2, ii);
34+
title(num2str(ii));
35+
end
36+
37+
[~, i1] = tools.imshow_binary(imgs{ii}, imgs_binary{ii}, varargin{:});
38+
39+
if ii==1
40+
if nargout>0; h = gca; end % organize outputs
41+
i0 = i1; % store first figure panel for output
42+
end
43+
44+
end
45+
46+
if nargout>1; f = gcf; end
47+
48+
end
49+

+tools/load_imgs.m

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,14 @@
291291
bw1 = im2bw(1 - double(Imgs(jj).raw) ./ ...
292292
max(max(double(Imgs(jj).raw))), 0.98);
293293

294-
% If no text, loop for white text isntead of black.
295-
if nnz(bw1) < 500
294+
% If no text, loop for white text instead of black.
295+
if nnz(bw1) / numel(bw1) < 0.01
296296
bw1 = ~im2bw(1 - double(Imgs(jj).raw) ./ ...
297-
max(max(double(Imgs(jj).raw))), 0.01);
297+
max(max(double(Imgs(jj).raw))), 0.08);
298+
299+
se = strel('disk', 1);
300+
bw1 = imclose(bw1, se);
301+
bw1 = imopen(bw1, se);
298302
end
299303

300304
% Remove any small regions below a certain number of pixels.

.github/workflows/draft-pdf.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
on: [push]
2+
3+
jobs:
4+
paper:
5+
runs-on: ubuntu-latest
6+
name: Paper Draft
7+
steps:
8+
- name: Checkout
9+
uses: actions/checkout@v3
10+
- name: Build draft PDF
11+
uses: openjournals/openjournals-draft-action@master
12+
with:
13+
journal: joss
14+
paper-path: docs/paper/paper.md
15+
- name: Upload
16+
uses: actions/upload-artifact@v1
17+
with:
18+
name: paper
19+
path: docs/paper/paper.pdf

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ results/
99
results\
1010
+working/
1111
+\working
12-
figs/
13-
figs\
12+
docs/figs/
13+
docs\figs\
1414

1515
temp/
1616
temp\
@@ -173,3 +173,4 @@ cython_debug/
173173

174174
carboseg/FPN-resnet50-imagenet.onnx
175175
+agg/config/km.v6.1s2.json
176+
docs/paper/instructions.txt

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ This program contains very significantly modified versions of the code distribut
393393

394394
Also included with this program is the MATLAB code of [Kook et al. (2015)][kook], modified to accommodate the expected inputs and outputs common to the other functions.
395395

396-
This code also contain an adaptation of **EDM-SBS** method of [Bescond et al. (2014)][bescond]. We thank the authors, in particular Jérôme Yon, for their help in understanding their original [Scilab code and ImageJ plugin](http://www.coria.fr/spip.php?article910). Modifications to allow the method to work directly on binary images (rather than a custom output from ImageJ) and to integrate the method into the MATLAB environment may present some minor compatibility issues, but allows use of the aggregate segmentation methods given in the **agg** package.
396+
This code also contain an adaptation of **EDM-SBS** method of [Bescond et al. (2014)][bescond]. We thank the authors, in particular Jérôme Yon, for their help in understanding their original [Scilab code and ImageJ plugin](https://www.coria.fr/en/edm-sbs-automated-analysis-of-tem-images/). Modifications to allow the method to work directly on binary images (rather than a custom output from ImageJ) and to integrate the method into the MATLAB environment may present some minor compatibility issues, but allows use of the aggregate segmentation methods given in the **agg** package.
397397

398398
The **carboseg** method follows from collaborative work with [Max Frei](https://github.com/maxfrei750) and is associated with [Sipkens et al. (2021)][ptech.cnn].
399399

docs/paper/01-sample-image.png

6.25 MB
Loading

docs/paper/02-seg-methods.png

2.95 MB
Loading

docs/paper/media/01-sample-image.png

6.25 MB
Loading

docs/paper/media/02-seg-methods.png

2.95 MB
Loading

docs/paper/media/02-seg-methods.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)