publish eve_rock_watcher.py
This commit is contained in:
parent
11d569c8ac
commit
a728b529c5
1 changed files with 43 additions and 41 deletions
|
|
@ -90,55 +90,57 @@ QUANTITY_RE = re.compile(r"quantit[yvſ]\s*[:.]?\s*([\d.,]{2,})\s*units?", re.I)
|
|||
UNITS_RE = re.compile(r"([\d.,]{3,})\s*units?\b", re.I)
|
||||
|
||||
|
||||
def _ocr_window_text(cp):
|
||||
"""OCR the EVE window with sparse-text mode (psm 11) — far better than uniform-block
|
||||
(psm 6) at picking scattered UI text off a busy nebula background. Returns flat text."""
|
||||
def read_selected_quantity(cp):
|
||||
"""Return (units, ore) for the currently-selected rock from its floating info popup.
|
||||
Two-pass: (1) locate the word 'Units' anywhere in the window via sparse OCR, then
|
||||
(2) crop just that line, zoom + grayscale it, and OCR the digits cleanly — small text
|
||||
over the nebula garbles in a full-window pass ('5b Units'), but reads fine zoomed in."""
|
||||
import pytesseract
|
||||
from PIL import Image # noqa: F401 (capture_window already returns a PIL image)
|
||||
tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip()
|
||||
if tcmd:
|
||||
pytesseract.pytesseract.tesseract_cmd = tcmd
|
||||
img = w.capture_window()
|
||||
if img is None:
|
||||
return None
|
||||
out = []
|
||||
for psm in (11, 6): # sparse first, then block fallback
|
||||
try:
|
||||
out.append(pytesseract.image_to_string(img, config=f"--psm {psm}"))
|
||||
except Exception:
|
||||
pass
|
||||
return " ".join(out).replace("\n", " ")
|
||||
|
||||
|
||||
def read_selected_quantity(cp):
|
||||
"""Return (units, ore) for the currently-selected rock from its floating info popup,
|
||||
found anywhere in the EVE window. (None, None) if no rock is selected/visible."""
|
||||
flat = _ocr_window_text(cp)
|
||||
if flat is None:
|
||||
return None, None
|
||||
m = QUANTITY_RE.search(flat)
|
||||
if not m: # "Quantity" garbled? take any "N Units"
|
||||
for cand in UNITS_RE.finditer(flat):
|
||||
v = int(re.sub(r"\D", "", cand.group(1)) or 0)
|
||||
if 100 <= v <= 5_000_000: # plausible asteroid remaining
|
||||
m = cand
|
||||
try:
|
||||
d = pytesseract.image_to_data(img, config="--psm 11",
|
||||
output_type=pytesseract.Output.DICT)
|
||||
except Exception:
|
||||
return None, None
|
||||
n = len(d["text"])
|
||||
cands = [i for i in range(n) if d["text"][i].strip().lower().startswith("unit")]
|
||||
dbg = []
|
||||
for i in cands:
|
||||
uy, uh, ux = d["top"][i], d["height"][i], d["left"][i]
|
||||
# crop the line just LEFT of "Units" — that's "Quantity <number>"
|
||||
box = img.crop((max(0, ux - 320), max(0, uy - 8), ux + 6, uy + uh + 8))
|
||||
z = box.convert("L").resize((box.width * 4, box.height * 4))
|
||||
line = pytesseract.image_to_string(
|
||||
z, config="--psm 7 -c tessedit_char_whitelist=0123456789,QuantiyUns ")
|
||||
dbg.append(repr(line.strip()))
|
||||
mm = re.search(r"([\d,]{3,})", line)
|
||||
if not mm:
|
||||
continue
|
||||
v = int(re.sub(r"\D", "", mm.group(1)) or 0)
|
||||
if not (100 <= v <= 5_000_000): # plausible asteroid remaining
|
||||
continue
|
||||
# ore name = a token a little above the 'Units' line, same popup block
|
||||
ore = "rock"
|
||||
for j in range(n):
|
||||
if d["text"][j].strip() and 0 < (uy - d["top"][j]) < 120 \
|
||||
and abs(d["left"][j] - (ux - 160)) < 260:
|
||||
o = match_ore(d["text"][j].strip().lower())
|
||||
if o:
|
||||
ore = o
|
||||
break
|
||||
if not m:
|
||||
# leave a breadcrumb so we can see what OCR produced when it misses
|
||||
return v, ore
|
||||
try:
|
||||
with open(os.path.join(w.HERE, "_rockocr.txt"), "w", encoding="utf-8") as fh:
|
||||
fh.write(flat[:4000])
|
||||
fh.write(f"units-candidates={len(cands)} crops={dbg}\n")
|
||||
except Exception:
|
||||
pass
|
||||
return None, None
|
||||
digits = re.sub(r"\D", "", m.group(1))
|
||||
if len(digits) < 2:
|
||||
return None, None
|
||||
# the rock's name sits just before its 'Quantity' line in the same popup block
|
||||
# (e.g. "Omber Distance ... Quantity 47,765 Units") — match there, not the whole
|
||||
# window (the hold's "Compressed Kernite" would otherwise win).
|
||||
ore = match_ore(flat[max(0, m.start() - 180):m.start()].lower()) \
|
||||
or match_ore(flat.lower()) or "rock"
|
||||
return int(digits), ore
|
||||
|
||||
|
||||
def save_rock_region(cp, l, t, wd, ht, mode="survey"):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue