Three Kingdoms: Warlord's Fate — complete playable game

- Stylized 3D ink-painting map of China (12 provinces, 32 cities, 17 factions)
- Custom warlord creation (8 origins, banner, starting city) or historical factions
- City management: 7 buildings, 5 dev tiers, recruitment from levies
- Character system: stats, traits, loyalty, relationships, wounds, capture, death, succession
- Turn-based tactical battles with formations, stances, hero skills, cinematic 3D replay
- Sieges: assault, starvation, bribery, infiltration
- Diplomacy with trust memory, alliances, NAPs, trade, marriage, espionage, betrayal
- Scripted diverging history (Dong Zhuo, Guandu, Red Cliffs...) + world crises + court events
- AI factions with distinct personalities; prisoners (execute/release/recruit/ransom)
- Procedural guqin/taiko WebAudio score; save/load; victory + dynasty chronicle screens
- View-relative camera controls; headless test suites (smoke, stress, map validator)
This commit is contained in:
deepseek
2026-08-23 06:59:40 +00:00
commit f040bb6be0
29 changed files with 60362 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""Programmatic visual review of screenshots: OCR geometry, contrast, palette, composition."""
import sys, subprocess, csv, io, math
from PIL import Image
import numpy as np
SHOTS = sys.argv[1:]
LANG = "eng+chi_sim"
def rel_lum(arr):
a = arr.astype(np.float64) / 255.0
def f(c): return np.where(c <= 0.03928, c / 12.92, ((c + 0.055) / 1.055) ** 2.4)
return 0.2126 * f(a[..., 0]) + 0.7152 * f(a[..., 1]) + 0.0722 * f(a[..., 2])
def cr(l1, l2):
hi, lo = max(l1, l2), min(l1, l2)
return (hi + 0.05) / (lo + 0.05)
def hexc(rgb):
return "#%02x%02x%02x" % tuple(int(x) for x in rgb)
def ocr_lines(img_path):
"""Return list of (text, x,y,w,h, conf) grouped per line."""
p = subprocess.run(
["tesseract", img_path, "stdout", "-l", LANG, "--psm", "11", "tsv"],
capture_output=True, text=True)
rows = list(csv.DictReader(io.StringIO(p.stdout), delimiter="\t"))
lines = {}
for r in rows:
try:
conf = float(r["conf"])
except Exception:
continue
if conf < 35 or not r["text"].strip():
continue
key = (r["block_num"], r["par_num"], r["line_num"])
e = lines.setdefault(key, {"words": [], "x0": 10**9, "y0": 10**9, "x1": -1, "y1": -1, "confs": []})
x, y, w, h = int(r["left"]), int(r["top"]), int(r["width"]), int(r["height"])
e["words"].append((r["text"], conf))
e["confs"].append(conf)
e["x0"] = min(e["x0"], x); e["y0"] = min(e["y0"], y)
e["x1"] = max(e["x1"], x + w); e["y1"] = max(e["y1"], y + h)
out = []
for k in sorted(lines, key=lambda k: (lines[k]["y0"], lines[k]["x0"])):
e = lines[k]
out.append({"text": " ".join(w for w, _ in e["words"]),
"bbox": (e["x0"], e["y0"], e["x1"] - e["x0"], e["y1"] - e["y0"]),
"conf": sum(e["confs"]) / len(e["confs"])})
return out
def analyze(path):
im = Image.open(path).convert("RGB")
W, H = im.size
arr = np.asarray(im)
L = rel_lum(arr)
gray = np.asarray(im.convert("L"))
print(f"\n{'='*78}\n{path} ({W}x{H})\n{'='*78}")
# Global tone
print(f"luminance mean={L.mean():.3f} p5={np.percentile(L,5):.3f} p50={np.percentile(L,50):.3f} "
f"p95={np.percentile(L,95):.3f} | dark(<0.15)={100*(L<0.15).mean():.0f}% bright(>0.85)={100*(L>0.85).mean():.0f}%")
# Palette
q = im.quantize(colors=8, method=Image.Quantize.MEDIANCUT)
pal = q.getpalette()
counts = sorted(q.getcolors(W * H), reverse=True)
tot = W * H
tops = []
for cnt, idx in counts[:8]:
rgb = pal[idx*3:idx*3+3]
tops.append(f"{hexc(rgb)} {100*cnt/tot:.0f}%")
print("palette: " + " ".join(tops))
# Composition grid: 16 cols x 10 rows -> mean luminance (0-9) and dominant hue class letter
GX, GY = 16, 10
print("composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):")
hsv = np.asarray(im.convert("HSV")).astype(int)
hh, ss, vv = hsv[..., 0], hsv[..., 1], hsv[..., 2]
for gy in range(GY):
row = ""
for gx in range(GX):
cell = L[gy*H//GY:(gy+1)*H//GY, gx*W//GX:(gx+1)*W//GX]
m = cell.mean()
# dominant hue of saturated pixels
ch = hh[gy*H//GY:(gy+1)*H//GY, gx*W//GX:(gx+1)*W//GX]
cs = ss[gy*H//GY:(gy+1)*H//GY, gx*W//GX:(gx+1)*W//GX]
sat = cs > 60
if m > 0.85: c = "W"
elif sat.mean() > 0.12:
ang = np.median(ch[sat]) * 360 / 255
c = "R" if ang < 25 or ang >= 330 else "Y" if ang < 70 else "G" if ang < 160 else "C" if ang < 200 else "B" if ang < 270 else "M"
elif m > 0.45: c = "N"
else: c = "K"
row += str(min(9, int(m * 10))) + c
print(" " + row)
# Low-variance (flat) regions — candidate dead space
flat = []
for gy in range(GY):
for gx in range(GX):
cell = gray[gy*H//GY:(gy+1)*H//GY, gx*W//GX:(gx+1)*W//GX]
if cell.std() < 6:
flat.append((gx, gy, round(float(cell.mean()))))
print(f"flat cells (std<6): {len(flat)}/{GX*GY}" + (f" at {flat[:12]}" if flat else ""))
# OCR line analysis
lines = ocr_lines(path)
print(f"OCR: {len(lines)} lines (conf>=35)")
low_contrast, overlaps, tiny = [], [], []
boxes = []
for ln in lines:
x, y, w, h = ln["bbox"]
if w <= 1 or h <= 1 or x < 0 or y < 0 or x + w > W or y + h > H:
continue
pad = 2
x0, y0 = max(0, x - pad), max(0, y - pad)
x1, y1 = min(W, x + w + pad), min(H, y + h + pad)
reg = L[y0:y1, x0:x1]
lo, hi = np.percentile(reg, 5), np.percentile(reg, 95)
ratio = cr(hi, lo)
boxes.append((x, y, w, h, ln["text"]))
if h < 9 and ln["conf"] > 50:
tiny.append(ln)
if ratio < 4.0 and len(ln["text"].strip()) > 1:
low_contrast.append((ln["text"][:40], (x, y, w, h), round(ratio, 2)))
# overlap between different lines (>25% of smaller area)
for i in range(len(boxes)):
for j in range(i + 1, len(boxes)):
ax, ay, aw, ah, at = boxes[i]; bx, by, bw, bh, bt = boxes[j]
ox = max(0, min(ax+aw, bx+bw) - max(ax, bx)); oy = max(0, min(ay+ah, by+bh) - max(ay, by))
inter = ox * oy
small = min(aw*ah, bw*bh)
if small and inter / small > 0.30 and at != bt:
overlaps.append((at[:28], bt[:28], round(100*inter/small)))
if low_contrast:
print("LOW CONTRAST (<4:1):")
for t, b, r in low_contrast[:14]:
print(f" {r:>5}:1 @({b[0]},{b[1]},{b[2]}x{b[3]}) '{t}'")
if len(low_contrast) > 14: print(f" ... +{len(low_contrast)-14} more")
else:
print("LOW CONTRAST: none flagged")
if overlaps:
print("OVERLAPPING TEXT BOXES:")
for a, b, pct in overlaps[:10]:
print(f" {pct}% '{a}' vs '{b}'")
if tiny:
print(f"VERY SMALL TEXT (<9px tall): {len(tiny)} e.g. " + "; ".join(t['text'][:18] for t in tiny[:5]))
# Print all OCR lines with geometry so reviewer can reconstruct layout
print("--- OCR transcript (x,y w h | conf | text) ---")
for ln in lines:
x, y, w, h = ln["bbox"]
print(f" ({x:>4},{y:>4} {w:>4}x{h:<3}|{ln['conf']:.0f}) {ln['text'][:90]}")
for p in SHOTS:
try:
analyze(p)
except Exception as e:
print(f"\nFAILED {p}: {type(e).__name__}: {e}")
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python3
"""Zoom into a region: upscale, stats, OCR."""
import sys, subprocess
from PIL import Image
import numpy as np
path, x, y, w, h = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]), int(sys.argv[5])
scale = int(sys.argv[6]) if len(sys.argv) > 6 else 3
im = Image.open(path).convert("RGB")
W, H = im.size
x0, y0 = max(0, x), max(0, y)
x1, y1 = min(W, x + w), min(H, y + h)
crop = im.crop((x0, y0, x1, y1))
arr = np.asarray(crop).astype(float)
print(f"region ({x0},{y0})-({x1},{y1}): mean RGB={arr.reshape(-1,3).mean(0).round(1)} "
f"lum={0.2126*arr[...,0].mean()/255+0.7152*arr[...,1].mean()/255+0.0722*arr[...,2].mean()/255:.3f} "
f"std={arr.std():.1f} max={arr.max():.0f}")
# brightest structures: threshold above local background
g = np.asarray(crop.convert("L"))
for pct in (99, 99.9):
print(f" p{pct} gray={np.percentile(g, pct):.0f}")
big = crop.resize((crop.width * scale, crop.height * scale), Image.LANCZOS)
big.save("/tmp/crop.png")
p = subprocess.run(["tesseract", "/tmp/crop.png", "stdout", "-l", "eng+chi_sim", "--psm", "11"],
capture_output=True, text=True)
txt = [ln.strip() for ln in p.stdout.splitlines() if ln.strip() and len(ln.strip()) > 1]
print("zoomed OCR:", txt if txt else "(nothing)")
+35
View File
@@ -0,0 +1,35 @@
==============================================================================
shots/01-title.png (1280x800)
==============================================================================
luminance mean=0.019 p5=0.004 p50=0.008 p95=0.022 | dark(<0.15)=98% bright(>0.85)=0%
palette: #271e12 25% #1b140c 14% #181009 13% #22170d 12% #1d1009 11% #130e09 11% #0f0a06 10% #433725 4%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y1Y1Y1Y1Y2Y1Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y1Y1Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0R0R0R0R0R0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0R0R0R0R0R0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0R0R0R0R0R0R0R0R0R0Y0Y0Y0Y0Y0Y0Y
0R0R0R0R0R0R0R0R0R0Y0Y0Y0Y0Y0Y0Y
flat cells (std<6): 109/160 at [(0, 0, 16), (1, 0, 16), (2, 0, 17), (3, 0, 19), (4, 0, 21), (5, 0, 23), (6, 0, 26), (7, 0, 28), (8, 0, 30), (9, 0, 32), (10, 0, 33), (11, 0, 34)]
OCR: 11 lines (conf>=35)
LOW CONTRAST (<4:1):
1.91:1 @(972,99,56x29) '群雄'
3.55:1 @(329,703,8x6) 'ri'
VERY SMALL TEXT (<9px tall): 1 e.g. ri
--- OCR transcript (x,y w h | conf | text) ---
( 972, 99 56x29 |76) 群雄
( 391, 104 483x47 |65) WARLORDS
( 542, 190 188x46 |96) FATE
( 350, 272 37x15 |63) =
( 427, 272 498x18 |89) We — A Three Kingdoms Chronicle
( 440, 320 394x16 |94) The Han collapses. Warlords rise. History is unwritten
( 317, 347 641x16 |96) Take a city, a banner, and a handful of sworn blades — and carve your name into the age.
( 545, 466 190x14 |84) 加 HUNDRED DAYS TRIAL
( 577, 576 144x10 |97) LOAD SAVED GAME
( 577, 631 125x11 |90) ? HOW TO PLAY
( 329, 703 8x6 |89) ri
+48
View File
@@ -0,0 +1,48 @@
==============================================================================
shots/03-setup.png (1280x800)
==============================================================================
luminance mean=0.011 p5=0.002 p50=0.006 p95=0.017 | dark(<0.15)=99% bright(>0.85)=0%
palette: #1e150c 19% #090603 18% #140e07 16% #191109 14% #0c0804 12% #1b120b 10% #1d140c 6% #4d3725 4%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0R0R0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
flat cells (std<6): 39/160 at [(0, 0, 8), (15, 0, 8), (0, 1, 8), (4, 1, 22), (11, 1, 22), (12, 1, 22), (13, 1, 22), (15, 1, 8), (0, 2, 8), (13, 2, 23), (15, 2, 8), (0, 3, 8)]
OCR: 20 lines (conf>=35)
LOW CONTRAST (<4:1):
3.72:1 @(145,274,581x39) '| Local Governor — An appointed administ'
3.41:1 @(582,371,453x32) '| | Xuchang: Yuzhou Wan Yuzhou Lujiang '
3.47:1 @(146,417,137x34) 'Banner emblem | x'
3.46:1 @(609,460,472x38) '| Rich plains at the crossroads of the C'
3.13:1 @(146,505,233x32) 'Faction name (optional) | House of'
3.07:1 @(160,601,415x43) 'Shepherd of the People |[ |) Vulture of '
2.64:1 @(349,660,299x50) '| ||'
--- OCR transcript (x,y w h | conf | text) ---
( 446, 98 385x23 |87) RAISE YOUR BANNER *%
( 146, 150 115x16 |76) I. Origin 出身
( 160, 185 859x31 |80) Local Governor | X Former Soldier | | 加 Fallen Noble | | DBandit Leader | | Merchant Princ
( 145, 230 291x31 |76) | Exiled General || Firebrand |
( 145, 274 581x39 |92) | Local Governor — An appointed administrator. +Politics, cities start orderly, cheap buil
( 146, 336 96x17 |74) I. Identity
( 610, 337 146x16 |87) III. Starting City
( 582, 371 453x32 |75) | | Xuchang: Yuzhou Wan Yuzhou Lujiang - Yangzhou |
( 146, 381 72x11 |95) Ruler name
( 240, 381 36x12 |96) Minh
( 609, 416 458x31 |81) | Changsha Jingzhou | Yunnan - Yizhou Anding Yongzhou |
( 146, 417 137x34 |93) Banner emblem | x
( 609, 460 472x38 |92) | Rich plains at the crossroads of the Central Plains — everyone's future prize
( 242, 465 47x26 |54) |
( 146, 472 81x11 |94) Banner color
( 146, 505 233x32 |92) Faction name (optional) | House of
( 146, 573 114x16 |97) IV. Difficulty
( 160, 601 415x43 |87) Shepherd of the People |[ |) Vulture of the Age |
( 349, 660 299x50 |65) | ||
( 767, 680 39x10 |96) BACK
+96
View File
@@ -0,0 +1,96 @@
==============================================================================
shots/04-game.png (1280x800)
==============================================================================
luminance mean=0.062 p5=0.004 p50=0.045 p95=0.149 | dark(<0.15)=95% bright(>0.85)=0%
palette: #6f5a3f 16% #0f0b0a 14% #443021 13% #4f4330 13% #332519 13% #6d4e37 11% #736d4e 10% #1c150f 10%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0Y0Y0Y0B0B0B0Y0Y0Y0Y0R0R
0Y0Y0Y0Y0R0R0R0R0Y0Y0Y0Y0Y0M0M0M
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y1Y1Y0Y0Y0Y0Y0Y0Y0R0Y0Y0Y0Y0Y
0Y1Y1Y1Y0Y0Y0Y0Y0R0R0R0R0Y1Y1Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0R0Y0R1R0R1Y1Y1Y
0Y0Y0Y0Y0Y0Y0R0R1R0R0Y0Y0Y0Y1Y1Y
0Y0Y0Y1Y1G0Y0Y0Y0G0Y0G0G0Y0Y0Y0Y
0Y0Y1Y1Y0Y0Y0Y0Y1G1G1G1G0G0Y0Y0Y
0Y0Y0Y0G0Y0Y0Y0Y0G0Y0Y0G0Y0Y0Y0G
flat cells (std<6): 11/160 at [(9, 0, 12), (10, 0, 12), (11, 0, 12), (0, 3, 75), (2, 3, 89), (15, 3, 75), (14, 4, 98), (15, 4, 88), (14, 5, 107), (15, 5, 95), (15, 6, 97)]
OCR: 59 lines (conf>=35)
LOW CONTRAST (<4:1):
2.22:1 @(55,20,8x8) 'TE'
3.81:1 @(28,89,179x14) 'China, or be crowned Emperor.'
2.21:1 @(628,142,41x11) 'Beihai'
1.91:1 @(956,218,48x22) '=a'
3.14:1 @(709,237,23x7) 'own:'
2.38:1 @(968,312,61x16) 'el'
2.49:1 @(635,315,46x16) 'ae'
3.11:1 @(486,340,9x7) 'tn'
2.43:1 @(853,368,17x19) 'Ay'
2.46:1 @(870,380,20x10) '/四'
2.84:1 @(258,390,91x70) 'by'
2.48:1 @(927,397,47x43) '“3'
2.69:1 @(681,457,42x14) '44,'
2.77:1 @(533,479,39x22) 'a a'
... +13 more
VERY SMALL TEXT (<9px tall): 2 e.g. TE; lage
--- OCR transcript (x,y w h | conf | text) ---
( 354, 16 60x16 |65) 四 7,000
( 91, 17 129x14 |89) Winter 193 - Jan
( 273, 18 41x14 |96) 2,800
( 471, 18 41x14 |96) 2,500
( 546, 18 20x12 |83) o1
( 601, 18 21x12 |53) 03
( 55, 20 8x8 |96) TE
( 27, 70 229x14 |96) Victory: hold 20 cities (now 1), or unite
( 28, 89 179x14 |94) China, or be crowned Emperor.
( 28, 108 209x14 |86) Hold Chang'an & Luoyang with high
( 28, 128 186x14 |96) legitimacy to claim the Mandate.
( 628, 142 41x11 |96) Beihai
( 927, 171 6x6 |42) Ww
( 381, 191 29x15 |70) ping
( 956, 218 48x22 |41) =a
( 709, 237 23x7 |40) own:
( 953, 243 13x12 |82) a
( 714, 247 23x11 |44) suche
( 968, 312 61x16 |43) el
( 701, 313 63x16 |57) +
( 635, 315 46x16 |52) ae
( 464, 322 31x13 |37) Luoy:
( 820, 323 31x24 |37) i
( 486, 340 9x7 |47) tn
( 725, 351 22x10 |74) ang
( 853, 368 17x19 |52) Ay
( 963, 374 17x10 |37) ~
( 870, 380 20x10 |54) /四
( 258, 390 91x70 |63) by
( 927, 397 47x43 |43) “3
(1048, 410 25x10 |82) ~
( 197, 418 46x14 |86) Anding
( 853, 430 73x33 |57) Vy 4,
(1043, 433 6x24 |37) r
( 681, 457 42x14 |50) 44,
( 745, 476 60x56 |39) a
( 533, 479 39x22 |77) a a
( 819, 489 30x11 |81) zhou
( 527, 511 27x20 |43) Ae
( 729, 560 4x10 |92) 全
( 512, 571 21x10 |97) ong
( 857, 585 37x22 |68) 4g
(1119, 585 49x10 |86) Yunnan
( 511, 587 24x8 |64) lage
( 648, 600 16x11 |50) du
( 799, 617 51x29 |65) on
( 790, 648 59x20 |38) ows,
( 923, 651 52x26 |82) on
( 731, 660 27x20 |57) %
( 538, 666 28x13 |69) fa
( 666, 678 312x42 |47) ae ~* 有
( 287, 705 57x62 |63) “a
( 236, 777 169x14 |75) & Generals 0 Cities
( 870, 777 85x14 |87) & Chronicle
( 545, 778 87x14 |49) Diplomacy
( 766, 778 63x13 |50) DJournal
( 997, 778 47x14 |87) 2 Help
( 457, 779 48x12 |75) Armies
( 672, 779 54x10 |86) = Court
+21
View File
@@ -0,0 +1,21 @@
==============================================================================
shots/05-generals.png (1280x800)
==============================================================================
luminance mean=0.049 p5=0.003 p50=0.021 p95=0.146 | dark(<0.15)=96% bright(>0.85)=0%
palette: #19120a 17% #71553c 17% #3a2e20 14% #130e08 13% #59422d 11% #0e0a06 10% #271a11 9% #786d4e 9%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0R0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y1Y1Y1Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y1Y1Y1Y0R0Y0Y0Y1R0R0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0R0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0R0R1R0R0Y0Y0Y0Y0Y0Y
0Y0Y0Y1Y1G0Y0Y0Y0R0R0Y0Y0Y0Y0Y0Y
0Y1Y1Y1Y0G0Y0Y0Y0G1G0G0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0G0Y0Y0Y0Y0Y0Y
flat cells (std<6): 2/160 at [(15, 1, 14), (15, 7, 14)]
OCR: 0 lines (conf>=35)
LOW CONTRAST: none flagged
--- OCR transcript (x,y w h | conf | text) ---
+21
View File
@@ -0,0 +1,21 @@
==============================================================================
shots/07-diplomacy.png (1280x800)
==============================================================================
luminance mean=0.049 p5=0.003 p50=0.020 p95=0.145 | dark(<0.15)=96% bright(>0.85)=0%
palette: #71563d 17% #1a130b 16% #3a2e1f 14% #151009 12% #271a11 11% #0f0a06 11% #58412d 11% #796c4f 9%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y1Y1Y1Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y1Y1Y1Y0Y0Y0Y0Y1R0R0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0R0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0R0R0R0R0Y0Y0Y0Y0Y0Y
0Y0Y0Y1Y1G0Y0Y0R1R1R0Y0Y0Y0Y0Y0Y
0Y0Y1Y1Y0G0Y0Y0Y0G1G0G0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0G0Y0Y0Y0Y0Y0Y
flat cells (std<6): 6/160 at [(0, 3, 82), (15, 3, 17), (15, 5, 17), (12, 6, 20), (15, 6, 17), (15, 8, 14)]
OCR: 0 lines (conf>=35)
LOW CONTRAST: none flagged
--- OCR transcript (x,y w h | conf | text) ---
+35
View File
@@ -0,0 +1,35 @@
==============================================================================
shots/14-battle-late.png (1280x800)
==============================================================================
luminance mean=0.058 p5=0.005 p50=0.055 p95=0.133 | dark(<0.15)=100% bright(>0.85)=0%
palette: #261b16 19% #5b4528 15% #7d6136 13% #684f2d 12% #735731 12% #201613 11% #462b1d 9% #130c0a 7%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R
0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R
0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R
0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R0R
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y1Y1Y1Y0Y0R0R0R1Y1Y1Y1Y1Y0Y0Y
0Y0Y1Y1Y1Y0Y1Y1Y1Y1Y1Y1Y1Y1Y0Y0Y
0Y0Y0Y1Y1Y1Y1Y1Y1Y1Y1Y1Y1Y0Y0Y0Y
0Y0Y0Y0Y0Y1Y1Y1Y1Y1Y1Y0Y0Y0Y0Y0Y
flat cells (std<6): 114/160 at [(5, 0, 16), (6, 0, 17), (9, 0, 17), (10, 0, 16), (0, 1, 20), (1, 1, 22), (2, 1, 24), (3, 1, 26), (4, 1, 28), (5, 1, 28), (6, 1, 29), (7, 1, 29)]
OCR: 9 lines (conf>=35)
LOW CONTRAST (<4:1):
1.7:1 @(576,374,50x44) 'mi'
2.32:1 @(540,431,88x69) 'Wi \'
2.43:1 @(486,474,46x60) 'mi'
1.3:1 @(533,488,7x24) 'i)'
2.64:1 @(556,506,42x54) 'the'
--- OCR transcript (x,y w h | conf | text) ---
( 568, 17 141x14 |96) ASSAULT 7/9
( 149, 18 39x9 |96) HOST
(1052, 18 81x9 |95) GARRISON
( 576, 374 50x44 |39) mi
( 540, 431 88x69 |49) Wi \
( 486, 474 46x60 |46) mi
( 533, 488 7x24 |40) i)
( 551, 498 3x20 |62) )
( 556, 506 42x54 |44) the
+21
View File
@@ -0,0 +1,21 @@
==============================================================================
shots/16-end.png (1100x700)
==============================================================================
luminance mean=0.012 p5=0.002 p50=0.006 p95=0.011 | dark(<0.15)=99% bright(>0.85)=0%
palette: #191108 20% #1e150c 18% #090603 16% #150e08 14% #1c130b 12% #1d140c 9% #17110a 6% #3a2a1c 4%
composition grid (mean lum 0-9; hue: R=red/warm Y=yellow/tan G=green C=cyan B=blue M=magenta K=neutral-dark N=neutral-mid W=white-ish):
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0R0R0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y0Y
flat cells (std<6): 67/160 at [(0, 0, 17), (1, 0, 19), (2, 0, 21), (3, 0, 22), (4, 0, 24), (5, 0, 25), (6, 0, 27), (7, 0, 27), (8, 0, 27), (9, 0, 27), (10, 0, 25), (11, 0, 24)]
OCR: 0 lines (conf>=35)
LOW CONTRAST: none flagged
--- OCR transcript (x,y w h | conf | text) ---