Refactor image processing in img_clean_sketch.py to enhance functionality
Browse filesThis commit modifies the img_clean_sketch.py script to improve image processing capabilities. Key changes include:
- Updated the process_image function to create a new data array for modifications, ensuring the original data remains unchanged.
- Enhanced white and grayscale pixel detection logic for better accuracy.
- Refactored process_directory to process multiple files and directories, improving flexibility in handling input paths.
- Updated the main function to accept multiple paths as arguments.
These improvements streamline the image processing workflow and enhance the script's usability.
- utils/img_clean_sketch.py +76 -49
utils/img_clean_sketch.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
|
2 |
# -*- coding: utf-8 -*-
|
3 |
#
|
4 |
# 画像の白い背景を透明にし、グレースケールを黒に変換する
|
@@ -10,6 +10,7 @@ from PIL import Image
|
|
10 |
import argparse
|
11 |
from pathlib import Path
|
12 |
import os
|
|
|
13 |
|
14 |
def process_image(image_path: Path, tolerance: int = 10, gray_tolerance: int = 5) -> None:
|
15 |
"""
|
@@ -25,69 +26,105 @@ def process_image(image_path: Path, tolerance: int = 10, gray_tolerance: int = 5
|
|
25 |
img = Image.open(image_path).convert("RGBA")
|
26 |
data = np.array(img)
|
27 |
|
28 |
-
#
|
|
|
|
|
|
|
29 |
r, g, b = data[:, :, 0], data[:, :, 1], data[:, :, 2]
|
30 |
-
white_mask = (abs(r - 255) <= tolerance) & \
|
31 |
-
(abs(g - 255) <= tolerance) & \
|
32 |
-
(abs(b - 255) <= tolerance)
|
33 |
|
34 |
-
#
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
-
#
|
41 |
-
|
42 |
|
43 |
-
#
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
# Create output path with suffix
|
47 |
output_path = image_path.parent / f"{image_path.stem}-processed.png"
|
48 |
|
49 |
# Save the modified image
|
50 |
-
Image.fromarray(
|
51 |
print(f"Processed image saved as {output_path}")
|
52 |
|
53 |
except Exception as e:
|
54 |
print(f"Error processing {image_path}: {e}")
|
55 |
|
56 |
-
def
|
57 |
"""
|
58 |
-
Process
|
59 |
|
60 |
Args:
|
61 |
-
|
62 |
-
tolerance
|
63 |
-
gray_tolerance
|
64 |
-
recursive
|
65 |
"""
|
66 |
-
# Supported image extensions
|
67 |
extensions = {".png", ".jpg", ".jpeg", ".webp", ".bmp"}
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
def main():
|
83 |
parser = argparse.ArgumentParser(
|
84 |
description="Remove white background and convert grayscale colors to black."
|
85 |
)
|
86 |
parser.add_argument(
|
87 |
-
"
|
88 |
-
|
89 |
-
|
90 |
-
help="Directory containing the image files (default: current directory)"
|
91 |
)
|
92 |
parser.add_argument(
|
93 |
"-t", "--tolerance",
|
@@ -108,17 +145,7 @@ def main():
|
|
108 |
)
|
109 |
args = parser.parse_args()
|
110 |
|
111 |
-
|
112 |
-
if not target_directory.exists():
|
113 |
-
print(f"Error: Directory {target_directory} does not exist.")
|
114 |
-
return 1
|
115 |
-
|
116 |
-
process_directory(
|
117 |
-
target_directory,
|
118 |
-
args.tolerance,
|
119 |
-
args.gray_tolerance,
|
120 |
-
args.recursive
|
121 |
-
)
|
122 |
return 0
|
123 |
|
124 |
if __name__ == "__main__":
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
# -*- coding: utf-8 -*-
|
3 |
#
|
4 |
# 画像の白い背景を透明にし、グレースケールを黒に変換する
|
|
|
10 |
import argparse
|
11 |
from pathlib import Path
|
12 |
import os
|
13 |
+
from typing import List, Union
|
14 |
|
15 |
def process_image(image_path: Path, tolerance: int = 10, gray_tolerance: int = 5) -> None:
|
16 |
"""
|
|
|
26 |
img = Image.open(image_path).convert("RGBA")
|
27 |
data = np.array(img)
|
28 |
|
29 |
+
# Get alpha channel
|
30 |
+
alpha = data[:, :, 3]
|
31 |
+
|
32 |
+
# Create masks for processing
|
33 |
r, g, b = data[:, :, 0], data[:, :, 1], data[:, :, 2]
|
|
|
|
|
|
|
34 |
|
35 |
+
# Calculate color intensity (average of RGB)
|
36 |
+
color_intensity = (r + g + b) / 3.0
|
37 |
+
|
38 |
+
# Detect white pixels (only in areas that aren't already transparent)
|
39 |
+
white_mask = ((color_intensity >= 250) & # Very bright pixels
|
40 |
+
(abs(r - g) <= tolerance) & # Similar RGB values
|
41 |
+
(abs(g - b) <= tolerance) &
|
42 |
+
(abs(r - b) <= tolerance) &
|
43 |
+
(alpha > 0)) # Only non-transparent pixels
|
44 |
+
|
45 |
+
# Detect grayscale pixels (excluding white and transparent)
|
46 |
+
gray_mask = ((abs(r - g) <= gray_tolerance) &
|
47 |
+
(abs(g - b) <= gray_tolerance) &
|
48 |
+
(abs(r - b) <= gray_tolerance) &
|
49 |
+
(color_intensity < 250) & # Not too bright
|
50 |
+
(alpha > 0) & # Not transparent
|
51 |
+
~white_mask) # Not white
|
52 |
+
|
53 |
+
# Debug info
|
54 |
+
print(f"Original alpha range: {alpha.min()}-{alpha.max()}")
|
55 |
+
print(f"White pixels detected: {white_mask.sum()}")
|
56 |
+
print(f"Gray pixels detected: {gray_mask.sum()}")
|
57 |
|
58 |
+
# Create new data array to avoid modifying original
|
59 |
+
new_data = data.copy()
|
60 |
|
61 |
+
# Make white pixels transparent
|
62 |
+
new_data[white_mask, 3] = 0
|
63 |
+
|
64 |
+
# Convert grayscale to black while preserving alpha
|
65 |
+
new_data[gray_mask, 0:3] = 0
|
66 |
+
|
67 |
+
# Debug info after modifications
|
68 |
+
print(f"Final alpha range: {new_data[:,:,3].min()}-{new_data[:,:,3].max()}")
|
69 |
|
70 |
# Create output path with suffix
|
71 |
output_path = image_path.parent / f"{image_path.stem}-processed.png"
|
72 |
|
73 |
# Save the modified image
|
74 |
+
Image.fromarray(new_data).save(output_path, "PNG")
|
75 |
print(f"Processed image saved as {output_path}")
|
76 |
|
77 |
except Exception as e:
|
78 |
print(f"Error processing {image_path}: {e}")
|
79 |
|
80 |
+
def process_paths(paths: List[Union[str, Path]], tolerance: int = 10, gray_tolerance: int = 5, recursive: bool = False) -> None:
|
81 |
"""
|
82 |
+
Process multiple files and/or directories.
|
83 |
|
84 |
Args:
|
85 |
+
paths: List of file and directory paths to process
|
86 |
+
tolerance: Color tolerance for white detection
|
87 |
+
gray_tolerance: Tolerance for grayscale detection
|
88 |
+
recursive: Whether to process subdirectories recursively
|
89 |
"""
|
90 |
+
# Supported image extensions
|
91 |
extensions = {".png", ".jpg", ".jpeg", ".webp", ".bmp"}
|
92 |
|
93 |
+
for path in paths:
|
94 |
+
path = Path(path)
|
95 |
+
|
96 |
+
if not path.exists():
|
97 |
+
print(f"Error: Path does not exist: {path}")
|
98 |
+
continue
|
99 |
+
|
100 |
+
if path.is_file():
|
101 |
+
if path.suffix.lower() in extensions:
|
102 |
+
process_image(path, tolerance, gray_tolerance)
|
103 |
+
else:
|
104 |
+
print(f"Skipping unsupported file: {path}")
|
105 |
+
|
106 |
+
elif path.is_dir():
|
107 |
+
# Process directory
|
108 |
+
if recursive:
|
109 |
+
files = [f for ext in extensions for f in path.rglob(f"*{ext}")]
|
110 |
+
else:
|
111 |
+
files = [f for ext in extensions for f in path.glob(f"*{ext}")]
|
112 |
+
|
113 |
+
if not files:
|
114 |
+
print(f"No supported image files found in {path}")
|
115 |
+
continue
|
116 |
+
|
117 |
+
for file_path in files:
|
118 |
+
process_image(file_path, tolerance, gray_tolerance)
|
119 |
|
120 |
def main():
|
121 |
parser = argparse.ArgumentParser(
|
122 |
description="Remove white background and convert grayscale colors to black."
|
123 |
)
|
124 |
parser.add_argument(
|
125 |
+
"paths",
|
126 |
+
nargs="+",
|
127 |
+
help="One or more image files or directories to process"
|
|
|
128 |
)
|
129 |
parser.add_argument(
|
130 |
"-t", "--tolerance",
|
|
|
145 |
)
|
146 |
args = parser.parse_args()
|
147 |
|
148 |
+
process_paths(args.paths, args.tolerance, args.gray_tolerance, args.recursive)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
return 0
|
150 |
|
151 |
if __name__ == "__main__":
|