ReActorとは?
face swap は deepfake として何年も前から存在しますが、当時は同じ人物の顔画像を何百枚も集めて学習させる必要がありました。
ReActor(正確にはそのコアである InsightFace )は、1枚の顔写真だけを参照にして、別の画像や動画に映っている顔を差し替えることができます。
現在は拡散モデルベースのより柔軟な ID 転送手段も登場していますが、ReActor は「比較的軽い」「良い意味で柔軟性がなく安定している」といった理由から、現在でもよく使われている手法です。
カスタムノードとインストール
インストール方法
このノードは導入が少し難しく、ComfyUI Manager からインストールするだけでは動きません。
-
- ComfyUI Manager から ReActor ノードをインストール。
-
ComfyUI/custom_nodes/ComfyUI-ReActor にある install.bat を実行。
-
- Windows ユーザーはこれだけでは動かず、別途 InsightFace のインストールが必要です。
-
- ComfyUI を再起動。
FaceSwap(inswapper)
基本的な FaceSwap は、ReActor ノードに「元画像」と「参照顔画像」を入力するだけです。
ReActor_Fast_Face_Swap.json
{
"id": "1b2ef2ef-9149-46e0-a6c1-7beda89a1fe6",
"revision": 0,
"last_node_id": 14,
"last_link_id": 23,
"nodes": [
{
"id": 12,
"type": "LoadImage",
"pos": [
160.4533870022538,
834.9161229359444
],
"size": [
496.38248812500007,
534.2926
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
21
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"pasted/image (6).png",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
160.4533870022538,
311.54146328666025
],
"size": [
497.8093985382229,
461.5989689256197
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
20
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"pasted/image (8).png",
"image"
]
},
{
"id": 1,
"type": "ReActorFaceSwap",
"pos": [
697.0210160550583,
311.54146328666025
],
"size": [
302.6424812758264,
358
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "input_image",
"type": "IMAGE",
"link": 20
},
{
"name": "source_image",
"shape": 7,
"type": "IMAGE",
"link": 21
},
{
"name": "face_model",
"shape": 7,
"type": "FACE_MODEL",
"link": null
},
{
"name": "face_boost",
"shape": 7,
"type": "FACE_BOOST",
"link": null
}
],
"outputs": [
{
"name": "SWAPPED_IMAGE",
"type": "IMAGE",
"links": [
23
]
},
{
"name": "FACE_MODEL",
"type": "FACE_MODEL",
"links": null
},
{
"name": "ORIGINAL_IMAGE",
"type": "IMAGE",
"links": null
}
],
"properties": {
"Node name for S&R": "ReActorFaceSwap"
},
"widgets_values": [
true,
"inswapper_128.onnx",
"retinaface_resnet50",
"GFPGANv1.3.pth",
0.5,
0.5,
"no",
"no",
"0,2",
"0,1",
1
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 14,
"type": "SaveImage",
"pos": [
1038.4217278454664,
311.54146328666025
],
"size": [
701.97,
560.1500000000001
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 23
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76"
},
"widgets_values": [
"ComfyUI"
]
}
],
"links": [
[
20,
2,
0,
1,
0,
"IMAGE"
],
[
21,
12,
0,
1,
1,
"IMAGE"
],
[
23,
1,
0,
14,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.8264462809917354,
"offset": [
-60.453387002253805,
-211.54146328666025
]
},
"workflowRendererVersion": "LG",
"frontendVersion": "1.33.10",
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}
input_image
source_image
- 参照したい顔画像(1枚の顔写真など)を接続します。
その他、よく使うパラメータを簡単にまとめます。
face_restore_model
GFPGANv1.3 を選ぶと、FaceSwap 後に GFPGAN による顔修復をかけます。
inswapper は顔の部分を 128px 四方にリサイズして処理するため、そのままだとディテールが失われやすく、このような後処理が重要になります。
- ただ、どうしてもノッペリした印象になりやすい点には注意が必要です。
detect_gender_input / detect_gender_source
- 入力画像・参照画像の性別を自動判定するかどうかの設定です。
- 性別の違いによって結果が不自然になる場合は、ON/OFF を切り替えて試してみるとよいでしょう。
input_faces_index
- 元画像の中に複数人の顔がある場合、どの顔を対象にするかを指定します。
0 が最初に見つかった顔、1 が2人目……というイメージです。
0,1 のようにカンマ区切りで複数指定すると、複数人を同時に置き換えることもできます。
source_faces_index
- 参照側の
source_image に複数人の顔がある場合、どの顔を使うかを input_faces_index と同じように指定します。
別の FaceSwap モデルを使う(HyperSwap)
先程使用した inswapper は、古いモデルということもありますが、社会的影響を考え、開発者によって高解像度版が封印されています。
代替モデルはいくつかありますが、FaceFusion Labs が開発している HyperSwap を使ってみましょう。
モデルのダウンロード
📂ComfyUI/
└── 📂models/
└── 📂hyperswap/
└── hyperswap_1a_256.onnx
workflow の設定
{
"id": "1b2ef2ef-9149-46e0-a6c1-7beda89a1fe6",
"revision": 0,
"last_node_id": 15,
"last_link_id": 23,
"nodes": [
{
"id": 12,
"type": "LoadImage",
"pos": [
160.4533870022538,
834.9161229359444
],
"size": [
496.38248812500007,
534.2926
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
21
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"pasted/image (10).png",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
160.4533870022538,
311.54146328666025
],
"size": [
497.8093985382229,
461.5989689256197
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
20
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"pasted/image (11).png",
"image"
]
},
{
"id": 1,
"type": "ReActorFaceSwap",
"pos": [
697.7024819970889,
311.54146328666025
],
"size": [
302.6424812758264,
358
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "input_image",
"type": "IMAGE",
"link": 20
},
{
"name": "source_image",
"shape": 7,
"type": "IMAGE",
"link": 21
},
{
"name": "face_model",
"shape": 7,
"type": "FACE_MODEL",
"link": null
},
{
"name": "face_boost",
"shape": 7,
"type": "FACE_BOOST",
"link": null
}
],
"outputs": [
{
"name": "SWAPPED_IMAGE",
"type": "IMAGE",
"links": [
23
]
},
{
"name": "FACE_MODEL",
"type": "FACE_MODEL",
"links": null
},
{
"name": "ORIGINAL_IMAGE",
"type": "IMAGE",
"links": null
}
],
"properties": {
"Node name for S&R": "ReActorFaceSwap"
},
"widgets_values": [
true,
"hyperswap_1a_256.onnx",
"retinaface_resnet50",
"GFPGANv1.3.pth",
0.5,
0.5,
"no",
"no",
"0",
"0",
1
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 15,
"type": "SaveImage",
"pos": [
1039.7846597295274,
311.54146328666025
],
"size": [
701.97,
560.1500000000001
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 23
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.76"
},
"widgets_values": [
"ComfyUI"
]
}
],
"links": [
[
20,
2,
0,
1,
0,
"IMAGE"
],
[
21,
12,
0,
1,
1,
"IMAGE"
],
[
23,
1,
0,
15,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.7513148009015777,
"offset": [
-60.453387002253805,
-211.54146328666025
]
},
"workflowRendererVersion": "LG",
"frontendVersion": "1.33.10",
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}
- ReActor ノードの
swap_model を、hyperswap_1a_256 に変更します。
NSFWフィルターについて
リポジトリが削除されないようにするため、ReActor には NSFW な画像に対するフィルターが入っています。
そのため、NSFW を含む画像を使った場合拒否されます。
あまり詳しくはいいませんが、簡単な手段で回避することは出来ます。
( Detailer が役に立つ……かもしれません )