@@ -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