Skip to content

Instantly share code, notes, and snippets.

@p0nce
Created October 17, 2021 13:32
Show Gist options
  • Select an option

  • Save p0nce/879bb716bdf61fb083f7d253b787bdea to your computer and use it in GitHub Desktop.

Select an option

Save p0nce/879bb716bdf61fb083f7d253b787bdea to your computer and use it in GitHub Desktop.
Vertical stack blur
module stackblur;
/// Perform a stack blur vertically over an image.
/// Params:
/// input a width x height buffer.
/// output a width x height buffer.
/// width Length in the X dimension.
/// height Length in the Y dimension.
/// kernelSize size of kernel, must be >= 1 and odd number.
/// tempBuf a temporary buffer of size width.
/// Reference: http://underdestruction.com/2004/02/25/stackblur-2004/
/// The result is scaled by kernelSize!
private void verticalStackBlur(float* input,
float* output,
int width,
int height,
int kernelSize,
float* tempBuf)
{
float* stack = tempBuf;
int kernelHalfSize = (kernelSize - 1) / 2; // 3 gives 1
assert(height > 0);
int queueIdx = 0;
// Fill the queue with replicated top of image.
// Fill the stack with sum of that top.
stack[0..width] = input[0..width] * kernelSize;
// Iteration: subtract queue[queueIdx] from stack
// queueIdx = (queueIdx + 1) % kernelSize
// add queue[queueIdx] into stack
void iter(int YAdd, int YRemove) //nothrow @nogc
{
assert(YAdd >= 0 && YAdd < height);
assert(YRemove >= 0 && YRemove < height);
float[] lineRemove = input[YRemove*width..(YRemove+1)*width];
float[] lineAdd = input[ YAdd*width..( YAdd+1)*width];
stack[0..width] += lineAdd[0..width] - lineRemove[0..width];
}
for (int n = 0; n + 1 < kernelHalfSize; ++n)
iter(n+1, 0);
for (int y = 0; y < height; ++y)
{
int YAdd = y + kernelHalfSize;
int YRemove = y - kernelHalfSize - 1;
if (YAdd >= height) YAdd = height - 1;
if (YRemove < 0) YRemove = 0;
iter(YAdd, YRemove);
output[y*width..(y+1)*width] = stack[0..width];
}
}
unittest
{
static float distance(float[12] A, float[12] B)
{
float absDiff = 0.0f;
foreach(i; 0..12)
{
float d = A[i] - B[i];
if (d < 0) d = -d;
absDiff += d;
}
return absDiff;
}
float[12] A = [1.0f, 2.0f, 4.0f, 1.0f,
0.0f, 1.0f, 2.0f, 4.0f,
-1.0f, 8.0f, 1.0f, 2.0f ];
float[12] R;
float[4 * 3] buf;
verticalStackBlur(A.ptr, R.ptr, 4, 3, 1, buf.ptr);
assert(distance(A, R) < 1e-7f);
verticalStackBlur(A.ptr, R.ptr, 4, 3, 3, buf.ptr);
float[12] Ref = [2.0f, 5, 10, 6,
0, 11, 7, 7,
-2, 17, 4, 8];
assert(distance(Ref, R) < 1e-7f);
verticalStackBlur(A.ptr, R.ptr, 4, 3, 5, buf.ptr);
float[12] Ref2 = [2.0f, 15, 15, 9,
0, 21, 12, 10,
-2, 27, 9, 11];
assert(distance(Ref2, R) < 1e-7f);
}
void main()
{}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment