parralel #2
No files matched your search
+5
-2
@@ -1,13 +1,16 @@
|
|||||||
from .sharp_node import SharpnessAnalyzer, SharpFrameSelector
|
from .sharp_node import SharpnessAnalyzer, SharpFrameSelector
|
||||||
|
from .parallel_loader import ParallelSharpnessLoader
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"SharpnessAnalyzer": SharpnessAnalyzer,
|
"SharpnessAnalyzer": SharpnessAnalyzer,
|
||||||
"SharpFrameSelector": SharpFrameSelector
|
"SharpFrameSelector": SharpFrameSelector,
|
||||||
|
"ParallelSharpnessLoader": ParallelSharpnessLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
"SharpnessAnalyzer": "1. Sharpness Analyzer",
|
"SharpnessAnalyzer": "1. Sharpness Analyzer",
|
||||||
"SharpFrameSelector": "2. Sharp Frame Selector"
|
"SharpFrameSelector": "2. Sharp Frame Selector",
|
||||||
|
"ParallelSharpnessLoader": "3. Parallel Video Loader (Sharpness)"
|
||||||
}
|
}
|
||||||
|
|
||||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@@ -0,0 +1,349 @@
|
|||||||
|
{
|
||||||
|
"id": "4fbf6f31-0f7b-4465-8ec8-25df4862e076",
|
||||||
|
"revision": 0,
|
||||||
|
"last_node_id": 34,
|
||||||
|
"last_link_id": 42,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": 31,
|
||||||
|
"type": "PrimitiveNode",
|
||||||
|
"pos": [
|
||||||
|
4672,
|
||||||
|
-928
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
210,
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 0,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "connect to widget input",
|
||||||
|
"type": "*",
|
||||||
|
"links": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Run widget replace on values": false,
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"version": "7.5.2",
|
||||||
|
"input_ue_unconnectable": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets_values": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 29,
|
||||||
|
"type": "ParallelSharpnessLoader",
|
||||||
|
"pos": [
|
||||||
|
4992,
|
||||||
|
-1024
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
320,
|
||||||
|
262
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 1,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"links": [
|
||||||
|
42
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "scores_info",
|
||||||
|
"type": "STRING",
|
||||||
|
"links": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "batch_int",
|
||||||
|
"type": "INT",
|
||||||
|
"links": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "batch_status",
|
||||||
|
"type": "STRING",
|
||||||
|
"links": [
|
||||||
|
39
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"aux_id": "ComfyUI-Sharp-Selector.git",
|
||||||
|
"ver": "dab38a1fbf0077655fe568d500866fce6ecc857d",
|
||||||
|
"Node name for S&R": "ParallelSharpnessLoader",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"C:\\path\\to\\video.mp4",
|
||||||
|
0,
|
||||||
|
1440,
|
||||||
|
1,
|
||||||
|
30,
|
||||||
|
24,
|
||||||
|
2000
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "SharpFrameSelector",
|
||||||
|
"pos": [
|
||||||
|
4992,
|
||||||
|
-704
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
288,
|
||||||
|
174
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 6,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "scores",
|
||||||
|
"type": "SHARPNESS_SCORES",
|
||||||
|
"link": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "selected_images",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"links": [
|
||||||
|
32
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "count",
|
||||||
|
"type": "INT",
|
||||||
|
"links": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"aux_id": "ComfyUI-Sharp-Selector.git",
|
||||||
|
"ver": "f30f948c9fa8acf9b7fe09559f172d8a63468c8d",
|
||||||
|
"Node name for S&R": "SharpFrameSelector",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"best_n",
|
||||||
|
144,
|
||||||
|
24,
|
||||||
|
3,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 34,
|
||||||
|
"type": "Note",
|
||||||
|
"pos": [
|
||||||
|
4224,
|
||||||
|
-1120
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
416,
|
||||||
|
736
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 2,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [],
|
||||||
|
"outputs": [],
|
||||||
|
"properties": {},
|
||||||
|
"widgets_values": [
|
||||||
|
"📌 ComfyUI Sharpness Tools Explained\n\n1. Parallel Video Loader (The \"Loader\")\n\n Best for: Processing long videos or movie files directly from disk.\n\n How it works: It opens the video file itself and uses multi-threading (parallel CPU cores) to scan thousands of frames without loading them into memory. It only \"decodes\" the final few sharpest frames.\n\n Use Case: Extracting dataset images, finding high-quality frames from a raw movie file, or scanning 10,000 frames without crashing your RAM.\n\n Key Feature: Features a \"Batch Counter\" to automatically page through long videos (e.g., scan minute 0-1, then minute 1-2).\n\n2. Standard Sharpness Duo (The \"Filter\")\n\n Best for: Processing images already inside your workflow (e.g., after an img2img pass, or a short generated GIF).\n\n How it works:\n\n Node A (Analyzer): Assigns a score to every image in the batch.\n\n Node B (Selector): Picks the best ones based on those scores.\n\n Use Case: Filtering bad generations, picking the best frame from a small batch of AnimateDiff results, or cleaning up a sequence.\n\n Limitation: It is single-threaded and requires all images to be loaded in VRAM/RAM first (slow for long videos).\n\n🚀 Which one to use?\n\n Starting from a Video File? → Use Parallel Loader.\n\n Starting from a Generation/Latent? → Use Standard Duo."
|
||||||
|
],
|
||||||
|
"color": "#432",
|
||||||
|
"bgcolor": "#653"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 33,
|
||||||
|
"type": "SaveImage",
|
||||||
|
"pos": [
|
||||||
|
5824,
|
||||||
|
-1024
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
270,
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 4,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": 42
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [],
|
||||||
|
"properties": {
|
||||||
|
"cnr_id": "comfy-core",
|
||||||
|
"ver": "0.9.2",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {}
|
||||||
|
},
|
||||||
|
"Node name for S&R": "SaveImage"
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"sharp/img_"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 32,
|
||||||
|
"type": "easy showAnything",
|
||||||
|
"pos": [
|
||||||
|
5344,
|
||||||
|
-1024
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
448,
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 5,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "anything",
|
||||||
|
"shape": 7,
|
||||||
|
"type": "*",
|
||||||
|
"link": 39
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "output",
|
||||||
|
"type": "*",
|
||||||
|
"links": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cnr_id": "comfyui-easy-use",
|
||||||
|
"ver": "5dfcbcf51d8a6efed947bc7bdd6797827fecab55",
|
||||||
|
"Node name for S&R": "easy showAnything",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"Batch 1: Skipped 3440 frames. Scanning range 3440 -> 4880."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "SharpnessAnalyzer",
|
||||||
|
"pos": [
|
||||||
|
4672,
|
||||||
|
-672
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
185.9771484375,
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 3,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "scores",
|
||||||
|
"type": "SHARPNESS_SCORES",
|
||||||
|
"links": [
|
||||||
|
3,
|
||||||
|
21
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"aux_id": "ComfyUI-Sharp-Selector.git",
|
||||||
|
"ver": "0df11447abb7f41bf7f12a2906aa868a5d2027b4",
|
||||||
|
"Node name for S&R": "SharpnessAnalyzer",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets_values": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
[
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
"SHARPNESS_SCORES"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
39,
|
||||||
|
29,
|
||||||
|
3,
|
||||||
|
32,
|
||||||
|
0,
|
||||||
|
"STRING"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
42,
|
||||||
|
29,
|
||||||
|
0,
|
||||||
|
33,
|
||||||
|
0,
|
||||||
|
"IMAGE"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"groups": [],
|
||||||
|
"config": {},
|
||||||
|
"extra": {
|
||||||
|
"workflowRendererVersion": "LG",
|
||||||
|
"ue_links": [],
|
||||||
|
"links_added_by_ue": [],
|
||||||
|
"ds": {
|
||||||
|
"scale": 0.8264462809917354,
|
||||||
|
"offset": [
|
||||||
|
-2054.6525613149634,
|
||||||
|
1737.5186871750661
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"frontendVersion": "1.36.14",
|
||||||
|
"VHS_latentpreview": true,
|
||||||
|
"VHS_latentpreviewrate": 0,
|
||||||
|
"VHS_MetadataImage": true,
|
||||||
|
"VHS_KeepIntermediate": true
|
||||||
|
},
|
||||||
|
"version": 0.4
|
||||||
|
}
|
||||||
@@ -1,699 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "4fbf6f31-0f7b-4465-8ec8-25df4862e076",
|
|
||||||
"revision": 0,
|
|
||||||
"last_node_id": 21,
|
|
||||||
"last_link_id": 25,
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"id": 17,
|
|
||||||
"type": "ImageResize+",
|
|
||||||
"pos": [
|
|
||||||
4736,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
270,
|
|
||||||
218
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 3,
|
|
||||||
"mode": 4,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "image",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 17
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "IMAGE",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
18
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "width",
|
|
||||||
"type": "INT",
|
|
||||||
"links": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "height",
|
|
||||||
"type": "INT",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui_essentials",
|
|
||||||
"ver": "1.1.0",
|
|
||||||
"Node name for S&R": "ImageResize+",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
512,
|
|
||||||
512,
|
|
||||||
"lanczos",
|
|
||||||
"keep proportion",
|
|
||||||
"always",
|
|
||||||
0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"type": "SharpnessAnalyzer",
|
|
||||||
"pos": [
|
|
||||||
5024,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
185.9771484375,
|
|
||||||
26
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 4,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "images",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 18
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "scores",
|
|
||||||
"type": "SHARPNESS_SCORES",
|
|
||||||
"links": [
|
|
||||||
3,
|
|
||||||
21
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"aux_id": "ComfyUI-Sharp-Selector.git",
|
|
||||||
"ver": "0df11447abb7f41bf7f12a2906aa868a5d2027b4",
|
|
||||||
"Node name for S&R": "SharpnessAnalyzer",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 19,
|
|
||||||
"type": "easy showAnything",
|
|
||||||
"pos": [
|
|
||||||
5248,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
256,
|
|
||||||
576
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 6,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "anything",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "*",
|
|
||||||
"link": 21
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "output",
|
|
||||||
"type": "*",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-easy-use",
|
|
||||||
"ver": "5dfcbcf51d8a6efed947bc7bdd6797827fecab55",
|
|
||||||
"Node name for S&R": "easy showAnything",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
"[\n 6.297575110409919,\n 6.144944418063888,\n 6.684313872650857,\n 6.4317192255713485,\n 7.3446416811676905,\n 6.8772988939768736,\n 7.302667338359446,\n 7.042105154536494,\n 8.10807532789576,\n 7.32163242554161,\n 7.8980447033352315,\n 7.542744378581509,\n 8.584784189394831,\n 7.795560856647257,\n 8.24026113686267,\n 8.623874058071168,\n 8.667561967030277,\n 7.746343436315587,\n 8.251487986940727,\n 7.880067028119204,\n 8.70787820115881,\n 7.8370928519337335,\n 8.395853223745585,\n 7.914898482178123,\n 9.01494284412045,\n 8.075362649053263,\n 8.682723998981517,\n 8.105303330190537,\n 9.115628245170683,\n 7.7830088804578885,\n 8.398492822970873,\n 7.4969409350188805,\n 8.322635864769449,\n 7.404455531102189,\n 7.403408557569797,\n 6.840819222523937,\n 7.475344198627222,\n 6.750361203354514,\n 7.572874586465522,\n 7.4827313485886,\n 8.377496252597329,\n 7.5220353353617515,\n 8.193480409472127,\n 7.156884268514871,\n 8.082848049367533,\n 7.63424852226778,\n 8.454396211558677,\n 7.840757371430993,\n 8.620649828747826,\n 8.00768301395503,\n 8.719161842252001,\n 8.327651062690222,\n 9.067907863955316,\n 8.20792956623959,\n 8.789784913672001,\n 8.259965273663884,\n 9.42687644190318,\n 8.433461968183975,\n 9.37003181954,\n 8.591939975007666,\n 10.1733471923221,\n 8.718065797609427,\n 9.245587979477488,\n 10.06436161212126,\n 9.65529525491009,\n 8.142324815556668,\n 9.078966764973876,\n 8.45252145816342,\n 9.707079351465795,\n 8.270712281892054,\n 9.058043110693236,\n 8.367201523498673,\n 9.753600689309108,\n 8.28629386901803,\n 8.884336398764388,\n 8.2309418113456,\n 9.666923248140298,\n 8.156200525152064,\n 8.75434154784892,\n 8.380946138350039,\n 9.311587514394974,\n 7.738351998254581,\n 8.174588124539842,\n 7.695874072615815,\n 9.341121212791347,\n 7.9843261262852545,\n 8.539380014979464,\n 7.899567376676831,\n 8.955174178780261,\n 6.751447808818923,\n 7.36971843495925,\n 6.832223454123367,\n 7.8993929904178986,\n 6.819163469043983,\n 7.608824176207361,\n 7.570297127902336,\n 9.037285148546417,\n 8.244525942401976,\n 9.189244068284188,\n 8.339524619020047,\n 10.021628566439258,\n 8.517800804063164,\n 9.219841337643302,\n 8.566254460416017,\n 10.059008366328793,\n 8.228836684981689,\n 8.99102539006089,\n 8.383533950614435,\n 10.375199652172869,\n 8.573858504932964,\n 9.299217301075009,\n 10.532476971679262,\n 10.130683333997316,\n 8.649116496013589,\n 9.626099641605425,\n 8.536719337544996,\n 8.409095757294688,\n 6.5515410267845455,\n 5.921841468991043,\n 6.418067963679305,\n 5.913852826367972,\n 6.313376360261261,\n 6.806761535915923,\n 6.569975869177406,\n 8.41885210405548,\n 6.800968356536217,\n 8.84110833314738,\n 8.120380728011211,\n 9.424228138273994,\n 8.044382817489616,\n 8.594205351542904,\n 7.951771427419306,\n 8.795560977732745,\n 7.70634077675412,\n 8.038942655352242,\n 7.419914755606816,\n 9.482411986048588,\n 7.585411597706476,\n 8.173441958796994,\n 7.773293060071969,\n 7.719108425046177,\n 5.877915085864361,\n 5.62501663174047,\n 5.282325536439449,\n 6.258285946216752,\n 5.7460862670744355,\n 5.8879322052832075,\n 5.305955207350254,\n 5.588074352874547,\n 5.0984621958779694,\n 5.307472000504878,\n 5.105555660548033,\n 5.729852294541612,\n 5.639345087465072,\n 5.990921581251159,\n 5.801898134016792,\n 5.902133593536372,\n 5.9400003511631905,\n 6.419309046570074,\n 6.757060893084156,\n 6.789226096335257,\n 6.26093253670092,\n 6.317426181959557,\n 6.100199972706731,\n 6.488035602065475,\n 6.275011640213154,\n 6.665604219412575,\n 6.2029694221146,\n 6.834827299811385,\n 6.345343059578458,\n 6.191776512038724,\n 5.66395208490513,\n 5.944153310633949,\n 5.583467198650693,\n 5.956398472027981,\n 6.001634981131615,\n 6.251462467992461,\n 6.231161200963715,\n 6.6780594793812895,\n 6.4117190610235735,\n 7.261556894543717,\n 7.038173442990873,\n 7.29484215708148,\n 7.108871493662606,\n 7.870499828042389,\n 7.006509078723072,\n 7.2169158554384,\n 6.596709217606309,\n 7.535010120944718,\n 6.687042334032516,\n 7.118254836845995,\n 6.440380490440168,\n 6.91829776242904,\n 6.017377623473521,\n 6.3998302370443225,\n 5.77743067022077,\n 6.403883332077408,\n 5.802018213686007,\n 6.071120132250568,\n 5.585466928460238,\n 6.193240363600254,\n 5.612886761459725,\n 5.833689472808629,\n 5.523342368877241,\n 6.190735183316677,\n 5.526805067161219,\n 5.979545110921056,\n 6.140775218114808,\n 5.788Line truncated
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 18,
|
|
||||||
"type": "VHS_VideoCombine",
|
|
||||||
"pos": [
|
|
||||||
6656,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
226.3349609375,
|
|
||||||
238
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 8,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "images",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 23
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "audio",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "AUDIO",
|
|
||||||
"link": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "meta_batch",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "VHS_BatchManager",
|
|
||||||
"link": 19
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "vae",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "VAE",
|
|
||||||
"link": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "Filenames",
|
|
||||||
"type": "VHS_FILENAMES",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-videohelpersuite",
|
|
||||||
"ver": "1.7.9",
|
|
||||||
"Node name for S&R": "VHS_VideoCombine",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": {
|
|
||||||
"frame_rate": 1,
|
|
||||||
"loop_count": 0,
|
|
||||||
"filename_prefix": "AnimateDiff",
|
|
||||||
"format": "video/8bit-png",
|
|
||||||
"pingpong": false,
|
|
||||||
"save_output": false,
|
|
||||||
"videopreview": {
|
|
||||||
"hidden": false,
|
|
||||||
"paused": false,
|
|
||||||
"params": {
|
|
||||||
"filename": "AnimateDiff_00001.001.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp",
|
|
||||||
"format": "image/png",
|
|
||||||
"frame_rate": 1,
|
|
||||||
"workflow": "AnimateDiff_00001.png",
|
|
||||||
"fullpath": "/basedir/temp/AnimateDiff_00001.%03d.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 15,
|
|
||||||
"type": "VHS_BatchManager",
|
|
||||||
"pos": [
|
|
||||||
4096,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
262.53125,
|
|
||||||
58
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 0,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "meta_batch",
|
|
||||||
"type": "VHS_BatchManager",
|
|
||||||
"links": [
|
|
||||||
19,
|
|
||||||
24,
|
|
||||||
25
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-videohelpersuite",
|
|
||||||
"ver": "1.7.9",
|
|
||||||
"Node name for S&R": "VHS_BatchManager",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": {
|
|
||||||
"frames_per_batch": 1000,
|
|
||||||
"count": 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 20,
|
|
||||||
"type": "easy imageChooser",
|
|
||||||
"pos": [
|
|
||||||
5888,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
704,
|
|
||||||
704
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 7,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "images",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 22
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "image",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
23
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-easy-use",
|
|
||||||
"ver": "5dfcbcf51d8a6efed947bc7bdd6797827fecab55",
|
|
||||||
"Node name for S&R": "easy imageChooser",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
"Always Pause",
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"isWaitingSelection": false,
|
|
||||||
"currentMode": "Always Pause",
|
|
||||||
"imageData": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00015_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 1,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00016_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 2,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00017_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 3,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00018_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 4,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00019_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 5,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00020_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 6,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00021_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 7,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00022_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 8,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00023_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 9,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00024_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 10,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00025_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 11,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00026_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 12,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00027_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 13,
|
|
||||||
"filename": "ComfyUI_temp_ytveg_00028_.png",
|
|
||||||
"subfolder": "",
|
|
||||||
"type": "temp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isExecuting": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 21,
|
|
||||||
"type": "easy showAnything",
|
|
||||||
"pos": [
|
|
||||||
4416,
|
|
||||||
-704
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
416,
|
|
||||||
96
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 1,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "anything",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "*",
|
|
||||||
"link": 24
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "output",
|
|
||||||
"type": "*",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-easy-use",
|
|
||||||
"ver": "5dfcbcf51d8a6efed947bc7bdd6797827fecab55",
|
|
||||||
"Node name for S&R": "easy showAnything",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
"</basedir/custom_nodes/comfyui-videohelpersuite.videohelpersuite.nodes.BatchManager object at 0x148563b8d520>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"type": "SharpFrameSelector",
|
|
||||||
"pos": [
|
|
||||||
5536,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
288,
|
|
||||||
174
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 5,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "images",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "scores",
|
|
||||||
"type": "SHARPNESS_SCORES",
|
|
||||||
"link": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "selected_images",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
22
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "count",
|
|
||||||
"type": "INT",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"aux_id": "ComfyUI-Sharp-Selector.git",
|
|
||||||
"ver": "f30f948c9fa8acf9b7fe09559f172d8a63468c8d",
|
|
||||||
"Node name for S&R": "SharpFrameSelector",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
"batched",
|
|
||||||
72,
|
|
||||||
10,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"type": "VHS_LoadVideoPath",
|
|
||||||
"pos": [
|
|
||||||
4448,
|
|
||||||
-1184
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
243.74609375,
|
|
||||||
286
|
|
||||||
],
|
|
||||||
"flags": {},
|
|
||||||
"order": 2,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "meta_batch",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "VHS_BatchManager",
|
|
||||||
"link": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "vae",
|
|
||||||
"shape": 7,
|
|
||||||
"type": "VAE",
|
|
||||||
"link": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "IMAGE",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
1,
|
|
||||||
17
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "frame_count",
|
|
||||||
"type": "INT",
|
|
||||||
"links": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "audio",
|
|
||||||
"type": "AUDIO",
|
|
||||||
"links": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "video_info",
|
|
||||||
"type": "VHS_VIDEOINFO",
|
|
||||||
"links": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"cnr_id": "comfyui-videohelpersuite",
|
|
||||||
"ver": "1.7.9",
|
|
||||||
"Node name for S&R": "VHS_LoadVideoPath",
|
|
||||||
"ue_properties": {
|
|
||||||
"widget_ue_connectable": {},
|
|
||||||
"input_ue_unconnectable": {},
|
|
||||||
"version": "7.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets_values": {
|
|
||||||
"video": "",
|
|
||||||
"force_rate": 0,
|
|
||||||
"custom_width": 0,
|
|
||||||
"custom_height": 0,
|
|
||||||
"frame_load_cap": 0,
|
|
||||||
"skip_first_frames": 0,
|
|
||||||
"select_every_nth": 1,
|
|
||||||
"format": "None",
|
|
||||||
"videopreview": {
|
|
||||||
"hidden": false,
|
|
||||||
"paused": false,
|
|
||||||
"params": {
|
|
||||||
"filename": "",
|
|
||||||
"type": "path",
|
|
||||||
"format": "video/",
|
|
||||||
"force_rate": 0,
|
|
||||||
"custom_width": 0,
|
|
||||||
"custom_height": 0,
|
|
||||||
"frame_load_cap": 0,
|
|
||||||
"skip_first_frames": 0,
|
|
||||||
"select_every_nth": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"links": [
|
|
||||||
[
|
|
||||||
1,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
5,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
"SHARPNESS_SCORES"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
17,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
17,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
18,
|
|
||||||
17,
|
|
||||||
0,
|
|
||||||
5,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
19,
|
|
||||||
15,
|
|
||||||
0,
|
|
||||||
18,
|
|
||||||
2,
|
|
||||||
"VHS_BatchManager"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
21,
|
|
||||||
5,
|
|
||||||
0,
|
|
||||||
19,
|
|
||||||
0,
|
|
||||||
"SHARPNESS_SCORES"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
22,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
20,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
23,
|
|
||||||
20,
|
|
||||||
0,
|
|
||||||
18,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
24,
|
|
||||||
15,
|
|
||||||
0,
|
|
||||||
21,
|
|
||||||
0,
|
|
||||||
"VHS_BatchManager"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
25,
|
|
||||||
15,
|
|
||||||
0,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
"VHS_BatchManager"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"groups": [],
|
|
||||||
"config": {},
|
|
||||||
"extra": {
|
|
||||||
"workflowRendererVersion": "LG",
|
|
||||||
"ue_links": [],
|
|
||||||
"links_added_by_ue": [],
|
|
||||||
"ds": {
|
|
||||||
"scale": 0.6830134553650705,
|
|
||||||
"offset": [
|
|
||||||
-1600.6139750990876,
|
|
||||||
2070.1633937160614
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"frontendVersion": "1.36.14",
|
|
||||||
"VHS_latentpreview": true,
|
|
||||||
"VHS_latentpreviewrate": 0,
|
|
||||||
"VHS_MetadataImage": true,
|
|
||||||
"VHS_KeepIntermediate": true
|
|
||||||
},
|
|
||||||
"version": 0.4
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
|
||||||
|
|
||||||
app.registerExtension({
|
|
||||||
name: "SharpFrames.Tooltips",
|
|
||||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
||||||
if (nodeData.name === "SharpFrameSelector") {
|
|
||||||
const tooltips = {
|
|
||||||
// Must match Python INPUT_TYPES keys exactly
|
|
||||||
"selection_method": "Strategy:\n• 'batched': Best for video. Splits time into slots.\n• 'best_n': Global top sharpest frames.",
|
|
||||||
"batch_size": "For 'batched' mode.\nSize of the analysis window (in frames).",
|
|
||||||
"batch_buffer": "For 'batched' mode.\nFrames to skip AFTER each batch (dead zone).",
|
|
||||||
"num_frames": "For 'best_n' mode.\nTotal frames to output.",
|
|
||||||
"min_sharpness": "Threshold Filter.\nDiscard frames with score below this.\nNote: Scores are lower on resized images.",
|
|
||||||
"images": "Input High-Res images.",
|
|
||||||
"scores": "Input Sharpness Scores from Analyzer."
|
|
||||||
};
|
|
||||||
|
|
||||||
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
||||||
nodeType.prototype.onNodeCreated = function () {
|
|
||||||
onNodeCreated?.apply(this, arguments);
|
|
||||||
|
|
||||||
if (this.widgets) {
|
|
||||||
for (const w of this.widgets) {
|
|
||||||
if (tooltips[w.name]) {
|
|
||||||
w.tooltip = tooltips[w.name];
|
|
||||||
// Force update for immediate feedback
|
|
||||||
w.options = w.options || {};
|
|
||||||
w.options.tooltip = tooltips[w.name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import cv2
|
||||||
|
import torch
|
||||||
|
import numpy as np
|
||||||
|
import concurrent.futures
|
||||||
|
import os
|
||||||
|
|
||||||
|
class ParallelSharpnessLoader:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"video_path": ("STRING", {"default": "C:\\path\\to\\video.mp4"}),
|
||||||
|
|
||||||
|
# BATCHING CONTROLS
|
||||||
|
"batch_index": ("INT", {"default": 0, "min": 0, "max": 10000, "step": 1, "label": "Batch Counter (Auto-Increment)"}),
|
||||||
|
"scan_limit": ("INT", {"default": 1440, "min": 1, "max": 10000000, "step": 1, "label": "Frames per Batch"}),
|
||||||
|
|
||||||
|
# STANDARD CONTROLS
|
||||||
|
"frame_scan_step": ("INT", {"default": 5, "min": 1, "step": 1, "label": "Analyze Every Nth Frame"}),
|
||||||
|
"return_count": ("INT", {"default": 4, "min": 1, "max": 1024, "step": 1, "label": "Best Frames to Return"}),
|
||||||
|
"min_distance": ("INT", {"default": 24, "min": 0, "max": 10000, "step": 1, "label": "Min Distance (Frames)"}),
|
||||||
|
"manual_skip_start": ("INT", {"default": 0, "min": 0, "max": 10000000, "step": 1, "label": "Global Start Offset"}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Added a 4th output: STRING (The status sentence)
|
||||||
|
RETURN_TYPES = ("IMAGE", "STRING", "INT", "STRING")
|
||||||
|
RETURN_NAMES = ("images", "scores_info", "batch_int", "batch_status")
|
||||||
|
FUNCTION = "load_video"
|
||||||
|
CATEGORY = "BetaHelper/Video"
|
||||||
|
|
||||||
|
def calculate_sharpness(self, frame_data):
|
||||||
|
gray = cv2.cvtColor(frame_data, cv2.COLOR_BGR2GRAY)
|
||||||
|
return cv2.Laplacian(gray, cv2.CV_64F).var()
|
||||||
|
|
||||||
|
def load_video(self, video_path, batch_index, scan_limit, frame_scan_step, return_count, min_distance, manual_skip_start):
|
||||||
|
|
||||||
|
# 1. Validation
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
video_path = video_path.strip('"')
|
||||||
|
if not os.path.exists(video_path):
|
||||||
|
raise FileNotFoundError(f"Video not found: {video_path}")
|
||||||
|
|
||||||
|
# 2. Calculate Offsets
|
||||||
|
current_skip = (batch_index * scan_limit) + manual_skip_start
|
||||||
|
range_end = current_skip + scan_limit
|
||||||
|
|
||||||
|
# Create the Status String
|
||||||
|
status_msg = f"Batch {batch_index}: Skipped {current_skip} frames. Scanning range {current_skip} -> {range_end}."
|
||||||
|
print(f"xx- Parallel Loader | {status_msg}")
|
||||||
|
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
|
||||||
|
if current_skip >= total_frames:
|
||||||
|
print("xx- End of video reached.")
|
||||||
|
empty_img = torch.zeros((1, 64, 64, 3))
|
||||||
|
return (empty_img, "End of Video", batch_index, "End of Video Reached")
|
||||||
|
|
||||||
|
# 3. Scanning (Pass 1)
|
||||||
|
if current_skip > 0:
|
||||||
|
cap.set(cv2.CAP_PROP_POS_FRAMES, current_skip)
|
||||||
|
|
||||||
|
frame_scores = []
|
||||||
|
current_frame = current_skip
|
||||||
|
scanned_count = 0
|
||||||
|
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
|
||||||
|
futures = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if scanned_count >= scan_limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret: break
|
||||||
|
|
||||||
|
future = executor.submit(self.calculate_sharpness, frame)
|
||||||
|
futures.append((current_frame, future))
|
||||||
|
scanned_count += 1
|
||||||
|
|
||||||
|
# Manual Stepping
|
||||||
|
if frame_scan_step > 1:
|
||||||
|
for _ in range(frame_scan_step - 1):
|
||||||
|
if not cap.grab(): break
|
||||||
|
current_frame += 1
|
||||||
|
|
||||||
|
current_frame += 1
|
||||||
|
|
||||||
|
for idx, future in futures:
|
||||||
|
frame_scores.append((idx, future.result()))
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
|
||||||
|
# 4. Selection
|
||||||
|
if not frame_scores:
|
||||||
|
return (torch.zeros((1, 64, 64, 3)), "No frames in batch", batch_index, status_msg + " (No frames found)")
|
||||||
|
|
||||||
|
frame_scores.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
selected = []
|
||||||
|
|
||||||
|
for idx, score in frame_scores:
|
||||||
|
if len(selected) >= return_count: break
|
||||||
|
if all(abs(s[0] - idx) >= min_distance for s in selected):
|
||||||
|
selected.append((idx, score))
|
||||||
|
|
||||||
|
selected.sort(key=lambda x: x[0])
|
||||||
|
|
||||||
|
# 5. Extraction (Pass 2)
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
output_tensors = []
|
||||||
|
info_log = []
|
||||||
|
|
||||||
|
for idx, score in selected:
|
||||||
|
cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if ret:
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
frame = frame.astype(np.float32) / 255.0
|
||||||
|
output_tensors.append(torch.from_numpy(frame))
|
||||||
|
info_log.append(f"F:{idx} (Score:{int(score)})")
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
|
||||||
|
if not output_tensors:
|
||||||
|
return (torch.zeros((1, 64, 64, 3)), "Extraction Failed", batch_index, status_msg)
|
||||||
|
|
||||||
|
# Return all 4 outputs
|
||||||
|
return (torch.stack(output_tensors), ", ".join(info_log), batch_index, status_msg)
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
# 🔪 ComfyUI Sharp Frame Selector
|
# 🔪 ComfyUI Sharp Frame Selector
|
||||||
|
|
||||||
A suite of custom nodes for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) designed to intelligently extract the sharpest frames from video footage.
|
A collection of high-performance custom nodes for **ComfyUI** designed to detect blur, calculate sharpness scores, and automatically extract the best frames from videos or image batches.
|
||||||
|
|
||||||
Based on the [sharp-frames](https://github.com/Reflct/sharp-frames-python) logic, this tool uses **Laplacian Variance** to score image clarity. It is optimized for high-resolution video processing using a **Sidechain Workflow** that saves massive amounts of RAM.
|
This pack includes two distinct approaches:
|
||||||
|
1. **Parallel Video Loader:** A multi-threaded, path-based loader for processing massive video files directly from disk (Low RAM usage).
|
||||||
|
2. **Standard Sharpness Duo:** A classic filter setup for processing images/latents *inside* your existing workflow.
|
||||||
|
|
||||||
## ✨ Key Features
|
---
|
||||||
|
---
|
||||||
|
|
||||||
* **Sidechain Optimization:** Analyze lightweight 512px proxy images to control the selection of heavy 4K raw frames.
|
## 🚀 Key Features
|
||||||
* **Batched Extraction:** Splits video into time slots (e.g., 1 second) and picks the single best frame from each slot. Perfect for ensuring action scenes are not missed.
|
|
||||||
* **Threshold Filtering:** Automatically discards frames that are too blurry, even if they are the "winner" of their batch.
|
### 1. New: Parallel Video Loader (Path-Based)
|
||||||
* **Buffer Control:** Optional dead-zones between batches to reduce frame count or ensure temporal separation.
|
* **Zero-RAM Scanning:** Scans video files directly from disk without decoding every frame to memory.
|
||||||
|
* **Multi-Threaded:** Uses all CPU cores to calculate sharpness scores at high speed.
|
||||||
|
* **Batching Support:** Includes a "Page" system to process long movies in chunks (e.g., minute-by-minute) without restarting ComfyUI.
|
||||||
|
* **Smart Selection:** Automatically skips "adjacent" frames to ensure you get a diverse selection of sharp images.
|
||||||
|
|
||||||
|
### 2. Standard Sharpness Duo (Tensor-Based)
|
||||||
|
* **Workflow Integration:** Works with any node that outputs an `IMAGE` batch (e.g., AnimateDiff, VideoHelperSuite).
|
||||||
|
* **Precision Filtering:** Sorts and filters generated frames before saving or passing to a second pass (img2img).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Installation
|
## 📦 Installation
|
||||||
|
|
||||||
### Option 1: ComfyUI Manager (Recommended)
|
1. Clone this repository into your `custom_nodes` folder:
|
||||||
1. Open ComfyUI Manager.
|
```bash
|
||||||
2. Search for **"Sharp Frame Selector"**.
|
cd ComfyUI/custom_nodes/
|
||||||
3. Click **Install**.
|
git clone https://github.com/ethanfel/ComfyUI-Sharp-Selector.git
|
||||||
|
|
||||||
### Option 2: Manual Installation
|
|
||||||
Clone this repository into your `custom_nodes` folder:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ComfyUI/custom_nodes/
|
|
||||||
git clone [https://github.com/YOUR_USERNAME/ComfyUI-Sharp-Selector.git](https://github.com/YOUR_USERNAME/ComfyUI-Sharp-Selector.git)
|
|
||||||
pip install -r ComfyUI-Sharp-Selector/requirements.txt
|
|
||||||
Reference in new issue
Block a user