Views
No views yet
![]() Generated Video |
![]() Input |
1import torch
2from diffusers import AutoencoderKLWan, WanImageToVideoPipeline
3from diffusers.utils import export_to_video, load_image
4from transformers import CLIPVisionModel
5from huggingface_hub import hf_hub_download
6from typing import List, Tuple, Union
7from PIL import Image, ImageOps
8
9
10def pil_resize(
11 image: Image.Image,
12 target_size: Tuple[int, int],
13 pad_input: bool = False,
14 padding_color: Union[str, int, Tuple[int, ...]] = "white",
15) -> Image.Image:
16 """Resizing it to the target size.
17
18 Args:
19 image: Input image to be processed.
20 target_size: Target size (width, height).
21 pad_input: If set resizes the image while keeping the aspect ratio and pads the unfilled part.
22 padding_color: The color for the padded pixels.
23
24 Returns:
25 The resized image
26 """
27 if pad_input:
28 # Resize image, keep aspect ratio
29 image = ImageOps.contain(image, size=target_size)
30 # Pad while keeping image in center
31 image = ImageOps.pad(image, size=target_size, color=padding_color)
32 else:
33 image = image.resize(target_size)
34 return image
35
36
37def undo_pil_resize(
38 image: Image.Image,
39 target_size: Tuple[int, int],
40) -> Image.Image:
41 """Undo the resizing and padding of the input image to the a new image with size target_size.
42
43 Args:
44 image: Input image to be processed.
45 target_size: Target size (width, height).
46
47 Returns:
48 The resized image
49 """
50 tmp_img = Image.new(mode="RGB", size=target_size)
51 # Get the resized image size
52 tmp_img = ImageOps.contain(tmp_img, size=image.size)
53
54 # Undo padding by center cropping
55 width, height = image.size
56 tmp_width, tmp_height = tmp_img.size
57
58 left = int(round((width - tmp_width) / 2.0))
59 top = int(round((height - tmp_height) / 2.0))
60 right = left + tmp_width
61 bottom = top + tmp_height
62 cropped = image.crop((left, top, right, bottom))
63
64 # Undo resizing
65 ret = cropped.resize(target_size)
66 return ret
67
68# Set to True if you have a GPU with less than 80GB VRAM --> Very slow inference!
69enable_sequential_cpu_offload = True
70
71# Download the LoRA file
72lora_path = hf_hub_download(repo_id="Markus-Pobitzer/wlp-lora", filename="base.safetensors")
73print(f"LoRA path: {lora_path}")
74
75# Loads the pipeline
76model_id = "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
77vae = AutoencoderKLWan.from_pretrained(model_id, subfolder="vae", torch_dtype=torch.float32)
78image_encoder = CLIPVisionModel.from_pretrained(
79 model_id, subfolder="image_encoder", torch_dtype=torch.float32
80)
81# Takes more than 100 GB of disk space
82pipe = WanImageToVideoPipeline.from_pretrained(
83 model_id, vae=vae, image_encoder=image_encoder, torch_dtype=torch.bfloat16
84)
85
86# Load LoRA
87pipe.load_lora_weights(lora_path)
88pipe.fuse_lora()
89
90# Either offload or directly to GPU
91if enable_sequential_cpu_offload:
92 pipe.enable_sequential_cpu_offload()
93else:
94 pipe.to("cuda")
95
96
97### INFERENCE ###
98image = load_image(
99 "https://uploads3.wikiart.org/images/claude-monet/haystacks-at-giverny.jpg"
100)
101og_size = image.size
102height = 480
103width = 832
104# Resize and pad
105ref_image = pil_resize(image, target_size=(width, height), pad_input=True)
106prompt = "Painting process step by step."
107
108output = pipe(
109 image=ref_image,
110 prompt=prompt,
111 height=height,
112 width=width,
113 num_frames=81,
114 output_type="pil",
115 guidance_scale=1.0,
116).frames[0]
117# To original image size
118output = [undo_pil_resize(img, og_size) for img in output][::-1]
119# Save video
120export_to_video(output, "output.mp4", fps=3)lora_path = hf_hub_download(repo_id="Markus-Pobitzer/wlp-lora", filename="art_media_transfer.safetensors")1art_media = "..."
2painting_desc = "..."
3prompt = f"<{art_media}> Painting process step by step. {painting_desc}"prompt = f"<acrylic> Painting process step by step. The image depicts a serene landscape with a small brown and green island in the center of a body of water, surrounded by green trees and a few boats. The sky is blue with scattered clouds, and there are birds flying in the background."prompt = f"<pencil> Painting process step by step. The image depicts a serene landscape with a small island in the center of a body of water, surrounded by trees and a few boats. There are scattered clouds, and birds flying in the background."1@misc{pobitzer2025loomispainter,
2 title={Loomis Painter: Reconstructing the Painting Process},
3 author={Markus Pobitzer and Chang Liu and Chenyi Zhuang and Teng Long and Bin Ren and Nicu Sebe},
4 year={2025},
5 eprint={2511.17344},
6 archivePrefix={arXiv},
7 primaryClass={cs.CV},
8 url={https://arxiv.org/abs/2511.17344},
9}