1
1
package glimpse.core
2
2
3
3
import android.graphics.Color
4
- import kotlin.math.exp
5
- import kotlin.math.max
6
- import kotlin.math.min
4
+ import kotlin.math.*
7
5
8
6
object MathUtils {
9
7
fun populateTensorFromPixels (tensor : Array <Array <Array <FloatArray >>>, pixels : IntArray ) {
@@ -28,18 +26,8 @@ object MathUtils {
28
26
return exp.map { it / sum }.toFloatArray()
29
27
}
30
28
31
- fun getAveragedFocusArea (heatMap : Array <FloatArray >): FocusArea {
32
- var x = 0f
33
- var y = 0f
34
-
35
- heatMap.forEachIndexed { positionY, row ->
36
- row.forEachIndexed { positionX, value ->
37
- x + = value * positionX
38
- y + = value * positionY
39
- }
40
- }
41
-
42
- return FocusArea (Pair (x / heatMap[0 ].size, y / heatMap.size), Pair (0f , 0f ))
29
+ private fun distance (pointA : Pair <Float , Float >, pointB : Pair <Float , Float >): Float {
30
+ return sqrt((pointA.x - pointB.x).pow(2 ) + (pointA.y - pointB.y).pow(2 ))
43
31
}
44
32
45
33
fun getLargestFocusArea (
@@ -60,36 +48,55 @@ object MathUtils {
60
48
}
61
49
}
62
50
63
- val largestBlob = blobs.maxBy { it.size }
51
+ val largestBlob = blobs.maxBy { it.getRelevance() } ? : blobs.first()
52
+ if (blobs.size in 2 .. 3 ) {
53
+ for (i in 0 .. blobs.lastIndex) {
54
+ val targetBlob = blobs[i]
55
+ if (targetBlob != largestBlob) {
56
+ val distance = distance(
57
+ Pair (largestBlob.centerX, largestBlob.centerY), Pair (targetBlob.centerX, targetBlob.centerY)
58
+ )
59
+ if (distance <= 2f && targetBlob.getRelevance() > largestBlob.getRelevance() * 0.75f ) {
60
+ largestBlob.merge(targetBlob)
61
+ }
62
+ }
63
+ }
64
+ }
64
65
65
- val surface = largestBlob? .let {
66
- val focusWidth = ( it.hBounds.second - it.hBounds.first) / heatMap[0 ].size.toFloat()
67
- val focusHeight = ( it.vBounds.second - it.vBounds.first) / heatMap.size.toFloat()
66
+ val surface = largestBlob.let {
67
+ val focusWidth = it.getBoxDims().x / heatMap[0 ].size.toFloat()
68
+ val focusHeight = it.getBoxDims().y / heatMap.size.toFloat()
68
69
Pair (focusWidth, focusHeight)
69
- } ? : Pair ( 0f , 0f )
70
+ }
70
71
71
- val center = largestBlob? .let {
72
+ val center = largestBlob.let {
72
73
val centerPosition = it.getCenter()
73
- Pair (centerPosition.first / heatMap[0 ].size, centerPosition.second / heatMap.size)
74
- } ? : Pair ( 0.5f , 0.5f )
74
+ Pair (centerPosition.x / heatMap[0 ].size, centerPosition.y / heatMap.size)
75
+ }
75
76
76
77
return FocusArea (center, surface)
77
78
}
78
79
79
80
private class BinaryBlob (startingX : Int , startingY : Int ) {
80
- var size = 0
81
+ var pixelCount = 0
81
82
var hBounds = Pair (startingX, startingX)
82
83
var vBounds = Pair (startingY, startingY)
84
+ var centerX: Float = 0f
85
+ var centerY: Float = 0f
86
+ var weightSum = 0f
83
87
84
- fun addPixel (x : Int , y : Int ) {
85
- size ++
88
+ fun addPixel (x : Int , y : Int , weight : Float ) {
89
+ pixelCount ++
86
90
hBounds = Pair (min(hBounds.first, x), max(hBounds.second, x))
87
91
vBounds = Pair (min(vBounds.first, y), max(vBounds.second, y))
92
+ centerX + = x * weight
93
+ centerY + = y * weight
94
+ weightSum + = weight
88
95
}
89
96
90
97
fun explore (j : Int , i : Int , heatMap : Array <FloatArray >, cheatSheet : Array <IntArray >, lowerBound : Float ) {
91
98
if (heatMap.getOrNull(i)?.getOrNull(j) ? : 0f > lowerBound && cheatSheet[i][j] == 0 ) {
92
- addPixel(j, i)
99
+ addPixel(j, i, heatMap[i][j] )
93
100
cheatSheet[i][j] = 1
94
101
95
102
explore(j + 1 , i, heatMap, cheatSheet, lowerBound)
@@ -99,7 +106,19 @@ object MathUtils {
99
106
}
100
107
}
101
108
102
- fun getCenter () = Pair ((hBounds.second + hBounds.first) / 2f , (vBounds.second + vBounds.first) / 2f )
109
+ fun merge (targetBlob : BinaryBlob ) {
110
+ centerX = (centerX + targetBlob.centerX) / 2f
111
+ centerY = (centerY + targetBlob.centerY) / 2f
112
+ weightSum + = targetBlob.weightSum
113
+ pixelCount + = targetBlob.pixelCount
114
+
115
+ hBounds = Pair (min(hBounds.first, targetBlob.hBounds.first), max(hBounds.second, targetBlob.hBounds.second))
116
+ vBounds = Pair (min(vBounds.first, targetBlob.vBounds.first), max(vBounds.second, targetBlob.vBounds.second))
117
+ }
118
+
119
+ fun getCenter () = Pair (centerX / weightSum, centerY / weightSum)
120
+ fun getBoxDims () = Pair (1f * hBounds.second - hBounds.first, 1f * vBounds.second - vBounds.first)
121
+ fun getRelevance () = weightSum / pixelCount
103
122
}
104
123
105
124
data class FocusArea (val center : Pair <Float , Float >, val surface : Pair <Float , Float >)
0 commit comments