feat: Add Paste / Mask Blur / Color Correction to Inpainting

Seam options are now removed. They are replaced by two options --Mask Blur and Mask Blur Method .. which control the softness of the mask that is being painted.
This commit is contained in:
blessedcoolant 2023-08-12 03:28:19 +12:00
parent 69a9dc7b36
commit 1affb7f647
11 changed files with 147 additions and 155 deletions

View File

@ -503,6 +503,9 @@
"hiresStrength": "High Res Strength", "hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size", "imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity", "codeformerFidelity": "Fidelity",
"maskAdjustmentsHeader": "Mask Adjustments",
"maskBlur": "Mask Blur",
"maskBlurMethod": "Mask Blur Method",
"seamSize": "Seam Size", "seamSize": "Seam Size",
"seamBlur": "Seam Blur", "seamBlur": "Seam Blur",
"seamStrength": "Seam Strength", "seamStrength": "Seam Strength",

View File

@ -13,12 +13,15 @@ import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph'; import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import { import {
CLIP_SKIP, CLIP_SKIP,
COLOR_CORRECT,
INPAINT, INPAINT,
INPAINT_FINAL_IMAGE,
INPAINT_GRAPH, INPAINT_GRAPH,
INPAINT_IMAGE, INPAINT_IMAGE,
ITERATE, ITERATE,
LATENTS_TO_IMAGE, LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER, MAIN_MODEL_LOADER,
MASK_BLUR,
NEGATIVE_CONDITIONING, NEGATIVE_CONDITIONING,
NOISE, NOISE,
POSITIVE_CONDITIONING, POSITIVE_CONDITIONING,
@ -50,10 +53,8 @@ export const buildCanvasInpaintGraph = (
vaePrecision, vaePrecision,
shouldUseNoiseSettings, shouldUseNoiseSettings,
shouldUseCpuNoise, shouldUseCpuNoise,
seamSize, maskBlur,
seamBlur, maskBlurMethod,
seamSteps,
seamStrength,
tileSize, tileSize,
infillMethod, infillMethod,
clipSkip, clipSkip,
@ -90,7 +91,6 @@ export const buildCanvasInpaintGraph = (
scheduler: scheduler, scheduler: scheduler,
denoising_start: 1 - strength, denoising_start: 1 - strength,
denoising_end: 1, denoising_end: 1,
mask: canvasMaskImage,
}, },
[INPAINT_IMAGE]: { [INPAINT_IMAGE]: {
type: 'i2l', type: 'i2l',
@ -137,7 +137,27 @@ export const buildCanvasInpaintGraph = (
is_intermediate: true, is_intermediate: true,
skipped_layers: clipSkip, skipped_layers: clipSkip,
}, },
[COLOR_CORRECT]: {
type: 'color_correct',
id: COLOR_CORRECT,
is_intermediate: true,
reference: canvasInitImage,
mask: canvasMaskImage,
},
[MASK_BLUR]: {
type: 'img_blur',
id: MASK_BLUR,
is_intermediate: true,
image: canvasMaskImage,
radius: maskBlur,
blur_type: maskBlurMethod,
},
[INPAINT_FINAL_IMAGE]: {
type: 'img_paste',
id: INPAINT_FINAL_IMAGE,
is_intermediate: true,
base_image: canvasInitImage,
},
[RANGE_OF_SIZE]: { [RANGE_OF_SIZE]: {
type: 'range_of_size', type: 'range_of_size',
id: RANGE_OF_SIZE, id: RANGE_OF_SIZE,
@ -234,6 +254,16 @@ export const buildCanvasInpaintGraph = (
field: 'latents', field: 'latents',
}, },
}, },
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: INPAINT,
field: 'mask',
},
},
{ {
source: { source: {
node_id: RANGE_OF_SIZE, node_id: RANGE_OF_SIZE,
@ -264,6 +294,36 @@ export const buildCanvasInpaintGraph = (
field: 'latents', field: 'latents',
}, },
}, },
{
source: {
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
destination: {
node_id: COLOR_CORRECT,
field: 'image',
},
},
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: INPAINT_FINAL_IMAGE,
field: 'mask',
},
},
{
source: {
node_id: COLOR_CORRECT,
field: 'image',
},
destination: {
node_id: INPAINT_FINAL_IMAGE,
field: 'image',
},
},
], ],
}; };

View File

@ -0,0 +1,21 @@
import { Flex } from '@chakra-ui/react';
import IAICollapse from 'common/components/IAICollapse';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import ParamMaskBlur from './ParamMaskBlur';
import ParamMaskBlurMethod from './ParamMaskBlurMethod';
const ParamMaskAdjustmentCollapse = () => {
const { t } = useTranslation();
return (
<IAICollapse label={t('parameters.maskAdjustmentsHeader')}>
<Flex sx={{ flexDirection: 'column', gap: 2 }}>
<ParamMaskBlur />
<ParamMaskBlurMethod />
</Flex>
</IAICollapse>
);
};
export default memo(ParamMaskAdjustmentCollapse);

View File

@ -1,31 +1,31 @@
import type { RootState } from 'app/store/store'; import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider'; import IAISlider from 'common/components/IAISlider';
import { setSeamBlur } from 'features/parameters/store/generationSlice'; import { setMaskBlur } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function ParamSeamBlur() { export default function ParamMaskBlur() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const seamBlur = useAppSelector( const maskBlur = useAppSelector(
(state: RootState) => state.generation.seamBlur (state: RootState) => state.generation.maskBlur
); );
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<IAISlider <IAISlider
label={t('parameters.seamBlur')} label={t('parameters.maskBlur')}
min={0} min={0}
max={64} max={64}
sliderNumberInputProps={{ max: 512 }} sliderNumberInputProps={{ max: 512 }}
value={seamBlur} value={maskBlur}
onChange={(v) => { onChange={(v) => {
dispatch(setSeamBlur(v)); dispatch(setMaskBlur(v));
}} }}
withInput withInput
withSliderMarks withSliderMarks
withReset withReset
handleReset={() => { handleReset={() => {
dispatch(setSeamBlur(16)); dispatch(setMaskBlur(16));
}} }}
/> />
); );

View File

@ -0,0 +1,36 @@
import { SelectItem } from '@mantine/core';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import { setMaskBlurMethod } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export type MaskBlurMethods = 'box' | 'gaussian';
const maskBlurMethods: SelectItem[] = [
{ label: 'Box Blur', value: 'box' },
{ label: 'Gaussian Blur', value: 'gaussian' },
];
export default function ParamMaskBlurMethod() {
const maskBlurMethod = useAppSelector(
(state: RootState) => state.generation.maskBlurMethod
);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleMaskBlurMethodChange = (v: string | null) => {
if (!v) return;
dispatch(setMaskBlurMethod(v as MaskBlurMethods));
};
return (
<IAIMantineSelect
value={maskBlurMethod}
onChange={handleMaskBlurMethodChange}
label={t('parameters.maskBlurMethod')}
data={maskBlurMethods}
/>
);
}

View File

@ -1,22 +0,0 @@
import IAICollapse from 'common/components/IAICollapse';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import ParamSeamBlur from './ParamSeamBlur';
import ParamSeamSize from './ParamSeamSize';
import ParamSeamSteps from './ParamSeamSteps';
import ParamSeamStrength from './ParamSeamStrength';
const ParamSeamCorrectionCollapse = () => {
const { t } = useTranslation();
return (
<IAICollapse label={t('parameters.seamCorrectionHeader')}>
<ParamSeamSize />
<ParamSeamBlur />
<ParamSeamStrength />
<ParamSeamSteps />
</IAICollapse>
);
};
export default memo(ParamSeamCorrectionCollapse);

View File

@ -1,31 +0,0 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setSeamSize } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function ParamSeamSize() {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const seamSize = useAppSelector(
(state: RootState) => state.generation.seamSize
);
return (
<IAISlider
label={t('parameters.seamSize')}
min={1}
max={256}
sliderNumberInputProps={{ max: 512 }}
value={seamSize}
onChange={(v) => {
dispatch(setSeamSize(v));
}}
withInput
withSliderMarks
withReset
handleReset={() => dispatch(setSeamSize(96))}
/>
);
}

View File

@ -1,32 +0,0 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setSeamSteps } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function ParamSeamSteps() {
const { t } = useTranslation();
const seamSteps = useAppSelector(
(state: RootState) => state.generation.seamSteps
);
const dispatch = useAppDispatch();
return (
<IAISlider
label={t('parameters.seamSteps')}
min={1}
max={100}
sliderNumberInputProps={{ max: 999 }}
value={seamSteps}
onChange={(v) => {
dispatch(setSeamSteps(v));
}}
withInput
withSliderMarks
withReset
handleReset={() => {
dispatch(setSeamSteps(30));
}}
/>
);
}

View File

@ -1,32 +0,0 @@
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setSeamStrength } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
export default function ParamSeamStrength() {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const seamStrength = useAppSelector(
(state: RootState) => state.generation.seamStrength
);
return (
<IAISlider
label={t('parameters.seamStrength')}
min={0.01}
max={0.99}
step={0.01}
value={seamStrength}
onChange={(v) => {
dispatch(setSeamStrength(v));
}}
withInput
withSliderMarks
withReset
handleReset={() => {
dispatch(setSeamStrength(0.7));
}}
/>
);
}

View File

@ -4,6 +4,7 @@ import { roundToMultiple } from 'common/util/roundDownToMultiple';
import { configChanged } from 'features/system/store/configSlice'; import { configChanged } from 'features/system/store/configSlice';
import { clamp } from 'lodash-es'; import { clamp } from 'lodash-es';
import { ImageDTO } from 'services/api/types'; import { ImageDTO } from 'services/api/types';
import { MaskBlurMethods } from '../components/Parameters/Canvas/MaskAdjustment/ParamMaskBlurMethod';
import { clipSkipMap } from '../types/constants'; import { clipSkipMap } from '../types/constants';
import { import {
CfgScaleParam, CfgScaleParam,
@ -33,10 +34,8 @@ export interface GenerationState {
positivePrompt: PositivePromptParam; positivePrompt: PositivePromptParam;
negativePrompt: NegativePromptParam; negativePrompt: NegativePromptParam;
scheduler: SchedulerParam; scheduler: SchedulerParam;
seamBlur: number; maskBlur: number;
seamSize: number; maskBlurMethod: MaskBlurMethods;
seamSteps: number;
seamStrength: number;
seed: SeedParam; seed: SeedParam;
seedWeights: string; seedWeights: string;
shouldFitToWidthHeight: boolean; shouldFitToWidthHeight: boolean;
@ -72,10 +71,8 @@ export const initialGenerationState: GenerationState = {
positivePrompt: '', positivePrompt: '',
negativePrompt: '', negativePrompt: '',
scheduler: 'euler', scheduler: 'euler',
seamBlur: 16, maskBlur: 16,
seamSize: 96, maskBlurMethod: 'box',
seamSteps: 30,
seamStrength: 0.7,
seed: 0, seed: 0,
seedWeights: '', seedWeights: '',
shouldFitToWidthHeight: true, shouldFitToWidthHeight: true,
@ -196,17 +193,11 @@ export const generationSlice = createSlice({
clearInitialImage: (state) => { clearInitialImage: (state) => {
state.initialImage = undefined; state.initialImage = undefined;
}, },
setSeamSize: (state, action: PayloadAction<number>) => { setMaskBlur: (state, action: PayloadAction<number>) => {
state.seamSize = action.payload; state.maskBlur = action.payload;
}, },
setSeamBlur: (state, action: PayloadAction<number>) => { setMaskBlurMethod: (state, action: PayloadAction<MaskBlurMethods>) => {
state.seamBlur = action.payload; state.maskBlurMethod = action.payload;
},
setSeamStrength: (state, action: PayloadAction<number>) => {
state.seamStrength = action.payload;
},
setSeamSteps: (state, action: PayloadAction<number>) => {
state.seamSteps = action.payload;
}, },
setTileSize: (state, action: PayloadAction<number>) => { setTileSize: (state, action: PayloadAction<number>) => {
state.tileSize = action.payload; state.tileSize = action.payload;
@ -312,10 +303,8 @@ export const {
setPositivePrompt, setPositivePrompt,
setNegativePrompt, setNegativePrompt,
setScheduler, setScheduler,
setSeamBlur, setMaskBlur,
setSeamSize, setMaskBlurMethod,
setSeamSteps,
setSeamStrength,
setSeed, setSeed,
setSeedWeights, setSeedWeights,
setShouldFitToWidthHeight, setShouldFitToWidthHeight,

View File

@ -2,10 +2,10 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse'; import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse'; import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse'; import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse';
import ParamSeamCorrectionCollapse from 'features/parameters/components/Parameters/Canvas/SeamCorrection/ParamSeamCorrectionCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse'; import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse'; import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse'; // import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
import ParamMaskAdjustmentCollapse from 'features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskAdjustmentCollapse';
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea'; import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons'; import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters'; import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters';
@ -21,7 +21,7 @@ const UnifiedCanvasParameters = () => {
<ParamDynamicPromptsCollapse /> <ParamDynamicPromptsCollapse />
{/* <ParamVariationCollapse /> */} {/* <ParamVariationCollapse /> */}
<ParamSymmetryCollapse /> <ParamSymmetryCollapse />
<ParamSeamCorrectionCollapse /> <ParamMaskAdjustmentCollapse />
<ParamInfillAndScalingCollapse /> <ParamInfillAndScalingCollapse />
<ParamAdvancedCollapse /> <ParamAdvancedCollapse />
</> </>