docs: 部署编排与运维文档
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
按像素精确解析 PNG 平面图 —— 精确颜色分类 + 高分辨率网格化
|
||||
颜色规则(依据实际采样校准):
|
||||
W 黑色(0,0,0) = 墙壁
|
||||
O 灰色(176,176,176) = 办公室
|
||||
P 蓝色(64,176,240) = 过道
|
||||
R 绿色(80,176,96) = 休息厅
|
||||
Y 橙色(240,112,16) = 共享工位区 / 楼道
|
||||
C 青绿(80,224,192) = 玻璃顶
|
||||
. 白色(240,240,240) = 空白/底
|
||||
"""
|
||||
import zlib, struct, sys, collections
|
||||
|
||||
def read_png(path):
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read()
|
||||
assert data[:8] == b'\x89PNG\r\n\x1a\n', 'Not a PNG'
|
||||
pos = 8
|
||||
width = height = None
|
||||
bit_depth = color_type = None
|
||||
idat = b''
|
||||
while pos < len(data):
|
||||
ln = struct.unpack('>I', data[pos:pos+4])[0]
|
||||
typ = data[pos+4:pos+8]
|
||||
chunk = data[pos+8:pos+8+ln]
|
||||
pos += 12 + ln
|
||||
if typ == b'IHDR':
|
||||
width, height, bit_depth, color_type, _, _, _ = struct.unpack('>IIBBBBB', chunk)
|
||||
elif typ == b'IDAT':
|
||||
idat += chunk
|
||||
elif typ == b'IEND':
|
||||
break
|
||||
assert bit_depth == 8 and color_type in (2, 6) and width and height
|
||||
raw = zlib.decompress(idat)
|
||||
channels = 4 if color_type == 6 else 3
|
||||
bpp = channels
|
||||
stride = width * bpp
|
||||
rows = []
|
||||
off = 0
|
||||
prev = bytearray(stride)
|
||||
for y in range(height):
|
||||
ft = raw[off]; off += 1
|
||||
line = bytearray(raw[off:off+stride]); off += stride
|
||||
if ft == 1:
|
||||
for i in range(bpp, stride): line[i] = (line[i] + line[i-bpp]) & 0xFF
|
||||
elif ft == 2:
|
||||
for i in range(stride): line[i] = (line[i] + prev[i]) & 0xFF
|
||||
elif ft == 3:
|
||||
for i in range(stride):
|
||||
a = line[i-bpp] if i >= bpp else 0
|
||||
line[i] = (line[i] + ((a + prev[i]) >> 1)) & 0xFF
|
||||
elif ft == 4:
|
||||
for i in range(stride):
|
||||
a = line[i-bpp] if i >= bpp else 0
|
||||
b = prev[i]
|
||||
c = prev[i-bpp] if i >= bpp else 0
|
||||
p = a + b - c
|
||||
pa, pb, pc = abs(p-a), abs(p-b), abs(p-c)
|
||||
pr = a if (pa <= pb and pa <= pc) else (b if pb <= pc else c)
|
||||
line[i] = (line[i] + pr) & 0xFF
|
||||
rows.append(bytes(line))
|
||||
prev = line
|
||||
rgba = []
|
||||
for line in rows:
|
||||
if channels == 4:
|
||||
rgba.append([(line[i], line[i+1], line[i+2], line[i+3]) for i in range(0, stride, 4)])
|
||||
else:
|
||||
rgba.append([(line[i], line[i+1], line[i+2], 255) for i in range(0, stride, 3)])
|
||||
return width, height, rgba
|
||||
|
||||
# 精确色板(中心色 + 容差)
|
||||
PALETTE = [
|
||||
('W', (0, 0, 0), 70), # 黑 = 墙壁
|
||||
('O', (176, 176, 176), 40), # 灰 = 办公室
|
||||
('P', (64, 176, 240), 45), # 蓝 = 过道
|
||||
('R', (80, 176, 96), 40), # 绿 = 休息厅
|
||||
('Y', (240, 112, 16), 55), # 橙 = 共享工位/楼道
|
||||
('C', (80, 224, 192), 55), # 青绿 = 玻璃顶
|
||||
('.', (240, 240, 240), 40), # 白 = 空白
|
||||
]
|
||||
|
||||
def classify(rgb):
|
||||
r, g, b = rgb[:3]
|
||||
best, best_d = '?', 1e9
|
||||
for tag, (cr, cg, cb), tol in PALETTE:
|
||||
d = abs(r-cr) + abs(g-cg) + abs(b-cb)
|
||||
if d <= tol * 3 and d < best_d:
|
||||
best, best_d = tag, d
|
||||
return best
|
||||
|
||||
def main(path, grid_cols=48, grid_rows=28, sub=3):
|
||||
w, h, rgba = read_png(path)
|
||||
print(f'PNG: {w}x{h} 网格: {grid_cols}x{grid_rows}')
|
||||
cw, ch = w / grid_cols, h / grid_rows
|
||||
grid = []
|
||||
for gy in range(grid_rows):
|
||||
row = []
|
||||
for gx in range(grid_cols):
|
||||
cx = int((gx + 0.5) * cw)
|
||||
cy = int((gy + 0.5) * ch)
|
||||
votes = collections.Counter()
|
||||
rad_x, rad_y = max(2, int(cw*0.3)), max(2, int(ch*0.3))
|
||||
for dy in range(-rad_y, rad_y+1, sub):
|
||||
for dx in range(-rad_x, rad_x+1, sub):
|
||||
yy, xx = cy+dy, cx+dx
|
||||
if 0 <= yy < h and 0 <= xx < w:
|
||||
votes[classify(rgba[yy][xx])] += 1
|
||||
row.append(votes.most_common(1)[0][0])
|
||||
grid.append(row)
|
||||
# 打印
|
||||
print(' ' + ''.join(str(c % 10) for c in range(grid_cols)))
|
||||
for gy, row in enumerate(grid):
|
||||
print(f'{gy:2d} ' + ''.join(row))
|
||||
return grid
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = sys.argv[1] if len(sys.argv) > 1 else '详细的布局.png'
|
||||
main(path)
|
||||
Reference in New Issue
Block a user