Created
October 17, 2021 13:32
-
-
Save p0nce/879bb716bdf61fb083f7d253b787bdea to your computer and use it in GitHub Desktop.
Vertical stack blur
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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