Added orx-integral-image
Fixed bug in JumpFlood
This commit is contained in:
@@ -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-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-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
|
## Usage
|
||||||
|
|
||||||
|
|||||||
12
orx-integral-image/README.md
Normal file
12
orx-integral-image/README.md
Normal file
@@ -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))
|
||||||
|
```
|
||||||
80
orx-integral-image/src/main/kotlin/IntegralImage.kt
Normal file
80
orx-integral-image/src/main/kotlin/IntegralImage.kt
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.openrndr.extra.jumpfill
|
package org.openrndr.extra.jumpfill
|
||||||
|
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
import org.openrndr.draw.*
|
import org.openrndr.draw.*
|
||||||
import org.openrndr.filter.filterShaderFromUrl
|
import org.openrndr.filter.filterShaderFromUrl
|
||||||
import org.openrndr.math.Matrix44
|
import org.openrndr.math.Matrix44
|
||||||
@@ -72,6 +73,7 @@ class JumpFlooder(val width: Int, val height: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawer.isolatedWithTarget(square) {
|
drawer.isolatedWithTarget(square) {
|
||||||
|
drawer.background(ColorRGBa.BLACK)
|
||||||
drawer.ortho(square)
|
drawer.ortho(square)
|
||||||
drawer.view = Matrix44.IDENTITY
|
drawer.view = Matrix44.IDENTITY
|
||||||
drawer.model = 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])
|
pixelDistance.apply(coordinates[exp % 2], coordinates[exp % 2])
|
||||||
drawer.isolatedWithTarget(final) {
|
drawer.isolatedWithTarget(final) {
|
||||||
|
drawer.background(ColorRGBa.BLACK)
|
||||||
drawer.ortho(final)
|
drawer.ortho(final)
|
||||||
drawer.view = Matrix44.IDENTITY
|
drawer.view = Matrix44.IDENTITY
|
||||||
drawer.model = Matrix44.IDENTITY
|
drawer.model = Matrix44.IDENTITY
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
rootProject.name = 'orx'
|
rootProject.name = 'orx'
|
||||||
|
|
||||||
include 'orx-jumpflood',
|
include 'orx-jumpflood',
|
||||||
'orx-kdtree'
|
'orx-kdtree',
|
||||||
|
'orx-integral-image'
|
||||||
|
|||||||
Reference in New Issue
Block a user