Convert orx-shader-phrases and orx-noise to MPP
This commit is contained in:
45
orx-jvm/orx-boofcv/README.md
Normal file
45
orx-jvm/orx-boofcv/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# orx-boofcv
|
||||
|
||||
Helper functions to ease working with the BoofCV computer vision library
|
||||
and its data types.
|
||||
|
||||
BoofCV is an open source library written from scratch for real-time
|
||||
computer vision. Its functionality covers a range of subjects,
|
||||
low-level image processing, camera calibration, feature detection/tracking,
|
||||
structure-from-motion, fiducial detection, and recognition.
|
||||
BoofCV has been released under an Apache 2.0 license for both
|
||||
academic and commercial use.
|
||||
|
||||
Examples of what BoofCV offers can be found at
|
||||
[http://boofcv.org/](http://boofcv.org/)
|
||||
|
||||
As BoofCV implements it's own data types for images, lines, points, etc.
|
||||
this addon provides some helper functions to convert them to OPENRNDR types:
|
||||
|
||||
- Bindings: converts to and from `ColorBuffer`.
|
||||
- Drawing: allows directly drawing BoofCV line segments and other shapes.
|
||||
- Point conversion to and from `Vector2`.
|
||||
- Contour conversion from `BoofCV.Contour` to `Shape` and `ShapeContour`.
|
||||
- `ImageFlow` to `ColorBuffer` conversion.
|
||||
|
||||
<!-- __demos__ -->
|
||||
## Demos
|
||||
### DemoContours01
|
||||
[source code](src/demo/kotlin/DemoContours01.kt)
|
||||
|
||||

|
||||
|
||||
### DemoResize01
|
||||
[source code](src/demo/kotlin/DemoResize01.kt)
|
||||
|
||||

|
||||
|
||||
### DemoResize02
|
||||
[source code](src/demo/kotlin/DemoResize02.kt)
|
||||
|
||||

|
||||
|
||||
### DemoSimplified01
|
||||
[source code](src/demo/kotlin/DemoSimplified01.kt)
|
||||
|
||||

|
||||
20
orx-jvm/orx-boofcv/build.gradle
Normal file
20
orx-jvm/orx-boofcv/build.gradle
Normal file
@@ -0,0 +1,20 @@
|
||||
sourceSets {
|
||||
demo {
|
||||
java {
|
||||
srcDirs = ["src/demo/kotlin"]
|
||||
compileClasspath += main.getCompileClasspath()
|
||||
runtimeClasspath += main.getRuntimeClasspath()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def boofcvVersion = "0.37"
|
||||
|
||||
dependencies {
|
||||
api("org.boofcv:boofcv-core:$boofcvVersion")
|
||||
demoImplementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||
demoImplementation("org.openrndr:openrndr-extensions:$openrndrVersion")
|
||||
demoRuntimeOnly("org.openrndr:openrndr-gl3:$openrndrVersion")
|
||||
demoRuntimeOnly("org.openrndr:openrndr-gl3-natives-$openrndrOS:$openrndrVersion")
|
||||
demoImplementation(sourceSets.getByName("main").output)
|
||||
}
|
||||
74
orx-jvm/orx-boofcv/src/demo/kotlin/DemoContours01.kt
Normal file
74
orx-jvm/orx-boofcv/src/demo/kotlin/DemoContours01.kt
Normal file
@@ -0,0 +1,74 @@
|
||||
import boofcv.alg.filter.binary.BinaryImageOps
|
||||
import boofcv.alg.filter.binary.GThresholdImageOps
|
||||
import boofcv.alg.filter.binary.ThresholdImageOps
|
||||
import boofcv.struct.ConnectRule
|
||||
import boofcv.struct.image.GrayU8
|
||||
import org.openrndr.application
|
||||
import org.openrndr.boofcv.binding.toGrayF32
|
||||
import org.openrndr.boofcv.binding.toShapeContours
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.color.rgb
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
suspend fun main() {
|
||||
application {
|
||||
program {
|
||||
|
||||
// -- this block is for automation purposes only
|
||||
if (System.getProperty("takeScreenshot") == "true") {
|
||||
extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
|
||||
// Load an image, convert to BoofCV format using orx-boofcv
|
||||
val input = loadImage("demo-data/images/image-001.png").toGrayF32()
|
||||
|
||||
// BoofCV: calculate a good threshold for the loaded image
|
||||
val threshold = GThresholdImageOps.computeOtsu(input, 0.0, 255.0)
|
||||
|
||||
// BoofCV: use the threshold to convert the image to black and white
|
||||
val binary = GrayU8(input.width, input.height)
|
||||
ThresholdImageOps.threshold(input, binary, threshold.toFloat(), false)
|
||||
|
||||
// BoofCV: Contract and expand the white areas to remove noise
|
||||
var filtered = BinaryImageOps.erode8(binary, 1, null)
|
||||
filtered = BinaryImageOps.dilate8(filtered, 1, null)
|
||||
|
||||
// BoofCV: Calculate contours as vector data
|
||||
val contours = BinaryImageOps.contour(filtered, ConnectRule.EIGHT, null)
|
||||
|
||||
// orx-boofcv: convert vector data to OPENRNDR ShapeContours
|
||||
val externalShapes = contours.toShapeContours(true,
|
||||
internal = false, external = true)
|
||||
val internalShapes = contours.toShapeContours(true,
|
||||
internal = true, external = false)
|
||||
|
||||
extend {
|
||||
drawer.run {
|
||||
// Zoom in and out over time
|
||||
translate(bounds.center)
|
||||
scale(1.5 + 0.5 * cos(seconds * 0.2))
|
||||
translate(-bounds.center)
|
||||
|
||||
stroke = null
|
||||
|
||||
// Draw all external shapes
|
||||
fill = rgb(0.2)
|
||||
contours(externalShapes)
|
||||
|
||||
// Draw internal shapes one by one to set unique colors
|
||||
internalShapes.forEachIndexed { i, shp ->
|
||||
val shade = 0.2 + (i % 7) * 0.1 +
|
||||
0.1 * sin(i + seconds)
|
||||
fill = ColorRGBa.PINK.shade(shade)
|
||||
contour(shp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
orx-jvm/orx-boofcv/src/demo/kotlin/DemoResize01.kt
Normal file
33
orx-jvm/orx-boofcv/src/demo/kotlin/DemoResize01.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.boofcv.binding.*
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
|
||||
|
||||
suspend fun main() {
|
||||
application {
|
||||
program {
|
||||
if (System.getProperty("takeScreenshot") == "true") {
|
||||
extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
|
||||
// Load an image, convert to BoofCV format using orx-boofcv
|
||||
val input = loadImage("demo-data/images/image-001.png")
|
||||
|
||||
val scaled = input.resizeBy(0.5)
|
||||
val scaled2 = input.resizeBy(0.25, convertToGray = true)
|
||||
val scaled3 = input.resizeBy(0.1)
|
||||
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.BLACK)
|
||||
drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
|
||||
drawer.image(scaled)
|
||||
drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
|
||||
drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
orx-jvm/orx-boofcv/src/demo/kotlin/DemoResize02.kt
Normal file
32
orx-jvm/orx-boofcv/src/demo/kotlin/DemoResize02.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.boofcv.binding.*
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
|
||||
|
||||
suspend fun main() {
|
||||
application {
|
||||
program {
|
||||
if (System.getProperty("takeScreenshot") == "true") {
|
||||
extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
|
||||
// Load an image, convert to BoofCV format using orx-boofcv
|
||||
val input = loadImage("demo-data/images/image-001.png")
|
||||
val scaled = input.resizeTo(input.width / 3)
|
||||
val scaled2 = input.resizeTo(newHeight = input.height / 4, convertToGray = true)
|
||||
val scaled3 = input.resizeTo(input.width / 5, input.height / 5)
|
||||
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.BLACK)
|
||||
drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
|
||||
drawer.image(scaled)
|
||||
drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
|
||||
drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
orx-jvm/orx-boofcv/src/demo/kotlin/DemoSimplified01.kt
Normal file
109
orx-jvm/orx-boofcv/src/demo/kotlin/DemoSimplified01.kt
Normal file
@@ -0,0 +1,109 @@
|
||||
import boofcv.alg.filter.binary.BinaryImageOps
|
||||
import boofcv.alg.filter.binary.GThresholdImageOps
|
||||
import boofcv.alg.filter.binary.ThresholdImageOps
|
||||
import boofcv.struct.ConnectRule
|
||||
import boofcv.struct.image.GrayU8
|
||||
import org.openrndr.application
|
||||
import org.openrndr.boofcv.binding.toGrayF32
|
||||
import org.openrndr.boofcv.binding.toShapeContours
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.ColorBuffer
|
||||
import org.openrndr.draw.isolatedWithTarget
|
||||
import org.openrndr.draw.renderTarget
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
import org.openrndr.math.CatmullRomChain2
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Rectangle
|
||||
import org.openrndr.shape.ShapeContour
|
||||
import org.openrndr.shape.simplify
|
||||
import org.openrndr.shape.toContour
|
||||
|
||||
suspend fun main() {
|
||||
application {
|
||||
program {
|
||||
|
||||
// -- this block is for automation purposes only
|
||||
if (System.getProperty("takeScreenshot") == "true") {
|
||||
extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
|
||||
// Create a buffer where to draw something for boofcv
|
||||
val rt = renderTarget(width, height) {
|
||||
colorBuffer()
|
||||
depthBuffer()
|
||||
}
|
||||
// Draw some shapes on that buffer
|
||||
drawer.isolatedWithTarget(rt) {
|
||||
clear(ColorRGBa.BLACK)
|
||||
fill = ColorRGBa.WHITE
|
||||
stroke = null
|
||||
rectangle(Rectangle.fromCenter(bounds.position(0.33, 0.5),
|
||||
150.0, 150.0))
|
||||
translate(bounds.position(0.62, 0.5))
|
||||
rotate(30.0)
|
||||
rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0, 200.0))
|
||||
rectangle(0.0, -200.0, 60.0, 60.0)
|
||||
circle(0.0, 190.0, 60.0)
|
||||
}
|
||||
// Convert the bitmap buffer into ShapeContours
|
||||
val vectorized = imageToContours(rt.colorBuffer(0))
|
||||
|
||||
// Show amount of segments in each shape (high number)
|
||||
vectorized.forEachIndexed { i, it ->
|
||||
println("boofcv shape $i: ${it.segments.size} segments")
|
||||
}
|
||||
|
||||
// Make a simplified list of points
|
||||
val simplePoints = vectorized.map {
|
||||
simplify(it.adaptivePositions(), 4.0)
|
||||
}.filter { it.size >= 3 }
|
||||
|
||||
// Use the simplified list to make a smooth contour
|
||||
val smooth = simplePoints.map {
|
||||
CatmullRomChain2(it, 0.0, true).toContour()
|
||||
}
|
||||
|
||||
// Use the simplified list to make a polygonal contour
|
||||
val polygonal = simplePoints.map {
|
||||
ShapeContour.fromPoints(it, true)
|
||||
}
|
||||
|
||||
// Show amount of segments in simplified shapes (low number).
|
||||
// Note: `smooth` and `polygonal` have the same number of segments
|
||||
smooth.forEachIndexed { i, it ->
|
||||
println("simplified shape $i: ${it.segments.size} segments")
|
||||
}
|
||||
|
||||
extend {
|
||||
drawer.run {
|
||||
fill = null // ColorRGBa.PINK.opacify(0.15)
|
||||
stroke = ColorRGBa.PINK.opacify(0.7)
|
||||
contours(polygonal)
|
||||
contours(smooth)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun imageToContours(input: ColorBuffer): List<ShapeContour> {
|
||||
val bitmap = input.toGrayF32()
|
||||
// BoofCV: calculate a good threshold for the loaded image
|
||||
val threshold = GThresholdImageOps.computeOtsu(bitmap, 0.0, 255.0)
|
||||
|
||||
// BoofCV: use the threshold to convert the image to black and white
|
||||
val binary = GrayU8(bitmap.width, bitmap.height)
|
||||
ThresholdImageOps.threshold(bitmap, binary, threshold.toFloat(), false)
|
||||
|
||||
// BoofCV: Contract and expand the white areas to remove noise
|
||||
var filtered = BinaryImageOps.erode8(binary, 1, null)
|
||||
filtered = BinaryImageOps.dilate8(filtered, 1, null)
|
||||
|
||||
// BoofCV: Calculate contours as vector data
|
||||
val contours = BinaryImageOps.contour(filtered, ConnectRule.EIGHT, null)
|
||||
|
||||
// orx-boofcv: convert vector data to OPENRNDR ShapeContours
|
||||
return contours.toShapeContours(true, internal = true, external = true)
|
||||
}
|
||||
187
orx-jvm/orx-boofcv/src/main/kotlin/Binding.kt
Normal file
187
orx-jvm/orx-boofcv/src/main/kotlin/Binding.kt
Normal file
@@ -0,0 +1,187 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import boofcv.struct.image.GrayF32
|
||||
import boofcv.struct.image.GrayF64
|
||||
import boofcv.struct.image.GrayU8
|
||||
import boofcv.struct.image.Planar
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.ColorBuffer
|
||||
import org.openrndr.draw.ColorFormat
|
||||
import org.openrndr.draw.ColorType
|
||||
import org.openrndr.draw.colorBuffer
|
||||
import kotlin.experimental.and
|
||||
|
||||
fun ColorBuffer.toGrayF32() : GrayF32 {
|
||||
val p = GrayF32(width, height)
|
||||
shadow.download()
|
||||
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val c = shadow.read(x, y)
|
||||
p.data[offset] = (c.r * 255).toFloat()
|
||||
offset++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
fun ColorBuffer.toGrayF64() : GrayF64 {
|
||||
val p = GrayF64(width, height)
|
||||
shadow.download()
|
||||
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val c = shadow.read(x, y)
|
||||
p.data[offset] = (c.r * 255)
|
||||
offset++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
fun ColorBuffer.toPlanarF32() : Planar<GrayF32> {
|
||||
val p = Planar<GrayF32>(GrayF32::class.java, width, height, format.componentCount)
|
||||
shadow.download()
|
||||
|
||||
val bands = p.bands
|
||||
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val c = shadow.read(x, y)
|
||||
bands[0].data[offset] = (c.r * 255).toFloat()
|
||||
bands[1].data[offset] = (c.g * 255).toFloat()
|
||||
bands[2].data[offset] = (c.b * 255).toFloat()
|
||||
offset++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
fun ColorBuffer.toPlanarU8() : Planar<GrayU8> {
|
||||
val p = Planar<GrayU8>(GrayU8::class.java, width, height, format.componentCount)
|
||||
shadow.download()
|
||||
|
||||
val bands = p.bands
|
||||
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val c = shadow.read(x, y)
|
||||
bands[0].data[offset] = (c.r * 255).toInt().toByte()
|
||||
bands[1].data[offset] = (c.g * 255).toInt().toByte()
|
||||
bands[2].data[offset] = (c.b * 255).toInt().toByte()
|
||||
offset++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
fun ColorBuffer.toGrayU8() : GrayU8 {
|
||||
val p = GrayU8(width, height)
|
||||
shadow.download()
|
||||
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val c = shadow.read(x, y)
|
||||
p.data[offset] = (c.r * 255).toInt().coerceIn(0, 255).toByte()
|
||||
offset++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
fun GrayU8.toColorBuffer() : ColorBuffer {
|
||||
val cb = colorBuffer(width, height, 1.0, ColorFormat.RGB, ColorType.UINT8)
|
||||
val shadow = cb.shadow
|
||||
shadow.buffer.rewind()
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val r = (data[offset].toInt() and 0xff).toDouble() / 255.0
|
||||
offset++
|
||||
shadow.write(x, y, ColorRGBa(r, r, r, 1.0))
|
||||
}
|
||||
}
|
||||
shadow.upload()
|
||||
return cb
|
||||
}
|
||||
|
||||
fun GrayF32.toColorBuffer() : ColorBuffer {
|
||||
val cb = colorBuffer(width, height, 1.0, ColorFormat.RGB, ColorType.FLOAT32)
|
||||
val shadow = cb.shadow
|
||||
shadow.buffer.rewind()
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val r = data[offset].toDouble() / 255.0
|
||||
offset++
|
||||
shadow.write(x, y, ColorRGBa(r, r, r))
|
||||
}
|
||||
}
|
||||
shadow.upload()
|
||||
return cb
|
||||
}
|
||||
|
||||
fun Planar<GrayU8>.toColorBuffer() : ColorBuffer {
|
||||
val bandCount = bands.size
|
||||
val format = when (bandCount) {
|
||||
1 -> ColorFormat.R
|
||||
2 -> ColorFormat.RG
|
||||
3 -> ColorFormat.RGB
|
||||
4 -> ColorFormat.RGBa
|
||||
else -> throw IllegalArgumentException("only 1 to 4 bands supported")
|
||||
}
|
||||
|
||||
val bands = bands
|
||||
val cb = colorBuffer(width, height, 1.0, format, ColorType.UINT8)
|
||||
val shadow = cb.shadow
|
||||
shadow.buffer.rewind()
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val r = (bands[0].data[offset].toInt() and 0xff).toDouble() / 255.0
|
||||
val g = if (bandCount >= 2) (bands[1].data[offset].toInt() and 0xff).toDouble() / 255.0 else 0.0
|
||||
val b = if (bandCount >= 3) (bands[2].data[offset].toInt() and 0xff).toDouble() / 255.0 else 0.0
|
||||
val a = if (bandCount >= 4) (bands[2].data[offset].toInt() and 0xff).toDouble() / 255.0 else 1.0
|
||||
offset++
|
||||
shadow.write(x, y, ColorRGBa(r, g, b, a))
|
||||
}
|
||||
}
|
||||
shadow.upload()
|
||||
return cb
|
||||
}
|
||||
|
||||
@JvmName("grayF32ToColorBuffer")
|
||||
fun Planar<GrayF32>.toColorBuffer() : ColorBuffer {
|
||||
val bandCount = bands.size
|
||||
val format = when (bandCount) {
|
||||
1 -> ColorFormat.R
|
||||
2 -> ColorFormat.RG
|
||||
3 -> ColorFormat.RGB
|
||||
4 -> ColorFormat.RGBa
|
||||
else -> throw IllegalArgumentException("only 1 to 4 bands supported")
|
||||
}
|
||||
|
||||
val bands = bands
|
||||
val cb = colorBuffer(width, height, 1.0, format, ColorType.UINT8)
|
||||
val shadow = cb.shadow
|
||||
shadow.buffer.rewind()
|
||||
var offset = 0
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val r = bands[0].data[offset] / 255.0
|
||||
val g = if (bandCount >= 2) bands[1].data[offset] / 255.0 else 0.0
|
||||
val b = if (bandCount >= 3) bands[2].data[offset] / 255.0 else 0.0
|
||||
val a = if (bandCount >= 4) bands[3].data[offset] / 255.0 else 1.0
|
||||
offset++
|
||||
shadow.write(x, y, ColorRGBa(r, g, b, a))
|
||||
}
|
||||
}
|
||||
shadow.upload()
|
||||
return cb
|
||||
}
|
||||
51
orx-jvm/orx-boofcv/src/main/kotlin/ContourConversion.kt
Normal file
51
orx-jvm/orx-boofcv/src/main/kotlin/ContourConversion.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import boofcv.alg.filter.binary.Contour
|
||||
import org.openrndr.shape.Shape
|
||||
import org.openrndr.shape.ShapeContour
|
||||
|
||||
fun Contour.toShape(closed: Boolean = false, getInternal: Boolean, getExternal: Boolean): Shape {
|
||||
val contours = mutableListOf<ShapeContour>()
|
||||
|
||||
if (getExternal) {
|
||||
val externalPoints = external.toVector2s()
|
||||
contours.addAll(listOf(ShapeContour.fromPoints(externalPoints, closed)))
|
||||
}
|
||||
if (getInternal) {
|
||||
val internalCurves = internal.filter { it.size >= 3 }.map { it.toVector2s() }
|
||||
contours.addAll(internalCurves.map { internalCurve ->
|
||||
ShapeContour.fromPoints(internalCurve, closed)
|
||||
})
|
||||
}
|
||||
return Shape(contours)
|
||||
}
|
||||
|
||||
fun List<Contour>.toShapes(closed: Boolean = false,
|
||||
internal: Boolean = true,
|
||||
external: Boolean = true): List<Shape> {
|
||||
return this.filter { it.external.size >= 3 }.map {
|
||||
it.toShape(closed, internal, external)
|
||||
}
|
||||
}
|
||||
|
||||
fun List<Contour>.toShapeContours(closed: Boolean = false,
|
||||
internal: Boolean = true,
|
||||
external: Boolean = true): List<ShapeContour> {
|
||||
val contours = mutableListOf<ShapeContour>()
|
||||
this.forEach { contour ->
|
||||
if(contour.external.size >= 3) {
|
||||
if (external) {
|
||||
val externalPoints = contour.external.toVector2s()
|
||||
contours.add(ShapeContour.fromPoints(externalPoints, closed))
|
||||
}
|
||||
if (internal) {
|
||||
val internalCurves = contour.internal.filter { it.size >= 3 }
|
||||
.map { it.toVector2s() }
|
||||
internalCurves.forEach { internalContour ->
|
||||
contours.add(ShapeContour.fromPoints(internalContour, closed))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return contours
|
||||
}
|
||||
70
orx-jvm/orx-boofcv/src/main/kotlin/Distortion.kt
Normal file
70
orx-jvm/orx-boofcv/src/main/kotlin/Distortion.kt
Normal file
@@ -0,0 +1,70 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import boofcv.abst.distort.FDistort
|
||||
import boofcv.struct.image.ImageBase
|
||||
import org.openrndr.draw.ColorBuffer
|
||||
import org.openrndr.draw.ColorType
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun <T : ImageBase<out ImageBase<*>>?> ImageBase<T>.resizeBy(scaleX: Double, scaleY: Double = scaleX): T {
|
||||
val scaled = this.createNew((this.width * scaleX).toInt(), (this.height * scaleY).toInt())
|
||||
|
||||
FDistort(this, scaled).scaleExt().apply()
|
||||
|
||||
return scaled
|
||||
}
|
||||
|
||||
fun <T : ImageBase<out ImageBase<*>>?> ImageBase<T>.resizeTo(newWidth: Int? = null, newHeight: Int? = null): T {
|
||||
val ar = this.width / this.height.toDouble()
|
||||
|
||||
val scaled = (if (newWidth != null && newHeight != null) {
|
||||
val w = newWidth
|
||||
val h = newHeight
|
||||
|
||||
this.createNew(w, h)
|
||||
} else if (newWidth != null && newHeight == null) {
|
||||
val w = newWidth
|
||||
val h = newWidth / ar
|
||||
|
||||
this.createNew(w, h.roundToInt())
|
||||
} else if (newWidth == null && newHeight != null) {
|
||||
val w = newHeight * ar
|
||||
val h = newHeight
|
||||
|
||||
this.createNew(w.roundToInt(), h)
|
||||
} else {
|
||||
this.createNew(this.width, this.height)
|
||||
})
|
||||
|
||||
FDistort(this, scaled).scaleExt().apply()
|
||||
|
||||
return scaled
|
||||
}
|
||||
|
||||
fun ColorBuffer.resizeBy(scaleX: Double, scaleY: Double = scaleX, convertToGray: Boolean = false): ColorBuffer {
|
||||
return if (convertToGray) {
|
||||
when (this.type) {
|
||||
ColorType.FLOAT32, ColorType.FLOAT16 -> this.toGrayF32().resizeBy(scaleX, scaleY).toColorBuffer()
|
||||
else -> this.toGrayU8().resizeBy(scaleX, scaleY).toColorBuffer()
|
||||
}
|
||||
} else {
|
||||
when (this.type) {
|
||||
ColorType.FLOAT32, ColorType.FLOAT16 -> this.toPlanarF32().resizeBy(scaleX, scaleY).toColorBuffer()
|
||||
else -> this.toPlanarU8().resizeBy(scaleX, scaleY).toColorBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ColorBuffer.resizeTo(newWidth: Int? = null, newHeight: Int? = null, convertToGray: Boolean = false): ColorBuffer {
|
||||
return if (convertToGray) {
|
||||
when (this.type) {
|
||||
ColorType.FLOAT32, ColorType.FLOAT16 -> this.toGrayF32().resizeTo(newWidth, newHeight).toColorBuffer()
|
||||
else -> this.toGrayU8().resizeTo(newWidth, newHeight).toColorBuffer()
|
||||
}
|
||||
} else {
|
||||
when (this.type) {
|
||||
ColorType.FLOAT32, ColorType.FLOAT16 -> this.toPlanarF32().resizeTo(newWidth, newHeight).toColorBuffer()
|
||||
else -> this.toPlanarU8().resizeTo(newWidth, newHeight).toColorBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
83
orx-jvm/orx-boofcv/src/main/kotlin/Drawing.kt
Normal file
83
orx-jvm/orx-boofcv/src/main/kotlin/Drawing.kt
Normal file
@@ -0,0 +1,83 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import georegression.struct.line.LineSegment2D_F32
|
||||
import georegression.struct.line.LineSegment2D_F64
|
||||
import georegression.struct.trig.Circle2D_F32
|
||||
import georegression.struct.trig.Circle2D_F64
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.shape.Circle
|
||||
|
||||
fun Drawer.lineSegment(segment: LineSegment2D_F32) {
|
||||
lineSegment(
|
||||
segment.a.x.toDouble(),
|
||||
segment.a.y.toDouble(),
|
||||
segment.b.x.toDouble(),
|
||||
segment.b.y.toDouble()
|
||||
)
|
||||
}
|
||||
|
||||
@JvmName("lineSegments2D_F32")
|
||||
fun Drawer.lineSegments(segments: List<LineSegment2D_F32>) {
|
||||
lineSegments(
|
||||
segments.flatMap { segment ->
|
||||
listOf(
|
||||
Vector2(segment.a.x.toDouble(), segment.a.y.toDouble()),
|
||||
Vector2(segment.b.x.toDouble(), segment.b.y.toDouble())
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun Drawer.lineSegment(segment: LineSegment2D_F64) {
|
||||
lineSegment(
|
||||
segment.a.x,
|
||||
segment.a.y,
|
||||
segment.b.x,
|
||||
segment.b.y
|
||||
)
|
||||
}
|
||||
|
||||
@JvmName("lineSegments2D_F64")
|
||||
fun Drawer.lineSegments(segments: List<LineSegment2D_F64>) {
|
||||
lineSegments(
|
||||
segments.flatMap { segment ->
|
||||
listOf(
|
||||
Vector2(segment.a.x, segment.a.y),
|
||||
Vector2(segment.b.x, segment.b.y)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun Drawer.circle(circle: Circle2D_F32) {
|
||||
circle(
|
||||
circle.center.x.toDouble(), circle.center.y.toDouble(),
|
||||
circle.radius.toDouble()
|
||||
)
|
||||
}
|
||||
|
||||
fun Drawer.circle(circle: Circle2D_F64) {
|
||||
circle(
|
||||
circle.center.x, circle.center.y,
|
||||
circle.radius
|
||||
)
|
||||
}
|
||||
|
||||
@JvmName("circles2D_F32")
|
||||
fun Drawer.circles(circles: List<Circle2D_F32>) {
|
||||
circles(
|
||||
circles.map {
|
||||
Circle(it.center.x.toDouble(), it.center.y.toDouble(), it.radius.toDouble())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmName("circles2D_F64")
|
||||
fun Drawer.circles(circles: List<Circle2D_F64>) {
|
||||
circles(
|
||||
circles.map {
|
||||
Circle(it.center.x.toDouble(), it.center.y.toDouble(), it.radius.toDouble())
|
||||
}
|
||||
)
|
||||
}
|
||||
33
orx-jvm/orx-boofcv/src/main/kotlin/ImageFlowConversion.kt
Normal file
33
orx-jvm/orx-boofcv/src/main/kotlin/ImageFlowConversion.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import boofcv.struct.flow.ImageFlow
|
||||
import org.openrndr.draw.ColorBuffer
|
||||
import org.openrndr.draw.ColorFormat
|
||||
import org.openrndr.draw.ColorType
|
||||
import org.openrndr.draw.colorBuffer
|
||||
import java.nio.Buffer
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
fun ImageFlow.toColorBuffer(): ColorBuffer {
|
||||
|
||||
val cb = colorBuffer(
|
||||
width, height, format = ColorFormat.RG,
|
||||
type = ColorType.FLOAT32
|
||||
)
|
||||
|
||||
val bb = ByteBuffer.allocateDirect(width * height * 8)
|
||||
bb.order(ByteOrder.nativeOrder())
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val f = get(x, y)
|
||||
bb.putFloat(f.x)
|
||||
bb.putFloat(f.y)
|
||||
}
|
||||
}
|
||||
|
||||
(bb as Buffer).rewind()
|
||||
cb.write(bb)
|
||||
cb.flipV = true
|
||||
return cb
|
||||
}
|
||||
19
orx-jvm/orx-boofcv/src/main/kotlin/MatrixConversion.kt
Normal file
19
orx-jvm/orx-boofcv/src/main/kotlin/MatrixConversion.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import georegression.struct.affine.Affine2D_F32
|
||||
import georegression.struct.affine.Affine2D_F64
|
||||
import org.openrndr.math.Matrix44
|
||||
|
||||
fun Affine2D_F32.toMatrix44() = Matrix44(
|
||||
c0r0 = a11.toDouble(), c1r0 = a12.toDouble(), c3r0 = tx.toDouble(),
|
||||
c0r1 = a21.toDouble(), c1r1 = a22.toDouble(), c3r1 = ty.toDouble(),
|
||||
c2r2 = 1.0,
|
||||
c3r3 = 1.0
|
||||
)
|
||||
|
||||
fun Affine2D_F64.toMatrix44() = Matrix44(
|
||||
c0r0 = a11, c1r0 = a12, c3r0 = tx,
|
||||
c0r1 = a21, c1r1 = a22, c3r1 = ty,
|
||||
c2r2 = 1.0,
|
||||
c3r3 = 1.0
|
||||
)
|
||||
11
orx-jvm/orx-boofcv/src/main/kotlin/PointConversion.kt
Normal file
11
orx-jvm/orx-boofcv/src/main/kotlin/PointConversion.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.openrndr.boofcv.binding
|
||||
|
||||
import georegression.struct.point.Point2D_F32
|
||||
import georegression.struct.point.Point2D_F64
|
||||
import georegression.struct.point.Point2D_I32
|
||||
import org.openrndr.math.Vector2
|
||||
|
||||
fun Point2D_I32.toVector2() = Vector2(x.toDouble(), y.toDouble())
|
||||
fun Point2D_F32.toVector2() = Vector2(x.toDouble(), y.toDouble())
|
||||
fun Point2D_F64.toVector2() = Vector2(x.toDouble(), y.toDouble())
|
||||
fun List<Point2D_I32>.toVector2s() = this.map { it.toVector2() }
|
||||
Reference in New Issue
Block a user