Skip to content

Commit d4cd638

Browse files
author
david.roddy
committed
GPUSPECT: forward rotation and interpolation in cuda
1 parent 5d300cf commit d4cd638

File tree

1 file changed

+98
-1
lines changed

1 file changed

+98
-1
lines changed

src/recon_buildblock/SPECTGPU_projector/SPECTGPURotateAndGaussianInterpolate.cu

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,106 @@ __global__ void rotateKernel_pull(const float* __restrict__ in_im,
3434
float3 origin,
3535
float angle_rad)
3636
{
37+
// parallelise the operation across all image voxels
38+
int i = threadIdx.x + blockDim.x * blockIdx.x;
39+
int j = threadIdx.y + blockDim.y * blockIdx.y;
40+
int k = threadIdx.z + blockDim.z * blockIdx.z;
3741

42+
// check we are not outside the image
43+
if (i >= dim.x || j >= dim.y || k >= dim.z) {
44+
return;
45+
};
3846

39-
}
47+
// get the 1-dimensional index
48+
int idx = i + (j * dim.x) + (k * dim.x * dim.y);
49+
50+
// move to centre of voxel and convert from voxel to image space
51+
float Xs_rel_x = (i + 0.5f) * spacing.x - origin.x;
52+
float Xs_rel_y = (j + 0.5f) * spacing.y - origin.y;
53+
float Xs_rel_z = (k + 0.5f) * spacing.z - origin.z;
54+
55+
// perform the rotation by 'angle_rad'
56+
float X_rot_x = (Xs_rel_x * cosf(angle_rad)) - (Xs_rel_y * sinf(angle_rad));
57+
float X_rot_y = (Xs_rel_x * sinf(angle_rad)) + (Xs_rel_y * cosf(angle_rad));
58+
float X_rot_z = Xs_rel_z;
59+
60+
// convert back to voxel space origin (corner of image) but keep image space dimensions
61+
float Xr_x = X_rot_x + origin.x;
62+
float Xr_y = X_rot_y + origin.y;
63+
float Xr_z = X_rot_z + origin.z;
64+
65+
// now we go fully back to voxel space (but now it's been rotated)
66+
float p_r = Xr_x / spacing.x;
67+
float q_r = Xr_y / spacing.y;
68+
float r_r = Xr_z / spacing.z;
69+
70+
// first loop is for finding the value of a gaussian kernel at
71+
// each nearest neighbour position and summing them all. This will allow normalisation
72+
// of each NN contribution in the next loop.
73+
float G = 0; // accumulator variable
74+
float sigma = 1; // gaussian kernel sigma
75+
76+
for (int dr = -1; dr <= 1; dr++) {
77+
int r = (int)roundf(r_r) + dr; // nearest neighbour z coordinate in rotated voxel space
78+
float x_r = (r * spacing.z) - origin.z; // converted to image space
79+
80+
for (int dq = -1; dq <= 1; dq++) {
81+
int q = (int)roundf(q_r) + dq;
82+
float x_q = (q * spacing.y) - origin.y;
83+
84+
for (int dp = -1; dp <= 1; dp++) {
85+
int p = (int)roundf(p_r) + dp;
86+
float x_p = (p * spacing.x) - origin.x;
87+
88+
// get distance between nearest neighbour and central voxel
89+
// both need to be in image space
90+
float delta_x = X_rot_x - x_p;
91+
float delta_y = X_rot_y - x_q;
92+
float delta_z = X_rot_z - x_r;
93+
94+
// caulculate gaussian kernel
95+
float g = expf(-1. * ((delta_x*delta_x) + (delta_y*delta_y) + (delta_z*delta_z)) / (2*sigma*sigma))
96+
G += g;
97+
};
98+
};
99+
};
100+
101+
// loop again but this time actually fetch the image values
102+
float accumulation = 0;
103+
104+
for (int dr = -1; dr <= 1; dr++) {
105+
float r = dr + (int)roundf(r_r);
106+
float x_r = origin.z + (r * spacing.z);
107+
108+
for (int dq = -1; dq <= 1; dq++) {
109+
float q = dq + (int)roundf(q_r);
110+
float x_q = origin.y + (q * spacing.y);
111+
112+
for (int dp = -1; dp <= 1; dp++) {
113+
float p = dp + (int)roundf(p_r);
114+
float x_p = origin.x + (p * spacing.x);
115+
116+
float delta_x = Xr_x - x_p;
117+
float delta_y = Xr_y - x_q;
118+
float delta_z = Xr_z - x_r;
119+
120+
// get input image voxel index that we are at
121+
int i_idx = p + (q * dim.x) + (r * dim.x * dim.y);
122+
123+
// calculate gaussian weighting for this voxel
124+
float g = expf(-1. * ((delta_x*delta_x) + (delta_y*delta_y) + (delta_z*delta_z)) / (2*sigma*sigma));
125+
126+
// record the weighted value from this voxel
127+
accumulation += in_im[i_idx] * g / G;
128+
129+
};
130+
};
131+
};
132+
133+
// assign the pulled voxel values to a single voxel in the output image
134+
out_im[idx] = accumulation;
135+
136+
};
40137

41138
// the following is the adjoint operation (push)
42139
__global__ void rotateKernel_push(const float* __restrict__ in_im,

0 commit comments

Comments
 (0)