
QwenImageEdit2509で、ピクセル単位で一致する線画の作り方わかった!!!!
— とりにく (@tori29umai) October 1, 2025
①まず線画LoRAを作ります
②画像のサイズを1メガピクセルかつ16の倍数にリサイズ
③リサイズした画像の縦横をそれぞれ-8したサイズで画像をさらにリサイズして、下と右に白い余白を追加する… pic.twitter.com/sFSe356OMa
修正:右・下-8固定にしてたけど、解像度によって変わるみたい。 ひとまず、 (1024, 1024), (1152, 896), (896, 1152), (1216, 832), (832, 1216), (1344, 768), (768, 1344), (1536, 640), (640, 1536), のパターンではこんな感じの法則性で、ズレがあったのでその分小さくして、白い余白追加した pic.twitter.com/3qi6S1M4iT
— とりにく (@tori29umai) October 1, 2025
こんな感じの検証をしているので報告。
一先ず検証中のLoRA(まだ学習途上です)
prompt
Converts an image into a pixel-precise line drawing, devoid of color or shading information, just line drawings.こんな感じの組み合わせで学習素材25枚で学習


[general]
resolution = [1024, 1024]
caption_extension = ".txt"
batch_size = 1
enable_bucket = true
bucket_no_upscale = false
[[datasets]]
image_directory = "./mp4_dataset/QIE_image2line_V5/image"
control_directory = "./mp4_dataset/QIE_image2line_V5/control"
cache_directory = "./mp4_dataset/QIE_image2line_V5/cache"
qwen_image_edit_control_resolution = [1024, 1024]学習コマンド
accelerate launch src/musubi_tuner/qwen_image_train_network.py \
--edit_plus \
--dit "./Qwen-Image_models/dit/qwen_image_edit_2509_bf16.safetensors" \
--vae "./Qwen-Image_models/vae/diffusion_pytorch_model.safetensors" \
--text_encoder "./Qwen-Image_models/text_encoder/qwen_2.5_vl_7b.safetensors" \
--dataset_config "./mp4_dataset/QIE_image2line_V5/image2line.toml" \
--mixed_precision bf16 \
--flash_attn \
--timestep_sampling shift \
--weighting_scheme none \
--discrete_flow_shift 2.0 \
--optimizer_type adamw8bit \
--learning_rate 1e-3 \
--gradient_checkpointing \
--max_data_loader_n_workers 2 \
--persistent_data_loader_workers \
--network_module networks.lora_qwen_image \
--network_dim 4 \
--max_train_epochs 100 \
--save_every_n_epochs 1 \
--seed 42 \
--output_dir "train_LoRA" \
--output_name QIE_image2line_V5_dim4_1e-3 \
--ddp_gradient_as_bucket_view \
--ddp_static_graphなんかQwenImageEditのズレに法則性があることに気づいたので、事前の画像処理で解決できないか検証してみました。
こんな感じでのコードをPython Interpreter(ComfyUIのカスタムノードで簡単なpythonコードをComfyUIの中で動かせる)で事前処理させました
import torch
from torchvision.transforms import ToPILImage
from PIL import Image
import numpy as np
# 1) NHWC [1,H,W,3] -> [H,W,3]
nhwc = image1.data
assert nhwc.ndim == 4 and nhwc.shape[-1] in (1,3), f"Unexpected shape: {nhwc.shape}"
hwc = nhwc.squeeze(0) # [H,W,C]
# 2) ToPILImage は [C,H,W] を想定するので変換
chw = hwc.permute(2, 0, 1).contiguous() # [C,H,W]
pil_img = ToPILImage()(chw)
# 3) 候補解像度の中で最も近いアスペクト比を選ぶ
candidates = [
(1024, 1024),
(1152, 896), (896, 1152),
(1216, 832), (832, 1216),
(1344, 768), (768, 1344),
(1536, 640), (640, 1536),
]
_w, _h = pil_img.size
_src_ratio = _w / _h
def _ratio(wh): return wh[0] / wh[1]
best_w, best_h = min(candidates, key=lambda s: abs(_src_ratio - _ratio(s)))
# 正方形は 1024x1024 を優先
if best_w == best_h:
target_size = (1024, 1024)
else:
target_size = (best_w, best_h)
# 4) 候補サイズにリサイズ(Lanczos)
pil_img = pil_img.resize(target_size, Image.LANCZOS)
w, h = pil_img.size
print(f"chosen size: {w}x{h}")
# 4) 解像度ごとの余白設定(left, top, right, bottom)
pad_map = {
(1024, 1024): (0, 0, 0, 0),
(1152, 896): (0, 0, 8, 8),
( 896, 1152): (0, 0, 8, 8),
(1216, 832): (16,4, 8, 16),
( 832, 1216): (4,16, 16, 8),
(1344, 768): (0, 0, 8, 8),
( 768, 1344): (0, 0, 8, 8),
(1536, 640): (16,16,32,8),
( 640, 1536): (16,16,8,32),
}
# chosen size(= target_size)に対するパディングを取得
best_w, best_h = target_size
left, top, right, bottom = pad_map.get((best_w, best_h), (0, 0, 0, 0))
# 5) 先に“足す分だけ”小さくしてから足す(最終は必ず chosen size)
inner_w = max(1, best_w - (left + right))
inner_h = max(1, best_h - (top + bottom))
print(f"chosen size: {best_w}x{best_h}, padding(L,T,R,B)=({left},{top},{right},{bottom}), inner={inner_w}x{inner_h}")
# 6) 内側サイズにリサイズ(Lanczos)
resized = pil_img.resize((inner_w, inner_h), Image.LANCZOS)
# 7) 白キャンバス(= chosen size)に (left, top) で貼り付け
final_img = Image.new("RGB", (best_w, best_h), (255, 255, 255))
final_img.paste(resized, (left, top))
# 8) PIL -> NHWC float [1,H,W,3](ComfyUI形式)
arr = np.array(final_img) # uint8 [H,W,3]
out = torch.from_numpy(arr).to(torch.float32) / 255.0
out = out.unsqueeze(0).contiguous() # [1,H,W,3]
image1.data = out
とりあえずこれで自分の環境ではピクセル単位の一致はするようになりました
QwenImageEdit2509のズレ、解像度によって、ズレが変わるから、リストの中からアスペクト比が違いものを選んで、そのアスペクト比にリサイズしてから、ズレ補正をしたら、色んなサイズの画像で、ピクセル単位の一致ができた pic.twitter.com/7k7ptIfNaZ
— とりにく (@tori29umai) October 1, 2025