From 40b8a8ace73b13723d366d138a0506cc1980d450 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Tue, 30 Oct 2018 15:41:48 +0100 Subject: [PATCH] Added orx-integral-image Fixed bug in JumpFlood --- README.md | 1 + orx-integral-image/README.md | 12 +++ .../src/main/kotlin/IntegralImage.kt | 80 +++++++++++++++++++ orx-jumpflood/src/main/kotlin/JumpFlood.kt | 3 + settings.gradle | 3 +- 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 orx-integral-image/README.md create mode 100644 orx-integral-image/src/main/kotlin/IntegralImage.kt diff --git a/README.md b/README.md index 1ec93792..1f97ef15 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ A growing library of assorted data structures, algorithms and utilities. - orx-kdtree, a kd-tree implementation for fast nearest point searches - orx-jumpflood, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields +- orx-integral-image, a CPU-based implementation for integral images (summed area tables) ## Usage diff --git a/orx-integral-image/README.md b/orx-integral-image/README.md new file mode 100644 index 00000000..0a794137 --- /dev/null +++ b/orx-integral-image/README.md @@ -0,0 +1,12 @@ +# orx-integral-image + +#### Usage + +``` +val image = colorBuffer( ... ) +image.shadow.download() +val integralImage = IntegralImage.fromColorBufferShadow(image.shadow) + +// -- the sum for a given area can be queried using +val sum = integralImage.sum(IntRectangle(20, 20, 100, 100)) +``` diff --git a/orx-integral-image/src/main/kotlin/IntegralImage.kt b/orx-integral-image/src/main/kotlin/IntegralImage.kt new file mode 100644 index 00000000..4c1df7f2 --- /dev/null +++ b/orx-integral-image/src/main/kotlin/IntegralImage.kt @@ -0,0 +1,80 @@ +package studio.rndnr.packture + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.ColorBufferShadow +import org.openrndr.shape.IntRectangle + +class IntegralImage(val width: Int, val height: Int, val integral: LongArray) { + + internal val maximum: Long + get() = integral[integral.size - 1] + + companion object { + fun fromColorBufferShadow(shadow: ColorBufferShadow, sampler: (ColorRGBa) -> Long = { (it.r * 255.0).toLong() }): IntegralImage { + val integral = LongArray(shadow.colorBuffer.width * shadow.colorBuffer.height) + + val width = shadow.colorBuffer.width + val height = shadow.colorBuffer.height + + for (i in integral.indices) { + integral[i] = 0 + } + + for (y in 0 until height) { + for (x in 0 until width) { + val i = sampler(shadow.read(x, y)) + + var i10: Long = 0 + if (x > 0) + i10 = integral[x - 1 + y * width] + + var i01: Long = 0 + if (y > 0) { + i01 = integral[x + (y - 1) * width] + } + + var i11: Long = 0 + if (y > 0 && x > 0) { + i11 = integral[x - 1 + (y - 1) * width] + } + + integral[y * width + x] = i + i10 + i01 - i11 + } + } + return IntegralImage(width, height, integral) + } + } + + + private fun clip(x: Int, left: Int, right: Int): Int { + return Math.min(right, Math.max(left, x)) + } + + fun sum(area: IntRectangle): Long { + return sum(area.x, area.y, area.x + area.width - 1, area.y + area.height - 1) + } + + private fun sum(left: Int, top: Int, right: Int, bottom: Int): Long { + var left = left + var top = top + var right = right + var bottom = bottom + top = clip(top, 0, height - 1) + bottom = clip(bottom, 0, height - 1) + + left = clip(left, 0, width - 1) + right = clip(right, 0, width - 1) + + val a = integral[left + top * width] + val b = integral[right + top * width] + val c = integral[right + bottom * width] + val d = integral[left + bottom * width] + + return a + c - b - d + } + + private fun average(left: Int, top: Int, right: Int, bottom: Int): Double { + val area = ((right - left) * (bottom - top)).toDouble() + return sum(left, top, right, bottom) / area + } +} \ No newline at end of file diff --git a/orx-jumpflood/src/main/kotlin/JumpFlood.kt b/orx-jumpflood/src/main/kotlin/JumpFlood.kt index 8589289f..d8767dcc 100644 --- a/orx-jumpflood/src/main/kotlin/JumpFlood.kt +++ b/orx-jumpflood/src/main/kotlin/JumpFlood.kt @@ -1,5 +1,6 @@ package org.openrndr.extra.jumpfill +import org.openrndr.color.ColorRGBa import org.openrndr.draw.* import org.openrndr.filter.filterShaderFromUrl import org.openrndr.math.Matrix44 @@ -72,6 +73,7 @@ class JumpFlooder(val width: Int, val height: Int) { } drawer.isolatedWithTarget(square) { + drawer.background(ColorRGBa.BLACK) drawer.ortho(square) drawer.view = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY @@ -86,6 +88,7 @@ class JumpFlooder(val width: Int, val height: Int) { pixelDistance.apply(coordinates[exp % 2], coordinates[exp % 2]) drawer.isolatedWithTarget(final) { + drawer.background(ColorRGBa.BLACK) drawer.ortho(final) drawer.view = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY diff --git a/settings.gradle b/settings.gradle index 857b6acb..8b3e7576 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ rootProject.name = 'orx' include 'orx-jumpflood', - 'orx-kdtree' \ No newline at end of file + 'orx-kdtree', + 'orx-integral-image'