feat(ui): move strength to init image layer

This further splits the control layers state into its own thing.
This commit is contained in:
psychedelicious 2024-05-07 10:10:03 +10:00
parent e8d60e8d83
commit 4adc592657
7 changed files with 64 additions and 21 deletions

View File

@ -8,6 +8,7 @@ import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerT
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
import {
iiLayerDenoisingStrengthChanged,
iiLayerImageChanged,
layerSelected,
selectIILayerOrThrow,
@ -36,6 +37,13 @@ export const IILayer = memo(({ layerId }: Props) => {
[dispatch, layerId]
);
const onChangeDenoisingStrength = useCallback(
(denoisingStrength: number) => {
dispatch(iiLayerDenoisingStrengthChanged({ layerId, denoisingStrength }));
},
[dispatch, layerId]
);
const droppableData = useMemo<IILayerImageDropData>(
() => ({
actionType: 'SET_II_LAYER_IMAGE',
@ -67,7 +75,7 @@ export const IILayer = memo(({ layerId }: Props) => {
</Flex>
{isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
<ImageToImageStrength />
<ImageToImageStrength value={layer.denoisingStrength} onChange={onChangeDenoisingStrength} />
<InitialImagePreview
image={layer.image}
onChangeImage={onChangeImage}

View File

@ -49,7 +49,7 @@ import type {
} from './types';
export const initialControlLayersState: ControlLayersState = {
_version: 1,
_version: 2,
selectedLayerId: null,
brushSize: 100,
layers: [],
@ -642,6 +642,7 @@ export const controlLayersSlice = createSlice({
isEnabled: true,
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
isSelected: true,
denoisingStrength: 0.75,
};
state.layers.push(layer);
state.selectedLayerId = layer.id;
@ -666,6 +667,11 @@ export const controlLayersSlice = createSlice({
const layer = selectIILayerOrThrow(state, layerId);
layer.opacity = opacity;
},
iiLayerDenoisingStrengthChanged: (state, action: PayloadAction<{ layerId: string; denoisingStrength: number }>) => {
const { layerId, denoisingStrength } = action.payload;
const layer = selectIILayerOrThrow(state, layerId);
layer.denoisingStrength = denoisingStrength;
},
//#endregion
//#region Globals
@ -841,6 +847,7 @@ export const {
iiLayerAdded,
iiLayerImageChanged,
iiLayerOpacityChanged,
iiLayerDenoisingStrengthChanged,
// Globals
positivePromptChanged,
negativePromptChanged,
@ -860,6 +867,10 @@ export const selectControlLayersSlice = (state: RootState) => state.controlLayer
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
const migrateControlLayersState = (state: any): any => {
if (state._version === 1) {
// Reset state for users on v1 (e.g. beta users), some changes could cause
return deepClone(initialControlLayersState);
}
return state;
};

View File

@ -79,12 +79,13 @@ export type InitialImageLayer = RenderableLayerBase & {
type: 'initial_image_layer';
opacity: number;
image: ImageWithDims | null;
denoisingStrength: number;
};
export type Layer = RegionalGuidanceLayer | ControlAdapterLayer | IPAdapterLayer | InitialImageLayer;
export type ControlLayersState = {
_version: 1;
_version: 2;
selectedLayerId: string | null;
layers: Layer[];
brushSize: number;

View File

@ -15,13 +15,13 @@ export const addInitialImageToLinearGraph = (
denoiseNodeId: string
): boolean => {
// Remove Existing UNet Connections
const { img2imgStrength, vaePrecision, model } = state.generation;
const { vaePrecision, model } = state.generation;
const { refinerModel, refinerStart } = state.sdxl;
const { width, height } = state.controlLayers.present.size;
const initialImageLayer = state.controlLayers.present.layers.find(isInitialImageLayer);
const initialImage = initialImageLayer?.isEnabled ? initialImageLayer?.image : null;
if (!initialImage) {
if (!initialImage || !initialImageLayer) {
return false;
}
@ -31,7 +31,10 @@ export const addInitialImageToLinearGraph = (
const denoiseNode = graph.nodes[denoiseNodeId];
assert(denoiseNode?.type === 'denoise_latents', `Missing denoise node or incorrect type: ${denoiseNode?.type}`);
denoiseNode.denoising_start = useRefinerStartEnd ? Math.min(refinerStart, 1 - img2imgStrength) : 1 - img2imgStrength;
const { denoisingStrength } = initialImageLayer;
denoiseNode.denoising_start = useRefinerStartEnd
? Math.min(refinerStart, 1 - denoisingStrength)
: 1 - denoisingStrength;
denoiseNode.denoising_end = useRefinerStartEnd ? refinerStart : 1;
// We conditionally hook the image in depending on if a resize is needed
@ -122,7 +125,7 @@ export const addInitialImageToLinearGraph = (
upsertMetadata(graph, {
generation_mode: isSDXL ? 'sdxl_img2img' : 'img2img',
strength: img2imgStrength,
strength: denoisingStrength,
init_image: initialImage.imageName,
});

View File

@ -0,0 +1,20 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import ImageToImageStrength from 'features/parameters/components/ImageToImage/ImageToImageStrength';
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
const ParamImageToImageStrength = () => {
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
const dispatch = useAppDispatch();
const onChange = useCallback(
(v: number) => {
dispatch(setImg2imgStrength(v));
},
[dispatch]
);
return <ImageToImageStrength value={img2imgStrength} onChange={onChange} />;
};
export default memo(ParamImageToImageStrength);

View File

@ -1,14 +1,17 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
const marks = [0, 0.5, 1];
const ImageToImageStrength = () => {
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
type Props = {
value: number;
onChange: (v: number) => void;
};
const ImageToImageStrength = ({ value, onChange }: Props) => {
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
const sliderMin = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMax);
@ -16,11 +19,8 @@ const ImageToImageStrength = () => {
const numberInputMax = useAppSelector((s) => s.config.sd.img2imgStrength.numberInputMax);
const coarseStep = useAppSelector((s) => s.config.sd.img2imgStrength.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.img2imgStrength.fineStep);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleChange = useCallback((v: number) => dispatch(setImg2imgStrength(v)), [dispatch]);
return (
<FormControl>
<InformationalPopover feature="paramDenoisingStrength">
@ -31,8 +31,8 @@ const ImageToImageStrength = () => {
fineStep={fineStep}
min={sliderMin}
max={sliderMax}
onChange={handleChange}
value={img2imgStrength}
onChange={onChange}
value={value}
defaultValue={initial}
marks={marks}
/>
@ -41,8 +41,8 @@ const ImageToImageStrength = () => {
fineStep={fineStep}
min={numberInputMin}
max={numberInputMax}
onChange={handleChange}
value={img2imgStrength}
onChange={onChange}
value={value}
defaultValue={initial}
/>
</FormControl>

View File

@ -9,7 +9,7 @@ import { selectHrfSlice } from 'features/hrf/store/hrfSlice';
import ParamScaleBeforeProcessing from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaleBeforeProcessing';
import ParamScaledHeight from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight';
import ParamScaledWidth from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth';
import ImageToImageStrength from 'features/parameters/components/ImageToImage/ImageToImageStrength';
import ParamImageToImageStrength from 'features/parameters/components/Canvas/ParamImageToImageStrength';
import { ParamSeedNumberInput } from 'features/parameters/components/Seed/ParamSeedNumberInput';
import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSeedRandomize';
import { ParamSeedShuffle } from 'features/parameters/components/Seed/ParamSeedShuffle';
@ -87,7 +87,7 @@ export const ImageSettingsAccordion = memo(() => {
<Flex px={4} pt={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
<Flex flexDir="column" gap={4}>
{activeTabName === 'canvas' ? <ImageSizeCanvas /> : <ImageSizeLinear />}
{activeTabName === 'canvas' && <ImageToImageStrength />}
{activeTabName === 'canvas' && <ParamImageToImageStrength />}
</Flex>
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
<Flex gap={4} pb={4} flexDir="column">