I have piece of code where I draw output from model pixel by pixel:
fun draw(
canvas: Canvas) {
val rotated = sensorOrientation % 180 == 90
var rotatedW = frameWidth;
var rotatedH = frameHeight;
if(rotated) {
rotatedW = frameHeight
rotatedH = frameWidth
}
val multiplier =
min(
canvas.height.toFloat() / rotatedH.toFloat(),
canvas.width.toFloat() / rotatedW.toFloat()
)
val w = (rotatedW * multiplier).toInt()
val h = (rotatedH * multiplier).toInt()
results?.let {
var pos: Int
val xw = w / 256f
val xh = h / 256f
val rectF = RectF()
for (y in 0 until 256) {
for (x in 0 until 256) {
pos = getIndexOfMax(results!![0][y][x])
if (pos > 0) {
val vertical = y / 256f * h
val horizontal = x / 256f * w
rectF.left = horizontal - xw
rectF.top = vertical - xh
rectF.right = horizontal + xw
rectF.bottom = vertical + xh
canvas.drawRect(rectF, boxPaint)
}
}
}
}
}
However this works really slow. Nested for
is probably one of the main issues here. I don't know how can I speed it up. As you can see both counters are necessary here because I need to get certain field from results
. I've heard that Bitmap uasage instead of Canvas
would be partial solution because I am able to get certain pixels but I don't really know how to use it right. Method draw()
is called here inside MainActivity
:
trackingOverlay.addCallback(
object : OverlayView.DrawCallback {
override fun drawCallback(canvas: Canvas?) = tracker.draw(canvas!!)
}
)
And the trackingOverlay
is an instance of OverlayView
class which inherits from View
:
class OverlayView(ctx: Context, attr: AttributeSet) : View(ctx, attr) {
private val callbacks: MutableList<DrawCallback> =
LinkedList()
fun addCallback(callback: DrawCallback) { callbacks.add(callback) }
@Synchronized
override fun draw(canvas: Canvas) {
for (callback in callbacks) {
callback.drawCallback(canvas)
}
}
interface DrawCallback {
fun drawCallback(canvas: Canvas?)
}
}
I've tried creating Bitmap
before draw (to reuse it) and then use canvas.drawBitmap()
but it needs transformation Matrix
to fill whole screen, otherwise it covers only small chunk of it and even then I haven't noticed any performance increase.
EDIT
That's how getIndexOfMax()
looks like:
private fun getIndexOfMax(array: FloatArray): Int {
if (array.isEmpty()) return -1
return when {
array[0] > array[1] -> 0
else -> 1
}
}
Results is 4 dim Array
of Float
1 Answer 1
TL;DR
Introduce coroutines in your code.
Analysis
It is difficult to optimize a code, where multiple parts are missing, like:
- what does
getIndexOfMax
do? Maybe this is the bottleneck - How do
results
look like? Arrays? Maps? HashMaps?
I found also some strange code parts, like:
- Why
results?.let {
? This can be removed completely. var pos: Int
should be moved inside the inner loop and made aval
Suggestion
I have too little context and I'm not familiar with Android, so the only thing I can suggest is using coroutines. My Example:
suspend fun draw(canvas: Canvas) = coroutineScope {
val rotated = sensorOrientation % 180 == 90
var rotatedW = frameWidth;
var rotatedH = frameHeight;
if (rotated) {
rotatedW = frameHeight
rotatedH = frameWidth
}
val multiplier =
min(
canvas.height.toFloat() / rotatedH.toFloat(),
canvas.width.toFloat() / rotatedW.toFloat()
)
val w = (rotatedW * multiplier).toInt()
val h = (rotatedH * multiplier).toInt()
val xw = w / 256f
val xh = h / 256f
val rectF = RectF()
for (y in 0 until 256) {
for (x in 0 until 256) {
launch { // <-----
val pos = getIndexOfMax(results!![0][y][x])
if (pos > 0) {
val vertical = y / 256f * h
val horizontal = x / 256f * w
rectF.left = horizontal - xw
rectF.top = vertical - xh
rectF.right = horizontal + xw
rectF.bottom = vertical + xh
canvas.drawRect(rectF, boxPaint)
}
}
}
}
}
-
\$\begingroup\$ I've made edit to my question. Instead of making
index of max
I can just get value ofarray[1]
and check if pos > 0.6 (or 0.7) \$\endgroup\$SkypeDogg– SkypeDogg2020年09月26日 10:45:12 +00:00Commented Sep 26, 2020 at 10:45