linoyts HF Staff commited on
Commit
16cf3ea
·
verified ·
1 Parent(s): 771b737

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ examples/landscape_compressed.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ examples/people_compressed.mp4 filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,13 +1,20 @@
1
  ---
2
- title: Ltx 2.3 Decompress
3
- emoji: 🌖
4
  colorFrom: gray
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.18.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: LTX-2.3 Video Decompress
3
+ emoji: 🧼
4
  colorFrom: gray
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 6.13.0
8
+ python_version: "3.12"
9
  app_file: app.py
10
  pinned: false
11
+ hardware: zero-a10g
12
+ short_description: Remove compression artifacts with an LTX-2.3 IC-LoRA
13
+ models:
14
+ - diffusers/LTX-2.3-Distilled-Diffusers
15
+ - linoyts/LTX-2.3-loras
16
  ---
17
 
18
+ # 🧼 LTX-2.3 Video Decompression
19
+ Removes macroblocking, chroma bleed, ringing and banding from low-bitrate video via the decompression
20
+ IC-LoRA on distilled LTX-2.3 (`LTX2InContextPipeline`, 8-step). Optional generated audio.
app.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ os.environ.setdefault("TORCH_COMPILE_DISABLE", "1")
4
+ os.environ.setdefault("TORCHDYNAMO_DISABLE", "1")
5
+
6
+ import random
7
+ import tempfile
8
+
9
+ import numpy as np
10
+ import imageio.v3 as iio
11
+ import spaces
12
+ import torch
13
+ import gradio as gr
14
+ from PIL import Image, ImageOps
15
+ from huggingface_hub import hf_hub_download
16
+ from safetensors.torch import load_file
17
+
18
+ from diffusers import LTX2InContextPipeline
19
+ from diffusers.pipelines.ltx2.pipeline_ltx2_ic_lora import LTX2ReferenceCondition
20
+ from diffusers.pipelines.ltx2.utils import DISTILLED_SIGMA_VALUES
21
+ from diffusers.utils import load_video, encode_video
22
+
23
+ # --- Config -----------------------------------------------------------------
24
+ BASE_MODEL = "diffusers/LTX-2.3-Distilled-Diffusers"
25
+ LORA_REPO = "linoyts/LTX-2.3-loras"
26
+ LORA_FILE = "ltx-2.3-22b-ic-lora-decompression-0.9.safetensors"
27
+ LORA_SCALE = 1.0
28
+ FPS = 24
29
+ NUM_STEPS = len(DISTILLED_SIGMA_VALUES)
30
+ MAX_SEED = np.iinfo(np.int32).max
31
+ HF_TOKEN = os.environ.get("HF_TOKEN")
32
+
33
+ RES_PRESETS = {"Fast (768×448)": (768, 448), "Quality (960×544)": (960, 544)}
34
+ FRAME_CHOICES = [49, 73, 97, 121]
35
+
36
+ pipe = LTX2InContextPipeline.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16)
37
+ pipe.to("cuda")
38
+ pipe.vae.enable_tiling()
39
+ _lora_path = hf_hub_download(LORA_REPO, LORA_FILE, token=HF_TOKEN)
40
+ pipe.load_lora_weights(load_file(_lora_path), adapter_name="decompress")
41
+ pipe.set_adapters("decompress", LORA_SCALE)
42
+
43
+
44
+ def _src_fps(path, default=FPS):
45
+ try:
46
+ return float(iio.immeta(path, plugin="pyav").get("fps", default)) or default
47
+ except Exception:
48
+ return default
49
+
50
+
51
+ def _load_frames(path, num_frames, width, height):
52
+ frames = load_video(path)
53
+ if not frames:
54
+ return []
55
+ fps = _src_fps(path)
56
+ out = []
57
+ for i in range(num_frames):
58
+ idx = min(int(round(i / FPS * fps)), len(frames) - 1)
59
+ out.append(ImageOps.fit(frames[idx].convert("RGB"), (width, height), Image.LANCZOS))
60
+ return out
61
+
62
+
63
+ def _pick_resolution(first_frame, preset):
64
+ w, h = RES_PRESETS[preset]
65
+ if first_frame.height > first_frame.width:
66
+ w, h = h, w
67
+ return w, h
68
+
69
+
70
+ def _build_prompt(scene, audio):
71
+ scene = scene.strip() or "the scene"
72
+ p = (
73
+ f"Reference shows {scene}, heavily compressed with visible macroblocking, chroma bleed, and ringing artifacts. "
74
+ f"Edited shows the same scene restored to high quality with sharp detail, clean edges, and no compression artifacts. "
75
+ f"ENHANCE QUALITY {scene}. "
76
+ f"Subject identity, framing, and background geometry are identical to the reference; "
77
+ f"only compression artifacts and image quality differ between reference and edited."
78
+ )
79
+ if audio.strip():
80
+ p += f" Audio: {audio.strip()}."
81
+ return p
82
+
83
+
84
+ def _export(video_np, audio, path):
85
+ kw = {}
86
+ if audio is not None:
87
+ kw = dict(audio=audio[0].float().cpu(), audio_sample_rate=pipe.vocoder.config.output_sampling_rate)
88
+ encode_video(video_np, fps=FPS, output_path=path, **kw)
89
+
90
+
91
+ def _duration(*args, **kwargs):
92
+ preset = next((a for a in args if a in RES_PRESETS), "Fast")
93
+ num_frames = next((a for a in args if a in FRAME_CHOICES), 73)
94
+ per_frame = 1.6 if "Quality" in str(preset) else 1.0
95
+ return int(60 + int(num_frames) * per_frame)
96
+
97
+
98
+ @spaces.GPU(duration=_duration)
99
+ def decompress(video, scene, audio, preset, num_frames, seed, randomize,
100
+ progress=gr.Progress(track_tqdm=True)):
101
+ if video is None:
102
+ raise gr.Error("Please upload a compressed / low-bitrate video.")
103
+ if randomize:
104
+ seed = random.randint(0, MAX_SEED)
105
+ seed = int(seed)
106
+ num_frames = int(num_frames)
107
+
108
+ probe = load_video(video)
109
+ if not probe:
110
+ raise gr.Error("Could not read any frames from that video.")
111
+ width, height = _pick_resolution(probe[0], preset)
112
+ ref = _load_frames(video, num_frames, width, height)
113
+ prompt = _build_prompt(scene, audio)
114
+
115
+ def _cb(p, i, t, kw):
116
+ progress((i + 1) / NUM_STEPS, desc=f"Restoring — step {i + 1}/{NUM_STEPS}")
117
+ return {}
118
+
119
+ video_out, audio_out = pipe(
120
+ prompt=prompt, negative_prompt="",
121
+ reference_conditions=[LTX2ReferenceCondition(frames=ref, strength=1.0)],
122
+ reference_downscale_factor=1,
123
+ width=width, height=height, num_frames=num_frames, frame_rate=FPS,
124
+ num_inference_steps=NUM_STEPS, sigmas=DISTILLED_SIGMA_VALUES,
125
+ guidance_scale=1.0, stg_scale=0.0, audio_guidance_scale=1.0, audio_stg_scale=0.0,
126
+ generator=torch.Generator(device="cuda").manual_seed(seed),
127
+ output_type="np", return_dict=False, callback_on_step_end=_cb,
128
+ )
129
+ out_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
130
+ _export(video_out[0], audio_out, out_path)
131
+ return out_path, seed
132
+
133
+
134
+ with gr.Blocks(title="LTX-2.3 Decompress") as demo:
135
+ gr.Markdown(
136
+ "# 🧼 LTX-2.3 Video Decompression\n"
137
+ "Remove compression artifacts — macroblocking, chroma bleed, ringing, banding — from low-bitrate / "
138
+ "heavily-compressed video, restoring sharp detail while keeping subject, framing, and geometry intact. "
139
+ "Optionally describe the soundscape for generated audio. "
140
+ "IC-LoRA: [`linoyts/LTX-2.3-loras`](https://huggingface.co/linoyts/LTX-2.3-loras) · base: distilled LTX-2.3."
141
+ )
142
+ with gr.Row():
143
+ with gr.Column():
144
+ video_in = gr.Video(label="Compressed / low-bitrate video")
145
+ scene = gr.Textbox(label="Scene description (optional)", lines=2,
146
+ placeholder="a busy city street with pedestrians and storefronts in daylight")
147
+ audio = gr.Textbox(label="Sound / audio (optional)", lines=1,
148
+ placeholder="city ambience, footsteps, distant traffic")
149
+ with gr.Accordion("Settings", open=False):
150
+ preset = gr.Dropdown(list(RES_PRESETS), value="Fast (768×448)", label="Resolution")
151
+ num_frames = gr.Dropdown(FRAME_CHOICES, value=73, label="Frames (24fps)")
152
+ randomize = gr.Checkbox(True, label="Randomize seed")
153
+ seed = gr.Slider(0, MAX_SEED, value=42, step=1, label="Seed")
154
+ run = gr.Button("Restore", variant="primary")
155
+ with gr.Column():
156
+ video_out = gr.Video(label="Restored result")
157
+ used_seed = gr.Number(label="Seed used", interactive=False)
158
+
159
+ run.click(decompress, inputs=[video_in, scene, audio, preset, num_frames, seed, randomize],
160
+ outputs=[video_out, used_seed])
161
+
162
+ gr.Examples(
163
+ examples=[
164
+ ["examples/people_compressed.mp4",
165
+ "two people slow dancing together in a warm-lit room, smiling",
166
+ "soft music, gentle footsteps, a quiet room tone",
167
+ "Fast (768×448)", 73, 42, False],
168
+ ["examples/landscape_compressed.mp4",
169
+ "a misty green mountain landscape over calm still water",
170
+ "gentle wind over water, distant birdsong",
171
+ "Fast (768×448)", 73, 42, False],
172
+ ],
173
+ inputs=[video_in, scene, audio, preset, num_frames, seed, randomize],
174
+ outputs=[video_out, used_seed], fn=decompress, cache_examples=True, cache_mode="lazy",
175
+ )
176
+
177
+ if __name__ == "__main__":
178
+ demo.launch(show_error=True)
examples/landscape_compressed.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:147eb9a424e835629eba177c99d210f36c7409699fa862b0cbbdfd6c96b2f074
3
+ size 352741
examples/people_compressed.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:97bf8f9791287330119c57ac820dff95782ebb6c5e5102b878779ff7ec824093
3
+ size 387634
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ git+https://github.com/huggingface/diffusers
2
+ transformers
3
+ accelerate
4
+ peft
5
+ safetensors
6
+ sentencepiece
7
+ imageio
8
+ imageio-ffmpeg
9
+ av