import cv2
import numpy as np
from PIL import ImageGrab
import pytesseract
import time
def generate_ast():
print("[*] Kaapataan ruutu...")
# Kaapataan koko ruutu (tai voit rajata bboxilla)
img_pil = ImageGrab.grab()
img_np = np.array(img_pil)
# Muunnetaan RGB (Pillow) -> BGR (OpenCV) -> HarmaasC$vy
gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
print("[*] Pass 1: Edge Mapping & Dilation (OpenCV)...")
# EtsitC$C$n C$C$riviivat
edges = cv2.Canny(gray, 50, 150)
# Dilaatio (yhdistC$C$ lC$hekkC$in olevat kirjaimet/reunat yhdeksi
laatikoksi)
# 10x5 kernel on leveC$mpi kuin korkea, sopii hyvin tekstiriveille
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 5))
dilated = cv2.dilate(edges, kernel, iterations=1)
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
nodes = []
print(f"[*] LC6ydettiin {len(contours)} potentiaalista elementtiC$.
Analysoidaan...")
for i, contour in enumerate(contours):
x, y, w, h = cv2.boundingRect(contour)
# Suodatetaan liian pienet (kohina) ja liian suuret (koko ruudun
taustat)
if w < 12 or h < 12 or w > img_np.shape[1] * 0.9:
continue
crop = gray[y:y+h, x:x+w]
# Pass 2: Kognitiivinen Luokittelu
# --psm 7 tarkoittaa "Treat the image as a single text line"
text = pytesseract.image_to_string(crop, config='--psm 7 -l
eng+fin').strip()
# Puhdistetaan OCR-roskaa
text = "".join([c for c in text if c.isalnum() or c in " .,?!-()/:"])
if len(text) > 1:
nodes.append({
"id": f"node_{i}", "type": "TextNode",
"content": text, "x": x, "y": y, "w": w, "h": h
})
else:
nodes.append({
"id": f"node_{i}", "type": "IconNode",
"content": "Graphic", "x": x, "y": y, "w": w, "h": h
})
return nodes
def build_ast_md(nodes):
print("[*] Pass 4: Rakennetaan AST-MD semanttinen kartta...")
# JC$rjestetC$C$n elementit ylhC$C$ltC$ alas, vasemmalta oikealle
lukujC$rjestykseen
nodes.sort(key=lambda n: (n['y'] // 20, n['x']))
md = "# AST-MD: Visuaalinen KC$yttC6liittymC$kartta
"
md += "## Layout Elements
"
for node in nodes:
node_id = node['id']
x, y, w, h = node['x'], node['y'], node['w'], node['h']
if node['type'] == 'TextNode':
md += f"- `[{node_id}]` **TextNode**: \"{node['content']}\"
(X:{x}, Y:{y}, W:{w}, H:{h})
"
else:
md += f"- `[{node_id}]` **IconNode**: *{node['content']}* (X:{x},
Y:{y}, W:{w}, H:{h})
"
return md
if __name__ == "__main__":
start_time = time.time()
ast_nodes = generate_ast()
markdown_output = build_ast_md(ast_nodes)
print("
" + "="*50)
print(markdown_output)
print("="*50)
print(f"[+] AST-MD generointi valmis ({(time.time()-start_time):.2f}
sekuntia).")