"""Desentorta quadros do original para o plano do jornal (coordenadas do mundo da cena) e monta um mosaico,
ficando em cada ponto o quadro que tem mais resolução ali. Serve para decalcar a diagramação da página.
Uso: python -I retificar_quadros.py F|J escala saida.png quadro1 quadro2 ...   (escala = px por unidade do plano)"""
import json, sys, cv2, numpy as np
CENA, ESC, OUT = sys.argv[1], float(sys.argv[2]), sys.argv[3]
QS = [int(x) for x in sys.argv[4:]]
VID = "<SUA_CENTRAL>/05-pesquisa/referencias/2026-10-17-subzmotion/midia/05-DeMZpQ5gv-t.mp4"
d = json.load(open(f"camera3d-{CENA}.json")); Q = {q["f"]: q for q in d["quadros"]}
K = np.array([[1500, 0, 540], [0, 1500, 540], [0, 0, 1.0]])
def Hps(f):
    R = np.array(Q[f]["R"]); t = np.array(Q[f]["tc"]); return K @ np.c_[R[:, 0], R[:, 1], t]
# extensão: o maior quadro (mais recuado) define a área
fl = max(QS, key=lambda f: Q[f]["tc"][2])
Hi = np.linalg.inv(Hps(fl)); cs = np.array([[0, 0, 1], [1080, 0, 1], [1080, 1080, 1], [0, 1080, 1.0]]) @ Hi.T
cs = cs[:, :2] / cs[:, 2:3]; x0, y0 = cs.min(0); x1, y1 = cs.max(0)
if len(sys.argv) > 4 and "--" in sys.argv: pass
W, Hh = int((x1 - x0) * ESC), int((y1 - y0) * ESC)
T = np.array([[ESC, 0, -x0 * ESC], [0, ESC, -y0 * ESC], [0, 0, 1.0]])
cap = cv2.VideoCapture(VID)
acc = np.zeros((Hh, W, 3), np.float32); best = np.zeros((Hh, W), np.float32)
for f in sorted(QS):
    cap.set(cv2.CAP_PROP_POS_FRAMES, f); ok, im = cap.read()
    M = Hps(f) @ np.linalg.inv(T)  # saída -> tela
    w = cv2.warpPerspective(im, M, (W, Hh), flags=cv2.INTER_LINEAR | cv2.WARP_INVERSE_MAP)
    # resolução local: px de tela por unidade do plano ~ f / z_cam
    yy, xx = np.mgrid[0:Hh, 0:W].astype(np.float32)
    X = xx / ESC + x0; Y = yy / ESC + y0
    R = np.array(Q[f]["R"]); t = np.array(Q[f]["tc"])
    zc = R[2, 0] * X + R[2, 1] * Y + t[2]
    P = np.stack([X, Y, np.ones_like(X)], -1) @ Hps(f).T; u = P[..., 0] / P[..., 2]; v = P[..., 1] / P[..., 2]
    dentro = (u > 2) & (u < 1078) & (v > 2) & (v < 1078) & (zc > 0)
    res = np.where(dentro, 1500 / np.maximum(zc, 1), 0)
    m = res > best
    acc[m] = w[m]; best[m] = res[m]
    print(f, "z", round(t[2]), "px/unidade", round(1500 / t[2], 3))
cv2.imencode(".png", acc.astype(np.uint8))[1].tofile(OUT)
json.dump({"x0": float(x0), "y0": float(y0), "escala": ESC, "W": W, "H": Hh}, open(OUT + ".json", "w"))
print("extensão do plano", round(x0), round(y0), round(x1), round(y1), "->", W, Hh)
