Skip to content

Commit 3140023

Browse files
authored
POL5650 new wholeslide workflow (PolusAI#261)
1 parent 1548529 commit 3140023

File tree

110 files changed

+3235
-2203
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+3235
-2203
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ set(SOURCE
207207
src/nyx/gpucache.cpp
208208
src/nyx/globals.cpp
209209
src/nyx/image_loader.cpp
210+
src/nyx/output_2_apache.cpp
210211
src/nyx/output_2_buffer.cpp
211212
src/nyx/output_2_csv.cpp
212213
src/nyx/output_writers.cpp
213-
src/nyx/parallel.cpp
214214
src/nyx/phase1.cpp
215215
src/nyx/phase2.cpp
216216
src/nyx/phase3.cpp
@@ -222,7 +222,11 @@ set(SOURCE
222222
src/nyx/roi_cache.cpp
223223
src/nyx/roi_cache_basic.cpp
224224
src/nyx/scan_fastloader_way.cpp
225+
src/nyx/slideprops.cpp
225226
src/nyx/strpat.cpp
227+
src/nyx/workflow_3d.cpp
228+
src/nyx/workflow_segmented.cpp
229+
src/nyx/workflow_wholeslide.cpp
226230
)
227231

228232
# CLI

src/nyx/arrow_output_stream.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
#include <iostream>
22
#include "arrow_output_stream.h"
3-
4-
#if __has_include(<filesystem>)
5-
#include <filesystem>
6-
namespace fs = std::filesystem;
7-
#elif __has_include(<experimental/filesystem>)
8-
#include <experimental/filesystem>
9-
namespace fs = std::experimental::filesystem;
10-
#else
11-
error "Missing the <filesystem> header."
12-
#endif
3+
#include "helpers/fsystem.h"
134

145
namespace Nyxus {
156

src/nyx/cli_nested_roi_options.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,7 @@
77
#include "globals.h"
88
#include "nested_roi.h"
99
#include "results_cache.h"
10-
#if __has_include(<filesystem>)
11-
#include <filesystem>
12-
namespace fs = std::filesystem;
13-
#elif __has_include(<experimental/filesystem>)
14-
#include <experimental/filesystem>
15-
namespace fs = std::experimental::filesystem;
16-
#else
17-
error "Missing the <filesystem> header."
18-
#endif
10+
#include "helpers/fsystem.h"
1911

2012
bool NestedRoiOptions::empty()
2113
{

src/nyx/dirs_and_files.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44

55
#include <fstream>
66
#include <string>
7-
#if __has_include(<filesystem>)
8-
#include <filesystem>
9-
namespace fs = std::filesystem;
10-
#elif __has_include(<experimental/filesystem>)
11-
#include <experimental/filesystem>
12-
namespace fs = std::experimental::filesystem;
13-
#else
14-
error "Missing the <filesystem> header."
15-
#endif
7+
#include "helpers/fsystem.h"
168

179
#include <vector>
1810
#include <iostream>
@@ -40,10 +32,7 @@ namespace Nyxus
4032
{
4133
// Skip hidden objects, e.g. directories '.DS_store' in OSX
4234
if (entry.path().filename().string()[0] == '.')
43-
{
44-
std::cout << "Skipping " << entry.path().filename().string() << "\n";
4535
continue;
46-
}
4736

4837
std::string fullPath = entry.path().string(),
4938
pureFname = entry.path().filename().string();
@@ -79,7 +68,6 @@ namespace Nyxus
7968
return 1;
8069
}
8170

82-
8371
// Check directories
8472

8573
if (!existsOnFilesystem(dirIntens))
@@ -88,8 +76,6 @@ namespace Nyxus
8876
return 1;
8977
}
9078

91-
92-
9379
if (intLabMappingFile.empty())
9480
{
9581
std::vector<std::string> purefnames_i, purefnames_m; // we need these temp sets to check the 1:1 matching
@@ -239,8 +225,6 @@ namespace Nyxus
239225
}
240226
else { throw (std::runtime_error("Tile Loader ERROR: The file can not be opened.")); }
241227
}
242-
243-
244228

245229
bool readDirectoryFiles_3D (const std::string & dir, const StringPattern & filePatt, std::vector <Imgfile3D_layoutA> & files)
246230
{
@@ -259,7 +243,7 @@ namespace Nyxus
259243
std::string ermsg;
260244
if (!filePatt.match(pureFname, imgDirs, ermsg))
261245
{
262-
std::cerr << "Error parsing file name " << pureFname << ": " << ermsg << '\n';
246+
std::cerr << "Error parsing file name " << fpath << " : " << ermsg << '\n';
263247
break;
264248
}
265249

src/nyx/env_features.cpp

Lines changed: 59 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,22 @@
3939
#include "features/3d_gldzm.h"
4040
#include "features/3d_glrlm.h"
4141
#include "features/3d_glszm.h"
42+
#include "features/radial_distribution.h"
4243
#include "features/roi_radius.h"
44+
#include "features/zernike.h"
4345
#include "helpers/helpers.h"
4446
#include "helpers/system_resource.h"
4547
#include "helpers/timing.h"
4648
#include "version.h"
4749

4850
using namespace Nyxus;
4951

50-
bool Environment::spellcheck_raw_featurelist(const std::string& comma_separated_fnames, std::vector<std::string>& fnames)
52+
// The purpose of this methos is checking user's feature request but not changing the state of the Environment instance.
53+
// Specifically, it:
54+
// (1) splits 'comma_separated_fnames' into identifiers,
55+
// (2) checks if they are known feature and group names in the corresponding context (2D or 3D), and
56+
// (3) saves them in vector 'fnames'
57+
bool Environment::spellcheck_raw_featurelist (const std::string & comma_separated_fnames, std::vector<std::string> & fnames)
5158
{
5259
fnames.clear();
5360

@@ -76,58 +83,59 @@ bool Environment::spellcheck_raw_featurelist(const std::string& comma_separated_
7683

7784
}
7885

79-
// Chop the CS-list
86+
// Chop the comma-separated feature list
8087
bool success = true;
8188
std::vector<std::string> strings;
82-
parse_delimited_string(comma_separated_fnames, ",", strings);
89+
parse_delimited_string (comma_separated_fnames, ",", strings);
8390

8491
// Check names of features and feature-groups
85-
for (const std::string& s : strings)
92+
for (const std::string & s : strings)
8693
{
8794
// Forgive user's typos of consecutive commas e.g. MIN,MAX,,MEDIAN
8895
if (s.empty())
8996
continue;
9097

9198
auto s_uppr = Nyxus::toupper(s);
99+
92100
if (dim() == 2)
93101
{
94-
// Is feature found among 2D features?
95-
int fg; // signed Fgroup2D
96-
bool gnameExists = theFeatureSet.find_2D_GroupByString (s_uppr, fg);
97-
98-
// Intercept an error: 2D feature group exists but requested in the non-2D mode
99-
if (gnameExists && dim() != 2)
102+
//==== feature group ?
103+
104+
int _; // feature code, unused
105+
bool gfound1 = theFeatureSet.find_2D_GroupByString (s_uppr, _),
106+
gfound2 = theFeatureSet.find_IMQ_GroupByString (s_uppr, _);
107+
108+
// if 's' is recognized as a group, register it and skip checking it as an individual feature name
109+
if (gfound1 || gfound2)
100110
{
101-
success = false;
102-
std::cerr << "Error: 2D feature group '" << s << "' in non-2D mode\n";
103-
continue;
104-
}
111+
// set the IMQ flag if applicable
112+
if (gfound2)
113+
theEnvironment.set_imq (true);
105114

106-
// If a group is found, register it
107-
if (gnameExists)
108-
{
109-
fnames.push_back(s_uppr);
115+
fnames.push_back (s_uppr);
110116
continue;
111117
}
112118

113-
int fcode; // signed Feature2D
114-
bool fnameExists = theFeatureSet.find_2D_FeatureByString (s_uppr, fcode);
119+
//==== individual feature ?
115120

116-
// 2D feature group requested on a non-2D mode ?
117-
if (fnameExists && dim() != 2)
118-
{
119-
success = false;
120-
std::cerr << "Error: 2D feature '" << s << "' in non-2D mode\n";
121-
continue;
122-
}
121+
bool ffound1 = theFeatureSet.find_2D_FeatureByString (s_uppr, _),
122+
ffound2 = theFeatureSet.find_IMQ_FeatureByString (s_uppr, _);
123123

124-
if (!fnameExists)
124+
// if a feature is found, register it
125+
if (! (ffound1 || ffound2))
125126
{
126127
success = false;
127-
std::cerr << "Error: expecting '" + s + "' to be a proper 2D feature name or feature file path\n";
128+
std::cerr << "Error: expecting " + s + " to be a proper 2D feature name or feature file path\n";
128129
}
129130
else
131+
{
132+
// set the IMQ flag if applicable
133+
if (ffound2)
134+
theEnvironment.set_imq (true);
135+
130136
fnames.push_back(s_uppr);
137+
}
138+
131139
} // 2D
132140

133141
if (dim() == 3)
@@ -136,39 +144,23 @@ bool Environment::spellcheck_raw_featurelist(const std::string& comma_separated_
136144
int afg; // signed Fgroup3D
137145
bool gnameExists = theFeatureSet.find_3D_GroupByString (s_uppr, afg);
138146

139-
// Intercept an error: 3D feature group exists but requested in the non-3D mode
140-
if (gnameExists && dim() != 3)
141-
{
142-
success = false;
143-
std::cerr << "Error: 3D feature group '" << s << "' in non-3D mode\n";
144-
continue;
145-
}
146-
147147
// If a group is found, register it
148148
if (gnameExists)
149149
{
150-
fnames.push_back(s_uppr);
150+
fnames.push_back (s_uppr);
151151
continue;
152152
}
153153

154154
int af; // signed Feature3D
155155
bool fnameExists = theFeatureSet.find_3D_FeatureByString (s_uppr, af);
156156

157-
// 3D feature group requested on a non-3D mode ?
158-
if (fnameExists && dim() != 3)
159-
{
160-
success = false;
161-
std::cerr << "Error: 3D feature '" << s << "' in non-3D mode\n";
162-
continue;
163-
}
164-
165-
if (!fnameExists)
157+
if (! fnameExists)
166158
{
167159
success = false;
168160
std::cerr << "Error: expecting '" << s << "' to be a proper 3D feature name or feature file path\n";
169161
}
170162
else
171-
fnames.push_back(s_uppr);
163+
fnames.push_back (s_uppr);
172164
} // 3D
173165
}
174166

@@ -204,51 +196,26 @@ bool Environment::expand_2D_featuregroup (const std::string & s)
204196

205197
if ((Fgroup2D)fgcode == Fgroup2D::FG2_ALL)
206198
{
207-
Nyxus::theFeatureSet.enableAll (enable);
199+
// enable just the 2D part of the feature set
200+
for (int i = (int) Nyxus::Feature2D::_FIRST_; i < (int) Nyxus::Feature2D::_COUNT_; i++)
201+
Nyxus::theFeatureSet.enableFeature (i);
208202
return true;
209203
}
210204

211205
if ((Fgroup2D)fgcode == Fgroup2D::FG2_WHOLESLIDE)
212206
{
213-
Nyxus::theFeatureSet.enableAll(enable);
214-
215-
// Handle whole-slide mode differently: disable features irrelevant to this mode (shape, neighbors, etc)
216-
std::cout << box_text(
217-
"Activating whole slide (aka single-ROI) mode\n"
218-
"Using GPU is advised!\n"
219-
"ATTENTION: disabling inappplicable and time-sonsuming features:\n"
220-
" - morphological features\n"
221-
" - neighbor features\n"
222-
" - GLDZM");
223-
224-
theFeatureSet.disableFeatures (BasicMorphologyFeatures::featureset);
225-
theFeatureSet.disableFeatures (EnclosingInscribingCircumscribingCircleFeature::featureset);
226-
// enabling ContourFeature (builds a special trivial wholeslide contour)
227-
theFeatureSet.disableFeatures (ConvexHullFeature::featureset); // depends on ContourFeature
228-
theFeatureSet.disableFeatures (FractalDimensionFeature::featureset); // depends on ContourFeature
229-
theFeatureSet.disableFeatures (GeodeticLengthThicknessFeature::featureset); // depends on ContourFeature
230-
theFeatureSet.disableFeatures (NeighborsFeature::featureset); // no neighbors for whole slide; depends on ContourFeature
231-
theFeatureSet.disableFeatures (RoiRadiusFeature::featureset); // depends on ContourFeature
232-
theFeatureSet.disableFeatures (EllipseFittingFeature::featureset);
233-
theFeatureSet.disableFeatures (EulerNumberFeature::featureset);
234-
theFeatureSet.disableFeatures (ExtremaFeature::featureset);
235-
theFeatureSet.disableFeatures (ErosionPixelsFeature::featureset);
236-
theFeatureSet.disableFeatures (CaliperFeretFeature::featureset);
237-
theFeatureSet.disableFeatures (CaliperMartinFeature::featureset);
238-
theFeatureSet.disableFeatures (CaliperNassensteinFeature::featureset);
239-
theFeatureSet.disableFeatures (ChordsFeature::featureset);
240-
241-
// enabling GaborFeature
242-
// enabling only intensity image moments
243-
theFeatureSet.disableFeatures (Smoms2D_feature::featureset);
244-
// enabling GLCMFeature
245-
// enabling GLDMFeature
246-
theFeatureSet.disableFeatures (GLDZMFeature::featureset); // costs about 82 %
247-
// enabling GLRLMFeature
248-
// enabling GLSZMFeature
249-
// enabling NGLDMfeature
250-
// enabling NGTDMFeature
251-
207+
theFeatureSet.enableFeatures (ContourFeature::featureset, enable);
208+
theFeatureSet.enableFeatures (PixelIntensityFeatures::featureset, enable);
209+
theFeatureSet.enableFeatures (GLCMFeature::featureset, enable);
210+
theFeatureSet.enableFeatures (GLDMFeature::featureset, enable);
211+
theFeatureSet.enableFeatures (GLRLMFeature::featureset, enable);
212+
theFeatureSet.enableFeatures (GLSZMFeature::featureset, enable);
213+
theFeatureSet.enableFeatures (NGLDMfeature::featureset, enable);
214+
theFeatureSet.enableFeatures (NGTDMFeature::featureset, enable);
215+
theFeatureSet.enableFeatures (GaborFeature::featureset, enable);
216+
theFeatureSet.enableFeatures(Imoms2D_feature::featureset, enable);
217+
theFeatureSet.enableFeatures (RadialDistributionFeature::featureset, enable);
218+
theFeatureSet.enableFeatures (ZernikeFeature::featureset, enable);
252219
return true;
253220
}
254221

@@ -533,11 +500,11 @@ void Environment::expand_featuregroups()
533500
if (expand_IMQ_featuregroup (s))
534501
return;
535502

536-
FeatureIMQ a;
503+
int a;
537504
if (!theFeatureSet.find_IMQ_FeatureByString(s, a))
538505
throw std::invalid_argument("Error: '" + s + "' is not a valid Image Quality feature name \n");
539506

540-
theFeatureSet.enableFeature (int(a));
507+
theFeatureSet.enableFeature (a);
541508
continue;
542509
}
543510

@@ -571,10 +538,9 @@ void Environment::expand_featuregroups()
571538
if (dim() == 3)
572539
{
573540
int a; // signed Feature3D
574-
if (!Nyxus::theFeatureSet.find_3D_FeatureByString(s, a))
541+
if (!theFeatureSet.find_3D_FeatureByString(s, a))
575542
throw std::invalid_argument("Error: '" + s + "' is not a valid 3D feature name \n");
576-
577-
Nyxus::theFeatureSet.enableFeature (int(a));
543+
theFeatureSet.enableFeature (a);
578544
continue;
579545
}
580546
}

0 commit comments

Comments
 (0)