Skip to content

Commit 87c9063

Browse files
docs: add more comprehensive cpp directions to main README
1 parent 0551137 commit 87c9063

File tree

1 file changed

+83
-10
lines changed

1 file changed

+83
-10
lines changed

README.md

+83-10
Original file line numberDiff line numberDiff line change
@@ -97,25 +97,98 @@ dt = edt.edt(
9797

9898
*Note on Memory Usage: Make sure the input array to edt is contiguous memory or it will make a copy. You can determine if this is the case with `print(data.flags)`.*
9999

100-
### C++ Usage
100+
## C++ Instructions for MLAEDT-3D
101101

102-
Include the edt.hpp header which includes the implementation in namespace `edt`. You'll need to also include `threadpool.h` and add the `-pthread` compiler flag. The code is written to the C++11 standard.
102+
Compute the Euclidean Distance Transform of a 1d, 2d, or 3d labeled image containing multiple labels in a single pass with support for anisotropic dimensions. C++ function expect the input array to be in Fortran (column-major) order. If your array is in C (row-major) order, it will also work but you must
103+
reverse the order of the dimension and anisotropy arguments (sx,sy,sz -> sz,sy,sx and wx,wy,wz -> wz,wy,wx).
104+
105+
### Compiling
106+
107+
You only need `edt.hpp`, `test.cpp` is only there for testing.
108+
109+
```bash
110+
make shared # compile edt.so
111+
make test # compile ./test with debugging information
112+
```
113+
114+
If you statically integrate `edt.hpp` into your own C++ program, I recommend compiler flags `-O3` and `-ffast-math` for optimal performance.
115+
116+
### C++ Examples
103117

104118
```cpp
105119
#include "edt.hpp"
106120

107-
int main () {
121+
int* labels1d = new int[512]();
122+
int* labels2d = new int[512*512]();
123+
int* labels3d = new int[512*512*512]();
124+
125+
// ... populate labels ...
126+
127+
// 1d, 2d, and 3d anisotropic transforms, wx = anisotropy on x-axis
128+
float* dt = edt::edt<int>(labels1d, /*sx=*/512, /*wx=*/1.0, /*black_border=*/true);
129+
float* dt = edt::edt<int>(labels2d,
130+
/*sx=*/512, /*sy=*/512, /*wx=*/1.0, /*wy=*/1.0,
131+
/*black_border=*/true, /*parallel=*/1);
132+
float* dt = edt::edt<int>(labels3d,
133+
/*sx=*/512, /*sy=*/512, /*sz=*/512,
134+
/*wx=*/4.0, /*wy=*/4.0, /*wz=*/40.0,
135+
/*black_border=*/true, /*parallel=*/2);
136+
137+
// get the squared distance instead (avoids computing sqrt)
138+
float* dt = edt::edtsq<int>(labels1d, /*sx=*/512, /*wx=*/1.0, /*black_border=*/true);
139+
float* dt = edt::edtsq<int>(labels2d,
140+
/*sx=*/512, /*sy=*/512, /*wx=*/1.0, /*wy=*/1.0,
141+
/*black_border=*/true, /*parallel=*/4);
142+
float* dt = edt::edtsq<int>(labels3d,
143+
/*sx=*/512, /*sy=*/512, /*sz=*/512,
144+
/*wx=*/4.0, /*wy=*/4.0, /*wz=*/40.0,
145+
/*black_border=*/true, /*parallel=*/8);
146+
147+
// signed distance field edt::sdf and edt::sdfsq
148+
float* dt = edt::sdf<int>(labels3d,
149+
/*sx=*/512, /*sy=*/512, /*sz=*/512,
150+
/*wx=*/4.0, /*wy=*/4.0, /*wz=*/40.0,
151+
/*black_border=*/true, /*parallel=*/8);
152+
153+
```
154+
155+
### High Performance Binary Images
156+
157+
Binary images are treated specially in 2D and 3D to avoid executing the extra multi-label logic (1D is very fast even with it). This results in a substantial savings of perhaps 20-50% depending on the compiler. For a 512x512x512 cube filled with ones, on a 4.0 GHz linux machine with g++, I witnessed reductions from 9 sec. to 7 sec. (1.29x). On 2.8 GHz Mac OS with clang-902.0.39.2 I saw a reduction from 12.4 sec to 7.9 sec (1.56x).
108158

109-
int* labels = new int[3*3*3]();
159+
The code will easily handle all integer types, and the image only needs to be binary in the sense that there is a single non-zero label, it doesn't have to be ones.
110160

111-
int sx = 3, sy = 3, sz = 3;
112-
float wx = 6, wy = 6, wz = 30; // anisotropy
161+
Boolean typed images are handled specially by a specialization of the edt function, so nothing different from above needs to be done. If you have an integer typed image, you'll need to use `binary_edt` or `binary_edtsq` instead to take advantage of this.
113162

114-
float* dt = edt::edt<int>(labels, sx, sy, sz, wx, wy, wz);
163+
You'll get slightly higher performance setting `black_border=true`.
115164

116-
return 0;
117-
}
118-
```
165+
```cpp
166+
#include "edt.hpp"
167+
168+
using namespace edt;
169+
170+
bool* labels2d = new bool[512*512]();
171+
bool* labels3d = new bool[512*512*512]();
172+
173+
float* dt = edt<bool>(labels2d,
174+
/*sx=*/512, /*sy=*/512, /*wx=*/1.0, /*wy=*/1.0,
175+
/*black_border=*/true);
176+
float* dt = edt<bool>(labels3d,
177+
/*sx=*/512, /*sy=*/512, /*sz=*/512,
178+
/*wx=*/4.0, /*wy=*/4.0, /*wz=*/40.0,
179+
/*black_border=*/true);
180+
181+
182+
int* labels2d = new int[512*512]();
183+
int* labels3d = new int[512*512*512]();
184+
185+
float* dt = binary_edt<int>(labels2d, /*sx=*/512, /*sy=*/512, /*wx=*/1.0, /*wy=*/1.0);
186+
float* dt = binary_edt<int>(labels3d,
187+
/*sx=*/512, /*sy=*/512, /*sz=*/512,
188+
/*wx=*/4.0, /*wy=*/4.0, /*wz=*/40.0,
189+
/*black_border=*/true);
190+
191+
```
119192

120193
### Motivation
121194

0 commit comments

Comments
 (0)