Skip to content

Commit 410a2f6

Browse files
authored
Merge pull request #66 from Sj-Si/feature/energy-bar-analysis
FEATURE: Energy Bar Analysis
2 parents d52f7b4 + 7128474 commit 410a2f6

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed
481 Bytes
Loading
344 Bytes
Loading
289 Bytes
Loading

android/app/src/main/java/com/steve1316/uma_android_automation/utils/CustomImageUtils.kt

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,4 +1455,126 @@ class CustomImageUtils(context: Context, private val game: Game) : ImageUtils(co
14551455
debugName
14561456
)
14571457
}
1458+
1459+
/**
1460+
* Gets the filled percentage of the energy bar.
1461+
*
1462+
* @return If energy bar is detected, returns the filled percentage, else returns null.
1463+
*/
1464+
fun analyzeEnergyBar(): Int? {
1465+
val (sourceBitmap, templateBitmap) = getBitmaps("energy")
1466+
if (templateBitmap == null) {
1467+
game.printToLog("analyzeEnergyBar:: Failed to find template bitmap for \"energy\".", isError = true, tag = tag)
1468+
return null
1469+
}
1470+
val energyTextLocation = findImage("energy", tries = 1, region = regionTopHalf).first
1471+
if (energyTextLocation == null) {
1472+
game.printToLog("analyzeEnergyBar:: Failed to find bitmap for \"energy\".", isError = true, tag = tag)
1473+
return null
1474+
}
1475+
1476+
// Get top right of energyText.
1477+
var x: Int = (energyTextLocation.x + (templateBitmap.width / 2)).toInt()
1478+
var y: Int = (energyTextLocation.y - (templateBitmap.height / 2)).toInt()
1479+
var w: Int = 700
1480+
var h: Int = 75
1481+
1482+
// Crop just the energy bar in the image.
1483+
// This crop extends to the right beyond the energy bar a bit
1484+
// since the bar is able to grow.
1485+
var croppedBitmap = createSafeBitmap(sourceBitmap, x, y, w, h, "analyzeEnergyBar:: Crop energy bar.")
1486+
if (croppedBitmap == null) {
1487+
game.printToLog("analyzeEnergyBar:: Failed to crop bitmap.", isError = true, tag = tag)
1488+
return null
1489+
}
1490+
1491+
// Now find the left and right brackets of the energy bar
1492+
// to refine our cropped region.
1493+
1494+
val energyBarLeftPartTemplateBitmap: Bitmap? = getBitmaps("energy_bar_left_part").second
1495+
if (energyBarLeftPartTemplateBitmap == null) {
1496+
game.printToLog("analyzeEnergyBar:: Failed to find left part of energy bar.", isError = true, tag = tag)
1497+
return null
1498+
}
1499+
1500+
val leftPartLocation: Point? = match(croppedBitmap, energyBarLeftPartTemplateBitmap, "energy_bar_left_part").second
1501+
if (leftPartLocation == null) {
1502+
game.printToLog("analyzeEnergyBar:: Failed to find left part of energy bar.", isError = true, tag = tag)
1503+
return null
1504+
}
1505+
1506+
// The right side of the energy bar looks very different depending on whether
1507+
// the max energy has been increased. Thus we need to look for one of two bitmaps.
1508+
var energyBarRightPartTemplateBitmap: Bitmap? = getBitmaps("energy_bar_right_part_0").second
1509+
var rightPartLocation: Point? = null
1510+
if (energyBarRightPartTemplateBitmap == null) {
1511+
energyBarRightPartTemplateBitmap = getBitmaps("energy_bar_right_part_1").second
1512+
if (energyBarRightPartTemplateBitmap == null) {
1513+
game.printToLog("analyzeEnergyBar:: Failed to find right part of energy bar.", isError = true, tag = tag)
1514+
return null
1515+
}
1516+
rightPartLocation = match(croppedBitmap, energyBarRightPartTemplateBitmap, "energy_bar_right_part_1").second
1517+
} else {
1518+
rightPartLocation = match(croppedBitmap, energyBarRightPartTemplateBitmap, "energy_bar_right_part_0").second
1519+
}
1520+
1521+
if (rightPartLocation == null) {
1522+
game.printToLog("analyzeEnergyBar:: Failed to find right part of energy bar.", isError = true, tag = tag)
1523+
return null
1524+
}
1525+
1526+
// Crop the energy bar further to refine the cropped region so that
1527+
// we can measure the length of the bar.
1528+
// This crop is just a single pixel high line at the center of the
1529+
// bounding region.
1530+
val left: Int = (leftPartLocation.x + (energyBarLeftPartTemplateBitmap.width / 2)).toInt()
1531+
val right: Int = (rightPartLocation.x - (energyBarRightPartTemplateBitmap.width / 2)).toInt()
1532+
x = left
1533+
y = (croppedBitmap.height / 2).toInt()
1534+
w = (right - left).toInt()
1535+
h = 1
1536+
1537+
croppedBitmap = createSafeBitmap(croppedBitmap, x, y, w, h, "analyzeEnergyBar:: Refine cropped energy bar.")
1538+
if (croppedBitmap == null) {
1539+
game.printToLog("analyzeEnergyBar:: Failed to refine cropped bitmap region.", isError = true, tag = tag)
1540+
return null
1541+
}
1542+
1543+
// HSV color range for gray portion of energy bar.
1544+
val grayLower = Scalar(0.0, 0.0, 116.0)
1545+
val grayUpper = Scalar(180.0, 255.0, 118.0)
1546+
val colorLower = Scalar(5.0, 0.0, 120.0)
1547+
val colorUpper = Scalar(180.0, 255.0, 255.0)
1548+
1549+
// Convert the cropped region to HSV
1550+
val barMat = Mat()
1551+
Utils.bitmapToMat(croppedBitmap, barMat)
1552+
val hsvMat = Mat()
1553+
Imgproc.cvtColor(barMat, hsvMat, Imgproc.COLOR_BGR2HSV)
1554+
1555+
// Create masks for the gray and color portions of the image.
1556+
val grayMask = Mat()
1557+
val colorMask = Mat()
1558+
Core.inRange(hsvMat, grayLower, grayUpper, grayMask)
1559+
Core.inRange(hsvMat, colorLower, colorUpper, colorMask)
1560+
1561+
// Calculate ratio of color and gray pixels.
1562+
val grayPixels = Core.countNonZero(grayMask)
1563+
val colorPixels = Core.countNonZero(colorMask)
1564+
val totalPixels = grayPixels + colorPixels
1565+
1566+
var fillPercent: Double = 0.0
1567+
if (totalPixels > 0) {
1568+
fillPercent = (colorPixels.toDouble() / totalPixels.toDouble()) * 100.0
1569+
}
1570+
val result: Int = fillPercent.toInt().coerceIn(0, 100)
1571+
1572+
barMat.release()
1573+
hsvMat.release()
1574+
grayMask.release()
1575+
colorMask.release()
1576+
1577+
game.printToLog("analyzeEnergyBar:: Pixel Colors: Gray=$grayPixels, Color=$colorPixels, Energy=$result", tag = tag)
1578+
return result
1579+
}
14581580
}

0 commit comments

Comments
 (0)