Reconstrucción de rango k
Despliega, calcula la SVD sin centrar, trunca y vuelve a plegar:
M = tensor.reshape(H, W*C)
U, s, Vt = np.linalg.svd(M, full_matrices=False)
M_k = (U[:, :k] * s[:k]) @ Vt[:k, :] # difusión; no hace falta la matriz diag
restored = M_k.reshape(H, W, C)
U[:, :k] es una base de filas; s[:k, None] * Vt[:k] da k puntuaciones latentes por par columna/canal.
El resultado tiene rango matricial como máximo k en este desplegado, no necesariamente rango CP k. El rango 0 devuelve ceros, y las imágenes enteras se promueven a float64 para que nada se redondee de vuelta a uint8.