Skip to content

Commit bc1cb50

Browse files
committed
improve a little the center finding algorithm
1 parent eb650bc commit bc1cb50

File tree

3 files changed

+48
-40
lines changed

3 files changed

+48
-40
lines changed

glimpse-core/src/main/java/glimpse/core/BitmapExtensions.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ fun Bitmap.crop(
5858
}
5959

6060
fun Bitmap.findCenter(
61-
centerMode: CenterMode = CenterMode.LARGEST,
6261
temperature: Float = 0.25f,
6362
lowerBound: Float = 0.25f,
6463
useLightModel: Boolean = true
@@ -86,9 +85,5 @@ fun Bitmap.findCenter(
8685
val reshaped = softmaxed.reshape(output[0][0].size, output[0][0][0].size)
8786

8887
// get averaged center
89-
return if (centerMode == CenterMode.AVERAGE) {
90-
MathUtils.getAveragedFocusArea(reshaped[0][0])
91-
} else {
92-
MathUtils.getLargestFocusArea(reshaped[0][0], lowerBound = lowerBound)
93-
}
88+
return MathUtils.getLargestFocusArea(reshaped[0][0], lowerBound = lowerBound)
9489
}

glimpse-core/src/main/java/glimpse/core/CenterMode.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.

glimpse-core/src/main/java/glimpse/core/MathUtils.kt

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package glimpse.core
22

33
import android.graphics.Color
4-
import kotlin.math.exp
5-
import kotlin.math.max
6-
import kotlin.math.min
4+
import kotlin.math.*
75

86
object MathUtils {
97
fun populateTensorFromPixels(tensor: Array<Array<Array<FloatArray>>>, pixels: IntArray) {
@@ -28,18 +26,8 @@ object MathUtils {
2826
return exp.map { it / sum }.toFloatArray()
2927
}
3028

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))
4331
}
4432

4533
fun getLargestFocusArea(
@@ -60,36 +48,55 @@ object MathUtils {
6048
}
6149
}
6250

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+
}
6465

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()
6869
Pair(focusWidth, focusHeight)
69-
} ?: Pair(0f, 0f)
70+
}
7071

71-
val center = largestBlob?.let {
72+
val center = largestBlob.let {
7273
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+
}
7576

7677
return FocusArea(center, surface)
7778
}
7879

7980
private class BinaryBlob(startingX: Int, startingY: Int) {
80-
var size = 0
81+
var pixelCount = 0
8182
var hBounds = Pair(startingX, startingX)
8283
var vBounds = Pair(startingY, startingY)
84+
var centerX: Float = 0f
85+
var centerY: Float = 0f
86+
var weightSum = 0f
8387

84-
fun addPixel(x: Int, y: Int) {
85-
size++
88+
fun addPixel(x: Int, y: Int, weight: Float) {
89+
pixelCount++
8690
hBounds = Pair(min(hBounds.first, x), max(hBounds.second, x))
8791
vBounds = Pair(min(vBounds.first, y), max(vBounds.second, y))
92+
centerX += x * weight
93+
centerY += y * weight
94+
weightSum += weight
8895
}
8996

9097
fun explore(j: Int, i: Int, heatMap: Array<FloatArray>, cheatSheet: Array<IntArray>, lowerBound: Float) {
9198
if (heatMap.getOrNull(i)?.getOrNull(j) ?: 0f > lowerBound && cheatSheet[i][j] == 0) {
92-
addPixel(j, i)
99+
addPixel(j, i, heatMap[i][j])
93100
cheatSheet[i][j] = 1
94101

95102
explore(j + 1, i, heatMap, cheatSheet, lowerBound)
@@ -99,7 +106,19 @@ object MathUtils {
99106
}
100107
}
101108

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
103122
}
104123

105124
data class FocusArea(val center: Pair<Float, Float>, val surface: Pair<Float, Float>)

0 commit comments

Comments
 (0)