techfreakworm commited on
Commit
036940b
·
unverified ·
1 Parent(s): 8759971

feat(preprocessors): canny/depth/pose via controlnet_aux (lazy imports)

Browse files
Files changed (2) hide show
  1. preprocessors.py +59 -0
  2. tests/test_preprocessors.py +37 -0
preprocessors.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ControlNet preprocessors — lazy imports so an unused mode pays no cost."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from PIL import Image
7
+
8
+ MODES: tuple[str, ...] = ("Canny", "Depth", "Pose", "Pre-processed")
9
+
10
+
11
+ def run(mode: str, image: Image.Image | None) -> Image.Image:
12
+ if image is None:
13
+ raise ValueError("preprocessor needs an input image")
14
+ if mode == "Canny":
15
+ return _run_canny(image)
16
+ if mode == "Depth":
17
+ return _run_depth(image)
18
+ if mode == "Pose":
19
+ return _run_pose(image)
20
+ if mode == "Pre-processed":
21
+ return image
22
+ raise ValueError(f"unknown preprocessor mode: {mode!r}; expected one of {MODES}")
23
+
24
+
25
+ def _run_canny(image: Image.Image) -> Image.Image:
26
+ import cv2
27
+ import numpy as np
28
+ arr = np.array(image.convert("RGB"))
29
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
30
+ edges = cv2.Canny(gray, threshold1=100, threshold2=200)
31
+ rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
32
+ return Image.fromarray(rgb)
33
+
34
+
35
+ def _run_depth(image: Image.Image) -> Image.Image:
36
+ proc = _get_processor("midas")
37
+ out: Any = proc(image)
38
+ if isinstance(out, Image.Image):
39
+ return out.convert("RGB")
40
+ return Image.fromarray(out).convert("RGB")
41
+
42
+
43
+ def _run_pose(image: Image.Image) -> Image.Image:
44
+ proc = _get_processor("openpose")
45
+ out: Any = proc(image)
46
+ if isinstance(out, Image.Image):
47
+ return out.convert("RGB")
48
+ return Image.fromarray(out).convert("RGB")
49
+
50
+
51
+ _PROCESSOR_CACHE: dict[str, Any] = {}
52
+
53
+
54
+ def _get_processor(name: str) -> Any:
55
+ """Lazy-init and cache a controlnet_aux Processor."""
56
+ if name not in _PROCESSOR_CACHE:
57
+ from controlnet_aux.processor import Processor
58
+ _PROCESSOR_CACHE[name] = Processor(name)
59
+ return _PROCESSOR_CACHE[name]
tests/test_preprocessors.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pytest
3
+ from PIL import Image
4
+
5
+ import preprocessors
6
+
7
+
8
+ @pytest.fixture
9
+ def gradient_image():
10
+ arr = np.linspace(0, 255, 256 * 256, dtype=np.uint8).reshape(256, 256)
11
+ return Image.fromarray(arr).convert("RGB")
12
+
13
+
14
+ def test_modes_are_listed():
15
+ assert preprocessors.MODES == ("Canny", "Depth", "Pose", "Pre-processed")
16
+
17
+
18
+ def test_canny_returns_rgb_image_of_same_size(gradient_image):
19
+ out = preprocessors.run("Canny", gradient_image)
20
+ assert isinstance(out, Image.Image)
21
+ assert out.size == gradient_image.size
22
+ assert out.mode == "RGB"
23
+
24
+
25
+ def test_passthrough_returns_input_unchanged(gradient_image):
26
+ out = preprocessors.run("Pre-processed", gradient_image)
27
+ assert out is gradient_image
28
+
29
+
30
+ def test_unknown_mode_raises():
31
+ with pytest.raises(ValueError):
32
+ preprocessors.run("Sobel", Image.new("RGB", (32, 32)))
33
+
34
+
35
+ def test_run_with_image_none_raises():
36
+ with pytest.raises(ValueError):
37
+ preprocessors.run("Canny", None)