| import os |
| import torch |
| from torch import nn |
| import cv2 |
| import numpy as np |
| from safetensors.torch import load_file, save_file |
|
|
| |
| class VideoNet128(nn.Module): |
| def __init__(self): |
| super().__init__() |
| self.enc = nn.Sequential( |
| nn.Conv3d(3, 32, 3, padding=1), nn.ReLU(True), nn.MaxPool3d((1, 2, 2)), |
| nn.Conv3d(32, 64, 3, padding=1), nn.ReLU(True), nn.MaxPool3d((1, 2, 2)), |
| nn.Conv3d(64, 128, 3, padding=1), nn.ReLU(True), nn.MaxPool3d((1, 2, 2)) |
| ) |
| self.dec = nn.Sequential( |
| nn.Upsample(scale_factor=(1, 2, 2)), nn.Conv3d(128, 64, 3, padding=1), nn.ReLU(True), |
| nn.Upsample(scale_factor=(1, 2, 2)), nn.Conv3d(64, 32, 3, padding=1), nn.ReLU(True), |
| nn.Upsample(scale_factor=(1, 2, 2)), nn.Conv3d(32, 16, 3, padding=1), nn.ReLU(True), |
| nn.Conv3d(16, 3, 3, padding=1), nn.Tanh() |
| ) |
| def forward(self, x): |
| return self.dec(self.enc(x)) |
|
|
| |
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| model = VideoNet128().to(device) |
|
|
| |
| pth_path = 'model.pth' |
| safetensors_path = 'model.safetensors' |
|
|
| if not os.path.exists(safetensors_path): |
| if os.path.exists(pth_path): |
| print("обнаружен старый формат весов! запускаю конвертацию в .safetensors...") |
| try: |
| model.load_state_dict(torch.load(pth_path, map_location='cpu')) |
| save_file(model.state_dict(), safetensors_path) |
| print("конвертация успешно завершена! создан файл model.safetensors.") |
| except Exception as e: |
| print(f"ошибка при конвертации: {e}") |
| else: |
| print(f"E: не найдены файлы весов ({pth_path} или {safetensors_path})!") |
| exit(1) |
|
|
| |
| try: |
| weights = load_file(safetensors_path, device=device) |
| model.load_state_dict(weights) |
| print("веса hueglot (.safetensors) успешно применены!") |
| except Exception as e: |
| print(f"критическая ошибка загрузки .safetensors: {e}!") |
| exit(1) |
|
|
| model.eval() |
|
|
| |
| def process_user_video(video_path, output_path="output.mp4"): |
| |
| cap = cv2.VideoCapture(video_path) |
| frames = [] |
| while len(frames) < 16: |
| ret, frame = cap.read() |
| if not ret: |
| break |
| frame = cv2.resize(frame, (128, 128)) |
| frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) |
| cap.release() |
| |
| if len(frames) < 16: |
| print("E: видео слишком короткое, нужно минимум 16 кадров!") |
| return |
|
|
| |
| v = np.array(frames, dtype=np.float32) |
| v = torch.from_numpy(v).permute(3, 0, 1, 2).unsqueeze(0).to(device) |
| v = (v / 127.5) - 1.0 |
|
|
| |
| print("перемалываем видео через латентное пространство...") |
| with torch.no_grad(): |
| output = model(v) |
| vid = ((output.squeeze(0).clamp(-1, 1) + 1) / 2 * 255).cpu().numpy().astype(np.uint8).transpose(1, 2, 3, 0) |
|
|
| |
| NEW_SIZE = (1024, 1024) |
| out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'mp4v'), 60, NEW_SIZE) |
|
|
| print("рендерим плавные 60 FPS через интерполяцию кадров...") |
| for i in range(15): |
| frame1 = cv2.resize(cv2.cvtColor(vid[i], cv2.COLOR_RGB2BGR), NEW_SIZE, interpolation=cv2.INTER_CUBIC) |
| frame2 = cv2.resize(cv2.cvtColor(vid[i+1], cv2.COLOR_RGB2BGR), NEW_SIZE, interpolation=cv2.INTER_CUBIC) |
| out.write(frame1) |
| for alpha in [0.25, 0.5, 0.75]: |
| out.write(cv2.addWeighted(frame1, 1 - alpha, frame2, alpha, 0)) |
| |
| out.write(cv2.resize(cv2.cvtColor(vid[-1], cv2.COLOR_RGB2BGR), NEW_SIZE, interpolation=cv2.INTER_CUBIC)) |
| out.release() |
| print(f"[+] Готово! Шизо-видео успешно обработано и сохранено в: {output_path}") |
|
|
| |
| |
| process_user_video("video.mp4") |