-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathimage_processor.py
More file actions
131 lines (113 loc) · 4.13 KB
/
image_processor.py
File metadata and controls
131 lines (113 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
"""
Image Processor Script
Processes an input image to generate two binary bitmaps (stiff and soft materials)
at two specified DPIs, saving each as a 1-bit BMP.
"""
import argparse
import logging
from fractions import Fraction
from pathlib import Path
import numpy as np
from PIL import Image
class ImageProcessor:
"""
Processes images to produce binary bitmaps for two material types
at specified DPIs.
"""
def __init__(
self,
primary_dpi: Fraction = Fraction('127/2'),
secondary_dpi: Fraction = Fraction('635/20')
):
self.primary_dpi = primary_dpi
self.secondary_dpi = secondary_dpi
def load_image(self, path: Path) -> Image.Image:
"""
Load an image from disk and ensure it's in RGB mode.
"""
if not path.exists():
raise FileNotFoundError(f"Input file not found: {path}")
img = Image.open(path)
return img.convert('RGB')
def process_first_bitmap(self, img: Image.Image) -> Image.Image:
"""
Generate a bitmap for Material 1 (stiff):
Black-ish pixels (<35) become white (255), others become black (0).
"""
arr = np.array(img)
mask = np.all(arr < 35, axis=2)
out = np.zeros(arr.shape[:2], dtype=np.uint8)
out[mask] = 255
return Image.fromarray(out, mode='L')
def process_second_bitmap(self, img: Image.Image) -> Image.Image:
"""
Generate a bitmap for Material 2 (soft):
White-ish pixels (>225) become white (255); black-ish (<30) become black (0).
All other pixels (void) are black (0).
"""
arr = np.array(img)
mask_white = np.all(arr > 225, axis=2)
out = np.zeros(arr.shape[:2], dtype=np.uint8)
out[mask_white] = 255
return Image.fromarray(out, mode='L')
def save_bitmap(self, bitmap: Image.Image, path: Path, dpi: Fraction) -> None:
"""
Save the bitmap as a 1-bit BMP file with specified DPI.
"""
bitmap_1bit = bitmap.convert('1', dither=Image.NONE)
dpi_val = float(dpi)
# Ensure output directory exists
path.parent.mkdir(parents=True, exist_ok=True)
bitmap_1bit.save(path, format='BMP', dpi=(dpi_val, dpi_val))
logging.info(f"Saved {path} at DPI {dpi_val}")
def get_output_path(self, output_dir: Path, mat_num: int, dpi: Fraction) -> Path:
"""
Construct an output filename based on material number and DPI (decimal).
"""
# Use decimal representation for DPI in filename
dpi_str = f"{float(dpi):.2f}".rstrip('0').rstrip('.')
return output_dir / f"mat_{mat_num:02d}_{dpi_str}.bmp"
def main():
parser = argparse.ArgumentParser(
description="Process images into binary bitmaps with precise DPI control"
)
parser.add_argument(
"input_file", type=Path, help="Path to input image"
)
parser.add_argument(
"output_dir", type=Path, help="Directory to save output files"
)
parser.add_argument(
"--primary-dpi",
type=Fraction,
default=Fraction('127/2'),
help='Primary DPI (e.g., "127/2" for 63.5)'
)
parser.add_argument(
"--secondary-dpi",
type=Fraction,
default=Fraction('635/20'),
help='Secondary DPI (e.g., "635/20" for 31.75)'
)
args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format='%(message)s')
output_dir = args.output_dir
output_dir.mkdir(parents=True, exist_ok=True)
processor = ImageProcessor(
primary_dpi=args.primary_dpi,
secondary_dpi=args.secondary_dpi
)
image = processor.load_image(args.input_file)
# Generate bitmaps for both materials
bitmaps = {
1: processor.process_first_bitmap(image),
2: processor.process_second_bitmap(image),
}
# Save each bitmap at both DPIs
for mat_num, bmp in bitmaps.items():
for dpi in (processor.primary_dpi, processor.secondary_dpi):
out_path = processor.get_output_path(output_dir, mat_num, dpi)
processor.save_bitmap(bmp, out_path, dpi)
if __name__ == "__main__":
main()