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)
|
UNITS_RE = re.compile(r"([\d.,]{3,})\s*units?\b", re.I)
|
||||||
|
|
||||||
|
|
||||||
def _ocr_window_text(cp):
|
def read_selected_quantity(cp):
|
||||||
"""OCR the EVE window with sparse-text mode (psm 11) — far better than uniform-block
|
"""Return (units, ore) for the currently-selected rock from its floating info popup.
|
||||||
(psm 6) at picking scattered UI text off a busy nebula background. Returns flat text."""
|
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
|
import pytesseract
|
||||||
|
from PIL import Image # noqa: F401 (capture_window already returns a PIL image)
|
||||||
tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip()
|
tcmd = cp.get("ocr", "tesseract_cmd", fallback="").strip()
|
||||||
if tcmd:
|
if tcmd:
|
||||||
pytesseract.pytesseract.tesseract_cmd = tcmd
|
pytesseract.pytesseract.tesseract_cmd = tcmd
|
||||||
img = w.capture_window()
|
img = w.capture_window()
|
||||||
if img is None:
|
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
|
return None, None
|
||||||
m = QUANTITY_RE.search(flat)
|
try:
|
||||||
if not m: # "Quantity" garbled? take any "N Units"
|
d = pytesseract.image_to_data(img, config="--psm 11",
|
||||||
for cand in UNITS_RE.finditer(flat):
|
output_type=pytesseract.Output.DICT)
|
||||||
v = int(re.sub(r"\D", "", cand.group(1)) or 0)
|
except Exception:
|
||||||
if 100 <= v <= 5_000_000: # plausible asteroid remaining
|
return None, None
|
||||||
m = cand
|
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
|
break
|
||||||
if not m:
|
return v, ore
|
||||||
# leave a breadcrumb so we can see what OCR produced when it misses
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(w.HERE, "_rockocr.txt"), "w", encoding="utf-8") as fh:
|
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return None, None
|
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"):
|
def save_rock_region(cp, l, t, wd, ht, mode="survey"):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue