mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): move strength to init image layer
This further splits the control layers state into its own thing.
This commit is contained in:
parent
e8d60e8d83
commit
4adc592657
@ -8,6 +8,7 @@ import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerT
|
|||||||
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
|
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
|
||||||
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
|
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
|
||||||
import {
|
import {
|
||||||
|
iiLayerDenoisingStrengthChanged,
|
||||||
iiLayerImageChanged,
|
iiLayerImageChanged,
|
||||||
layerSelected,
|
layerSelected,
|
||||||
selectIILayerOrThrow,
|
selectIILayerOrThrow,
|
||||||
@ -36,6 +37,13 @@ export const IILayer = memo(({ layerId }: Props) => {
|
|||||||
[dispatch, layerId]
|
[dispatch, layerId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onChangeDenoisingStrength = useCallback(
|
||||||
|
(denoisingStrength: number) => {
|
||||||
|
dispatch(iiLayerDenoisingStrengthChanged({ layerId, denoisingStrength }));
|
||||||
|
},
|
||||||
|
[dispatch, layerId]
|
||||||
|
);
|
||||||
|
|
||||||
const droppableData = useMemo<IILayerImageDropData>(
|
const droppableData = useMemo<IILayerImageDropData>(
|
||||||
() => ({
|
() => ({
|
||||||
actionType: 'SET_II_LAYER_IMAGE',
|
actionType: 'SET_II_LAYER_IMAGE',
|
||||||
@ -67,7 +75,7 @@ export const IILayer = memo(({ layerId }: Props) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<Flex flexDir="column" gap={3} px={3} pb={3}>
|
<Flex flexDir="column" gap={3} px={3} pb={3}>
|
||||||
<ImageToImageStrength />
|
<ImageToImageStrength value={layer.denoisingStrength} onChange={onChangeDenoisingStrength} />
|
||||||
<InitialImagePreview
|
<InitialImagePreview
|
||||||
image={layer.image}
|
image={layer.image}
|
||||||
onChangeImage={onChangeImage}
|
onChangeImage={onChangeImage}
|
||||||
|
@ -49,7 +49,7 @@ import type {
|
|||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export const initialControlLayersState: ControlLayersState = {
|
export const initialControlLayersState: ControlLayersState = {
|
||||||
_version: 1,
|
_version: 2,
|
||||||
selectedLayerId: null,
|
selectedLayerId: null,
|
||||||
brushSize: 100,
|
brushSize: 100,
|
||||||
layers: [],
|
layers: [],
|
||||||
@ -642,6 +642,7 @@ export const controlLayersSlice = createSlice({
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
|
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
|
||||||
isSelected: true,
|
isSelected: true,
|
||||||
|
denoisingStrength: 0.75,
|
||||||
};
|
};
|
||||||
state.layers.push(layer);
|
state.layers.push(layer);
|
||||||
state.selectedLayerId = layer.id;
|
state.selectedLayerId = layer.id;
|
||||||
@ -666,6 +667,11 @@ export const controlLayersSlice = createSlice({
|
|||||||
const layer = selectIILayerOrThrow(state, layerId);
|
const layer = selectIILayerOrThrow(state, layerId);
|
||||||
layer.opacity = opacity;
|
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
|
//#endregion
|
||||||
|
|
||||||
//#region Globals
|
//#region Globals
|
||||||
@ -841,6 +847,7 @@ export const {
|
|||||||
iiLayerAdded,
|
iiLayerAdded,
|
||||||
iiLayerImageChanged,
|
iiLayerImageChanged,
|
||||||
iiLayerOpacityChanged,
|
iiLayerOpacityChanged,
|
||||||
|
iiLayerDenoisingStrengthChanged,
|
||||||
// Globals
|
// Globals
|
||||||
positivePromptChanged,
|
positivePromptChanged,
|
||||||
negativePromptChanged,
|
negativePromptChanged,
|
||||||
@ -860,6 +867,10 @@ export const selectControlLayersSlice = (state: RootState) => state.controlLayer
|
|||||||
|
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||||
const migrateControlLayersState = (state: any): 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;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,12 +79,13 @@ export type InitialImageLayer = RenderableLayerBase & {
|
|||||||
type: 'initial_image_layer';
|
type: 'initial_image_layer';
|
||||||
opacity: number;
|
opacity: number;
|
||||||
image: ImageWithDims | null;
|
image: ImageWithDims | null;
|
||||||
|
denoisingStrength: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Layer = RegionalGuidanceLayer | ControlAdapterLayer | IPAdapterLayer | InitialImageLayer;
|
export type Layer = RegionalGuidanceLayer | ControlAdapterLayer | IPAdapterLayer | InitialImageLayer;
|
||||||
|
|
||||||
export type ControlLayersState = {
|
export type ControlLayersState = {
|
||||||
_version: 1;
|
_version: 2;
|
||||||
selectedLayerId: string | null;
|
selectedLayerId: string | null;
|
||||||
layers: Layer[];
|
layers: Layer[];
|
||||||
brushSize: number;
|
brushSize: number;
|
||||||
|
@ -15,13 +15,13 @@ export const addInitialImageToLinearGraph = (
|
|||||||
denoiseNodeId: string
|
denoiseNodeId: string
|
||||||
): boolean => {
|
): boolean => {
|
||||||
// Remove Existing UNet Connections
|
// Remove Existing UNet Connections
|
||||||
const { img2imgStrength, vaePrecision, model } = state.generation;
|
const { vaePrecision, model } = state.generation;
|
||||||
const { refinerModel, refinerStart } = state.sdxl;
|
const { refinerModel, refinerStart } = state.sdxl;
|
||||||
const { width, height } = state.controlLayers.present.size;
|
const { width, height } = state.controlLayers.present.size;
|
||||||
const initialImageLayer = state.controlLayers.present.layers.find(isInitialImageLayer);
|
const initialImageLayer = state.controlLayers.present.layers.find(isInitialImageLayer);
|
||||||
const initialImage = initialImageLayer?.isEnabled ? initialImageLayer?.image : null;
|
const initialImage = initialImageLayer?.isEnabled ? initialImageLayer?.image : null;
|
||||||
|
|
||||||
if (!initialImage) {
|
if (!initialImage || !initialImageLayer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,10 @@ export const addInitialImageToLinearGraph = (
|
|||||||
const denoiseNode = graph.nodes[denoiseNodeId];
|
const denoiseNode = graph.nodes[denoiseNodeId];
|
||||||
assert(denoiseNode?.type === 'denoise_latents', `Missing denoise node or incorrect type: ${denoiseNode?.type}`);
|
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;
|
denoiseNode.denoising_end = useRefinerStartEnd ? refinerStart : 1;
|
||||||
|
|
||||||
// We conditionally hook the image in depending on if a resize is needed
|
// We conditionally hook the image in depending on if a resize is needed
|
||||||
@ -122,7 +125,7 @@ export const addInitialImageToLinearGraph = (
|
|||||||
|
|
||||||
upsertMetadata(graph, {
|
upsertMetadata(graph, {
|
||||||
generation_mode: isSDXL ? 'sdxl_img2img' : 'img2img',
|
generation_mode: isSDXL ? 'sdxl_img2img' : 'img2img',
|
||||||
strength: img2imgStrength,
|
strength: denoisingStrength,
|
||||||
init_image: initialImage.imageName,
|
init_image: initialImage.imageName,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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);
|
@ -1,14 +1,17 @@
|
|||||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
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 { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
|
import { memo } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const marks = [0, 0.5, 1];
|
const marks = [0, 0.5, 1];
|
||||||
|
|
||||||
const ImageToImageStrength = () => {
|
type Props = {
|
||||||
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
|
value: number;
|
||||||
|
onChange: (v: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImageToImageStrength = ({ value, onChange }: Props) => {
|
||||||
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
|
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
|
||||||
const sliderMin = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMin);
|
const sliderMin = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMin);
|
||||||
const sliderMax = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMax);
|
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 numberInputMax = useAppSelector((s) => s.config.sd.img2imgStrength.numberInputMax);
|
||||||
const coarseStep = useAppSelector((s) => s.config.sd.img2imgStrength.coarseStep);
|
const coarseStep = useAppSelector((s) => s.config.sd.img2imgStrength.coarseStep);
|
||||||
const fineStep = useAppSelector((s) => s.config.sd.img2imgStrength.fineStep);
|
const fineStep = useAppSelector((s) => s.config.sd.img2imgStrength.fineStep);
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleChange = useCallback((v: number) => dispatch(setImg2imgStrength(v)), [dispatch]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<InformationalPopover feature="paramDenoisingStrength">
|
<InformationalPopover feature="paramDenoisingStrength">
|
||||||
@ -31,8 +31,8 @@ const ImageToImageStrength = () => {
|
|||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
min={sliderMin}
|
min={sliderMin}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
onChange={handleChange}
|
onChange={onChange}
|
||||||
value={img2imgStrength}
|
value={value}
|
||||||
defaultValue={initial}
|
defaultValue={initial}
|
||||||
marks={marks}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
@ -41,8 +41,8 @@ const ImageToImageStrength = () => {
|
|||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
min={numberInputMin}
|
min={numberInputMin}
|
||||||
max={numberInputMax}
|
max={numberInputMax}
|
||||||
onChange={handleChange}
|
onChange={onChange}
|
||||||
value={img2imgStrength}
|
value={value}
|
||||||
defaultValue={initial}
|
defaultValue={initial}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
@ -9,7 +9,7 @@ import { selectHrfSlice } from 'features/hrf/store/hrfSlice';
|
|||||||
import ParamScaleBeforeProcessing from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaleBeforeProcessing';
|
import ParamScaleBeforeProcessing from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaleBeforeProcessing';
|
||||||
import ParamScaledHeight from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight';
|
import ParamScaledHeight from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledHeight';
|
||||||
import ParamScaledWidth from 'features/parameters/components/Canvas/InfillAndScaling/ParamScaledWidth';
|
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 { ParamSeedNumberInput } from 'features/parameters/components/Seed/ParamSeedNumberInput';
|
||||||
import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSeedRandomize';
|
import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSeedRandomize';
|
||||||
import { ParamSeedShuffle } from 'features/parameters/components/Seed/ParamSeedShuffle';
|
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 px={4} pt={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
|
||||||
<Flex flexDir="column" gap={4}>
|
<Flex flexDir="column" gap={4}>
|
||||||
{activeTabName === 'canvas' ? <ImageSizeCanvas /> : <ImageSizeLinear />}
|
{activeTabName === 'canvas' ? <ImageSizeCanvas /> : <ImageSizeLinear />}
|
||||||
{activeTabName === 'canvas' && <ImageToImageStrength />}
|
{activeTabName === 'canvas' && <ParamImageToImageStrength />}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
|
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
|
||||||
<Flex gap={4} pb={4} flexDir="column">
|
<Flex gap={4} pb={4} flexDir="column">
|
||||||
|
Loading…
Reference in New Issue
Block a user