Skip to content

Commit

Permalink
Unified crop node (#1996)
Browse files Browse the repository at this point in the history
* Unified crop node

* Fixed crop node

* Crop to Content
  • Loading branch information
RunDevelopment authored Aug 14, 2023
1 parent 4326953 commit ab1818d
Show file tree
Hide file tree
Showing 8 changed files with 726 additions and 156 deletions.
114 changes: 114 additions & 0 deletions backend/src/packages/chaiNNer_standard/image_dimension/crop/crop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from __future__ import annotations

from enum import Enum

import numpy as np

from nodes.groups import if_enum_group
from nodes.properties.inputs import EnumInput, ImageInput, NumberInput
from nodes.properties.outputs import ImageOutput
from nodes.utils.utils import get_h_w_c

from .. import crop_group


class CropMode(Enum):
BORDER = 0
EDGES = 1
OFFSETS = 2


@crop_group.register(
schema_id="chainner:image:crop",
name="Crop",
description="Crop an image.",
icon="MdCrop",
inputs=[
ImageInput(),
EnumInput(CropMode, default=CropMode.BORDER).with_id(1),
if_enum_group(1, CropMode.BORDER)(
NumberInput("Amount", unit="px").with_id(2),
),
if_enum_group(1, (CropMode.EDGES, CropMode.OFFSETS))(
NumberInput("Left", unit="px").with_id(4),
NumberInput("Top", unit="px").with_id(3),
),
if_enum_group(1, CropMode.EDGES)(
NumberInput("Right", unit="px").with_id(6),
NumberInput("Bottom", unit="px").with_id(5),
),
if_enum_group(1, CropMode.OFFSETS)(
NumberInput("Width", unit="px", minimum=1, default=1).with_id(8),
NumberInput("Height", unit="px", minimum=1, default=1).with_id(7),
),
],
outputs=[
ImageOutput(
image_type="""
let i = Input0;
let amount = Input2;
let top = Input3;
let left = Input4;
let bottom = Input5;
let right = Input6;
let height = Input7;
let width = Input8;
let size = match Input1 {
CropMode::Border => Image {
width: (i.width - amount * 2) & int(1..),
height: (i.height - amount * 2) & int(1..),
},
CropMode::Edges => Image {
width: (i.width - (left + right)) & int(1..),
height: (i.height - (top + bottom)) & int(1..),
},
CropMode::Offsets => Image {
width: min(width, i.width - left) & int(1..),
height: min(height, i.height - top) & int(1..),
},
};
size & Image { channels: i.channels }
""",
assume_normalized=True,
).with_never_reason(
"The cropped area would result in an image with no width or no height."
)
],
)
def crop_node(
img: np.ndarray,
mode: CropMode,
amount: int,
top: int,
left: int,
bottom: int,
right: int,
height: int,
width: int,
) -> np.ndarray:
h, w, _ = get_h_w_c(img)

if mode == CropMode.BORDER:
if amount == 0:
return img

assert 2 * amount < h, "Cropped area would result in an image with no height"
assert 2 * amount < w, "Cropped area would result in an image with no width"

return img[amount : h - amount, amount : w - amount]
elif mode == CropMode.EDGES:
if top == bottom == left == right == 0:
return img

assert top + bottom < h, "Cropped area would result in an image with no height"
assert left + right < w, "Cropped area would result in an image with no width"

return img[top : h - bottom, left : w - right]
elif mode == CropMode.OFFSETS:
assert top < h, "Cropped area would result in an image with no height"
assert left < w, "Cropped area would result in an image with no width"

return img[top : top + height, left : left + width]

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@crop_group.register(
schema_id="chainner:image:crop_content",
name="Crop (Content)",
name="Crop to Content",
description=(
"Crop an image to the boundaries of the visible image content, "
"removing borders at or below the given opacity threshold."
Expand Down Expand Up @@ -43,7 +43,7 @@
)
],
)
def crop_content_node(img: np.ndarray, thresh_val: float) -> np.ndarray:
def crop_to_content_node(img: np.ndarray, thresh_val: float) -> np.ndarray:
c = get_h_w_c(img)[2]
if c < 4:
return img
Expand Down
57 changes: 57 additions & 0 deletions src/common/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,62 @@ const saveImageWebPLossless: ModernMigration = (data) => {
return data;
};

const unifiedCrop: ModernMigration = (data) => {
const map = new Map<string, string>();
const changeInputId = (nodeId: string, from: number, to: number) => {
map.set(`${nodeId}-${from}`, `${nodeId}-${to}`);
};

data.nodes.forEach((node) => {
if (node.data.schemaId === 'chainner:image:crop_border') {
node.data.schemaId = 'chainner:image:crop' as SchemaId;
node.data.inputData = {
1: 0,
2: node.data.inputData[1],
};
changeInputId(node.id, 1, 2);
}

if (node.data.schemaId === 'chainner:image:crop_edges') {
node.data.schemaId = 'chainner:image:crop' as SchemaId;
node.data.inputData = {
1: 1,
3: node.data.inputData[1],
4: node.data.inputData[2],
5: node.data.inputData[4],
6: node.data.inputData[3],
};
changeInputId(node.id, 1, 3);
changeInputId(node.id, 2, 4);
changeInputId(node.id, 3, 6);
changeInputId(node.id, 4, 5);
}

if (node.data.schemaId === 'chainner:image:crop_offsets') {
node.data.schemaId = 'chainner:image:crop' as SchemaId;
node.data.inputData = {
1: 2,
3: node.data.inputData[1],
4: node.data.inputData[2],
7: node.data.inputData[3],
8: node.data.inputData[4],
};
changeInputId(node.id, 1, 3);
changeInputId(node.id, 2, 4);
changeInputId(node.id, 3, 7);
changeInputId(node.id, 4, 8);
}
});

data.edges.forEach((e) => {
if (e.targetHandle) {
e.targetHandle = map.get(e.targetHandle) ?? e.targetHandle;
}
});

return data;
};

// ==============

const versionToMigration = (version: string) => {
Expand Down Expand Up @@ -1268,6 +1324,7 @@ const migrations = [
emptyStringInput,
surfaceBlurRadius,
saveImageWebPLossless,
unifiedCrop,
];

export const currentMigration = migrations.length;
Expand Down
Loading

0 comments on commit ab1818d

Please sign in to comment.