[Python] 纯文本查看 复制代码
from PIL import Image
import itertools
from pathlib import Path
import posixpath
import sys
def detect_stripe_modulus(img: Image.Image, max_modulus=6, threshold=0.4):
img = img.convert("L")
pixels = img.load()
height, width = img.size
best_score = 0
best_mod = 2
best_xoff = 1
for xoff in range(1, max_modulus + 1):
for x_mod in range(2, max_modulus + 1):
score = 0
total = 0
for y in range(0, height,6):
for x in range(0, width,9):
if (x + y * xoff) % (x_mod) == 0:
if pixels[y, x] / 255 < threshold:
score += 1
total += 1
else:
if pixels[y, x] / 255 >= threshold:
score += 1
total += 1
match_ratio = score / total
print(xoff, x_mod, "match_ratio", score, match_ratio)
if match_ratio > best_score:
best_score = match_ratio
best_mod = x_mod
best_xoff = xoff
if match_ratio == 1:
break
return best_mod, best_xoff
def get_circle_pixels(center_x, center_y, r, max_x, max_y):
"""
使用中点圆算法生成圆环上的所有整数坐标点(去重)
返回: set of (x, y) 整数坐标
"""
points = set()
x = 0
y = int(r + 0.5) # 转为整数
p = 1 - y # 判断下一个点位置的决策参数
def add_symmetric_points(cx, cy, x, y):
"""添加8个对称点"""
points.add((cx + x, cy + y))
points.add((cx - x, cy + y))
points.add((cx + x, cy - y))
points.add((cx - x, cy - y))
points.add((cx + y, cy + x))
points.add((cx - y, cy + x))
points.add((cx + y, cy - x))
points.add((cx - y, cy - x))
add_symmetric_points(center_x, center_y, x, y)
while x < y:
x += 1
if p < 0:
p += 2 * x + 1
else:
y -= 1
p += 2 * (x - y) + 1
add_symmetric_points(center_x, center_y, x, y)
return set([p for p in points if 0 <= p[0] < max_x and 0 <= p[1] < max_y])
def decode(p, xoff=None, xmod=None):
path = Path(p)
lmax = 0
ori = Image.open(path)
new = Image.new(ori.mode, ori.size)
pixels = new.load()
print(xoff,xmod)
if xmod is None or xoff is None:
xmod, xoff = detect_stripe_modulus(ori)
print("choice",xoff, xmod, ori.size)
for y, x in itertools.product(*[range(r) for r in ori.size[::-1]]):
if not (x + y * xoff) % (xmod) == 0:
continue
r, g, b = ori.getpixel((x, y))
lmax = max(r, g, b, lmax)
amp = 255 / lmax
# amp = min(amp,6.5)
print(lmax, amp)
for y, x in itertools.product(*[range(r) for r in ori.size[::-1]]):
if not (x + y * xoff) % (xmod) == 0:
continue
r, g, b = ori.getpixel((x, y))
r *= amp
g *= amp
b *= amp
if r > 255 or g > 255 or b > 255:
print(r, g, b)
pixel = (int(min(r, 255)), int(min(g, 255)), int(min(b, 255)))
pixels[x, y] = pixel
# byd临近像素填充
for y, x in itertools.product(*[range(r) for r in ori.size[::-1]]):
if (x + y * xoff) % (xmod) == 0:
continue
n = 0
r, g, b = (0, 0, 0)
radius = 1
while n == 0:
for rx, ry in get_circle_pixels(x, y, radius, ori.size[0], ori.size[1]):
if not (rx + ry * xoff) % (xmod) == 0:
continue
rr, gg, bb = new.getpixel((rx, ry))
r += rr
g += gg
b += bb
n += 1
radius += 1
pixels[x, y] = (r // n, g // n, b // n)
new.save(
path.parent / (posixpath.splitext(path.name)[0] + "_decoded.png"),
)
if __name__ == "__main__":
decode(
sys.argv[1],
int(sys.argv[2]) if len(sys.argv) == 4 else None,
int(sys.argv[3]) if len(sys.argv) == 4 else None,
)