Plana-Archive commited on
Commit
658d9e6
·
verified ·
1 Parent(s): 4c22e60

Upload wd-tagger-heatmap-more-models/tagger/common.py with huggingface_hub

Browse files
wd-tagger-heatmap-more-models/tagger/common.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from dataclasses import dataclass
3
+ from functools import lru_cache
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+ import torch
10
+ from huggingface_hub import hf_hub_download
11
+ from huggingface_hub.utils import HfHubHTTPError
12
+ from PIL import Image
13
+ from torch import Tensor, nn
14
+
15
+
16
+ @dataclass
17
+ class Heatmap:
18
+ label: str
19
+ score: float
20
+ image: Image.Image
21
+
22
+
23
+ @dataclass
24
+ class LabelData:
25
+ names: list[str]
26
+ rating: list[np.int64]
27
+ general: list[np.int64]
28
+ character: list[np.int64]
29
+
30
+
31
+ @dataclass
32
+ class ImageLabels:
33
+ caption: str
34
+ booru: str
35
+ rating: dict[str, float]
36
+ general: dict[str, float]
37
+ character: dict[str, float]
38
+
39
+
40
+ @lru_cache(maxsize=5)
41
+ def load_labels_hf(
42
+ repo_id: str,
43
+ revision: Optional[str] = None,
44
+ token: Optional[str] = None,
45
+ ) -> LabelData:
46
+ try:
47
+ csv_path = hf_hub_download(
48
+ repo_id=repo_id, filename="selected_tags.csv", revision=revision, token=token
49
+ )
50
+ csv_path = Path(csv_path).resolve()
51
+ except HfHubHTTPError as e:
52
+ raise FileNotFoundError(f"selected_tags.csv failed to download from {repo_id}") from e
53
+
54
+ df: pd.DataFrame = pd.read_csv(csv_path, usecols=["name", "category"])
55
+ tag_data = LabelData(
56
+ names=df["name"].tolist(),
57
+ rating=list(np.where(df["category"] == 9)[0]),
58
+ general=list(np.where(df["category"] == 0)[0]),
59
+ character=list(np.where(df["category"] == 4)[0]),
60
+ )
61
+
62
+ return tag_data
63
+
64
+
65
+ def mcut_threshold(probs: np.ndarray) -> float:
66
+ """
67
+ Maximum Cut Thresholding (MCut)
68
+ Largeron, C., Moulin, C., & Gery, M. (2012). MCut: A Thresholding Strategy
69
+ for Multi-label Classification. In 11th International Symposium, IDA 2012
70
+ (pp. 172-183).
71
+ """
72
+ probs = probs[probs.argsort()[::-1]]
73
+ diffs = probs[:-1] - probs[1:]
74
+ idx = diffs.argmax()
75
+ thresh = (probs[idx] + probs[idx + 1]) / 2
76
+ return float(thresh)
77
+
78
+
79
+ def pil_ensure_rgb(image: Image.Image) -> Image.Image:
80
+ # convert to RGB/RGBA if not already (deals with palette images etc.)
81
+ if image.mode not in ["RGB", "RGBA"]:
82
+ image = image.convert("RGBA") if "transparency" in image.info else image.convert("RGB")
83
+ # convert RGBA to RGB with white background
84
+ if image.mode == "RGBA":
85
+ canvas = Image.new("RGBA", image.size, (255, 255, 255))
86
+ canvas.alpha_composite(image)
87
+ image = canvas.convert("RGB")
88
+ return image
89
+
90
+
91
+ def pil_pad_square(
92
+ image: Image.Image,
93
+ fill: tuple[int, int, int] = (255, 255, 255),
94
+ ) -> Image.Image:
95
+ w, h = image.size
96
+ # get the largest dimension so we can pad to a square
97
+ px = max(image.size)
98
+ # pad to square with white background
99
+ canvas = Image.new("RGB", (px, px), fill)
100
+ canvas.paste(image, ((px - w) // 2, (px - h) // 2))
101
+ return canvas
102
+
103
+
104
+ def preprocess_image(
105
+ image: Image.Image,
106
+ size_px: int | tuple[int, int],
107
+ upscale: bool = True,
108
+ ) -> Image.Image:
109
+ """
110
+ Preprocess an image to be square and centered on a white background.
111
+ """
112
+ if isinstance(size_px, int):
113
+ size_px = (size_px, size_px)
114
+
115
+ # ensure RGB and pad to square
116
+ image = pil_ensure_rgb(image)
117
+ image = pil_pad_square(image)
118
+
119
+ # resize to target size
120
+ if image.size[0] < size_px[0] or image.size[1] < size_px[1]:
121
+ if upscale is False:
122
+ raise ValueError("Image is smaller than target size, and upscaling is disabled")
123
+ image = image.resize(size_px, Image.LANCZOS)
124
+ if image.size[0] > size_px[0] or image.size[1] > size_px[1]:
125
+ image.thumbnail(size_px, Image.BICUBIC)
126
+
127
+ return image
128
+
129
+
130
+ def pil_make_grid(
131
+ images: list[Image.Image],
132
+ max_cols: int = 8,
133
+ padding: int = 4,
134
+ bg_color: tuple[int, int, int] = (40, 42, 54), # dracula background color
135
+ partial_rows: bool = True,
136
+ ) -> Image.Image:
137
+ n_cols = min(math.floor(math.sqrt(len(images))), max_cols)
138
+ n_rows = math.ceil(len(images) / n_cols)
139
+
140
+ # if the final row is not full and partial_rows is False, remove a row
141
+ if n_cols * n_rows > len(images) and not partial_rows:
142
+ n_rows -= 1
143
+
144
+ # assumes all images are same size
145
+ image_width, image_height = images[0].size
146
+
147
+ canvas_width = ((image_width + padding) * n_cols) + padding
148
+ canvas_height = ((image_height + padding) * n_rows) + padding
149
+
150
+ canvas = Image.new("RGB", (canvas_width, canvas_height), bg_color)
151
+ for i, img in enumerate(images):
152
+ x = (i % n_cols) * (image_width + padding) + padding
153
+ y = (i // n_cols) * (image_height + padding) + padding
154
+ canvas.paste(img, (x, y))
155
+
156
+ return canvas
157
+
158
+
159
+ # https://github.com/toriato/stable-diffusion-webui-wd14-tagger/blob/a9eacb1eff904552d3012babfa28b57e1d3e295c/tagger/ui.py#L368
160
+ kaomojis = [
161
+ "0_0",
162
+ "(o)_(o)",
163
+ "+_+",
164
+ "+_-",
165
+ "._.",
166
+ "<o>_<o>",
167
+ "<|>_<|>",
168
+ "=_=",
169
+ ">_<",
170
+ "3_3",
171
+ "6_9",
172
+ ">_o",
173
+ "@_@",
174
+ "^_^",
175
+ "o_o",
176
+ "u_u",
177
+ "x_x",
178
+ "|_|",
179
+ "||_||",
180
+ ]