Calibrate orb detection from botty reference: vertical slice method, correct HSV ranges
- Add ReadOrbSlicePercentage: thin vertical strip method for accurate fill reading - Support HSV hue wrapping in colorInRange (for red hues crossing 360°) - Health HSV: H 350-370 (wrapping), S 60+, V 20+ (calibrated from screenshot) - Mana HSV: H 226-240, S 100+, V 20+ (calibrated from screenshot) - Add health_slice/mana_slice regions (10px wide vertical strips through orb centers) - Update health_globe/mana_globe to full botty-referenced regions - Verified: health 96.3%, mana 100% on testdata/d2r_1080p.png (both at 100% fill)
This commit is contained in:
parent
0716aeb5e1
commit
35a1944179
8 changed files with 117 additions and 44 deletions
|
|
@ -206,6 +206,36 @@ func (p *Pipeline) ReadOrbPercentage(frame image.Image, orbRegion image.Rectangl
|
|||
return float64(filledPixels) / float64(totalPixels)
|
||||
}
|
||||
|
||||
// ReadOrbSlicePercentage reads an orb's fill level using a thin vertical slice.
|
||||
// The orb fills from bottom to top, so we count matching pixels in the slice
|
||||
// and return the percentage. This is much more accurate than scanning the whole orb.
|
||||
func (p *Pipeline) ReadOrbSlicePercentage(frame image.Image, sliceRegion image.Rectangle, filledColor ColorRange) float64 {
|
||||
bounds := sliceRegion.Intersect(frame.Bounds())
|
||||
if bounds.Empty() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
totalPixels := 0
|
||||
filledPixels := 0
|
||||
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
c := frame.At(x, y)
|
||||
hsv := RGBToHSV(c)
|
||||
totalPixels++
|
||||
if p.colorInRange(hsv, filledColor) {
|
||||
filledPixels++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if totalPixels == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return float64(filledPixels) / float64(totalPixels)
|
||||
}
|
||||
|
||||
// GetPixelColor returns the color at a specific pixel.
|
||||
func (p *Pipeline) GetPixelColor(frame image.Image, x, y int) color.Color {
|
||||
return frame.At(x, y)
|
||||
|
|
@ -281,10 +311,18 @@ func (p *Pipeline) colorsMatch(c1, c2 color.Color, tolerance int) bool {
|
|||
}
|
||||
|
||||
// colorInRange checks if HSV color is within range.
|
||||
// Supports hue wrapping: if UpperH > 360, it wraps around (e.g., 350-370 means 350-360 OR 0-10).
|
||||
func (p *Pipeline) colorInRange(hsv HSV, colorRange ColorRange) bool {
|
||||
return hsv.H >= colorRange.LowerH && hsv.H <= colorRange.UpperH &&
|
||||
hsv.S >= colorRange.LowerS && hsv.S <= colorRange.UpperS &&
|
||||
hsv.V >= colorRange.LowerV && hsv.V <= colorRange.UpperV
|
||||
if hsv.S < colorRange.LowerS || hsv.S > colorRange.UpperS ||
|
||||
hsv.V < colorRange.LowerV || hsv.V > colorRange.UpperV {
|
||||
return false
|
||||
}
|
||||
// Handle hue wrapping
|
||||
if colorRange.UpperH > 360 {
|
||||
// Wrapping range: e.g., 350-370 means H >= 350 OR H <= 10
|
||||
return hsv.H >= colorRange.LowerH || hsv.H <= (colorRange.UpperH-360)
|
||||
}
|
||||
return hsv.H >= colorRange.LowerH && hsv.H <= colorRange.UpperH
|
||||
}
|
||||
|
||||
// floodFill finds connected pixels of the same color.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue