mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
tweaks in response to psychedelicious review of PR
This commit is contained in:
parent
7ce5b6504f
commit
4194a0ed99
@ -16,21 +16,24 @@ Output Example:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## **Seamless Tiling**
|
## **Invisible Watermark**
|
||||||
|
|
||||||
The seamless tiling mode causes generated images to seamlessly tile
|
In keeping with the principles for responsible AI generation, and to
|
||||||
with itself creating repetitive wallpaper-like patterns. To use it,
|
help AI researchers avoid synthetic images contaminating their
|
||||||
activate the Seamless Tiling option in the Web GUI and then select
|
training sets, InvokeAI adds an invisible watermark to each of the
|
||||||
whether to tile on the X (horizontal) and/or Y (vertical) axes. Tiling
|
final images it generates. The watermark consists of the text
|
||||||
will then be active for the next set of generations.
|
"InvokeAI" and can be viewed using the
|
||||||
|
[invisible-watermarks](https://github.com/ShieldMnt/invisible-watermark)
|
||||||
|
tool.
|
||||||
|
|
||||||
A nice prompt to test seamless tiling with is:
|
Watermarking is controlled using the `invisible-watermark` setting in
|
||||||
|
`invokeai.yaml`. To turn it off, add the following line under the `Features`
|
||||||
|
category.
|
||||||
|
|
||||||
```
|
```
|
||||||
pond garden with lotus by claude monet"
|
invisible_watermark: false
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Weighted Prompts**
|
## **Weighted Prompts**
|
||||||
|
|
||||||
@ -39,34 +42,10 @@ priority to them, by adding `:<percent>` to the end of the section you wish to u
|
|||||||
example consider this prompt:
|
example consider this prompt:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tabby cat:0.25 white duck:0.75 hybrid
|
(tabby cat):0.25 (white duck):0.75 hybrid
|
||||||
```
|
```
|
||||||
|
|
||||||
This will tell the sampler to invest 25% of its effort on the tabby cat aspect of the image and 75%
|
This will tell the sampler to invest 25% of its effort on the tabby cat aspect of the image and 75%
|
||||||
on the white duck aspect (surprisingly, this example actually works). The prompt weights can use any
|
on the white duck aspect (surprisingly, this example actually works). The prompt weights can use any
|
||||||
combination of integers and floating point numbers, and they do not need to add up to 1.
|
combination of integers and floating point numbers, and they do not need to add up to 1.
|
||||||
|
|
||||||
## **Thresholding and Perlin Noise Initialization Options**
|
|
||||||
|
|
||||||
Under the Noise section of the Web UI, you will find two options named
|
|
||||||
Perlin Noise and Noise Threshold. [Perlin
|
|
||||||
noise](https://en.wikipedia.org/wiki/Perlin_noise) is a type of
|
|
||||||
structured noise used to simulate terrain and other natural
|
|
||||||
textures. The slider controls the percentage of perlin noise that will
|
|
||||||
be mixed into the image at the beginning of generation. Adding a little
|
|
||||||
perlin noise to a generation will alter the image substantially.
|
|
||||||
|
|
||||||
The noise threshold limits the range of the latent values during
|
|
||||||
sampling and helps combat the oversharpening seem with higher CFG
|
|
||||||
scale values.
|
|
||||||
|
|
||||||
For better intuition into what these options do in practice:
|
|
||||||
|
|
||||||
![here is a graphic demonstrating them both](../assets/truncation_comparison.jpg)
|
|
||||||
|
|
||||||
In generating this graphic, perlin noise at initialization was
|
|
||||||
programmatically varied going across on the diagram by values 0.0,
|
|
||||||
0.1, 0.2, 0.4, 0.5, 0.6, 0.8, 0.9, 1.0; and the threshold was varied
|
|
||||||
going down from 0, 1, 2, 3, 4, 5, 10, 20, 100. The other options are
|
|
||||||
fixed using the prompt "a portrait of a beautiful young lady" a CFG of
|
|
||||||
20, 100 steps, and a seed of 1950357039.
|
|
||||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
@ -20,7 +20,7 @@ from ...backend.model_management import BaseModelType, ModelType
|
|||||||
from ..models.image import ImageCategory, ImageField, ResourceOrigin
|
from ..models.image import ImageCategory, ImageField, ResourceOrigin
|
||||||
from .baseinvocation import (BaseInvocation, BaseInvocationOutput,
|
from .baseinvocation import (BaseInvocation, BaseInvocationOutput,
|
||||||
InvocationConfig, InvocationContext)
|
InvocationConfig, InvocationContext)
|
||||||
from .image_defs import ImageOutput, PILInvocationConfig
|
from ..models.image import ImageOutput, PILInvocationConfig
|
||||||
|
|
||||||
CONTROLNET_DEFAULT_MODELS = [
|
CONTROLNET_DEFAULT_MODELS = [
|
||||||
###########################################
|
###########################################
|
||||||
|
@ -4,24 +4,21 @@ from typing import Literal, Optional
|
|||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from PIL import Image, ImageFilter, ImageOps, ImageChops
|
from PIL import Image, ImageFilter, ImageOps, ImageChops
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import Field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from invokeai.app.invocations.metadata import CoreMetadata
|
from invokeai.app.invocations.metadata import CoreMetadata
|
||||||
from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker
|
from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker
|
||||||
from transformers import AutoFeatureExtractor
|
from transformers import AutoFeatureExtractor
|
||||||
from ..models.image import ImageCategory, ImageField, ResourceOrigin
|
from ..models.image import (
|
||||||
|
ImageCategory, ImageField, ResourceOrigin,
|
||||||
|
PILInvocationConfig, ImageOutput, MaskOutput,
|
||||||
|
)
|
||||||
from .baseinvocation import (
|
from .baseinvocation import (
|
||||||
BaseInvocation,
|
BaseInvocation,
|
||||||
BaseInvocationOutput,
|
|
||||||
InvocationContext,
|
InvocationContext,
|
||||||
InvocationConfig,
|
InvocationConfig,
|
||||||
)
|
)
|
||||||
from .image_defs import (
|
|
||||||
PILInvocationConfig,
|
|
||||||
ImageOutput,
|
|
||||||
MaskOutput,
|
|
||||||
)
|
|
||||||
from ..services.config import InvokeAIAppConfig
|
from ..services.config import InvokeAIAppConfig
|
||||||
from invokeai.backend.util.devices import choose_torch_device
|
from invokeai.backend.util.devices import choose_torch_device
|
||||||
from invokeai.backend import SilenceWarnings
|
from invokeai.backend import SilenceWarnings
|
||||||
@ -644,7 +641,7 @@ class ImageNSFWBlurInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
device = choose_torch_device()
|
device = choose_torch_device()
|
||||||
|
|
||||||
if self.enabled:
|
if self.enabled:
|
||||||
logger.info("Running NSFW checker")
|
logger.debug("Running NSFW checker")
|
||||||
safety_checker = StableDiffusionSafetyChecker.from_pretrained(config.models_path / 'core/convert/stable-diffusion-safety-checker')
|
safety_checker = StableDiffusionSafetyChecker.from_pretrained(config.models_path / 'core/convert/stable-diffusion-safety-checker')
|
||||||
feature_extractor = AutoFeatureExtractor.from_pretrained(config.models_path / 'core/convert/stable-diffusion-safety-checker')
|
feature_extractor = AutoFeatureExtractor.from_pretrained(config.models_path / 'core/convert/stable-diffusion-safety-checker')
|
||||||
|
|
||||||
@ -681,8 +678,8 @@ class ImageNSFWBlurInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _get_caution_img(self)->Image:
|
def _get_caution_img(self)->Image:
|
||||||
import invokeai.assets.web as web_assets
|
import invokeai.app.assets.images as image_assets
|
||||||
caution = Image.open(Path(web_assets.__path__[0]) / 'caution.png')
|
caution = Image.open(Path(image_assets.__path__[0]) / 'caution.png')
|
||||||
return caution.resize((caution.width // 2, caution.height //2))
|
return caution.resize((caution.width // 2, caution.height //2))
|
||||||
|
|
||||||
class ImageWatermarkInvocation(BaseInvocation, PILInvocationConfig):
|
class ImageWatermarkInvocation(BaseInvocation, PILInvocationConfig):
|
||||||
@ -716,7 +713,7 @@ class ImageWatermarkInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
logger = context.services.logger
|
logger = context.services.logger
|
||||||
image = context.services.images.get_pil_image(self.image.image_name)
|
image = context.services.images.get_pil_image(self.image.image_name)
|
||||||
if self.enabled:
|
if self.enabled:
|
||||||
logger.info("Running invisible watermarker")
|
logger.debug("Running invisible watermarker")
|
||||||
bgr = cv2.cvtColor(numpy.array(image.convert("RGB")), cv2.COLOR_RGB2BGR)
|
bgr = cv2.cvtColor(numpy.array(image.convert("RGB")), cv2.COLOR_RGB2BGR)
|
||||||
wm = self.text
|
wm = self.text
|
||||||
encoder = WatermarkEncoder()
|
encoder = WatermarkEncoder()
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
# Copyright 2023 Lincoln D. Stein and the InvokeAI Team
|
|
||||||
""" Common classes used by .image and .controlnet; avoids circular import issues """
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from typing import Literal
|
|
||||||
from ..models.image import ImageField
|
|
||||||
from .baseinvocation import (
|
|
||||||
BaseInvocationOutput,
|
|
||||||
InvocationConfig,
|
|
||||||
)
|
|
||||||
|
|
||||||
class PILInvocationConfig(BaseModel):
|
|
||||||
"""Helper class to provide all PIL invocations with additional config"""
|
|
||||||
|
|
||||||
class Config(InvocationConfig):
|
|
||||||
schema_extra = {
|
|
||||||
"ui": {
|
|
||||||
"tags": ["PIL", "image"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImageOutput(BaseInvocationOutput):
|
|
||||||
"""Base class for invocations that output an image"""
|
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
type: Literal["image_output"] = "image_output"
|
|
||||||
image: ImageField = Field(default=None, description="The output image")
|
|
||||||
width: int = Field(description="The width of the image in pixels")
|
|
||||||
height: int = Field(description="The height of the image in pixels")
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
schema_extra = {"required": ["type", "image", "width", "height"]}
|
|
||||||
|
|
||||||
|
|
||||||
class MaskOutput(BaseInvocationOutput):
|
|
||||||
"""Base class for invocations that output a mask"""
|
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
type: Literal["mask"] = "mask"
|
|
||||||
mask: ImageField = Field(default=None, description="The output mask")
|
|
||||||
width: int = Field(description="The width of the mask in pixels")
|
|
||||||
height: int = Field(description="The height of the mask in pixels")
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
schema_extra = {
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"mask",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,9 +1,80 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple, Literal
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from invokeai.app.util.metaenum import MetaEnum
|
from invokeai.app.util.metaenum import MetaEnum
|
||||||
|
from ..invocations.baseinvocation import (
|
||||||
|
BaseInvocationOutput,
|
||||||
|
InvocationConfig,
|
||||||
|
)
|
||||||
|
|
||||||
|
class ImageField(BaseModel):
|
||||||
|
"""An image field used for passing image objects between invocations"""
|
||||||
|
|
||||||
|
image_name: Optional[str] = Field(default=None, description="The name of the image")
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {"required": ["image_name"]}
|
||||||
|
|
||||||
|
|
||||||
|
class ColorField(BaseModel):
|
||||||
|
r: int = Field(ge=0, le=255, description="The red component")
|
||||||
|
g: int = Field(ge=0, le=255, description="The green component")
|
||||||
|
b: int = Field(ge=0, le=255, description="The blue component")
|
||||||
|
a: int = Field(ge=0, le=255, description="The alpha component")
|
||||||
|
|
||||||
|
def tuple(self) -> Tuple[int, int, int, int]:
|
||||||
|
return (self.r, self.g, self.b, self.a)
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressImage(BaseModel):
|
||||||
|
"""The progress image sent intermittently during processing"""
|
||||||
|
|
||||||
|
width: int = Field(description="The effective width of the image in pixels")
|
||||||
|
height: int = Field(description="The effective height of the image in pixels")
|
||||||
|
dataURL: str = Field(description="The image data as a b64 data URL")
|
||||||
|
|
||||||
|
class PILInvocationConfig(BaseModel):
|
||||||
|
"""Helper class to provide all PIL invocations with additional config"""
|
||||||
|
|
||||||
|
class Config(InvocationConfig):
|
||||||
|
schema_extra = {
|
||||||
|
"ui": {
|
||||||
|
"tags": ["PIL", "image"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageOutput(BaseInvocationOutput):
|
||||||
|
"""Base class for invocations that output an image"""
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
type: Literal["image_output"] = "image_output"
|
||||||
|
image: ImageField = Field(default=None, description="The output image")
|
||||||
|
width: int = Field(description="The width of the image in pixels")
|
||||||
|
height: int = Field(description="The height of the image in pixels")
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {"required": ["type", "image", "width", "height"]}
|
||||||
|
|
||||||
|
|
||||||
|
class MaskOutput(BaseInvocationOutput):
|
||||||
|
"""Base class for invocations that output a mask"""
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
type: Literal["mask"] = "mask"
|
||||||
|
mask: ImageField = Field(default=None, description="The output mask")
|
||||||
|
width: int = Field(description="The width of the mask in pixels")
|
||||||
|
height: int = Field(description="The height of the mask in pixels")
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"mask",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
class ResourceOrigin(str, Enum, metaclass=MetaEnum):
|
class ResourceOrigin(str, Enum, metaclass=MetaEnum):
|
||||||
"""The origin of a resource (eg image).
|
"""The origin of a resource (eg image).
|
||||||
@ -63,28 +134,3 @@ class InvalidImageCategoryException(ValueError):
|
|||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
|
|
||||||
class ImageField(BaseModel):
|
|
||||||
"""An image field used for passing image objects between invocations"""
|
|
||||||
|
|
||||||
image_name: Optional[str] = Field(default=None, description="The name of the image")
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
schema_extra = {"required": ["image_name"]}
|
|
||||||
|
|
||||||
|
|
||||||
class ColorField(BaseModel):
|
|
||||||
r: int = Field(ge=0, le=255, description="The red component")
|
|
||||||
g: int = Field(ge=0, le=255, description="The green component")
|
|
||||||
b: int = Field(ge=0, le=255, description="The blue component")
|
|
||||||
a: int = Field(ge=0, le=255, description="The alpha component")
|
|
||||||
|
|
||||||
def tuple(self) -> Tuple[int, int, int, int]:
|
|
||||||
return (self.r, self.g, self.b, self.a)
|
|
||||||
|
|
||||||
|
|
||||||
class ProgressImage(BaseModel):
|
|
||||||
"""The progress image sent intermittently during processing"""
|
|
||||||
|
|
||||||
width: int = Field(description="The effective width of the image in pixels")
|
|
||||||
height: int = Field(description="The effective height of the image in pixels")
|
|
||||||
dataURL: str = Field(description="The image data as a b64 data URL")
|
|
||||||
|
@ -135,7 +135,6 @@ class SqliteBoardImageRecordStorage(BoardImageRecordStorageBase):
|
|||||||
board_id: str,
|
board_id: str,
|
||||||
image_name: str,
|
image_name: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
print(f'DEBUG: board_id={board_id}, image_name={image_name}')
|
|
||||||
try:
|
try:
|
||||||
self._lock.acquire()
|
self._lock.acquire()
|
||||||
self._cursor.execute(
|
self._cursor.execute(
|
||||||
@ -147,7 +146,6 @@ class SqliteBoardImageRecordStorage(BoardImageRecordStorageBase):
|
|||||||
(board_id, image_name, board_id),
|
(board_id, image_name, board_id),
|
||||||
)
|
)
|
||||||
self._conn.commit()
|
self._conn.commit()
|
||||||
print('got here')
|
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
self._conn.rollback()
|
self._conn.rollback()
|
||||||
raise e
|
raise e
|
||||||
|
@ -48,7 +48,7 @@ export const buildLinearTextToImageGraph = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
v * The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
||||||
* full graph here as a template. Then use the parameters from app state and set friendlier node
|
* full graph here as a template. Then use the parameters from app state and set friendlier node
|
||||||
* ids.
|
* ids.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user