mirror of
https://github.com/Bing-su/adetailer.git
synced 2026-02-10 10:20:05 +00:00
Merge branch 'dev'
This commit is contained in:
45
.github/workflows/pypi.yml
vendored
Normal file
45
.github/workflows/pypi.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Publish to PyPI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
runs-on: macos-14
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install .
|
||||
pip install pytest
|
||||
|
||||
- name: Run tests
|
||||
run: pytest -v
|
||||
|
||||
build:
|
||||
name: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
needs: [test]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheel
|
||||
run: pipx run build
|
||||
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
4
.github/workflows/stale.yml
vendored
4
.github/workflows/stale.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
name: Close stale issues and PRs
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
@@ -9,5 +9,5 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: 23
|
||||
days-before-stale: 17
|
||||
days-before-close: 3
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
ci:
|
||||
autoupdate_branch: "dev"
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
@@ -13,7 +16,7 @@ repos:
|
||||
- id: mixed-line-ending
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.3.3
|
||||
rev: v0.3.4
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-python.black-formatter",
|
||||
"kevinrose.vsc-python-indent",
|
||||
"charliermarsh.ruff",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 2024-03-28
|
||||
|
||||
- v24.3.4
|
||||
- 인페인트에서, 이미지 해상도가 16의 배수가 아닐 때 사이즈 불일치로 인한 opencv 에러 방지
|
||||
|
||||
## 2024-03-25
|
||||
|
||||
- v24.3.3
|
||||
|
||||
@@ -24,4 +24,8 @@ tasks:
|
||||
|
||||
update:
|
||||
cmds:
|
||||
- "{{.PYTHON}} -m pip install -U ultralytics mediapipe ruff pre-commit black"
|
||||
- "{{.PYTHON}} -m pip install -U ultralytics mediapipe ruff pre-commit black devtools pytest"
|
||||
|
||||
update-torch:
|
||||
cmds:
|
||||
- "{{.PYTHON}} -m pip install -U torch torchvision torchaudio -f https://download.pytorch.org/whl/torch_stable.html"
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "24.3.3"
|
||||
__version__ = "24.3.4"
|
||||
|
||||
@@ -660,6 +660,8 @@ class AfterDetailerScript(scripts.Script):
|
||||
def inpaint_mask_filter(
|
||||
img2img_mask: Image.Image, ad_mask: list[Image.Image]
|
||||
) -> list[Image.Image]:
|
||||
if ad_mask and img2img_mask.size != ad_mask[0].size:
|
||||
img2img_mask = img2img_mask.resize(ad_mask[0].size, resample=images.LANCZOS)
|
||||
return [mask for mask in ad_mask if has_intersection(img2img_mask, mask)]
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -1,29 +1,18 @@
|
||||
from functools import cache
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
|
||||
@cache
|
||||
def _sample_image():
|
||||
url = "https://i.imgur.com/E5OVXvn.png"
|
||||
def get_image(url: str) -> Image.Image:
|
||||
resp = requests.get(url, stream=True, headers={"User-Agent": "Mozilla/5.0"})
|
||||
return Image.open(resp.raw)
|
||||
|
||||
|
||||
@cache
|
||||
def _sample_image2():
|
||||
url = "https://i.imgur.com/px5UT7T.png"
|
||||
resp = requests.get(url, stream=True, headers={"User-Agent": "Mozilla/5.0"})
|
||||
return Image.open(resp.raw)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture(scope="session")
|
||||
def sample_image():
|
||||
return _sample_image()
|
||||
return get_image("https://i.imgur.com/E5OVXvn.png")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture(scope="session")
|
||||
def sample_image2():
|
||||
return _sample_image2()
|
||||
return get_image("https://i.imgur.com/px5UT7T.png")
|
||||
|
||||
@@ -3,7 +3,15 @@ import numpy as np
|
||||
import pytest
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
from adetailer.mask import dilate_erode, has_intersection, is_all_black, offset
|
||||
from adetailer.mask import (
|
||||
bbox_area,
|
||||
dilate_erode,
|
||||
has_intersection,
|
||||
is_all_black,
|
||||
mask_invert,
|
||||
mask_merge,
|
||||
offset,
|
||||
)
|
||||
|
||||
|
||||
def test_dilate_positive_value():
|
||||
@@ -63,112 +71,162 @@ def test_offset():
|
||||
assert np.array_equal(np.array(result), expect)
|
||||
|
||||
|
||||
def test_is_all_black_1():
|
||||
class TestIsAllBlack:
|
||||
def test_is_all_black_1(self):
|
||||
img = Image.new("L", (10, 10), color="black")
|
||||
assert is_all_black(img)
|
||||
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.rectangle((4, 4, 5, 5), fill="white")
|
||||
assert not is_all_black(img)
|
||||
|
||||
def test_is_all_black_2(self):
|
||||
img = np.zeros((10, 10), dtype=np.uint8)
|
||||
assert is_all_black(img)
|
||||
|
||||
img[4:6, 4:6] = 255
|
||||
assert not is_all_black(img)
|
||||
|
||||
def test_is_all_black_rgb_image_pil(self):
|
||||
img = Image.new("RGB", (10, 10), color="red")
|
||||
assert not is_all_black(img)
|
||||
|
||||
img = Image.new("RGBA", (10, 10), color="red")
|
||||
assert not is_all_black(img)
|
||||
|
||||
def test_is_all_black_rgb_image_numpy(self):
|
||||
img = np.full((10, 10, 4), 127, dtype=np.uint8)
|
||||
with pytest.raises(cv2.error):
|
||||
is_all_black(img)
|
||||
|
||||
img = np.full((4, 10, 10), 0.5, dtype=np.float32)
|
||||
with pytest.raises(cv2.error):
|
||||
is_all_black(img)
|
||||
|
||||
|
||||
class TestHasIntersection:
|
||||
def test_has_intersection_1(self):
|
||||
arr1 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
arr2 = arr1.copy()
|
||||
assert not has_intersection(arr1, arr2)
|
||||
|
||||
def test_has_intersection_2(self):
|
||||
arr1 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 255, 255, 0],
|
||||
[0, 255, 255, 0],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
arr2 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 255, 255],
|
||||
[0, 0, 255, 255],
|
||||
]
|
||||
)
|
||||
assert has_intersection(arr1, arr2)
|
||||
|
||||
arr3 = np.array(
|
||||
[
|
||||
[255, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 255],
|
||||
[0, 0, 255, 255],
|
||||
]
|
||||
)
|
||||
assert not has_intersection(arr1, arr3)
|
||||
|
||||
def test_has_intersection_3(self):
|
||||
img1 = Image.new("L", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
img2 = Image.new("L", (10, 10), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((6, 6, 8, 8), fill="white")
|
||||
assert not has_intersection(img1, img2)
|
||||
|
||||
img3 = Image.new("L", (10, 10), color="black")
|
||||
draw3 = ImageDraw.Draw(img3)
|
||||
draw3.rectangle((2, 2, 8, 8), fill="white")
|
||||
assert has_intersection(img1, img3)
|
||||
|
||||
def test_has_intersection_4(self):
|
||||
img1 = Image.new("RGB", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
img2 = Image.new("RGBA", (10, 10), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((2, 2, 8, 8), fill="white")
|
||||
assert has_intersection(img1, img2)
|
||||
|
||||
def test_has_intersection_5(self):
|
||||
img1 = Image.new("RGB", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((4, 4, 5, 5), fill="white")
|
||||
img2 = np.full((10, 10, 4), 255, dtype=np.uint8)
|
||||
assert has_intersection(img1, img2)
|
||||
|
||||
|
||||
def test_bbox_area():
|
||||
bbox = [0.0, 0.0, 10.0, 10.0]
|
||||
assert bbox_area(bbox) == 100
|
||||
|
||||
|
||||
class TestMaskMerge:
|
||||
def test_mask_merge(self):
|
||||
img1 = Image.new("L", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
|
||||
img2 = Image.new("L", (10, 10), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((6, 6, 8, 8), fill="white")
|
||||
|
||||
merged = mask_merge([img1, img2])
|
||||
assert len(merged) == 1
|
||||
|
||||
expect = Image.new("L", (10, 10), color="black")
|
||||
draw3 = ImageDraw.Draw(expect)
|
||||
draw3.rectangle((3, 3, 5, 5), fill="white")
|
||||
draw3.rectangle((6, 6, 8, 8), fill="white")
|
||||
|
||||
assert np.array_equal(np.array(merged[0]), np.array(expect))
|
||||
|
||||
def test_merge_mask_different_size(self):
|
||||
img1 = Image.new("L", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
|
||||
img2 = Image.new("L", (20, 20), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((6, 6, 8, 8), fill="white")
|
||||
|
||||
with pytest.raises(
|
||||
cv2.error, match="-209:Sizes of input arguments do not match"
|
||||
):
|
||||
mask_merge([img1, img2])
|
||||
|
||||
|
||||
def test_mask_invert():
|
||||
img = Image.new("L", (10, 10), color="black")
|
||||
assert is_all_black(img)
|
||||
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.rectangle((4, 4, 5, 5), fill="white")
|
||||
assert not is_all_black(img)
|
||||
draw.rectangle((3, 3, 5, 5), fill="white")
|
||||
|
||||
inverted = mask_invert([img])
|
||||
assert len(inverted) == 1
|
||||
|
||||
def test_is_all_black_2():
|
||||
img = np.zeros((10, 10), dtype=np.uint8)
|
||||
assert is_all_black(img)
|
||||
expect = Image.new("L", (10, 10), color="white")
|
||||
draw = ImageDraw.Draw(expect)
|
||||
draw.rectangle((3, 3, 5, 5), fill="black")
|
||||
|
||||
img[4:6, 4:6] = 255
|
||||
assert not is_all_black(img)
|
||||
|
||||
|
||||
def test_is_all_black_rgb_image_pil():
|
||||
img = Image.new("RGB", (10, 10), color="red")
|
||||
assert not is_all_black(img)
|
||||
|
||||
img = Image.new("RGBA", (10, 10), color="red")
|
||||
assert not is_all_black(img)
|
||||
|
||||
|
||||
def test_is_all_black_rgb_image_numpy():
|
||||
img = np.full((10, 10, 4), 127, dtype=np.uint8)
|
||||
with pytest.raises(cv2.error):
|
||||
is_all_black(img)
|
||||
|
||||
img = np.full((4, 10, 10), 0.5, dtype=np.float32)
|
||||
with pytest.raises(cv2.error):
|
||||
is_all_black(img)
|
||||
|
||||
|
||||
def test_has_intersection_1():
|
||||
arr1 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
arr2 = arr1.copy()
|
||||
assert not has_intersection(arr1, arr2)
|
||||
|
||||
|
||||
def test_has_intersection_2():
|
||||
arr1 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 255, 255, 0],
|
||||
[0, 255, 255, 0],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
arr2 = np.array(
|
||||
[
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 255, 255],
|
||||
[0, 0, 255, 255],
|
||||
]
|
||||
)
|
||||
assert has_intersection(arr1, arr2)
|
||||
|
||||
arr3 = np.array(
|
||||
[
|
||||
[255, 0, 0, 0],
|
||||
[0, 0, 0, 0],
|
||||
[0, 0, 0, 255],
|
||||
[0, 0, 255, 255],
|
||||
]
|
||||
)
|
||||
assert not has_intersection(arr1, arr3)
|
||||
|
||||
|
||||
def test_has_intersection_3():
|
||||
img1 = Image.new("L", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
img2 = Image.new("L", (10, 10), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((6, 6, 8, 8), fill="white")
|
||||
assert not has_intersection(img1, img2)
|
||||
|
||||
img3 = Image.new("L", (10, 10), color="black")
|
||||
draw3 = ImageDraw.Draw(img3)
|
||||
draw3.rectangle((2, 2, 8, 8), fill="white")
|
||||
assert has_intersection(img1, img3)
|
||||
|
||||
|
||||
def test_has_intersection_4():
|
||||
img1 = Image.new("RGB", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((3, 3, 5, 5), fill="white")
|
||||
img2 = Image.new("RGBA", (10, 10), color="black")
|
||||
draw2 = ImageDraw.Draw(img2)
|
||||
draw2.rectangle((2, 2, 8, 8), fill="white")
|
||||
assert has_intersection(img1, img2)
|
||||
|
||||
|
||||
def test_has_intersection_5():
|
||||
img1 = Image.new("RGB", (10, 10), color="black")
|
||||
draw1 = ImageDraw.Draw(img1)
|
||||
draw1.rectangle((4, 4, 5, 5), fill="white")
|
||||
img2 = np.full((10, 10, 4), 255, dtype=np.uint8)
|
||||
assert has_intersection(img1, img2)
|
||||
assert np.array_equal(np.array(inverted[0]), np.array(expect))
|
||||
|
||||
Reference in New Issue
Block a user