Commit: 9959704e88e5abbfa34476e41a1304808bcff4af
Parent: d7e50c8308ff59a5870b78b0c2c6d2dca7f3e5f6
Author: Randy Palamar
Date: Thu, 15 May 2025 19:33:27 -0600
das: add optional coherency weighting to output data
Diffstat:
3 files changed, 29 insertions(+), 18 deletions(-)
diff --git a/beamformer_parameters.h b/beamformer_parameters.h
@@ -7,7 +7,7 @@
* programatically would be nice.
*/
-#define BEAMFORMER_PARAMETERS_VERSION (1UL)
+#define BEAMFORMER_PARAMETERS_VERSION (2UL)
/* X(enumarant, number, shader file name, needs header, pretty name) */
#define COMPUTE_SHADERS \
@@ -83,7 +83,8 @@ typedef enum {
X(off_axis_pos, float, , float, , "/* [m] Position on screen normal to beamform in TPW/VLSHERCULES */") \
X(beamform_plane, int32_t, , int, , "/* Plane to Beamform in TPW/VLS/HERCULES */") \
X(f_number, float, , float, , "/* F# (set to 0 to disable) */") \
- X(interpolate, uint32_t, , bool, , "/* Perform Cubic Interpolation of RF Samples */")
+ X(interpolate, uint32_t, , bool, , "/* Perform Cubic Interpolation of RF Samples */") \
+ X(coherency_weighting, uint32_t, , bool, , "/* Apply coherency weighting to output data */")
#define BEAMFORMER_PARAMS_HEAD_V0 \
X(channel_mapping, uint16_t, [256], uvec4, [32], "/* Transducer Channel to Verasonics Channel */") \
@@ -122,7 +123,7 @@ typedef struct {
BEAMFORMER_PARAMS_HEAD_V0
BEAMFORMER_UI_PARAMS
BEAMFORMER_PARAMS_TAIL
- float _pad[3];
+ float _pad[2];
} BeamformerParametersV0;
/* NOTE: This struct follows the OpenGL std140 layout. DO NOT modify unless you have
@@ -131,7 +132,7 @@ typedef struct {
BEAMFORMER_PARAMS_HEAD
BEAMFORMER_UI_PARAMS
BEAMFORMER_PARAMS_TAIL
- float _pad[3];
+ float _pad[2];
} BeamformerParameters;
#undef X
diff --git a/shaders/das.glsl b/shaders/das.glsl
@@ -107,7 +107,7 @@ float cylindricalwave_transmit_distance(vec3 point, float focal_depth, float tra
return length(orientation_projection(point - f, tx_rows));
}
-vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg)
+vec3 RCA(vec3 image_point, vec3 delta, float apodization_arg)
{
int ridx = 0;
int direction = beamform_plane;
@@ -119,7 +119,7 @@ vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg)
vec3 receive_point = world_space_to_rca_space(image_point, !rx_col);
delta = orientation_projection(delta, !rx_col);
- vec2 sum = vec2(0);
+ vec3 sum = vec3(0);
/* NOTE: For Each Acquistion in Raw Data */
// uint i = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); {
for (int i = 0; i < dec_data_dim.z; i++) {
@@ -142,7 +142,9 @@ vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg)
for (uint j = 0; j < dec_data_dim.y; j++) {
float sidx = sample_index(transmit_distance + length(receive_distance));
vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x);
- sum += apodize(sample_rf(ridx, sidx), apodization_arg, length(receive_distance.xy)) * valid;
+ vec2 samp = valid * apodize(sample_rf(ridx, sidx), apodization_arg,
+ length(receive_distance.xy));
+ sum += vec3(samp, length(samp));
receive_distance -= delta;
ridx += int(dec_data_dim.x);
}
@@ -150,7 +152,7 @@ vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg)
return sum;
}
-vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg)
+vec3 HERCULES(vec3 image_point, vec3 delta, float apodization_arg)
{
int uhercules = int(das_shader_id == DAS_ID_UHERCULES);
int ridx = int(dec_data_dim.y * dec_data_dim.x * uhercules);
@@ -174,7 +176,7 @@ vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg)
!tx_col);
}
- vec2 sum = vec2(0);
+ vec3 sum = vec3(0);
/* NOTE: For Each Acquistion in Raw Data */
for (int i = uhercules; i < dec_data_dim.z; i++) {
int channel = imageLoad(sparse_elements, i - uhercules).x;
@@ -190,15 +192,16 @@ vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg)
/* NOTE: tribal knowledge */
if (i == 0) valid *= inversesqrt(dec_data_dim.z);
- sum += apodize(sample_rf(ridx, sidx), apodization_arg,
- length(receive_distance.xy)) * valid;
+ vec2 samp = valid * apodize(sample_rf(ridx, sidx), apodization_arg,
+ length(receive_distance.xy));
+ sum += vec3(samp, length(samp));
ridx += int(dec_data_dim.x);
}
}
return sum;
}
-vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg)
+vec3 uFORCES(vec3 image_point, vec3 delta, float apodization_arg)
{
/* NOTE: skip first acquisition in uforces since its garbage */
int uforces = int(das_shader_id == DAS_ID_UFORCES);
@@ -206,7 +209,7 @@ vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg)
image_point = (xdc_transform * vec4(image_point, 1)).xyz;
- vec2 sum = vec2(0);
+ vec3 sum = vec3(0);
for (int i = uforces; i < dec_data_dim.z; i++) {
int channel = imageLoad(sparse_elements, i - uforces).x;
vec2 recieve_point = image_point.xz;
@@ -216,8 +219,9 @@ vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg)
for (uint j = 0; j < dec_data_dim.y; j++) {
float sidx = sample_index(transmit_dist + length(recieve_point));
vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x);
- sum += valid * apodize(sample_rf(ridx, sidx), apodization_arg,
+ vec2 samp = valid * apodize(sample_rf(ridx, sidx), apodization_arg,
recieve_point.x);
+ sum += vec3(samp, length(samp));
ridx += int(dec_data_dim.x);
recieve_point.x -= delta.x;
}
@@ -241,7 +245,7 @@ void main()
float apod_arg = f_number * radians(180) / abs(image_point.z);
/* NOTE: skip over channels corresponding to other arrays */
- vec2 sum;
+ vec3 sum;
switch (das_shader_id) {
case DAS_ID_FORCES:
case DAS_ID_UFORCES:
@@ -258,5 +262,8 @@ void main()
break;
}
- imageStore(u_out_data_tex, out_coord, vec4(sum, 0, 0));
+ /* TODO(rnp): scale such that brightness remains ~constant */
+ if (coherency_weighting) sum.xy *= sum.xy / (sum.z + float(sum.z == 0));
+
+ imageStore(u_out_data_tex, out_coord, vec4(sum.xy, 0, 0));
}
diff --git a/ui.c b/ui.c
@@ -955,9 +955,12 @@ add_beamformer_parameters_view(Variable *parent, BeamformerCtx *ctx)
add_beamformer_variable_f32(ui, group, &ui->arena, s8("F#:"), s8(""), &bp->f_number,
(v2){.y = 1e3}, 1, 0.1, V_INPUT|V_TEXT|V_CAUSES_COMPUTE, ui->font);
- local_persist s8 interpolate_labels[] = {s8("False"), s8("True")};
+ local_persist s8 true_false_labels[] = {s8("False"), s8("True")};
add_variable_cycler(ui, group, &ui->arena, V_CAUSES_COMPUTE, ui->font, s8("Interpolate:"),
- &bp->interpolate, interpolate_labels, countof(interpolate_labels));
+ &bp->interpolate, true_false_labels, countof(true_false_labels));
+
+ add_variable_cycler(ui, group, &ui->arena, V_CAUSES_COMPUTE, ui->font, s8("Coherency Weighting:"),
+ &bp->coherency_weighting, true_false_labels, countof(true_false_labels));
return result;
}