rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@1
|
2 #include <string.h>
|
nuclear@1
|
3 #include <ctype.h>
|
nuclear@1
|
4 #include <errno.h>
|
nuclear@1
|
5 #include <math.h>
|
nuclear@1
|
6 #include "volume.h"
|
nuclear@1
|
7
|
nuclear@1
|
8 static char *strip_space(char *s);
|
nuclear@1
|
9
|
nuclear@1
|
10
|
nuclear@1
|
11 Volume::~Volume()
|
nuclear@1
|
12 {
|
nuclear@1
|
13 }
|
nuclear@1
|
14
|
nuclear@1
|
15 int Volume::num_samples(int dim) const
|
nuclear@1
|
16 {
|
nuclear@1
|
17 return 0;
|
nuclear@1
|
18 }
|
nuclear@1
|
19
|
nuclear@1
|
20 void Volume::normalf(float *norm, float x, float y, float z, float delta)
|
nuclear@1
|
21 {
|
nuclear@1
|
22 float dx, dy, dz;
|
nuclear@1
|
23 dx = dy = dz = delta;
|
nuclear@1
|
24
|
nuclear@1
|
25 if(num_samples(0) > 0) {
|
nuclear@1
|
26 // discrete volume
|
nuclear@1
|
27 dx /= (float)num_samples(0);
|
nuclear@1
|
28 dy /= (float)num_samples(1);
|
nuclear@1
|
29 dz /= (float)num_samples(2);
|
nuclear@1
|
30 }
|
nuclear@1
|
31
|
nuclear@1
|
32 norm[0] = valuef(x + dx, y, z) - valuef(x - dx, y, z);
|
nuclear@1
|
33 norm[1] = valuef(x, y + dy, z) - valuef(x, y - dy, z);
|
nuclear@1
|
34 norm[2] = valuef(x, y, z + dz) - valuef(x, y, z - dz);
|
nuclear@1
|
35
|
nuclear@1
|
36 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
|
nuclear@1
|
37 if(len != 0.0) {
|
nuclear@1
|
38 norm[0] /= len;
|
nuclear@1
|
39 norm[1] /= len;
|
nuclear@1
|
40 norm[2] /= len;
|
nuclear@1
|
41 }
|
nuclear@1
|
42 }
|
nuclear@1
|
43
|
nuclear@1
|
44 void Volume::normali(float *norm, int x, int y, int z)
|
nuclear@1
|
45 {
|
nuclear@1
|
46 int sz[3];
|
nuclear@1
|
47
|
nuclear@1
|
48 if((sz[0] = num_samples(0)) <= 0) {
|
nuclear@1
|
49 // if it's a continuous volume, just call normalf
|
nuclear@1
|
50 normalf(norm, x, y, z);
|
nuclear@1
|
51 return;
|
nuclear@1
|
52 }
|
nuclear@1
|
53 sz[1] = num_samples(1);
|
nuclear@1
|
54 sz[2] = num_samples(2);
|
nuclear@1
|
55
|
nuclear@1
|
56 int prevx = x <= 0 ? 0 : x;
|
nuclear@1
|
57 int nextx = x >= sz[0] - 1 ? sz[0] - 1 : x;
|
nuclear@1
|
58 int prevy = y <= 0 ? 0 : y;
|
nuclear@1
|
59 int nexty = y >= sz[1] - 1 ? sz[1] - 1 : y;
|
nuclear@1
|
60 int prevz = z <= 0 ? 0 : z;
|
nuclear@1
|
61 int nextz = z >= sz[2] - 1 ? sz[2] - 1 : z;
|
nuclear@1
|
62
|
nuclear@1
|
63 norm[0] = valuei(nextx, y, z) - valuei(prevx, y, z);
|
nuclear@1
|
64 norm[1] = valuei(x, nexty, z) - valuei(x, prevy, z);
|
nuclear@1
|
65 norm[2] = valuei(x, y, nextz) - valuei(x, y, prevz);
|
nuclear@1
|
66
|
nuclear@1
|
67 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
|
nuclear@1
|
68 if(len != 0.0) {
|
nuclear@1
|
69 norm[0] /= len;
|
nuclear@1
|
70 norm[1] /= len;
|
nuclear@1
|
71 norm[2] /= len;
|
nuclear@1
|
72 }
|
nuclear@1
|
73 }
|
nuclear@1
|
74
|
nuclear@1
|
75 // ---- VoxelVolume (discrete) implementation ----
|
nuclear@1
|
76 VoxelVolume::VoxelVolume()
|
nuclear@1
|
77 {
|
nuclear@1
|
78 size[0] = size[1] = size[2] = 0;
|
nuclear@1
|
79 }
|
nuclear@1
|
80
|
nuclear@1
|
81 bool VoxelVolume::load(const char *fname)
|
nuclear@1
|
82 {
|
nuclear@1
|
83 FILE *fp = fopen(fname, "r");
|
nuclear@1
|
84 if(!fp) {
|
nuclear@1
|
85 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
|
nuclear@1
|
86 return false;
|
nuclear@1
|
87 }
|
nuclear@1
|
88
|
nuclear@1
|
89 char buf[512];
|
nuclear@1
|
90 while(fgets(buf, sizeof buf, fp)) {
|
nuclear@1
|
91 char *line = strip_space(buf);
|
nuclear@1
|
92
|
nuclear@1
|
93 Image img;
|
nuclear@1
|
94 if(!img.load(line)) {
|
nuclear@1
|
95 slices.clear();
|
nuclear@1
|
96 return false;
|
nuclear@1
|
97 }
|
nuclear@1
|
98
|
nuclear@1
|
99 if(slices.empty()) {
|
nuclear@1
|
100 size[0] = img.width;
|
nuclear@1
|
101 size[1] = img.height;
|
nuclear@1
|
102 } else {
|
nuclear@1
|
103 if(img.width != size[0] || img.height != size[1]) {
|
nuclear@1
|
104 fprintf(stderr, "slice %d \"%s\" size mismatch (%dx%d, %dx%d expected)\n",
|
nuclear@1
|
105 (int)slices.size(), line, img.width, img.height, size[0], size[1]);
|
nuclear@1
|
106 slices.clear();
|
nuclear@1
|
107 return false;
|
nuclear@1
|
108 }
|
nuclear@1
|
109 }
|
nuclear@1
|
110
|
nuclear@1
|
111 slices.push_back(img);
|
nuclear@1
|
112 img.pixels = 0; // otherwise the destructor will free it
|
nuclear@1
|
113 }
|
nuclear@1
|
114
|
nuclear@1
|
115 size[2] = slices.size();
|
nuclear@1
|
116 fclose(fp);
|
nuclear@1
|
117 return true;
|
nuclear@1
|
118 }
|
nuclear@1
|
119
|
nuclear@1
|
120 int VoxelVolume::num_samples(int dim) const
|
nuclear@1
|
121 {
|
nuclear@1
|
122 return size[dim];
|
nuclear@1
|
123 }
|
nuclear@1
|
124
|
nuclear@1
|
125 static inline int clamp(int x, int low, int high)
|
nuclear@1
|
126 {
|
nuclear@1
|
127 return x < low ? low : (x > high ? high : x);
|
nuclear@1
|
128 }
|
nuclear@1
|
129
|
nuclear@1
|
130 static inline float lookup(int x0, int y0, int x1, int y1, float tx, float ty,
|
nuclear@1
|
131 float *pixels, int width, int height)
|
nuclear@1
|
132 {
|
nuclear@1
|
133 float v00, v01, v10, v11;
|
nuclear@1
|
134
|
nuclear@1
|
135 v00 = pixels[y0 * width + x0];
|
nuclear@1
|
136 v01 = pixels[y1 * width + x0];
|
nuclear@1
|
137 v10 = pixels[y0 * width + x1];
|
nuclear@1
|
138 v11 = pixels[y1 * width + x1];
|
nuclear@1
|
139
|
nuclear@1
|
140 float v0 = v00 + (v01 - v00) * ty;
|
nuclear@1
|
141 float v1 = v10 + (v11 - v10) * ty;
|
nuclear@1
|
142
|
nuclear@1
|
143 return v0 + (v1 - v0) * tx;
|
nuclear@1
|
144 }
|
nuclear@1
|
145
|
nuclear@1
|
146 float VoxelVolume::valuef(float x, float y, float z) const
|
nuclear@1
|
147 {
|
nuclear@1
|
148 if(slices.empty()) {
|
nuclear@1
|
149 return 0.0f;
|
nuclear@1
|
150 }
|
nuclear@1
|
151
|
nuclear@1
|
152 float floor_x = floor(x);
|
nuclear@1
|
153 float ceil_x = ceil(x);
|
nuclear@1
|
154 float tx = x - floor_x;
|
nuclear@1
|
155
|
nuclear@1
|
156 float floor_y = floor(y);
|
nuclear@1
|
157 float ceil_y = ceil(y);
|
nuclear@1
|
158 float ty = y - floor_y;
|
nuclear@1
|
159
|
nuclear@1
|
160 float floor_z = floor(z);
|
nuclear@1
|
161 float ceil_z = ceil(z);
|
nuclear@1
|
162 float tz = z - floor_z;
|
nuclear@1
|
163
|
nuclear@1
|
164 int x0 = clamp(floor_x, 0, size[0] - 1);
|
nuclear@1
|
165 int x1 = clamp(ceil_x, 0, size[0] - 1);
|
nuclear@1
|
166
|
nuclear@1
|
167 int y0 = clamp(floor_y, 0, size[1] - 1);
|
nuclear@1
|
168 int y1 = clamp(ceil_y, 0, size[1] - 1);
|
nuclear@1
|
169
|
nuclear@1
|
170 int s0 = clamp(floor_z, 0, size[2] - 1);
|
nuclear@1
|
171 int s1 = clamp(ceil_z, 0, size[2] - 1);
|
nuclear@1
|
172
|
nuclear@1
|
173 float val_s0 = lookup(x0, y0, x1, y1, tx, ty, slices[s0].pixels, size[0], size[1]);
|
nuclear@1
|
174 float val_s1 = lookup(x0, y0, x1, y1, tx, ty, slices[s1].pixels, size[0], size[1]);
|
nuclear@1
|
175
|
nuclear@1
|
176 return val_s0 + (val_s1 - val_s0) * tz;
|
nuclear@1
|
177 }
|
nuclear@1
|
178
|
nuclear@1
|
179 float VoxelVolume::valuei(int x, int y, int z) const
|
nuclear@1
|
180 {
|
nuclear@1
|
181 x = clamp(x, 0, size[0] - 1);
|
nuclear@1
|
182 y = clamp(y, 0, size[1] - 1);
|
nuclear@1
|
183 z = clamp(z, 0, size[2] - 1);
|
nuclear@1
|
184
|
nuclear@1
|
185 return slices[z].pixels[y * size[0] + x];
|
nuclear@1
|
186 }
|
nuclear@1
|
187
|
nuclear@1
|
188 static char *strip_space(char *s)
|
nuclear@1
|
189 {
|
nuclear@1
|
190 while(*s && isspace(*s)) s++;
|
nuclear@1
|
191 if(!*s) return 0;
|
nuclear@1
|
192
|
nuclear@1
|
193 char *end = s + strlen(s) - 1;
|
nuclear@1
|
194 while(end > s && isspace(*end)) end--;
|
nuclear@1
|
195 end[1] = 0;
|
nuclear@1
|
196
|
nuclear@1
|
197 return s;
|
nuclear@1
|
198 }
|