diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index bcca3fc8e7..125554fc40 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -511,6 +511,7 @@ "maskBlur": "Blur", "maskBlurMethod": "Blur Method", "coherencePassHeader": "Coherence Pass", + "coherenceMode": "Mode", "coherenceSteps": "Steps", "coherenceStrength": "Strength", "seamLowThreshold": "Low", diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts index 34d37e9b17..8e77799293 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addVAEToGraph.ts @@ -32,7 +32,7 @@ export const addVAEToGraph = ( graph: NonNullableGraph, modelLoaderNodeId: string = MAIN_MODEL_LOADER ): void => { - const { vae } = state.generation; + const { vae, canvasCoherenceMode } = state.generation; const { boundingBoxScaleMethod } = state.canvas; const { shouldUseSDXLRefiner } = state.sdxl; @@ -136,16 +136,6 @@ export const addVAEToGraph = ( field: 'vae', }, }, - { - source: { - node_id: isAutoVae ? modelLoaderNodeId : VAE_LOADER, - field: isAutoVae && isOnnxModel ? 'vae_decoder' : 'vae', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'vae', - }, - }, { source: { node_id: isAutoVae ? modelLoaderNodeId : VAE_LOADER, @@ -157,6 +147,20 @@ export const addVAEToGraph = ( }, } ); + + // Handle Coherence Mode + if (canvasCoherenceMode === 'edge') { + graph.edges.push({ + source: { + node_id: isAutoVae ? modelLoaderNodeId : VAE_LOADER, + field: isAutoVae && isOnnxModel ? 'vae_decoder' : 'vae', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'vae', + }, + }); + } } if (shouldUseSDXLRefiner) { diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index 1783174079..a87d20a08d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -70,6 +70,7 @@ export const buildCanvasInpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, + canvasCoherenceMode, canvasCoherenceSteps, canvasCoherenceStrength, clipSkip, @@ -176,21 +177,6 @@ export const buildCanvasInpaintGraph = ( b: 1, is_intermediate: true, }, - [CANVAS_COHERENCE_MASK_EDGE]: { - type: 'mask_edge', - id: CANVAS_COHERENCE_MASK_EDGE, - is_intermediate: true, - edge_blur: maskBlur, - edge_size: maskBlur * 2, - low_threshold: 100, - high_threshold: 200, - }, - [CANVAS_COHERENCE_INPAINT_CREATE_MASK]: { - type: 'create_denoise_mask', - id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - is_intermediate: true, - fp32: vaePrecision === 'fp32' ? true : false, - }, [CANVAS_COHERENCE_DENOISE_LATENTS]: { type: 'denoise_latents', id: CANVAS_COHERENCE_DENOISE_LATENTS, @@ -333,27 +319,6 @@ export const buildCanvasInpaintGraph = ( field: 'denoise_mask', }, }, - // Create Coherence Mask - { - source: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'mask', - }, - }, - { - source: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'denoise_mask', - }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'denoise_mask', - }, - }, // Iterate { source: { @@ -537,26 +502,6 @@ export const buildCanvasInpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: INPAINT_IMAGE_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, // Color Correct The Inpainted Result { source: { @@ -618,16 +563,6 @@ export const buildCanvasInpaintGraph = ( ...(graph.nodes[INPAINT_CREATE_MASK] as CreateDenoiseMaskInvocation), image: canvasInitImage, }; - graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { - ...(graph.nodes[ - CANVAS_COHERENCE_INPAINT_CREATE_MASK - ] as CreateDenoiseMaskInvocation), - image: canvasInitImage, - }; - graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { - ...(graph.nodes[CANVAS_COHERENCE_MASK_EDGE] as MaskEdgeInvocation), - image: canvasMaskImage, - }; graph.edges.push( // Color Correct The Inpainted Result @@ -654,6 +589,84 @@ export const buildCanvasInpaintGraph = ( ); } + // Handle Coherence Mode + if (canvasCoherenceMode === 'edge') { + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + type: 'mask_edge', + id: CANVAS_COHERENCE_MASK_EDGE, + is_intermediate: true, + edge_blur: maskBlur, + edge_size: maskBlur * 2, + low_threshold: 100, + high_threshold: 200, + }; + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + type: 'create_denoise_mask', + id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + is_intermediate: true, + fp32: vaePrecision === 'fp32' ? true : false, + }; + + if (isUsingScaledDimensions) { + graph.edges.push( + { + source: { + node_id: MASK_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }, + { + source: { + node_id: INPAINT_IMAGE_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'image', + }, + } + ); + } else { + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + ...(graph.nodes[ + CANVAS_COHERENCE_INPAINT_CREATE_MASK + ] as CreateDenoiseMaskInvocation), + image: canvasInitImage, + }; + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + ...(graph.nodes[CANVAS_COHERENCE_MASK_EDGE] as MaskEdgeInvocation), + image: canvasMaskImage, + }; + } + + graph.edges.push( + { + source: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'mask', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'denoise_mask', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'denoise_mask', + }, + } + ); + } + // Handle Seed if (shouldRandomizeSeed) { // Random int node to generate the starting seed diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 20f81611fe..fe2d3f1698 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -71,6 +71,7 @@ export const buildCanvasOutpaintGraph = ( shouldUseNoiseSettings, shouldUseCpuNoise, maskBlur, + canvasCoherenceMode, canvasCoherenceSteps, canvasCoherenceStrength, infillTileSize, @@ -185,21 +186,6 @@ export const buildCanvasOutpaintGraph = ( b: 1, is_intermediate: true, }, - [CANVAS_COHERENCE_MASK_EDGE]: { - type: 'mask_edge', - id: CANVAS_COHERENCE_MASK_EDGE, - is_intermediate: true, - edge_blur: maskBlur, - edge_size: maskBlur * 2, - low_threshold: 100, - high_threshold: 200, - }, - [CANVAS_COHERENCE_INPAINT_CREATE_MASK]: { - type: 'create_denoise_mask', - id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - is_intermediate: true, - fp32: vaePrecision === 'fp32' ? true : false, - }, [CANVAS_COHERENCE_DENOISE_LATENTS]: { type: 'denoise_latents', id: CANVAS_COHERENCE_DENOISE_LATENTS, @@ -363,27 +349,6 @@ export const buildCanvasOutpaintGraph = ( field: 'denoise_mask', }, }, - // Create Coherence Mask - { - source: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'mask', - }, - }, - { - source: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'denoise_mask', - }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'denoise_mask', - }, - }, // Iterate { source: { @@ -476,6 +441,16 @@ export const buildCanvasOutpaintGraph = ( field: 'latents', }, }, + { + source: { + node_id: INPAINT_INFILL, + field: 'image', + }, + destination: { + node_id: INPAINT_CREATE_MASK, + field: 'image', + }, + }, // Decode the result from Inpaint { source: { @@ -588,26 +563,7 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, + // Take combined mask and resize and then blur { source: { @@ -619,16 +575,7 @@ export const buildCanvasOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, + // Resize Results Down { source: { @@ -712,37 +659,6 @@ export const buildCanvasOutpaintGraph = ( }; graph.edges.push( - // Take combined mask and plug it to blur - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, // Color Correct The Inpainted Result { source: { @@ -777,6 +693,82 @@ export const buildCanvasOutpaintGraph = ( ); } + // Handle Coherence Mode + if (canvasCoherenceMode === 'edge') { + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + type: 'mask_edge', + id: CANVAS_COHERENCE_MASK_EDGE, + is_intermediate: true, + edge_blur: maskBlur, + edge_size: maskBlur * 2, + low_threshold: 100, + high_threshold: 200, + }; + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + type: 'create_denoise_mask', + id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + is_intermediate: true, + fp32: vaePrecision === 'fp32' ? true : false, + }; + + if (isUsingScaledDimensions) { + graph.edges.push({ + source: { + node_id: MASK_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }); + } else { + graph.edges.push({ + source: { + node_id: MASK_COMBINE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }); + } + + graph.edges.push( + { + source: { + node_id: INPAINT_INFILL, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'image', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'mask', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'denoise_mask', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'denoise_mask', + }, + } + ); + } + // Handle Seed if (shouldRandomizeSeed) { // Random int node to generate the starting seed diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index ca3f39257e..6b898e1db6 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -71,6 +71,7 @@ export const buildCanvasSDXLInpaintGraph = ( shouldUseCpuNoise, maskBlur, maskBlurMethod, + canvasCoherenceMode, canvasCoherenceSteps, canvasCoherenceStrength, seamlessXAxis, @@ -182,21 +183,6 @@ export const buildCanvasSDXLInpaintGraph = ( b: 1, is_intermediate: true, }, - [CANVAS_COHERENCE_MASK_EDGE]: { - type: 'mask_edge', - id: CANVAS_COHERENCE_MASK_EDGE, - is_intermediate: true, - edge_blur: maskBlur, - edge_size: maskBlur * 2, - low_threshold: 100, - high_threshold: 200, - }, - [CANVAS_COHERENCE_INPAINT_CREATE_MASK]: { - type: 'create_denoise_mask', - id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - is_intermediate: true, - fp32: vaePrecision === 'fp32' ? true : false, - }, [CANVAS_COHERENCE_DENOISE_LATENTS]: { type: 'denoise_latents', id: CANVAS_COHERENCE_DENOISE_LATENTS, @@ -348,27 +334,6 @@ export const buildCanvasSDXLInpaintGraph = ( field: 'denoise_mask', }, }, - // Create Coherence Mask - { - source: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'mask', - }, - }, - { - source: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'denoise_mask', - }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'denoise_mask', - }, - }, // Iterate { source: { @@ -552,26 +517,6 @@ export const buildCanvasSDXLInpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: INPAINT_IMAGE_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, // Color Correct The Inpainted Result { source: { @@ -633,16 +578,6 @@ export const buildCanvasSDXLInpaintGraph = ( ...(graph.nodes[INPAINT_CREATE_MASK] as CreateDenoiseMaskInvocation), image: canvasInitImage, }; - graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { - ...(graph.nodes[ - CANVAS_COHERENCE_INPAINT_CREATE_MASK - ] as CreateDenoiseMaskInvocation), - image: canvasInitImage, - }; - graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { - ...(graph.nodes[CANVAS_COHERENCE_MASK_EDGE] as MaskEdgeInvocation), - image: canvasMaskImage, - }; graph.edges.push( // Color Correct The Inpainted Result @@ -669,6 +604,84 @@ export const buildCanvasSDXLInpaintGraph = ( ); } + // Handle Coherence Mode + if (canvasCoherenceMode === 'edge') { + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + type: 'mask_edge', + id: CANVAS_COHERENCE_MASK_EDGE, + is_intermediate: true, + edge_blur: maskBlur, + edge_size: maskBlur * 2, + low_threshold: 100, + high_threshold: 200, + }; + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + type: 'create_denoise_mask', + id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + is_intermediate: true, + fp32: vaePrecision === 'fp32' ? true : false, + }; + + if (isUsingScaledDimensions) { + graph.edges.push( + { + source: { + node_id: MASK_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }, + { + source: { + node_id: INPAINT_IMAGE_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'image', + }, + } + ); + } else { + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + ...(graph.nodes[ + CANVAS_COHERENCE_INPAINT_CREATE_MASK + ] as CreateDenoiseMaskInvocation), + image: canvasInitImage, + }; + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + ...(graph.nodes[CANVAS_COHERENCE_MASK_EDGE] as MaskEdgeInvocation), + image: canvasMaskImage, + }; + } + + graph.edges.push( + { + source: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'mask', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'denoise_mask', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'denoise_mask', + }, + } + ); + } + // Handle Seed if (shouldRandomizeSeed) { // Random int node to generate the starting seed diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index bd06228beb..c839815f98 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -72,9 +72,11 @@ export const buildCanvasSDXLOutpaintGraph = ( shouldUseNoiseSettings, shouldUseCpuNoise, maskBlur, + canvasCoherenceMode, canvasCoherenceSteps, canvasCoherenceStrength, infillTileSize, + infillPatchmatchDownscaleSize, infillMethod, seamlessXAxis, seamlessYAxis, @@ -190,21 +192,6 @@ export const buildCanvasSDXLOutpaintGraph = ( b: 1, is_intermediate: true, }, - [CANVAS_COHERENCE_MASK_EDGE]: { - type: 'mask_edge', - id: CANVAS_COHERENCE_MASK_EDGE, - is_intermediate: true, - edge_blur: maskBlur, - edge_size: maskBlur * 2, - low_threshold: 100, - high_threshold: 200, - }, - [CANVAS_COHERENCE_INPAINT_CREATE_MASK]: { - type: 'create_denoise_mask', - id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - is_intermediate: true, - fp32: vaePrecision === 'fp32' ? true : false, - }, [CANVAS_COHERENCE_DENOISE_LATENTS]: { type: 'denoise_latents', id: CANVAS_COHERENCE_DENOISE_LATENTS, @@ -377,27 +364,6 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'denoise_mask', }, }, - // Create Coherence Mask - { - source: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'mask', - }, - }, - { - source: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'denoise_mask', - }, - destination: { - node_id: CANVAS_COHERENCE_DENOISE_LATENTS, - field: 'denoise_mask', - }, - }, // Iterate { source: { @@ -490,6 +456,16 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'latents', }, }, + { + source: { + node_id: INPAINT_INFILL, + field: 'image', + }, + destination: { + node_id: INPAINT_CREATE_MASK, + field: 'image', + }, + }, // Decode inpainted latents to image { source: { @@ -602,26 +578,7 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, + // Take combined mask and resize and then blur { source: { @@ -633,16 +590,7 @@ export const buildCanvasSDXLOutpaintGraph = ( field: 'image', }, }, - { - source: { - node_id: MASK_RESIZE_UP, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, + // Resize Results Down { source: { @@ -726,37 +674,6 @@ export const buildCanvasSDXLOutpaintGraph = ( }; graph.edges.push( - // Take combined mask and plug it to blur - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: INPAINT_CREATE_MASK, - field: 'image', - }, - }, - { - source: { - node_id: MASK_COMBINE, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_MASK_EDGE, - field: 'image', - }, - }, - { - source: { - node_id: INPAINT_INFILL, - field: 'image', - }, - destination: { - node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, - field: 'image', - }, - }, // Color Correct The Inpainted Result { source: { @@ -791,6 +708,82 @@ export const buildCanvasSDXLOutpaintGraph = ( ); } + // Handle Coherence Mode + if (canvasCoherenceMode === 'edge') { + graph.nodes[CANVAS_COHERENCE_MASK_EDGE] = { + type: 'mask_edge', + id: CANVAS_COHERENCE_MASK_EDGE, + is_intermediate: true, + edge_blur: maskBlur, + edge_size: maskBlur * 2, + low_threshold: 100, + high_threshold: 200, + }; + graph.nodes[CANVAS_COHERENCE_INPAINT_CREATE_MASK] = { + type: 'create_denoise_mask', + id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + is_intermediate: true, + fp32: vaePrecision === 'fp32' ? true : false, + }; + + if (isUsingScaledDimensions) { + graph.edges.push({ + source: { + node_id: MASK_RESIZE_UP, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }); + } else { + graph.edges.push({ + source: { + node_id: MASK_COMBINE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + }); + } + + graph.edges.push( + { + source: { + node_id: INPAINT_INFILL, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'image', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_MASK_EDGE, + field: 'image', + }, + destination: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'mask', + }, + }, + { + source: { + node_id: CANVAS_COHERENCE_INPAINT_CREATE_MASK, + field: 'denoise_mask', + }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'denoise_mask', + }, + } + ); + } + // Handle Seed if (shouldRandomizeSeed) { // Random int node to generate the starting seed diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceMode.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceMode.tsx new file mode 100644 index 0000000000..398a11957c --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/CoherencePass/ParamCanvasCoherenceMode.tsx @@ -0,0 +1,41 @@ +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { IAISelectDataType } from 'common/components/IAIMantineSearchableSelect'; +import IAIMantineSelect from 'common/components/IAIMantineSelect'; +import { setCanvasCoherenceMode } from 'features/parameters/store/generationSlice'; +import { CanvasCoherenceModeParam } from 'features/parameters/types/parameterSchemas'; + +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +const coherenceModeSelectData: IAISelectDataType[] = [ + { label: 'Full', value: 'full' }, + { label: 'Edge', value: 'edge' }, +]; + +const ParamCanvasCoherenceMode = () => { + const dispatch = useAppDispatch(); + const canvasCoherenceMode = useAppSelector( + (state: RootState) => state.generation.canvasCoherenceMode + ); + const { t } = useTranslation(); + + const handleCoherenceModeChange = (v: string | null) => { + if (!v) { + return; + } + + dispatch(setCanvasCoherenceMode(v as CanvasCoherenceModeParam)); + }; + + return ( + + ); +}; + +export default memo(ParamCanvasCoherenceMode); diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx index c3c978e8a1..e06287c7c7 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse.tsx @@ -3,6 +3,7 @@ import IAICollapse from 'common/components/IAICollapse'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import SubParametersWrapper from '../../SubParametersWrapper'; +import ParamCanvasCoherenceMode from './CoherencePass/ParamCanvasCoherenceMode'; import ParamCanvasCoherenceSteps from './CoherencePass/ParamCanvasCoherenceSteps'; import ParamCanvasCoherenceStrength from './CoherencePass/ParamCanvasCoherenceStrength'; import ParamMaskBlur from './MaskAdjustment/ParamMaskBlur'; @@ -20,6 +21,7 @@ const ParamCompositingSettingsCollapse = () => { + diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 7bbfc5149d..7703376e43 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -7,6 +7,7 @@ import { ImageDTO } from 'services/api/types'; import { clipSkipMap } from '../types/constants'; import { + CanvasCoherenceModeParam, CfgScaleParam, HeightParam, MainModelParam, @@ -37,6 +38,7 @@ export interface GenerationState { scheduler: SchedulerParam; maskBlur: number; maskBlurMethod: MaskBlurMethodParam; + canvasCoherenceMode: CanvasCoherenceModeParam; canvasCoherenceSteps: number; canvasCoherenceStrength: StrengthParam; seed: SeedParam; @@ -78,6 +80,7 @@ export const initialGenerationState: GenerationState = { scheduler: 'euler', maskBlur: 16, maskBlurMethod: 'box', + canvasCoherenceMode: 'edge', canvasCoherenceSteps: 20, canvasCoherenceStrength: 0.3, seed: 0, @@ -208,6 +211,12 @@ export const generationSlice = createSlice({ setMaskBlurMethod: (state, action: PayloadAction) => { state.maskBlurMethod = action.payload; }, + setCanvasCoherenceMode: ( + state, + action: PayloadAction + ) => { + state.canvasCoherenceMode = action.payload; + }, setCanvasCoherenceSteps: (state, action: PayloadAction) => { state.canvasCoherenceSteps = action.payload; }, @@ -331,6 +340,7 @@ export const { setScheduler, setMaskBlur, setMaskBlurMethod, + setCanvasCoherenceMode, setCanvasCoherenceSteps, setCanvasCoherenceStrength, setSeed, diff --git a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts index e210efc414..e53749582b 100644 --- a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts +++ b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts @@ -418,6 +418,22 @@ export const isValidMaskBlurMethod = ( val: unknown ): val is MaskBlurMethodParam => zMaskBlurMethod.safeParse(val).success; +/** + * Zod schema for a Canvas Coherence Mode method parameter + */ +export const zCanvasCoherenceMode = z.enum(['full', 'edge']); +/** + * Type alias for Canvas Coherence Mode parameter, inferred from its zod schema + */ +export type CanvasCoherenceModeParam = z.infer; +/** + * Validates/type-guards a value as a mask blur method parameter + */ +export const isValidCoherenceModeParam = ( + val: unknown +): val is CanvasCoherenceModeParam => + zCanvasCoherenceMode.safeParse(val).success; + // /** // * Zod schema for BaseModelType // */