Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.

Commit b359129

Browse files
committed
The output buffer is no longer allocated by the distance transform
function. Minor cmake and msvc build fixes.
1 parent 0421b0e commit b359129

File tree

4 files changed

+41
-66
lines changed

4 files changed

+41
-66
lines changed

CMakeLists.txt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
cmake_minimum_required (VERSION 3.12)
1+
cmake_minimum_required (VERSION 3.20)
22

33
project(distance C)
44

5-
find_package(Doxygen)
6-
75
file(WRITE ${CMAKE_BINARY_DIR}/distance.c "#define DISTANCE_TRANSFORM_IMPLEMENTATION\n#include \"${CMAKE_CURRENT_SOURCE_DIR}/distance.h\"")
8-
add_library(distance STATIC ${CMAKE_BINARY_DIR}/distance.c)
9-
target_compile_options(distance PUBLIC -Wall -Wshadow -Wextra)
10-
6+
add_library(distance STATIC ${CMAKE_BINARY_DIR}/distance.c distance.h)
7+
target_include_directories(distance PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> )
8+
target_compile_options(distance PRIVATE $<IF:$<C_COMPILER_ID:MSVC>,/W4,-Wall -Wshadow -Wextra>)
9+
set_property(TARGET distance PROPERTY C_STANDARD 11)
1110
add_subdirectory(test)

distance.h

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/*
22
Distance_transform computation using the fast sweeping method
33
=========================================================================
4-
v0.0.1
4+
v0.1.0
55
Licensed under the MIT License
6-
(c) 2020 Vincent Cruz
6+
(c) 2020-2023 Vincent Cruz
77
88
This header file provides a function to compute the distance transform of an image.
99
The implementation is based upon the following papers:
@@ -20,25 +20,19 @@
2020
Before including this file, add the following line in the file where you want to have the
2121
implementation.
2222
#define DISTANCE_TRANSFORM_IMPLEMENTATION
23-
24-
You can define DISTANCE_TRANSFORM_MALLOC and DISTANCE_TRANSFORM_FREE before the include
25-
to replace malloc and free.
2623
2724
* Usage:
2825
29-
float* distance_transform(const uint8_t *in, int width, int height);
26+
void distance_transform(const uint8_t *in, float *out, int width, int height);
3027
3128
"in" is the pointer an 8bpp greyscale image.
29+
"output" is the pointer to the a floating point array of at least width*height elements.
30+
It will contain the distance map.
3231
"width" and "height" are its dimension.
3332
All pixels with a value of 0 are considered to be "inside", whereas any non-zero pixel is
3433
considered outside. As a consequence, a pixel is considered to be on the boundary if its
3534
value is 0 and at least one of its 8-neighbour is not zero.
36-
37-
"distance_transform" returns a pointer to an array of "width*height" floating point numbers
38-
containing for each pixel the distance to the closest boundary point.
39-
This array is allocated with `DISTANCE_TRANSFORM_MALLOC`. Use `DISTANCE_TRANSFORM_FREE`
40-
to delete it.
41-
35+
4236
* Note:
4337
This piece of code is not meant to be "production ready".
4438
@@ -55,7 +49,7 @@
5549
extern "C" {
5650
#endif
5751

58-
float* distance_transform(const uint8_t *in, int width, int height);
52+
void distance_transform(const uint8_t *in, float *output, int width, int height);
5953

6054
#ifdef __cplusplus
6155
}
@@ -65,31 +59,13 @@ float* distance_transform(const uint8_t *in, int width, int height);
6559

6660
#ifdef DISTANCE_TRANSFORM_IMPLEMENTATION
6761

68-
#if defined(DISTANCE_TRANSFORM_MALLOC) && defined(DISTANCE_TRANSFORM_FREE)
69-
// ok
70-
#elif !defined(DISTANCE_TRANSFORM_MALLOC) && !defined(DISTANCE_TRANSFORM_FREE)
71-
// ok
72-
#else
73-
#error "Must define all or none of DISTANCE_TRANSFORM_MALLOC and DISTANCE_TRANSFORM_FREE"
74-
#endif
75-
76-
#if !defined(DISTANCE_TRANSFORM_MALLOC)
77-
#define DISTANCE_TRANSFORM_MALLOC(sz) malloc(sz)
78-
#define DISTANCE_TRANSFORM_FREE(p) free(p)
79-
#endif
80-
81-
float* distance_transform(const uint8_t *in, int width, int height) {
62+
void distance_transform(const uint8_t *in, float *out, int width, int height) {
8263
int i, j;
8364
uint8_t c;
84-
const float max_dist = width*width + height*height;
85-
float *out = (float*)DISTANCE_TRANSFORM_MALLOC(width * height * sizeof(float));
65+
const float max_dist = (float)(width*width + height*height);
8666
float *ptr = out;
8767
float *line;
8868

89-
if(out == NULL) {
90-
return NULL;
91-
}
92-
9369
// Initialize distance map by setting distance at boundary point to 0 and any other points to the maximal possible distance (width^2 + height^2).
9470
// A boundary point is a pixel with a value of 0 and with a least one of its 8-neightbours different from 0.
9571
c = ~in[0] & (in[1] | in[width] | in[width+1]);
@@ -137,110 +113,108 @@ float* distance_transform(const uint8_t *in, int width, int height) {
137113
// Update distance in the 4 sweeping directions.
138114
#define update_distance(dx,dy,inc) \
139115
do { \
140-
ptr[0] = fmin(ptr[0], (fabs((dx)-(dy)) >= 1) ? (fmin((dx), (dy)) + 1.f) : (((dx) + (dy) + sqrt(2.f - ((dx)-(dy))*((dx)-(dy)))) / 2.f)); \
116+
ptr[0] = fminf(ptr[0], (fabs((dx)-(dy)) >= 1) ? (fminf((dx), (dy)) + 1.f) : (((dx) + (dy) + sqrtf(2.f - ((dx)-(dy))*((dx)-(dy)))) / 2.f)); \
141117
ptr += (inc); \
142118
} while(0)
143119

144120
// y=[0,height[ x=[0,width[
145121
ptr = out;
146122
update_distance(ptr[1], ptr[width], +1);
147123
for(i=1; i<(width-1); i++) {
148-
update_distance(fmin(ptr[-1], ptr[1]), ptr[width], +1);
124+
update_distance(fminf(ptr[-1], ptr[1]), ptr[width], +1);
149125
}
150126
update_distance(ptr[-1], ptr[width], +1);
151127

152128
line = ptr;
153129
for(j=1; j<(height-1); j++, line+=width) {
154130
ptr = line;
155-
update_distance(ptr[1], fmin(ptr[-width], ptr[width]), +1);
131+
update_distance(ptr[1], fminf(ptr[-width], ptr[width]), +1);
156132
for(i=1; i<(width-1); i++) {
157-
update_distance(fmin(ptr[-1], ptr[1]), fmin(ptr[-width], ptr[width]), +1);
133+
update_distance(fminf(ptr[-1], ptr[1]), fminf(ptr[-width], ptr[width]), +1);
158134
}
159-
update_distance(ptr[-1], fmin(ptr[-width], ptr[width]), +1);
135+
update_distance(ptr[-1], fminf(ptr[-width], ptr[width]), +1);
160136
}
161137

162138
update_distance(ptr[1], ptr[-width], +1);
163139
for(i=1; i<(width-1); i++) {
164-
update_distance(fmin(ptr[-1], ptr[1]), ptr[-width], +1);
140+
update_distance(fminf(ptr[-1], ptr[1]), ptr[-width], +1);
165141
}
166142
update_distance(ptr[-1], ptr[-width], +1);
167143

168144
// y=[0,height[ x=]width,0]
169145
ptr = out+width-1;
170146
update_distance(ptr[-1], ptr[width], -1);
171147
for(i=1; i<(width-1); i++) {
172-
update_distance(fmin(ptr[-1], ptr[1]), ptr[width], -1);
148+
update_distance(fminf(ptr[-1], ptr[1]), ptr[width], -1);
173149
}
174150
update_distance(ptr[1], ptr[width], -1);
175151

176152
line = out+width;
177153
for(j=1; j<(height-1); j++, line+=width) {
178154
ptr = line+width-1;
179155

180-
update_distance(ptr[-1], fmin(ptr[-width], ptr[width]), -1);
156+
update_distance(ptr[-1], fminf(ptr[-width], ptr[width]), -1);
181157
for(i=1; i<(width-1); i++) {
182-
update_distance(fmin(ptr[-1], ptr[1]), fmin(ptr[-width], ptr[width]), -1);
158+
update_distance(fminf(ptr[-1], ptr[1]), fminf(ptr[-width], ptr[width]), -1);
183159
}
184-
update_distance(ptr[1], fmin(ptr[-width], ptr[width]), -1);
160+
update_distance(ptr[1], fminf(ptr[-width], ptr[width]), -1);
185161
}
186162

187163
ptr = line + width-1;
188164
update_distance(ptr[-1], ptr[-width], -1);
189165
for(i=1; i<(width-1); i++) {
190-
update_distance(fmin(ptr[-1], ptr[1]), ptr[-width], -1);
166+
update_distance(fminf(ptr[-1], ptr[1]), ptr[-width], -1);
191167
}
192168
update_distance(ptr[1], ptr[-width], -1);
193169

194170
// y=]height,0] x=]width,0]
195171
ptr = out+width-1+(height-1)*width;
196172
update_distance(ptr[-1], ptr[-width], -1);
197173
for(i=1; i<(width-1); i++) {
198-
update_distance(fmin(ptr[-1], ptr[1]), ptr[-width], -1);
174+
update_distance(fminf(ptr[-1], ptr[1]), ptr[-width], -1);
199175
}
200176
update_distance(ptr[1], ptr[-width], -1);
201177

202178
for(j=1; j<(height-1); j++) {
203-
update_distance(ptr[-1], fmin(ptr[-width], ptr[width]), -1);
179+
update_distance(ptr[-1], fminf(ptr[-width], ptr[width]), -1);
204180
for(i=1; i<(width-1); i++) {
205-
update_distance(fmin(ptr[-1], ptr[1]), fmin(ptr[-width], ptr[width]), -1);
181+
update_distance(fminf(ptr[-1], ptr[1]), fminf(ptr[-width], ptr[width]), -1);
206182
}
207-
update_distance(ptr[1], fmin(ptr[-width], ptr[width]), -1);
183+
update_distance(ptr[1], fminf(ptr[-width], ptr[width]), -1);
208184
}
209185

210186
update_distance(ptr[-1], ptr[width], -1);
211187
for(i=1; i<(width-1); i++) {
212-
update_distance(fmin(ptr[-1], ptr[1]), ptr[width], -1);
188+
update_distance(fminf(ptr[-1], ptr[1]), ptr[width], -1);
213189
}
214190
update_distance(ptr[1], ptr[width], -1);
215191

216192
// y=]height,0] x=[0,width[
217193
line = ptr = out+(height-1)*width;
218194
update_distance(ptr[1], ptr[-width], +1);
219195
for(i=1; i<(width-1); i++) {
220-
update_distance(fmin(ptr[-1], ptr[1]), ptr[-width], +1);
196+
update_distance(fminf(ptr[-1], ptr[1]), ptr[-width], +1);
221197
}
222198
update_distance(ptr[-1], ptr[-width], +1);
223199

224200
line -= width;
225201
for(j=1; j<(height-1); j++, line-=width) {
226202
ptr = line;
227-
update_distance(ptr[1], fmin(ptr[-width], ptr[width]), +1);
203+
update_distance(ptr[1], fminf(ptr[-width], ptr[width]), +1);
228204
for(i=1; i<(width-1); i++) {
229-
update_distance(fmin(ptr[-1], ptr[1]), fmin(ptr[-width], ptr[width]), +1);
205+
update_distance(fminf(ptr[-1], ptr[1]), fminf(ptr[-width], ptr[width]), +1);
230206
}
231-
update_distance(ptr[-1], fmin(ptr[-width], ptr[width]), +1);
207+
update_distance(ptr[-1], fminf(ptr[-width], ptr[width]), +1);
232208
}
233209

234210
ptr = line;
235211
update_distance(ptr[1], ptr[width], +1);
236212
for(i=1; i<(width-1); i++) {
237-
update_distance(fmin(ptr[-1], ptr[1]), ptr[width], +1);
213+
update_distance(fminf(ptr[-1], ptr[1]), ptr[width], +1);
238214
}
239215
update_distance(ptr[-1], ptr[width], +1);
240216

241217
#undef update_distance
242-
243-
return out;
244218
}
245219

246220
#endif /* DISTANCE_TRANSFORM_IMPLEMENTATION */

test/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
21
add_library(stb_image STATIC stb_image.c stb_image.h stb_image_write.h)
32

43
add_executable(compute main.c)
5-
target_link_libraries(compute stb_image distance m)
4+
target_link_libraries(compute stb_image distance)

test/main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ int main(int argc, char **argv) {
3535
return EXIT_FAILURE;
3636
}
3737

38-
distance = distance_transform(input, width, height);
38+
distance = (float*)malloc(width * height * sizeof(float));
3939
if(distance == NULL) {
40+
fprintf(stderr, "Failed to allocate distance map\n");
4041
return EXIT_FAILURE;
4142
}
4243

44+
distance_transform(input, distance, width, height);
45+
4346
// find the maximum distance in order to scale the values to [0,1]
4447
float max_dist = -1.f;
4548
float *ptr = distance;
@@ -68,7 +71,7 @@ int main(int argc, char **argv) {
6871

6972
stbi_image_free(input);
7073

71-
DISTANCE_TRANSFORM_FREE(distance);
74+
free(distance);
7275

7376
free(output);
7477

0 commit comments

Comments
 (0)