find_button.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. """Pixel-analysis of the gameupdate window screenshot to find button regions.
  2. Buttons in Chinese game launchers are distinct-colored rectangles. Detect:
  3. 1. Horizontal color bands distinct from background
  4. 2. Rectangular regions of uniform color
  5. Then print candidate click coordinates (client coords).
  6. """
  7. from pathlib import Path
  8. from PIL import Image
  9. img = Image.open("gameupdate2.png").convert("RGB")
  10. w, h = img.size
  11. print(f"image: {w}x{h}")
  12. # 1. Sample a color histogram (quantized) to find dominant + accent colors
  13. colors: dict[tuple[int, int, int], int] = {}
  14. px = img.load()
  15. for y in range(0, h, 2):
  16. for x in range(0, w, 2):
  17. c = px[x, y]
  18. q = (c[0] // 32, c[1] // 32, c[2] // 32)
  19. colors[q] = colors.get(q, 0) + 1
  20. total = sum(colors.values())
  21. print("\ntop colors (quantized to 32):")
  22. for c, n in sorted(colors.items(), key=lambda kv: -kv[1])[:8]:
  23. print(f" RGB~({c[0]*32},{c[1]*32},{c[2]*32}) {n/total:.1%}")
  24. # 2. Row bands: average color per row → find rows that differ from neighbors (button rows)
  25. print("\nrow bands (rows where avg color changes sharply):")
  26. prev = None
  27. for y in range(h):
  28. rs = gs = bs = 0
  29. for x in range(0, w, 4):
  30. r, g, b = px[x, y]
  31. rs += r; gs += g; bs += b
  32. n = max(1, w // 4)
  33. avg = (rs // n, gs // n, bs // n)
  34. if prev and (abs(avg[0]-prev[0]) + abs(avg[1]-prev[1]) + abs(avg[2]-prev[2]) > 60):
  35. print(f" y={y}: {prev} -> {avg}")
  36. prev = avg
  37. # 3. Detect bright/saturated rectangles (buttons are usually brightest or most saturated)
  38. print("\nsaturated/bright pixel clusters (candidate buttons):")
  39. from collections import defaultdict
  40. clusters = defaultdict(int)
  41. for y in range(0, h, 3):
  42. for x in range(0, w, 3):
  43. r, g, b = px[x, y]
  44. sat = max(r, g, b) - min(r, g, b)
  45. bright = (r + g + b) / 3
  46. if sat > 80 or bright > 200: # strongly colored or very bright
  47. clusters[(x // 40, y // 40)] += 1
  48. # find dense clusters
  49. dense = sorted(clusters.items(), key=lambda kv: -kv[1])[:10]
  50. if dense:
  51. for (cx, cy), n in dense:
  52. # cluster center in client coords
  53. x = cx * 40 + 20
  54. y = cy * 40 + 20
  55. print(f" cluster @ ({x},{y}) density={n}")
  56. else:
  57. print(" no saturated clusters; window may be grayscale/gray button")
  58. # 4. Dump a coarse ASCII map of brightness to see the layout
  59. print("\nbrightness map (#=dark, .=light), 8px cells:")
  60. for y in range(0, h, 8):
  61. row = ""
  62. for x in range(0, w, 8):
  63. r, g, b = px[x, y]
  64. v = (r + g + b) / 3
  65. row += "#" if v < 80 else ("+" if v < 160 else ".")
  66. print(f" {y:3d} {row}")