new node : cut image from mask

This commit is contained in:
justumen
2024-08-24 15:00:56 +02:00
parent 4f4f6be7ff
commit aedb53c326
6 changed files with 77 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
# 🔗 Comfyui : Bjornulf_custom_nodes v0.13 🔗
# 🔗 Comfyui : Bjornulf_custom_nodes v0.14 🔗
# Dependencies
@@ -22,6 +22,7 @@
- **v0.11**: Add a new node : Text with random Seed - Generate a random seed, along with text.
- **v0.12**: Combine images : Add option to move vertically and horizontally. (from -50% to 150%)
- **v0.13**: Add a new node: Load image with transparency (alpha) - Load an image with transparency.
- **v0.14**: Add a new node: Cut image from a mask
# 📝 Nodes descriptions
@@ -233,4 +234,10 @@ FLUX : Here is an example of 4 images without Random Seed node on the left, and
**Description:**
Load an image with transparency.
The default `Load Image` node will not load the transparency.
The default `Load Image` node will not load the transparency.
## 30 - 🖼✂ Cut image with a mask
![Cut image](screenshots/image_mask_cut.png)
**Description:**
Cut an image from a mask.

View File

@@ -34,6 +34,7 @@ from .random_line_from_input import RandomLineFromInput
from .loop_lines import LoopAllLines
from .random_seed_with_text import TextToStringAndSeed
from .load_image_alpha import LoadImageWithTransparency
from .image_mask_cutter import ImageMaskCutter
# from .check_black_image import CheckBlackImage
# from .clear_vram import ClearVRAM
@@ -42,6 +43,7 @@ from .load_image_alpha import LoadImageWithTransparency
NODE_CLASS_MAPPINGS = {
# "Bjornulf_CustomStringType": CustomStringType,
"Bjornulf_ollamaLoader": ollamaLoader,
"Bjornulf_ImageMaskCutter": ImageMaskCutter,
"Bjornulf_LoadImageWithTransparency": LoadImageWithTransparency,
"Bjornulf_LoopAllLines": LoopAllLines,
"Bjornulf_TextToStringAndSeed": TextToStringAndSeed,
@@ -84,6 +86,7 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
# "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!",
"Bjornulf_ollamaLoader": "🦙 Ollama (Description)",
"Bjornulf_ImageMaskCutter": "🖼✂ Cut Image with Mask",
"Bjornulf_LoadImageWithTransparency": "🖼 Load Image with Transparency ▢",
"Bjornulf_GreenScreenToTransparency": "🟩➜▢ Green Screen to Transparency",
# "Bjornulf_CheckBlackImage": "🔲 Check Black Image (Empty mask)",

View File

@@ -8,7 +8,8 @@ class CombineBackgroundOverlay:
return {
"required": {
"background": ("IMAGE",),
"overlay_alpha": ("IMAGE",),
"overlay": ("IMAGE",),
"mask": ("MASK",),
"horizontal_position": ("FLOAT", {"default": 50, "min": -50, "max": 150, "step": 0.1}),
"vertical_position": ("FLOAT", {"default": 50, "min": -50, "max": 150, "step": 0.1}),
},
@@ -18,7 +19,7 @@ class CombineBackgroundOverlay:
FUNCTION = "combine_background_overlay"
CATEGORY = "Bjornulf"
def combine_background_overlay(self, background, overlay_alpha, horizontal_position, vertical_position):
def combine_background_overlay(self, background, overlay, mask, horizontal_position, vertical_position):
# Convert background from torch tensor to numpy array
bg = background[0].numpy()
bg = (bg * 255).astype(np.uint8)
@@ -26,17 +27,23 @@ class CombineBackgroundOverlay:
results = []
for overlay in overlay_alpha:
for ov, m in zip(overlay, mask):
# Convert overlay from torch tensor to numpy array
ov = overlay.numpy()
ov = ov.numpy()
ov = (ov * 255).astype(np.uint8)
# Convert mask from torch tensor to numpy array
m = m.numpy()
m = (m * 255).astype(np.uint8)
# Create PIL Image for overlay
if ov.shape[2] == 4:
ov_img = Image.fromarray(ov, 'RGBA')
else:
ov_img = Image.fromarray(ov, 'RGB')
ov_img = ov_img.convert('RGBA')
ov_img = Image.fromarray(ov, 'RGB')
# Create alpha channel from mask
alpha = Image.fromarray(m, 'L')
# Combine RGB overlay with alpha mask
ov_img.putalpha(alpha)
# Calculate horizontal position
x = int((horizontal_position / 100) * (bg_img.width - ov_img.width))
@@ -56,9 +63,8 @@ class CombineBackgroundOverlay:
# Convert back to numpy array and then to torch tensor
result_np = np.array(result)
# If the result is RGBA, convert to RGB
if result_np.shape[2] == 4:
result_np = result_np[:,:,:3]
# Convert RGBA to RGB
result_np = result_np[:,:,:3]
result_tensor = torch.from_numpy(result_np).float() / 255.0

46
image_mask_cutter.py Normal file
View File

@@ -0,0 +1,46 @@
import torch
class ImageMaskCutter:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"mask": ("MASK",),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "cut_image"
CATEGORY = "Bjornulf"
def cut_image(self, image, mask):
print(f"Image shape: {image.shape}")
print(f"Mask shape: {mask.shape}")
# Check if image channels are in the last dimension
if image.shape[-1] == 3 or image.shape[-1] == 4:
# Move channels to second dimension
image = image.permute(0, 3, 1, 2)
# Ensure image and mask have compatible dimensions
if image.shape[2:] != mask.shape[1:]:
raise ValueError(f"Image and mask must have compatible dimensions. Got image shape {image.shape} and mask shape {mask.shape}")
# Convert mask to float and ensure it's in the range [0, 1]
mask = mask.float()
mask = torch.clamp(mask, 0, 1)
# If image is RGB, convert to RGBA
if image.shape[1] == 3:
alpha = torch.ones((image.shape[0], 1, image.shape[2], image.shape[3]), device=image.device)
image = torch.cat([image, alpha], dim=1)
# Use the mask as the alpha channel
image[:, 3:4, :, :] = mask.unsqueeze(1)
# Move channels back to the last dimension
cut_image = image.permute(0, 2, 3, 1)
return (cut_image,)

View File

@@ -1,7 +1,7 @@
[project]
name = "bjornulf_custom_nodes"
description = "Nodes: Ollama, Green Screen to Transparency, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images (Background+Overlay alpha), Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..."
version = "0.13"
version = "0.14"
license = {file = "LICENSE"}
[project.urls]

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB