-
Notifications
You must be signed in to change notification settings - Fork 37
/
DemoSimplified01.kt
100 lines (88 loc) · 3.85 KB
/
DemoSimplified01.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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.extra.shapes.simplify.simplify
import org.openrndr.extra.shapes.splines.CatmullRomChain2
import org.openrndr.extra.shapes.splines.toContour
import org.openrndr.math.Vector2
import org.openrndr.shape.Rectangle
import org.openrndr.shape.ShapeContour
fun main() {
application {
program {
// 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)
}