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 { 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}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
});
|
||||
|
||||
|
@ -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 { 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>
|
||||
|
@ -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">
|
||||
|
Loading…
Reference in New Issue
Block a user