color match

This commit is contained in:
JJ
2025-11-25 01:18:44 +00:00
parent b594550a9f
commit 89aca4ba2f
3 changed files with 481 additions and 349 deletions
+366 -339
View File
@@ -1,8 +1,8 @@
{
"id": "c6e410bc-5e2c-460b-ae81-c91b6094fbb1",
"revision": 0,
"last_node_id": 167,
"last_link_id": 363,
"last_node_id": 168,
"last_link_id": 372,
"nodes": [
{
"id": 92,
@@ -890,7 +890,8 @@
2,
"linear",
0,
0.01
0.01,
"[2.0, 1.0, 1.0, 1.0, 1.0, 1.0]"
]
},
{
@@ -1140,12 +1141,12 @@
"hidden": false,
"paused": false,
"params": {
"filename": "WanVideo2_2_I2V_00005.mp4",
"filename": "WanVideo2_2_I2V_00002.mp4",
"subfolder": "",
"type": "temp",
"format": "video/h264-mp4",
"frame_rate": 16,
"workflow": "WanVideo2_2_I2V_00005.png",
"workflow": "WanVideo2_2_I2V_00002.png",
"fullpath": ""
}
}
@@ -1278,12 +1279,12 @@
"hidden": false,
"paused": false,
"params": {
"filename": "WanVideo2_2_I2V_00003.mp4",
"filename": "WanVideo2_2_I2V_00001.mp4",
"subfolder": "",
"type": "temp",
"format": "video/h264-mp4",
"frame_rate": 16,
"workflow": "WanVideo2_2_I2V_00003.png",
"workflow": "WanVideo2_2_I2V_00001.png",
"fullpath": ""
}
}
@@ -1312,7 +1313,7 @@
263,
278,
301,
346
365
]
},
{
@@ -1496,7 +1497,8 @@
"name": "IMAGE",
"type": "IMAGE",
"links": [
352
352,
366
]
},
{
@@ -1540,7 +1542,7 @@
"name": "IMAGE",
"type": "IMAGE",
"links": [
345
364
]
},
{
@@ -1564,192 +1566,6 @@
"image"
]
},
{
"id": 155,
"type": "PreviewImage",
"pos": [
-499.9862067775319,
491.79242257161894
],
"size": [
210,
667.7696706327888
],
"flags": {},
"order": 26,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 347
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.71",
"Node name for S&R": "PreviewImage",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": []
},
{
"id": 158,
"type": "MaskPreview+",
"pos": [
-268.09960736634764,
490.45363849199936
],
"size": [
210,
668.6430337189952
],
"flags": {},
"order": 27,
"mode": 0,
"inputs": [
{
"name": "mask",
"type": "MASK",
"link": 350
}
],
"outputs": [],
"properties": {
"cnr_id": "comfyui_essentials",
"ver": "9d9f4bedfc9f0321c19faf71855e228c93bd0dc9",
"Node name for S&R": "MaskPreview+",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": []
},
{
"id": 161,
"type": "CreateImageList",
"pos": [
-492.1722697061646,
281.26596728639873
],
"size": [
270,
118
],
"flags": {},
"order": 22,
"mode": 0,
"inputs": [
{
"name": "image1",
"shape": 7,
"type": "IMAGE",
"link": 345
},
{
"name": "image2",
"type": "IMAGE",
"link": 346
},
{
"name": "image3",
"type": "IMAGE",
"link": 352
},
{
"name": "image4",
"type": "IMAGE",
"link": null
}
],
"outputs": [
{
"name": "images",
"type": "IMAGE",
"links": [
347,
348,
349
]
},
{
"name": "masks",
"type": "MASK",
"links": [
350,
351
]
}
],
"properties": {
"cnr_id": "wanvideowrapper_qq",
"ver": "91d07cb0be299bb8c2c83b6d77faa422959a9b1f",
"Node name for S&R": "CreateImageList",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": [
true
],
"shape": 1
},
{
"id": 124,
"type": "LoadImage",
"pos": [
-484.35588731056015,
-95.80907240982795
],
"size": [
274.080078125,
314.0000000000001
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
218
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.71",
"Node name for S&R": "LoadImage",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": [
"bg.png",
"image"
],
"color": "#432",
"bgcolor": "#653",
"shape": 1
},
{
"id": 126,
"type": "ImageResizeKJv2",
@@ -1764,7 +1580,7 @@
"flags": {
"collapsed": true
},
"order": 23,
"order": 22,
"mode": 0,
"inputs": [
{
@@ -1842,7 +1658,8 @@
"0, 0, 0",
"center",
16,
"cpu"
"cpu",
"<tr><td>Output: </td><td><b>1</b> x <b>800</b> x <b>656 | 6.01MB</b></td></tr>"
]
},
{
@@ -1995,12 +1812,12 @@
"hidden": false,
"paused": false,
"params": {
"filename": "AnimateDiff_00007.mp4",
"filename": "AnimateDiff_00003.mp4",
"subfolder": "",
"type": "temp",
"format": "video/h264-mp4",
"frame_rate": 16,
"workflow": "AnimateDiff_00007.png",
"workflow": "AnimateDiff_00003.png",
"fullpath": ""
}
}
@@ -2077,80 +1894,17 @@
"hidden": false,
"paused": false,
"params": {
"filename": "AnimateDiff_00008.mp4",
"filename": "AnimateDiff_00004.mp4",
"subfolder": "",
"type": "temp",
"format": "video/h264-mp4",
"frame_rate": 16,
"workflow": "AnimateDiff_00008.png",
"workflow": "AnimateDiff_00004.png",
"fullpath": ""
}
}
}
},
{
"id": 121,
"type": "GetImageRangeFromBatch",
"pos": [
723.1343342581331,
178.8695429625597
],
"size": [
340.3267578125,
102
],
"flags": {
"collapsed": true
},
"order": 34,
"mode": 0,
"inputs": [
{
"name": "images",
"shape": 7,
"type": "IMAGE",
"link": 211
},
{
"name": "masks",
"shape": 7,
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
212,
362
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfyui-kjnodes",
"ver": "6ee278aa7d802c03ad713a7c5fbc02861b6773a8",
"Node name for S&R": "GetImageRangeFromBatch",
"ue_properties": {
"widget_ue_connectable": {
"num_frames": true
},
"version": "7.3",
"input_ue_unconnectable": {}
},
"aux_id": "kijai/ComfyUI-KJNodes"
},
"widgets_values": [
0,
1
]
},
{
"id": 89,
"type": "WanVideoImageToVideoEncode",
@@ -2288,7 +2042,7 @@
139.1564075673432
],
"flags": {},
"order": 14,
"order": 13,
"mode": 0,
"inputs": [],
"outputs": [
@@ -2334,7 +2088,7 @@
258
],
"flags": {},
"order": 28,
"order": 26,
"mode": 0,
"inputs": [
{
@@ -2433,7 +2187,7 @@
"flags": {
"collapsed": true
},
"order": 15,
"order": 14,
"mode": 0,
"inputs": [],
"outputs": [
@@ -2487,13 +2241,13 @@
{
"name": "ref_images",
"type": "IMAGE",
"link": 349
"link": 369
},
{
"name": "ref_masks",
"shape": 7,
"type": "MASK",
"link": 351
"link": 371
},
{
"name": "frames",
@@ -2556,7 +2310,7 @@
738
],
"flags": {},
"order": 29,
"order": 28,
"mode": 0,
"inputs": [
{
@@ -2569,7 +2323,7 @@
"name": "ref_images",
"shape": 7,
"type": "IMAGE",
"link": 348
"link": 368
},
{
"name": "frames",
@@ -2620,7 +2374,7 @@
}
},
"widgets_values": [
"[{\"on\":true,\"name\":\"Box 1\",\"type\":\"box_layer\",\"interpolation\":\"box\",\"repeat\":1,\"offset\":0,\"a_pause\":0,\"z_pause\":0,\"easing\":\"in_out\",\"easingConfig\":{\"path\":\"full\",\"strength\":1,\"acceleration\":0},\"driven\":false,\"_drivenConfig\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"scale\":1,\"points_store\":\"[{\\\"x\\\":0.3474681352975962,\\\"y\\\":0.8035198065615633,\\\"highlighted\\\":false,\\\"boxScale\\\":0.49486250274459376,\\\"pointScale\\\":0.49486250274459376,\\\"scale\\\":0.49486250274459376,\\\"rotation\\\":0,\\\"boxRotation\\\":0}]\",\"coordinates\":\"[]\",\"box_keys\":[{\"frame\":1,\"x\":0.17509084505505768,\"y\":0.8303768607157191,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":3,\"x\":0.16230817242646217,\"y\":0.8434348208345157,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":8,\"x\":0.16230817242646217,\"y\":0.8434348208345157,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":17,\"x\":0.37061313065648793,\"y\":0.7985304297774442,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":22,\"x\":0.3101511961248443,\"y\":0.7530653147096042,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":25,\"x\":0.30787570430834565,\"y\":0.8420188007118998,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":30,\"x\":0.25489021568489956,\"y\":0.8325304530018323,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":35,\"x\":0.363786853610673,\"y\":0.8368793142254553,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":40,\"x\":0.2805702985195647,\"y\":0.8436002925393168,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":44,\"x\":0.3407072478218575,\"y\":0.8281817124290963,\"scale\":0.45690062408212573,\"rotation\":0}],\"box_timeline_point\":16,\"box_interpolation\":\"linear\",\"ref_attachment\":{\"entries\":[{\"path\":\"bg/ref_image_0.png\",\"type\":\"image/png\",\"width\":300,\"height\":546,\"name\":\"ref_image_0.png\"},{\"path\":\"bg/ref_image_1.png\",\"type\":\"image/png\",\"width\":457,\"height\":586,\"name\":\"ref_image_1.png\"},{\"path\":\"bg/ref_image_2.png\",\"type\":\"image/png\",\"width\":512,\"height\":768,\"name\":\"ref_image_2.png\"}]},\"ref_selection\":\"ref_2\"},{\"on\":true,\"name\":\"Box 1_1\",\"type\":\"box_layer\",\"interpolation\":\"box\",\"repeat\":1,\"offset\":0,\"a_pause\":0,\"z_pause\":0,\"easing\":\"in_out\",\"easingConfig\":{\"path\":\"full\",\"strength\":1,\"acceleration\":0},\"driven\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"_drivenConfig\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"scale\":1,\"points_store\":\"[{\\\"x\\\":0.6806348749052255,\\\"y\\\":0.7474313451231609,\\\"highlighted\\\":false,\\\"boxScale\\\":0.6940336804011772,\\\"pointScale\\\":0.6940336804011772,\\\"scale\\\":0.6940336804011772,\\\"rotation\\\":0,\\\"boxRotation\\\":0,\\\"uid\\\":16981}]\",\"coordinates\":\"[]\",\"box_keys\":[{\"frame\":1,\"x\":0.6302263722980433,\"y\":0.7737771727381784,\"scale\":0.312739506683858,\"rotation\":0},{\"frame\":9,\"x\":0.7801197829741051,\"y\":0.7550457649727679,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":16,\"x\":0.6806348749052255,\"y\":0.7474313451231609,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":21,\"x\":0.7156002654484349,\"y\":0.6992066860756498,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":24,\"x\":0.7384942877962534,\"y\":0.7692594416414953,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":36,\"x\":0.688959973940796,\"y\":0.7697671006146228,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":46,\"x\":0.8155014538752791,\"y\":0.7885493982099611,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":52,\"x\":0.7476519475477528,\"y\":0.7860112582600921,\"scale\":1.0468844700694617,\"rotation\":0}],\"box_timeline_point\":16,\"box_interpolation\":\"linear\",\"ref_attachment\":{\"entries\":[{\"path\":\"bg/ref_image_0.png\",\"type\":\"image/png\",\"width\":400,\"height\":471,\"name\":\"ref_image_0.png\"},{\"path\":\"bg/ref_image_1.png\",\"type\":\"image/png\",\"width\":457,\"height\":586,\"name\":\"ref_image_1.png\"},{\"path\":\"bg/ref_image_2.png\",\"type\":\"image/png\",\"width\":300,\"height\":546,\"name\":\"ref_image_2.png\"}]},\"ref_selection\":\"ref_1\"}]",
"[{\"on\":true,\"name\":\"Box 1\",\"type\":\"box_layer\",\"interpolation\":\"box\",\"repeat\":1,\"offset\":0,\"a_pause\":0,\"z_pause\":0,\"easing\":\"in_out\",\"easingConfig\":{\"path\":\"full\",\"strength\":1,\"acceleration\":0},\"driven\":false,\"_drivenConfig\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"scale\":1,\"points_store\":\"[{\\\"x\\\":0.3474681352975962,\\\"y\\\":0.8035198065615633,\\\"highlighted\\\":false,\\\"boxScale\\\":0.49486250274459376,\\\"pointScale\\\":0.49486250274459376,\\\"scale\\\":0.49486250274459376,\\\"rotation\\\":0,\\\"boxRotation\\\":0}]\",\"coordinates\":\"[]\",\"box_keys\":[{\"frame\":1,\"x\":0.17509084505505768,\"y\":0.8303768607157191,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":3,\"x\":0.16230817242646217,\"y\":0.8434348208345157,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":8,\"x\":0.16230817242646217,\"y\":0.8434348208345157,\"scale\":0.7985575320443379,\"rotation\":0},{\"frame\":17,\"x\":0.37061313065648793,\"y\":0.7985304297774442,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":22,\"x\":0.3101511961248443,\"y\":0.7530653147096042,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":25,\"x\":0.30787570430834565,\"y\":0.8420188007118998,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":30,\"x\":0.25489021568489956,\"y\":0.8325304530018323,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":35,\"x\":0.363786853610673,\"y\":0.8368793142254553,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":40,\"x\":0.2805702985195647,\"y\":0.8436002925393168,\"scale\":0.45690062408212573,\"rotation\":0},{\"frame\":44,\"x\":0.3407072478218575,\"y\":0.8281817124290963,\"scale\":0.45690062408212573,\"rotation\":0}],\"box_timeline_point\":16,\"box_interpolation\":\"linear\",\"ref_attachment\":{\"entries\":[{\"path\":\"bg/ref_image_0.png\",\"type\":\"image/png\",\"width\":400,\"height\":471,\"name\":\"ref_image_0.png\"},{\"path\":\"bg/ref_image_1.png\",\"type\":\"image/png\",\"width\":457,\"height\":586,\"name\":\"ref_image_1.png\"},{\"path\":\"bg/ref_image_2.png\",\"type\":\"image/png\",\"width\":300,\"height\":546,\"name\":\"ref_image_2.png\"}]},\"ref_selection\":\"ref_2\"},{\"on\":true,\"name\":\"Box 1_1\",\"type\":\"box_layer\",\"interpolation\":\"box\",\"repeat\":1,\"offset\":0,\"a_pause\":0,\"z_pause\":0,\"easing\":\"in_out\",\"easingConfig\":{\"path\":\"full\",\"strength\":1,\"acceleration\":0},\"driven\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"_drivenConfig\":{\"driver\":\"\",\"rotate\":0,\"d_scale\":1},\"scale\":1,\"points_store\":\"[{\\\"x\\\":0.6806348749052255,\\\"y\\\":0.7474313451231609,\\\"highlighted\\\":false,\\\"boxScale\\\":0.6940336804011772,\\\"pointScale\\\":0.6940336804011772,\\\"scale\\\":0.6940336804011772,\\\"rotation\\\":0,\\\"boxRotation\\\":0,\\\"uid\\\":16981}]\",\"coordinates\":\"[]\",\"box_keys\":[{\"frame\":1,\"x\":0.6302263722980433,\"y\":0.7737771727381784,\"scale\":0.312739506683858,\"rotation\":0},{\"frame\":9,\"x\":0.7801197829741051,\"y\":0.7550457649727679,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":16,\"x\":0.6806348749052255,\"y\":0.7474313451231609,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":21,\"x\":0.7156002654484349,\"y\":0.6992066860756498,\"scale\":0.6940336804011772,\"rotation\":0},{\"frame\":24,\"x\":0.7384942877962534,\"y\":0.7692594416414953,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":36,\"x\":0.688959973940796,\"y\":0.7697671006146228,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":46,\"x\":0.8155014538752791,\"y\":0.7885493982099611,\"scale\":0.5705899451391455,\"rotation\":0},{\"frame\":52,\"x\":0.7476519475477528,\"y\":0.7860112582600921,\"scale\":1.0468844700694617,\"rotation\":0}],\"box_timeline_point\":16,\"box_interpolation\":\"linear\",\"ref_attachment\":{\"entries\":[{\"path\":\"bg/ref_image_0.png\",\"type\":\"image/png\",\"width\":400,\"height\":471,\"name\":\"ref_image_0.png\"},{\"path\":\"bg/ref_image_1.png\",\"type\":\"image/png\",\"width\":457,\"height\":586,\"name\":\"ref_image_1.png\"},{\"path\":\"bg/ref_image_2.png\",\"type\":\"image/png\",\"width\":300,\"height\":546,\"name\":\"ref_image_2.png\"}]},\"ref_selection\":\"ref_1\"}]",
null,
"[{\"x\":200,\"y\":240},{\"x\":304,\"y\":240}]",
640,
@@ -2733,8 +2487,8 @@
{
"path": "bg/ref_image_0.png",
"type": "image/png",
"width": 300,
"height": 546,
"width": 400,
"height": 471,
"name": "ref_image_0.png"
},
{
@@ -2747,8 +2501,8 @@
{
"path": "bg/ref_image_2.png",
"type": "image/png",
"width": 512,
"height": 768,
"width": 300,
"height": 546,
"name": "ref_image_2.png"
}
]
@@ -3267,7 +3021,7 @@
472.44472370929736
],
"flags": {},
"order": 16,
"order": 15,
"mode": 0,
"inputs": [
{
@@ -3331,7 +3085,7 @@
139.1564075673432
],
"flags": {},
"order": 17,
"order": 16,
"mode": 0,
"inputs": [],
"outputs": [
@@ -3364,6 +3118,263 @@
],
"color": "#323",
"bgcolor": "#535"
},
{
"id": 155,
"type": "PreviewImage",
"pos": [
-502.6022947118135,
646.6730215383718
],
"size": [
210,
667.7696706327888
],
"flags": {},
"order": 27,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 367
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.71",
"Node name for S&R": "PreviewImage",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": []
},
{
"id": 158,
"type": "MaskPreview+",
"pos": [
-261.5592877332859,
646.6730215383718
],
"size": [
210,
668.6430337189952
],
"flags": {},
"order": 29,
"mode": 0,
"inputs": [
{
"name": "mask",
"type": "MASK",
"link": 370
}
],
"outputs": [],
"properties": {
"cnr_id": "comfyui_essentials",
"ver": "9d9f4bedfc9f0321c19faf71855e228c93bd0dc9",
"Node name for S&R": "MaskPreview+",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": []
},
{
"id": 124,
"type": "LoadImage",
"pos": [
-484.35588731056015,
-95.80907240982795
],
"size": [
274.080078125,
314.0000000000001
],
"flags": {},
"order": 17,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
218,
372
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.71",
"Node name for S&R": "LoadImage",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.2.2"
}
},
"widgets_values": [
"bg.png",
"image"
],
"color": "#432",
"bgcolor": "#653",
"shape": 1
},
{
"id": 121,
"type": "GetImageRangeFromBatch",
"pos": [
723.1343342581331,
178.8695429625597
],
"size": [
340.3267578125,
102
],
"flags": {
"collapsed": true
},
"order": 34,
"mode": 0,
"inputs": [
{
"name": "images",
"shape": 7,
"type": "IMAGE",
"link": 211
},
{
"name": "masks",
"shape": 7,
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
212,
362
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfyui-kjnodes",
"ver": "6ee278aa7d802c03ad713a7c5fbc02861b6773a8",
"Node name for S&R": "GetImageRangeFromBatch",
"ue_properties": {
"widget_ue_connectable": {
"num_frames": true
},
"version": "7.3",
"input_ue_unconnectable": {}
},
"aux_id": "kijai/ComfyUI-KJNodes"
},
"widgets_values": [
0,
1
]
},
{
"id": 168,
"type": "CreateImageList",
"pos": [
-504.06366922322417,
335.96684961673895
],
"size": [
270,
210
],
"flags": {},
"order": 23,
"mode": 0,
"inputs": [
{
"name": "image1",
"shape": 7,
"type": "IMAGE",
"link": 364
},
{
"name": "image2",
"type": "IMAGE",
"link": 365
},
{
"name": "image3",
"type": "IMAGE",
"link": 366
},
{
"name": "image4",
"type": "IMAGE",
"link": null
},
{
"name": "image_ref",
"shape": 7,
"type": "IMAGE",
"link": 372
}
],
"outputs": [
{
"name": "images",
"type": "IMAGE",
"links": [
367,
368,
369
]
},
{
"name": "masks",
"type": "MASK",
"links": [
370,
371
]
}
],
"properties": {
"cnr_id": "wanvideowrapper_qq",
"ver": "b5fc414118021a88c7e70f178794fe8e2ac00225",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {}
},
"Node name for S&R": "CreateImageList"
},
"widgets_values": [
true,
"mkl",
0.4,
true
]
}
],
"links": [
@@ -3823,68 +3834,12 @@
0,
"IMAGE"
],
[
345,
118,
0,
161,
0,
"IMAGE"
],
[
346,
117,
0,
161,
1,
"IMAGE"
],
[
347,
161,
0,
155,
0,
"IMAGE"
],
[
348,
161,
0,
137,
1,
"IMAGE"
],
[
349,
161,
0,
123,
2,
"IMAGE"
],
[
350,
161,
1,
158,
0,
"MASK"
],
[
351,
161,
1,
123,
3,
"MASK"
],
[
352,
146,
0,
161,
2,
5,
"IMAGE"
],
[
@@ -3926,6 +3881,78 @@
104,
2,
"MASK"
],
[
364,
118,
0,
168,
0,
"IMAGE"
],
[
365,
117,
0,
168,
1,
"IMAGE"
],
[
366,
146,
0,
168,
2,
"IMAGE"
],
[
367,
168,
0,
155,
0,
"IMAGE"
],
[
368,
168,
0,
137,
1,
"IMAGE"
],
[
369,
168,
0,
123,
2,
"IMAGE"
],
[
370,
168,
1,
158,
0,
"MASK"
],
[
371,
168,
1,
123,
3,
"MASK"
],
[
372,
124,
0,
168,
4,
"IMAGE"
]
],
"groups": [
@@ -3946,10 +3973,10 @@
"config": {},
"extra": {
"ds": {
"scale": 0.5559917313492839,
"scale": 0.6303940863128492,
"offset": [
895.7180320253976,
656.250667639637
1548.6123884557073,
209.80359321404143
]
},
"frontendVersion": "1.33.5",
+94 -2
View File
@@ -4,6 +4,7 @@ import folder_paths
from PIL import Image
import numpy as np
import os
from concurrent.futures import ThreadPoolExecutor
class ImageBlend_GPU:
# Moved blend modes inside the class
@@ -225,7 +226,21 @@ class CreateImageList:
"export_alpha": ("BOOLEAN", {"default": True})
},
"optional": {
"image1": ("IMAGE",)
"image1": ("IMAGE",),
"image_ref": ("IMAGE",),
"method": (
[
'mkl',
'hm',
'reinhard',
'mvgd',
'hm-mvgd-hm',
'hm-mkl-hm',
], {
"default": 'mkl'
}),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
"multithread": ("BOOLEAN", {"default": True}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
@@ -237,6 +252,16 @@ class CreateImageList:
RETURN_NAMES = ("images", "masks")
FUNCTION = "batch"
CATEGORY = "WanVideoWrapper_QQ/image"
DESCRIPTION = """
Creates a batch of images from multiple dynamic image inputs.
Optionally applies color matching to all images if image_ref is provided.
Color matching uses the color-matcher library to transfer color characteristics
from a reference image to all batch images. This is useful for maintaining
consistent color grading across multiple images.
Supports alpha channel preservation with export_alpha option.
"""
def load_image_with_alpha(self, image_path):
"""Load image from path with alpha channel preserved"""
@@ -317,7 +342,66 @@ class CreateImageList:
print(f"Error in trace: {e}")
return None
def batch(self, export_alpha, unique_id=None, prompt=None, **kwargs):
def apply_color_match(self, images, image_ref, method, strength, multithread):
"""Apply color matching to a batch of images using a reference image"""
try:
from color_matcher import ColorMatcher
except:
raise Exception("Can't import color-matcher, did you install requirements.txt? Manual install: pip install color-matcher")
images = images.cpu()
image_ref = image_ref.cpu()
batch_size = images.size(0)
# Handle alpha channel: extract RGB for color matching
has_alpha = images.shape[-1] == 4
if has_alpha:
rgb_images = images[:, :, :, :3]
alpha_channel = images[:, :, :, 3]
else:
rgb_images = images
# Extract RGB from reference if it has alpha
if image_ref.shape[-1] == 4:
image_ref_rgb = image_ref[:, :, :, :3]
else:
image_ref_rgb = image_ref
images_rgb = rgb_images.squeeze()
images_ref = image_ref_rgb.squeeze()
image_ref_np = images_ref.numpy()
images_rgb_np = images_rgb.numpy()
def process(i):
cm = ColorMatcher()
image_rgb_np_i = images_rgb_np if batch_size == 1 else images_rgb[i].numpy()
image_ref_np_i = image_ref_np if image_ref_rgb.size(0) == 1 else images_ref[i].numpy()
try:
image_result = cm.transfer(src=image_rgb_np_i, ref=image_ref_np_i, method=method)
image_result = image_rgb_np_i + strength * (image_result - image_rgb_np_i)
return torch.from_numpy(image_result)
except Exception as e:
print(f"Color matching thread {i} error: {e}")
return torch.from_numpy(image_rgb_np_i) # fallback
if multithread and batch_size > 1:
max_threads = min(os.cpu_count() or 1, batch_size)
with ThreadPoolExecutor(max_workers=max_threads) as executor:
out = list(executor.map(process, range(batch_size)))
else:
out = [process(i) for i in range(batch_size)]
out = torch.stack(out, dim=0).to(torch.float32)
out.clamp_(0, 1)
# Reattach alpha channel if it was present
if has_alpha:
out = torch.cat([out, alpha_channel.unsqueeze(-1)], dim=-1)
return out
def batch(self, export_alpha, unique_id=None, prompt=None, image_ref=None, method='mkl', strength=1.0, multithread=True, **kwargs):
# Collect all image inputs from kwargs (dynamic inputs)
images = []
@@ -350,6 +434,10 @@ class CreateImageList:
if img.shape[-1] == 3:
img = torch.nn.functional.pad(img, (0, 1), mode='constant', value=1.0)
# Apply color matching if image_ref is provided
if image_ref is not None:
img = self.apply_color_match(img, image_ref, method, strength, multithread)
# Extract masks
masks = img[:, :, :, 3]
@@ -406,6 +494,10 @@ class CreateImageList:
# Concatenate all images
s = torch.cat(fitted_images, dim=0)
# Apply color matching if image_ref is provided
if image_ref is not None:
s = self.apply_color_match(s, image_ref, method, strength, multithread)
# Extract alpha channel as masks (MASK format is BHW, not BHWC)
masks = s[:, :, :, 3] # Shape: [B, H, W]
+21 -8
View File
@@ -4,6 +4,16 @@ app.registerExtension({
name: "WanVideoWrapper.CreateImageList",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === 'CreateImageList') {
// Helper function to ensure image_ref is at the bottom
const ensureImageRefAtBottom = function() {
const imageRefIndex = this.inputs.findIndex(inp => inp.name === 'image_ref');
if (imageRefIndex !== -1 && imageRefIndex < this.inputs.length - 1) {
// Move image_ref to the end
const imageRefInput = this.inputs.splice(imageRefIndex, 1)[0];
this.inputs.push(imageRefInput);
}
};
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
const stackTrace = new Error().stack;
@@ -29,14 +39,14 @@ app.registerExtension({
return;
}
// Don't process the export_alpha input (it's a widget converted to input)
// Don't process specific inputs (widgets converted to inputs or color matching params)
const input = this.inputs[index];
if (input && input.name === 'export_alpha') {
if (input && (input.name === 'export_alpha' || input.name === 'image_ref' || input.name === 'method' || input.name === 'strength' || input.name === 'multithread')) {
return;
}
// Count how many IMAGE type inputs we have (excluding export_alpha)
const imageInputCount = this.inputs.filter(inp => inp.type === 'IMAGE').length;
// Count how many IMAGE type inputs we have (excluding image_ref, which is for color matching)
const imageInputCount = this.inputs.filter(inp => inp.type === 'IMAGE' && inp.name !== 'image_ref').length;
// When disconnecting, remove the input if there's more than one IMAGE input
if (!connected && imageInputCount > 1) {
@@ -49,17 +59,17 @@ app.registerExtension({
}
}
// Ensure at least one IMAGE input exists
const remainingImageInputs = this.inputs.filter(inp => inp.type === 'IMAGE').length;
// Ensure at least one IMAGE input exists (excluding image_ref)
const remainingImageInputs = this.inputs.filter(inp => inp.type === 'IMAGE' && inp.name !== 'image_ref').length;
if (remainingImageInputs === 0) {
this.addInput("image1", "IMAGE");
}
// Renumber all IMAGE inputs sequentially
// Renumber all IMAGE inputs sequentially (excluding image_ref)
let slot_i = 1;
for (let i = 0; i < this.inputs.length; i++) {
const inp = this.inputs[i];
if (inp.type === 'IMAGE') {
if (inp.type === 'IMAGE' && inp.name !== 'image_ref') {
inp.name = `image${slot_i}`;
slot_i++;
}
@@ -69,6 +79,9 @@ app.registerExtension({
if (connected) {
this.addInput(`image${slot_i}`, "IMAGE");
}
// Ensure image_ref stays at the bottom
ensureImageRefAtBottom.call(this);
}
}
}