Upload LTX_Video_Img_to_Vid.ipynb
Browse files
LTX-Video/LTX_Video_Img_to_Vid.ipynb
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 0,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"colab": {
|
| 6 |
+
"provenance": [],
|
| 7 |
+
"gpuType": "T4"
|
| 8 |
+
},
|
| 9 |
+
"kernelspec": {
|
| 10 |
+
"name": "python3",
|
| 11 |
+
"display_name": "Python 3"
|
| 12 |
+
},
|
| 13 |
+
"language_info": {
|
| 14 |
+
"name": "python"
|
| 15 |
+
},
|
| 16 |
+
"accelerator": "GPU"
|
| 17 |
+
},
|
| 18 |
+
"cells": [
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "markdown",
|
| 21 |
+
"source": [
|
| 22 |
+
"# **LTX-VIDEO (Image to Video based on ComfyUI nodes library)**\n",
|
| 23 |
+
"ComfyUI Github Repository: https://github.com/comfyanonymous/ComfyUI"
|
| 24 |
+
],
|
| 25 |
+
"metadata": {
|
| 26 |
+
"id": "f4p1ysFKMbs_"
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"cell_type": "markdown",
|
| 31 |
+
"source": [
|
| 32 |
+
"- Note that this Notebook only references the ComfyUI nodes library; it does not display the ComfyUI GUI.\n",
|
| 33 |
+
"- You can use the free T4 GPU to run this depending on the output video resolution and number of frames. The default setting runs without issues, but at 768 by 512 output resolution with 73 frames, the decoding process crashes the 12.7GB RAM. For faster video generation with higher resolutions and frames, use higher GPUs.\n",
|
| 34 |
+
"- If you want to generate a video with n frames, then set frames to n+1. e.g. To generate a video with 72 frames, set frames to 73.\n",
|
| 35 |
+
"- You need to use detailed prompts to get decent results.\n",
|
| 36 |
+
"- Videos are generated at 24fps."
|
| 37 |
+
],
|
| 38 |
+
"metadata": {
|
| 39 |
+
"id": "EBB00lC6q-DA"
|
| 40 |
+
}
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"cell_type": "code",
|
| 44 |
+
"source": [
|
| 45 |
+
"# @title Prepare Environment\n",
|
| 46 |
+
"%cd /content\n",
|
| 47 |
+
"Always_Load_Models_for_Inference = False\n",
|
| 48 |
+
"Use_t5xxl_fp16 = False\n",
|
| 49 |
+
"\n",
|
| 50 |
+
"!pip install -q torchsde einops diffusers accelerate xformers\n",
|
| 51 |
+
"!pip install av\n",
|
| 52 |
+
"!git clone https://github.com/Isi-dev/ComfyUI\n",
|
| 53 |
+
"%cd /content/ComfyUI\n",
|
| 54 |
+
"!apt -y install -qq aria2 ffmpeg\n",
|
| 55 |
+
"\n",
|
| 56 |
+
"!aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/Isi99999/LTX-Video/resolve/main/ltx-video-2b-v0.9.5.safetensors -d /content/ComfyUI/models/checkpoints -o ltx-video-2b-v0.9.5.safetensors\n",
|
| 57 |
+
"if Use_t5xxl_fp16:\n",
|
| 58 |
+
" !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/Isi99999/LTX-Video/resolve/main/t5xxl_fp16.safetensors -d /content/ComfyUI/models/text_encoders -o t5xxl_fp16.safetensors\n",
|
| 59 |
+
"else:\n",
|
| 60 |
+
" !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/Isi99999/LTX-Video/resolve/main/t5xxl_fp8_e4m3fn_scaled.safetensors -d /content/ComfyUI/models/text_encoders -o t5xxl_fp8_e4m3fn_scaled.safetensors\n",
|
| 61 |
+
"\n",
|
| 62 |
+
"import torch\n",
|
| 63 |
+
"import numpy as np\n",
|
| 64 |
+
"from PIL import Image\n",
|
| 65 |
+
"import gc\n",
|
| 66 |
+
"import sys\n",
|
| 67 |
+
"import random\n",
|
| 68 |
+
"import os\n",
|
| 69 |
+
"import imageio\n",
|
| 70 |
+
"from google.colab import files\n",
|
| 71 |
+
"from IPython.display import display, HTML\n",
|
| 72 |
+
"sys.path.insert(0, '/content/ComfyUI')\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"from comfy import model_management\n",
|
| 75 |
+
"\n",
|
| 76 |
+
"from nodes import (\n",
|
| 77 |
+
" CheckpointLoaderSimple,\n",
|
| 78 |
+
" CLIPLoader,\n",
|
| 79 |
+
" CLIPTextEncode,\n",
|
| 80 |
+
" VAEDecode,\n",
|
| 81 |
+
" LoadImage,\n",
|
| 82 |
+
" SaveImage\n",
|
| 83 |
+
")\n",
|
| 84 |
+
"\n",
|
| 85 |
+
"from comfy_extras.nodes_custom_sampler import (\n",
|
| 86 |
+
" KSamplerSelect,\n",
|
| 87 |
+
" SamplerCustom\n",
|
| 88 |
+
")\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"from comfy_extras.nodes_lt import (\n",
|
| 91 |
+
" LTXVPreprocess,\n",
|
| 92 |
+
" LTXVImgToVideo,\n",
|
| 93 |
+
" LTXVScheduler,\n",
|
| 94 |
+
" LTXVConditioning\n",
|
| 95 |
+
")\n",
|
| 96 |
+
"\n",
|
| 97 |
+
"checkpoint_loader = CheckpointLoaderSimple()\n",
|
| 98 |
+
"clip_loader = CLIPLoader()\n",
|
| 99 |
+
"clip_encode_positive = CLIPTextEncode()\n",
|
| 100 |
+
"clip_encode_negative = CLIPTextEncode()\n",
|
| 101 |
+
"load_image = LoadImage()\n",
|
| 102 |
+
"save_node = SaveImage()\n",
|
| 103 |
+
"preprocess = LTXVPreprocess()\n",
|
| 104 |
+
"img_to_video = LTXVImgToVideo()\n",
|
| 105 |
+
"scheduler = LTXVScheduler()\n",
|
| 106 |
+
"sampler_select = KSamplerSelect()\n",
|
| 107 |
+
"conditioning = LTXVConditioning()\n",
|
| 108 |
+
"sampler = SamplerCustom()\n",
|
| 109 |
+
"vae_decode = VAEDecode()\n",
|
| 110 |
+
"\n",
|
| 111 |
+
"# if not Always_Load_Models_for_Inference:\n",
|
| 112 |
+
"with torch.inference_mode():\n",
|
| 113 |
+
" # Load models\n",
|
| 114 |
+
" print(\"Loading Model...\")\n",
|
| 115 |
+
" model, _, vae = checkpoint_loader.load_checkpoint(\"ltx-video-2b-v0.9.5.safetensors\")\n",
|
| 116 |
+
" print(\"Loaded model!\")\n",
|
| 117 |
+
" print(\"Loading Text_Encoder...\")\n",
|
| 118 |
+
" # if Use_t5xxl_fp16:\n",
|
| 119 |
+
" # clip = clip_loader.load_clip(\"t5xxl_fp16.safetensors\", \"ltxv\", \"default\")[0]\n",
|
| 120 |
+
" # else:\n",
|
| 121 |
+
" clip = clip_loader.load_clip(\"t5xxl_fp8_e4m3fn_scaled.safetensors\", \"ltxv\", \"default\")[0]\n",
|
| 122 |
+
" print(\"Loaded Text_Encoder!\")\n",
|
| 123 |
+
"\n",
|
| 124 |
+
"def clear_gpu_memory():\n",
|
| 125 |
+
" import gc\n",
|
| 126 |
+
" import torch\n",
|
| 127 |
+
"\n",
|
| 128 |
+
" gc.collect()\n",
|
| 129 |
+
" torch.cuda.empty_cache()\n",
|
| 130 |
+
" torch.cuda.ipc_collect()\n",
|
| 131 |
+
"\n",
|
| 132 |
+
" # if Always_Load_Models_for_Inference:\n",
|
| 133 |
+
" # for var_name in [\"model\", \"vae\", \"clip\"]:\n",
|
| 134 |
+
" # if var_name in globals():\n",
|
| 135 |
+
" # del globals()[var_name]\n",
|
| 136 |
+
"\n",
|
| 137 |
+
" gc.collect()\n",
|
| 138 |
+
" torch.cuda.empty_cache()\n",
|
| 139 |
+
"\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"def upload_image():\n",
|
| 142 |
+
" \"\"\"Handle image upload in Colab and store in /content/ComfyUI/input/\"\"\"\n",
|
| 143 |
+
" from google.colab import files\n",
|
| 144 |
+
" import os\n",
|
| 145 |
+
" import shutil\n",
|
| 146 |
+
"\n",
|
| 147 |
+
" os.makedirs('/content/ComfyUI/input', exist_ok=True)\n",
|
| 148 |
+
"\n",
|
| 149 |
+
" uploaded = files.upload()\n",
|
| 150 |
+
"\n",
|
| 151 |
+
" # Move each uploaded file to ComfyUI input directory\n",
|
| 152 |
+
" for filename in uploaded.keys():\n",
|
| 153 |
+
" src_path = f'/content/ComfyUI/{filename}'\n",
|
| 154 |
+
" dest_path = f'/content/ComfyUI/input/{filename}'\n",
|
| 155 |
+
"\n",
|
| 156 |
+
" shutil.move(src_path, dest_path)\n",
|
| 157 |
+
" print(f\"Image saved to: {dest_path}\")\n",
|
| 158 |
+
" return dest_path\n",
|
| 159 |
+
"\n",
|
| 160 |
+
" return None\n",
|
| 161 |
+
"\n",
|
| 162 |
+
"\n",
|
| 163 |
+
"def generate_video(\n",
|
| 164 |
+
" image_path: str = None,\n",
|
| 165 |
+
" positive_prompt: str = \"A red fox moving gracefully\",\n",
|
| 166 |
+
" negative_prompt: str = \"low quality, worst quality\",\n",
|
| 167 |
+
" width: int = 768,\n",
|
| 168 |
+
" height: int = 512,\n",
|
| 169 |
+
" seed: int = 0,\n",
|
| 170 |
+
" steps: int = 30,\n",
|
| 171 |
+
" cfg_scale: float = 2.05,\n",
|
| 172 |
+
" sampler_name: str = \"euler\",\n",
|
| 173 |
+
" length: int = 24, # Number of frames\n",
|
| 174 |
+
" fps: int = 24\n",
|
| 175 |
+
"):\n",
|
| 176 |
+
" \"\"\"Generate a video from an uploaded image using LTX-Video model\"\"\"\n",
|
| 177 |
+
" try:\n",
|
| 178 |
+
"\n",
|
| 179 |
+
" # if Always_Load_Models_for_Inference:\n",
|
| 180 |
+
" # with torch.inference_mode():\n",
|
| 181 |
+
" # # Load models\n",
|
| 182 |
+
" # print(\"Loading Model...\")\n",
|
| 183 |
+
" # model, _, vae = checkpoint_loader.load_checkpoint(\"ltx-video-2b-v0.9.5.safetensors\")\n",
|
| 184 |
+
" # print(\"Loaded model!\")\n",
|
| 185 |
+
" # print(\"Loading Text_Encoder...\")\n",
|
| 186 |
+
" # clip = clip_loader.load_clip(\"t5xxl_fp8_e4m3fn_scaled.safetensors\", \"ltxv\", \"default\")[0]\n",
|
| 187 |
+
" # print(\"Loaded Text_Encoder!\")\n",
|
| 188 |
+
"\n",
|
| 189 |
+
" assert width % 32 == 0, \"Width must be divisible by 32\"\n",
|
| 190 |
+
" assert height % 32 == 0, \"Height must be divisible by 32\"\n",
|
| 191 |
+
"\n",
|
| 192 |
+
"\n",
|
| 193 |
+
"\n",
|
| 194 |
+
" positive = clip_encode_positive.encode(clip, positive_prompt)[0]\n",
|
| 195 |
+
" negative = clip_encode_negative.encode(clip, negative_prompt)[0]\n",
|
| 196 |
+
"\n",
|
| 197 |
+
" if image_path is None:\n",
|
| 198 |
+
" print(\"Please upload an image file:\")\n",
|
| 199 |
+
" image_path = upload_image()\n",
|
| 200 |
+
" if image_path is None:\n",
|
| 201 |
+
" print(\"No image uploaded!\")\n",
|
| 202 |
+
" loaded_image = load_image.load_image(image_path)[0]\n",
|
| 203 |
+
" processed_image = preprocess.preprocess(loaded_image, 40)[0]\n",
|
| 204 |
+
"\n",
|
| 205 |
+
" video_output = img_to_video.generate(\n",
|
| 206 |
+
" positive=positive,\n",
|
| 207 |
+
" negative=negative,\n",
|
| 208 |
+
" vae=vae,\n",
|
| 209 |
+
" image=processed_image,\n",
|
| 210 |
+
" width=width,\n",
|
| 211 |
+
" height=height,\n",
|
| 212 |
+
" length=length,\n",
|
| 213 |
+
" batch_size=1\n",
|
| 214 |
+
" )\n",
|
| 215 |
+
"\n",
|
| 216 |
+
" sigmas = scheduler.get_sigmas(steps, cfg_scale, 0.95, True, 0.1)[0]\n",
|
| 217 |
+
" selected_sampler = sampler_select.get_sampler(sampler_name)[0]\n",
|
| 218 |
+
" conditioned = conditioning.append(video_output[0], video_output[1], 25.0)\n",
|
| 219 |
+
"\n",
|
| 220 |
+
" sampled = sampler.sample(\n",
|
| 221 |
+
" model=model,\n",
|
| 222 |
+
" add_noise=True,\n",
|
| 223 |
+
" noise_seed=seed if seed != 0 else random.randint(0, 2**32),\n",
|
| 224 |
+
" cfg=cfg_scale,\n",
|
| 225 |
+
" positive=conditioned[0],\n",
|
| 226 |
+
" negative=conditioned[1],\n",
|
| 227 |
+
" sampler=selected_sampler,\n",
|
| 228 |
+
" sigmas=sigmas,\n",
|
| 229 |
+
" latent_image=video_output[2]\n",
|
| 230 |
+
" )[0]\n",
|
| 231 |
+
"\n",
|
| 232 |
+
" # model_management.soft_empty_cache()\n",
|
| 233 |
+
"\n",
|
| 234 |
+
" with torch.no_grad():\n",
|
| 235 |
+
" try:\n",
|
| 236 |
+
" decoded = vae_decode.decode(vae, sampled)[0].detach()\n",
|
| 237 |
+
" # print(f\"Decoded frames shape: {decoded.shape}\")\n",
|
| 238 |
+
" except Exception as e:\n",
|
| 239 |
+
" print(f\"Error during decoding: {str(e)}\")\n",
|
| 240 |
+
" raise\n",
|
| 241 |
+
"\n",
|
| 242 |
+
" # Reshape to video frames (batch, frames, H, W, C)\n",
|
| 243 |
+
" # decoded_frames = decoded.reshape(1, length, height, width, 3)\n",
|
| 244 |
+
"\n",
|
| 245 |
+
" save_node.save_images(decoded, filename_prefix=\"video_frame\")\n",
|
| 246 |
+
"\n",
|
| 247 |
+
" output_path = \"/content/output.mp4\"\n",
|
| 248 |
+
" frames_np = (decoded.cpu().numpy() * 255).astype(np.uint8)\n",
|
| 249 |
+
" with imageio.get_writer(output_path, fps=fps) as writer:\n",
|
| 250 |
+
" for frame in frames_np:\n",
|
| 251 |
+
" writer.append_data(frame)\n",
|
| 252 |
+
"\n",
|
| 253 |
+
" print(f\"\\nVideo generation complete!\")\n",
|
| 254 |
+
" print(f\"Saved {len(decoded)} frames to ComfyUI output directory\")\n",
|
| 255 |
+
" print(f\"Video saved to: {output_path}\")\n",
|
| 256 |
+
" display_video(output_path)\n",
|
| 257 |
+
"\n",
|
| 258 |
+
" except Exception as e:\n",
|
| 259 |
+
" print(f\"Error during video generation: {str(e)}\")\n",
|
| 260 |
+
" raise\n",
|
| 261 |
+
" finally:\n",
|
| 262 |
+
" clear_gpu_memory()\n",
|
| 263 |
+
"\n",
|
| 264 |
+
"\n",
|
| 265 |
+
"def display_video(video_path):\n",
|
| 266 |
+
" \"\"\"Display video in Colab notebook with proper HTML5 player\"\"\"\n",
|
| 267 |
+
" from IPython.display import HTML\n",
|
| 268 |
+
" from base64 import b64encode\n",
|
| 269 |
+
"\n",
|
| 270 |
+
" mp4 = open(video_path,'rb').read()\n",
|
| 271 |
+
" data_url = \"data:video/mp4;base64,\" + b64encode(mp4).decode()\n",
|
| 272 |
+
"\n",
|
| 273 |
+
" display(HTML(f\"\"\"\n",
|
| 274 |
+
" <video width=512 controls autoplay loop>\n",
|
| 275 |
+
" <source src=\"{data_url}\" type=\"video/mp4\">\n",
|
| 276 |
+
" </video>\n",
|
| 277 |
+
" \"\"\"))"
|
| 278 |
+
],
|
| 279 |
+
"metadata": {
|
| 280 |
+
"cellView": "form",
|
| 281 |
+
"id": "rrXFIT4fMfyJ"
|
| 282 |
+
},
|
| 283 |
+
"execution_count": null,
|
| 284 |
+
"outputs": []
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"cell_type": "code",
|
| 288 |
+
"source": [
|
| 289 |
+
"# @title Run Image to Video\n",
|
| 290 |
+
"positive_prompt = \"A red fox moving gracefully, its russet coat vibrant against the white landscape, leaving perfect star-shaped prints behind as steam rises from its breath in the crisp winter air. The scene is wrapped in snow-muffled silence, broken only by the gentle murmur of water still flowing beneath the ice.\" # @param {\"type\":\"string\"}\n",
|
| 291 |
+
"negative_prompt = \"low quality, worst quality, deformed, distorted, disfigured, motion smear, motion artifacts, fused fingers, bad anatomy, weird hand, ugly\" # @param {\"type\":\"string\"}\n",
|
| 292 |
+
"width = 704 # @param {\"type\":\"number\"}\n",
|
| 293 |
+
"height = 480 # @param {\"type\":\"number\"}\n",
|
| 294 |
+
"seed = 1000 # @param {\"type\":\"integer\"}\n",
|
| 295 |
+
"steps = 20 # @param {\"type\":\"integer\", \"min\":1, \"max\":100}\n",
|
| 296 |
+
"cfg_scale = 2.5 # @param {\"type\":\"number\", \"min\":1, \"max\":20}\n",
|
| 297 |
+
"sampler_name = \"euler\" # @param [\"euler\", \"dpmpp_2m\", \"ddim\", \"lms\"]\n",
|
| 298 |
+
"frames = 73 # @param {\"type\":\"integer\", \"min\":1, \"max\":120}\n",
|
| 299 |
+
"\n",
|
| 300 |
+
"# @title Run Video Generation\n",
|
| 301 |
+
"print(\"Starting video generation workflow...\")\n",
|
| 302 |
+
"with torch.inference_mode():\n",
|
| 303 |
+
" generate_video(\n",
|
| 304 |
+
" image_path=None, # This will trigger upload\n",
|
| 305 |
+
" positive_prompt=positive_prompt,\n",
|
| 306 |
+
" negative_prompt=negative_prompt,\n",
|
| 307 |
+
" width=width,\n",
|
| 308 |
+
" height=height,\n",
|
| 309 |
+
" seed=seed,\n",
|
| 310 |
+
" steps=steps,\n",
|
| 311 |
+
" cfg_scale=cfg_scale,\n",
|
| 312 |
+
" sampler_name=sampler_name,\n",
|
| 313 |
+
" length=frames\n",
|
| 314 |
+
" )\n",
|
| 315 |
+
"clear_gpu_memory()"
|
| 316 |
+
],
|
| 317 |
+
"metadata": {
|
| 318 |
+
"cellView": "form",
|
| 319 |
+
"id": "roC59_oNNflb"
|
| 320 |
+
},
|
| 321 |
+
"execution_count": null,
|
| 322 |
+
"outputs": []
|
| 323 |
+
},
|
| 324 |
+
{
|
| 325 |
+
"cell_type": "markdown",
|
| 326 |
+
"source": [
|
| 327 |
+
"********************************************************************************************************************************************************************************************************************************************************************************************************************************"
|
| 328 |
+
],
|
| 329 |
+
"metadata": {
|
| 330 |
+
"id": "yWSMPSVcbmmn"
|
| 331 |
+
}
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"cell_type": "markdown",
|
| 335 |
+
"source": [
|
| 336 |
+
"********************************************************************************************************************************************************************************************************************************************************************************************************************************"
|
| 337 |
+
],
|
| 338 |
+
"metadata": {
|
| 339 |
+
"id": "FGDof1EkbnHv"
|
| 340 |
+
}
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"cell_type": "markdown",
|
| 344 |
+
"source": [
|
| 345 |
+
"# **LTX-VIDEO (Image to Video based on Lightricks LTX-VIDEO Github Repository)**\n",
|
| 346 |
+
"LTX-Video Github Repository: https://github.com/Lightricks/LTX-Video"
|
| 347 |
+
],
|
| 348 |
+
"metadata": {
|
| 349 |
+
"id": "6t7--x3NBdE5"
|
| 350 |
+
}
|
| 351 |
+
},
|
| 352 |
+
{
|
| 353 |
+
"cell_type": "markdown",
|
| 354 |
+
"source": [
|
| 355 |
+
"- You need compute units to run this section.\n",
|
| 356 |
+
"- Use detailed prompts to improve the generated video.\n",
|
| 357 |
+
"- If you want to generate a video with n frames, then set NUM_FRAMES to n+1. e.g. To generate a video with 120 frames, set NUM_FRAMES to 121.\n",
|
| 358 |
+
"- Videos are generated at 24fps.\n"
|
| 359 |
+
],
|
| 360 |
+
"metadata": {
|
| 361 |
+
"id": "KVykpe_nU7lK"
|
| 362 |
+
}
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"cell_type": "code",
|
| 366 |
+
"source": [
|
| 367 |
+
"# @title Prepare Environment\n",
|
| 368 |
+
"# Install dependencies\n",
|
| 369 |
+
"!git clone https://github.com/Isi-dev/LTX-Video.git\n",
|
| 370 |
+
"%cd LTX-Video\n",
|
| 371 |
+
"\n",
|
| 372 |
+
"# Install required packages\n",
|
| 373 |
+
"!pip install -e \".[inference-script]\"\n",
|
| 374 |
+
"\n",
|
| 375 |
+
"!pip install \"huggingface_hub[cli]\"\n",
|
| 376 |
+
"!apt-get install -y aria2\n",
|
| 377 |
+
"import os\n",
|
| 378 |
+
"from huggingface_hub import list_repo_files\n",
|
| 379 |
+
"\n",
|
| 380 |
+
"repo_id = \"Isi99999/LTX-Video\"\n",
|
| 381 |
+
"all_files = list_repo_files(repo_id)\n",
|
| 382 |
+
"base_url = f\"https://huggingface.co/{repo_id}/resolve/main/\"\n",
|
| 383 |
+
"\n",
|
| 384 |
+
"with open(\"file_list.txt\", \"w\") as f:\n",
|
| 385 |
+
" for file_path in all_files:\n",
|
| 386 |
+
" full_url = f\"{base_url}{file_path}\"\n",
|
| 387 |
+
" save_path = f\"MODEL_DIR/{file_path}\"\n",
|
| 388 |
+
" os.makedirs(os.path.dirname(save_path), exist_ok=True)\n",
|
| 389 |
+
" f.write(f\"{full_url}\\n out={save_path}\\n\")\n",
|
| 390 |
+
"!aria2c -x 16 -s 16 -i file_list.txt --continue=true --auto-file-renaming=false\n",
|
| 391 |
+
"\n",
|
| 392 |
+
"print(\"✅ All models downloaded successfully!\")"
|
| 393 |
+
],
|
| 394 |
+
"metadata": {
|
| 395 |
+
"cellView": "form",
|
| 396 |
+
"id": "S9doZlq9B36X"
|
| 397 |
+
},
|
| 398 |
+
"execution_count": null,
|
| 399 |
+
"outputs": []
|
| 400 |
+
},
|
| 401 |
+
{
|
| 402 |
+
"cell_type": "code",
|
| 403 |
+
"source": [
|
| 404 |
+
"# @title Upload Image\n",
|
| 405 |
+
"from google.colab import files\n",
|
| 406 |
+
"from PIL import Image\n",
|
| 407 |
+
"\n",
|
| 408 |
+
"uploaded = files.upload()\n",
|
| 409 |
+
"image_path = list(uploaded.keys())[0]\n",
|
| 410 |
+
"image = Image.open(image_path)\n",
|
| 411 |
+
"print(\"✅Image loaded successfully:\", image.size)"
|
| 412 |
+
],
|
| 413 |
+
"metadata": {
|
| 414 |
+
"cellView": "form",
|
| 415 |
+
"id": "QH2FBr4naeK2"
|
| 416 |
+
},
|
| 417 |
+
"execution_count": null,
|
| 418 |
+
"outputs": []
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"cell_type": "code",
|
| 422 |
+
"source": [
|
| 423 |
+
"# @title Generate Video\n",
|
| 424 |
+
"PROMPT =\"A red fox moving gracefully, its russet coat vibrant against the white landscape, leaving perfect star-shaped prints behind as steam rises from its breath in the crisp winter air. The scene is wrapped in snow-muffled silence, broken only by the gentle murmur of water still flowing beneath the ice.\" # @param {type:\"string\"}\n",
|
| 425 |
+
"STEPS = 20 # @param {\"type\":\"number\"}\n",
|
| 426 |
+
"Instruction_1 = \"choose from '720*1280', '1280*720', '480*832', '832*480', '480*704', '704*480' for width & height, and your input image should be of the same resolution as your selected width & height.\" # @param {\"type\":\"string\"}\n",
|
| 427 |
+
"WIDTH = 704 # @param {\"type\":\"number\"}\n",
|
| 428 |
+
"HEIGHT = 480 # @param {\"type\":\"number\"}\n",
|
| 429 |
+
"Instruction_2 = \"The NUM_FRAMES should not exceed 257.\" # @param {\"type\":\"string\"}\n",
|
| 430 |
+
"NUM_FRAMES = 121 # @param {\"type\":\"number\"}\n",
|
| 431 |
+
"SEED = 1000 # @param {\"type\":\"number\"}\n",
|
| 432 |
+
"\n",
|
| 433 |
+
"\n",
|
| 434 |
+
"total_vram = 0\n",
|
| 435 |
+
"import torch\n",
|
| 436 |
+
"if torch.cuda.is_available():\n",
|
| 437 |
+
" gpu_id = torch.cuda.current_device()\n",
|
| 438 |
+
" total_vram = torch.cuda.get_device_properties(gpu_id).total_memory / 1024**3\n",
|
| 439 |
+
"else:\n",
|
| 440 |
+
" print(\"No GPU found.\")\n",
|
| 441 |
+
"if total_vram < 18:\n",
|
| 442 |
+
" print(\"It seems you are using the free T4 GPU which is offered with a RAM of 12.7GB. The text encoder will crash the RAM. Choose a higher runtime type.\")\n",
|
| 443 |
+
"elif total_vram > 18 and total_vram < 30:\n",
|
| 444 |
+
" print(\"Setting low_vram flag to avoid Out of Memory Errors. Inference will be a bit slow.\")\n",
|
| 445 |
+
" !python inference.py --ckpt_path \"MODEL_DIR/\" --output_path \"outputVidFromImage\" --low_vram --offload_to_cpu --conditioning_media_paths {image_path} --conditioning_start_frames 0 --text_encoder_model_name_or_path \"MODEL_DIR/\" --prompt \"{PROMPT}\" --prompt_enhancement_words_threshold 0 --height {HEIGHT} --width {WIDTH} --num_frames {NUM_FRAMES} --seed {SEED} --num_inference_steps {STEPS}\n",
|
| 446 |
+
"else :\n",
|
| 447 |
+
" !python inference.py --ckpt_path \"MODEL_DIR/\" --output_path \"outputVidFromImage\" --conditioning_media_paths {image_path} --conditioning_start_frames 0 --text_encoder_model_name_or_path \"MODEL_DIR/\" --prompt \"{PROMPT}\" --prompt_enhancement_words_threshold 0 --height {HEIGHT} --width {WIDTH} --num_frames {NUM_FRAMES} --seed {SEED} --num_inference_steps {STEPS}\n",
|
| 448 |
+
"\n",
|
| 449 |
+
"if total_vram > 18:\n",
|
| 450 |
+
" import os\n",
|
| 451 |
+
" import glob\n",
|
| 452 |
+
" from IPython.display import display as displayVid, Video as outVid\n",
|
| 453 |
+
"\n",
|
| 454 |
+
" video_folder = \"outputVidFromImage/\"\n",
|
| 455 |
+
"\n",
|
| 456 |
+
" # Find the latest MP4 file\n",
|
| 457 |
+
" video_files = glob.glob(os.path.join(video_folder, \"*.mp4\"))\n",
|
| 458 |
+
"\n",
|
| 459 |
+
" if video_files:\n",
|
| 460 |
+
" latest_video = max(video_files, key=os.path.getctime) # Get the most recent video\n",
|
| 461 |
+
" print(f\"Displaying video: {latest_video}\")\n",
|
| 462 |
+
" displayVid(outVid(latest_video, embed=True))\n",
|
| 463 |
+
" else:\n",
|
| 464 |
+
" print(\"❌ No video found in outputVid/\")\n"
|
| 465 |
+
],
|
| 466 |
+
"metadata": {
|
| 467 |
+
"cellView": "form",
|
| 468 |
+
"id": "RHFnir7waoKm"
|
| 469 |
+
},
|
| 470 |
+
"execution_count": null,
|
| 471 |
+
"outputs": []
|
| 472 |
+
}
|
| 473 |
+
]
|
| 474 |
+
}
|