Merge pull request #831 from Bing-su/dev

v26.2.0
main v26.2.0
Dowon 2026-02-05 22:43:40 +09:00 committed by GitHub
commit 3a599f5d46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 105 additions and 60 deletions

View File

@ -3,6 +3,7 @@ on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
test:
@ -17,10 +18,11 @@ jobs:
needs: [test]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Build wheel
run: pipx run build
run: uv build
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

View File

@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
days-before-stale: 17
days-before-close: 3

View File

@ -4,7 +4,9 @@ on:
pull_request:
paths:
- "adetailer/**.py"
- ".github/workflows/test.yml"
workflow_call:
workflow_dispatch:
schedule:
- cron: "0 0 * * 0"
@ -13,18 +15,21 @@ jobs:
name: Test on python ${{ matrix.python-version }}
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v5
- uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
- name: Run tests
run: uv run --all-extras pytest -v
run: uv run --all-extras --with 'git+https://github.com/ultralytics/CLIP.git' pytest -v

View File

@ -5,7 +5,7 @@ exclude: ^modules/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: check-added-large-files
args: [--maxkb=100]
@ -19,13 +19,13 @@ repos:
- id: mixed-line-ending
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.5.3
rev: v3.8.1
hooks:
- id: prettier
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.9
rev: v0.15.0
hooks:
- id: ruff
- id: ruff-check
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format

View File

@ -1,7 +1,6 @@
{
"recommendations": [
"ms-python.vscode-pylance",
"ms-python.black-formatter",
"kevinrose.vsc-python-indent",
"charliermarsh.ruff",
"shardulm94.trailing-spaces"

View File

@ -1,5 +1,10 @@
# Changelog
## 2026-02-05
- v26.2.0
- segmentation 모델의 마스크 dtype이 uint8로 변경된 것에 대응
## 2025-03-10
- v25.3.0
@ -121,7 +126,6 @@
- YOLO World 모델 추가: 가장 큰 yolov8x-world.pt 모델만 기본적으로 선택할 수 있게 함.
- lllyasviel/stable-diffusion-webui-forge에서 컨트롤넷을 사용가능하게 함 (PR #517)
- 기본 스크립트 목록에 soft_inpainting 추가 (https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14208)
- 기존에 설치한 사람에게 소급적용되지는 않음
- 감지모델에 대한 간단한 pytest 추가함
@ -348,7 +352,6 @@
- `ad_inpaint_full_res``ad_inpaint_only_masked`
- `ad_inpaint_full_res_padding``ad_inpaint_only_masked_padding`
- mediapipe face mesh 모델 추가
- mediapipe 최소 버전 `0.10.0`
- rich traceback 제거함

View File

@ -1,4 +1,4 @@
from __future__ import annotations # noqa: A005
from __future__ import annotations
import io
import platform

View File

@ -1 +1 @@
__version__ = "25.3.0"
__version__ = "26.2.0"

View File

@ -61,11 +61,12 @@ def mask_to_pil(masks: torch.Tensor, shape: tuple[int, int]) -> list[Image.Image
"""
Parameters
----------
masks: torch.Tensor, dtype=torch.float32, shape=(N, H, W).
The device can be CUDA, but `to_pil_image` takes care of that.
masks: torch.Tensor, dtype=torch.float32 or torch.uint8, shape=(N, H, W).
uint8 tensor is expected to have values 0 or 1 (not 0-255).
shape: tuple[int, int]
(W, H) of the original image
"""
masks = masks.float()
n = masks.shape[0]
return [to_pil_image(masks[i], mode="L").resize(shape) for i in range(n)]

View File

@ -47,7 +47,7 @@ def install():
deps = [
# requirements
("ultralytics", "8.3.75", None),
("mediapipe", "0.10.13", "0.10.15"),
("mediapipe", "0.10.13", None),
("rich", "13.0.0", None),
]

View File

@ -1,26 +1,26 @@
[project]
name = "adetailer"
description = "An object detection and auto-mask extension for stable diffusion webui."
authors = [{ name = "dowon", email = "ks2515@naver.com" }]
requires-python = ">=3.9"
readme = "README.md"
requires-python = ">=3.9"
license = { text = "AGPL-3.0" }
dependencies = [
"ultralytics>=8.2",
"mediapipe>=0.10.13",
"pydantic<3",
"rich>=13",
"huggingface_hub",
]
authors = [{ name = "dowon", email = "ks2515@naver.com" }]
keywords = [
"stable-diffusion",
"stable-diffusion-webui",
"adetailer",
"ultralytics",
"adetailer",
"stable-diffusion",
"stable-diffusion-webui",
"ultralytics",
]
classifiers = [
"License :: OSI Approved :: GNU Affero General Public License v3",
"Topic :: Scientific/Engineering :: Image Recognition",
"License :: OSI Approved :: GNU Affero General Public License v3",
"Topic :: Scientific/Engineering :: Image Recognition",
]
dependencies = [
"huggingface-hub",
"mediapipe>=0.10.13",
"pydantic<3",
"rich>=13",
"ultralytics>=8.2",
]
dynamic = ["version"]
@ -28,7 +28,7 @@ dynamic = ["version"]
repository = "https://github.com/Bing-su/adetailer"
[project.optional-dependencies]
dev = ["ruff", "pre-commit", "devtools"]
dev = ["devtools"]
test = ["pytest", "hypothesis"]
[build-system]
@ -48,32 +48,33 @@ extend-exclude = ["modules"]
[tool.ruff.lint]
select = [
"A",
"B",
"C4",
"C90",
"E",
"EM",
"F",
"FA",
"I001",
"ISC",
"N",
"PD",
"PERF",
"PL",
"PIE",
"PT",
"PTH",
"RET",
"RUF",
"SIM",
"T20",
"TRY",
"UP",
"W",
"A",
"B",
"C4",
"C90",
"E",
"EM",
"F",
"FA",
"I001",
"ISC",
"N",
"PD",
"PERF",
"PL",
"PLC",
"PIE",
"PT",
"PTH",
"RET",
"RUF",
"SIM",
"T20",
"TRY",
"UP",
"W",
]
ignore = ["B905", "E501", "PLR2004", "PLW0603"]
ignore = ["B905", "E501", "PLC0415", "PLR2004", "PLW0603"]
unfixable = ["F401"]
[tool.ruff.lint.isort]

View File

@ -1,8 +1,10 @@
import numpy as np
import pytest
import torch
from huggingface_hub import hf_hub_download
from PIL import Image
from adetailer.ultralytics import ultralytics_predict
from adetailer.ultralytics import mask_to_pil, ultralytics_predict
@pytest.mark.parametrize(
@ -60,3 +62,35 @@ def test_yolo_world(sample_image2: Image.Image, klass: str):
assert len(result.masks) > 0
assert len(result.confidences) > 0
assert len(result.bboxes) == len(result.masks) == len(result.confidences)
class TestMaskToPil:
def test_mask_to_pil_float32(self):
mask = torch.tensor([[[0.0, 1.0], [0.0, 1.0]]], dtype=torch.float32)
imgs = mask_to_pil(mask, shape=(2, 2))
assert len(imgs) == 1
img = imgs[0]
assert isinstance(img, Image.Image)
arr = np.array(img)
assert arr.shape == (2, 2)
assert arr.dtype == np.uint8
expected = np.array([[0, 255], [0, 255]], dtype=np.uint8)
np.testing.assert_array_equal(arr, expected)
def test_mask_to_pil_uint8(self):
mask = torch.tensor([[[0, 1], [0, 1]]], dtype=torch.uint8)
imgs = mask_to_pil(mask, shape=(2, 2))
assert len(imgs) == 1
img = imgs[0]
assert isinstance(img, Image.Image)
arr = np.array(img)
assert arr.shape == (2, 2)
assert arr.dtype == np.uint8
expected = np.array([[0, 255], [0, 255]], dtype=np.uint8)
np.testing.assert_array_equal(arr, expected)