scene-detection / module /demo_images.py
jslmmfboom-coder
Add cover bg, scene mode selector, single image upload, demo hides upload, about page format
7347923
Raw
History Blame Contribute Delete
5.76 kB
"""示例场景图片管理 — 优先使用真实图片,缺失时生成合成图片
真实图片位于 test_imgs/complex/ 目录(通过 Git LFS 推送)
文本场景示例由合成生成(模拟合同文档)
"""
import os
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def _get_font(size):
try:
return ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size)
except Exception:
try:
return ImageFont.truetype("DejaVuSans.ttf", size)
except Exception:
return ImageFont.load_default()
def _generate_text_scene(path1, path2):
"""生成文本场景示例:模拟合同文档
两张图内容相同,但图2做了亮度调整和水平偏移,模拟不同角度拍摄
"""
w, h = 600, 800
for path, brightness, offset_x in [(path1, 0, 0), (path2, 30, 5)]:
img = Image.new('RGB', (w, h), (255, 255, 255))
draw = ImageDraw.Draw(img)
# 标题区域
draw.rectangle([50 + offset_x, 40, 550 + offset_x, 80], fill=(30, 30, 30))
# 正文行
for i in range(25):
y = 120 + i * 25
x_start = 50 + offset_x
x_end = 550 - (i % 5) * 20 + offset_x
draw.rectangle([x_start, y, x_end, y + 12], fill=(60, 60, 60))
# 模拟印章(红色圆形)
draw.ellipse([400 + offset_x, 650, 500 + offset_x, 750],
outline=(180, 30, 30), width=3)
draw.text((420 + offset_x, 680), "SEAL", fill=(180, 30, 30),
font=_get_font(20))
# 亮度调整
if brightness > 0:
import numpy as np
arr = np.array(img).astype(int) + brightness
arr = np.clip(arr, 0, 255).astype('uint8')
img = Image.fromarray(arr)
img.save(path, 'JPEG', quality=85)
def _scan_real_images(directory):
"""扫描目录中的真实图片文件"""
if not os.path.isdir(directory):
return []
exts = {'.jpg', '.jpeg', '.png', '.bmp', '.webp'}
imgs = []
for f in sorted(os.listdir(directory)):
if os.path.splitext(f)[1].lower() in exts:
imgs.append(os.path.join(directory, f))
return imgs
def ensure_demo_images(base_dir):
"""确保示例图片存在,优先使用真实图片
Args:
base_dir: 项目根目录
Returns:
dict: {'text': [path1, path2], 'complex': [path1, path2]} 或 None
"""
demo_dir = os.path.join(base_dir, 'test_imgs')
os.makedirs(demo_dir, exist_ok=True)
# === 复杂场景:优先使用真实图片 ===
complex_dir = os.path.join(demo_dir, 'complex')
real_complex = _scan_real_images(complex_dir)
if len(real_complex) >= 2:
complex_imgs = real_complex[:2]
else:
# Fallback:生成合成图片
c1 = os.path.join(demo_dir, 'demo_complex_1.jpg')
c2 = os.path.join(demo_dir, 'demo_complex_2.jpg')
if not os.path.exists(c1):
try:
_generate_complex_scene(c1, c2)
print("[示例] 已生成合成复杂场景图片")
except Exception as e:
print(f"[示例] 合成复杂场景生成失败: {e}")
return None
complex_imgs = [c1, c2]
# === 文本场景:优先使用真实图片 ===
text_dir = os.path.join(demo_dir, 'text')
real_text = _scan_real_images(text_dir)
if len(real_text) >= 2:
text_imgs = real_text[:2]
else:
# Fallback:生成合成图片
t1 = os.path.join(demo_dir, 'demo_text_1.jpg')
t2 = os.path.join(demo_dir, 'demo_text_2.jpg')
if not os.path.exists(t1):
try:
_generate_text_scene(t1, t2)
print("[示例] 已生成合成文本场景图片")
except Exception as e:
print(f"[示例] 合成文本场景生成失败: {e}")
return None
text_imgs = [t1, t2]
return {
'text': text_imgs,
'complex': complex_imgs,
}
def _generate_complex_scene(path1, path2):
"""生成复杂场景示例:模拟实景照片(fallback 用)"""
w, h = 600, 450
for path, shift_x, color_shift in [(path1, 0, 0), (path2, 15, 20)]:
img = Image.new('RGB', (w, h))
draw = ImageDraw.Draw(img)
# 天空渐变
for y in range(h // 2):
r = int(100 + y * 0.3 + color_shift)
g = int(150 + y * 0.2)
b = int(200 + y * 0.15)
draw.line([(0, y), (w, y)], fill=(min(r, 255), min(g, 255), min(b, 255)))
# 地面渐变
for y in range(h // 2, h):
r = int(80 + (y - h // 2) * 0.3)
g = int(120 + (y - h // 2) * 0.2)
b = int(60 + (y - h // 2) * 0.1)
draw.line([(0, y), (w, y)], fill=(min(r, 255), min(g, 255), min(b, 255)))
# 太阳
sun_x = 450 + shift_x
draw.ellipse([sun_x - 40, 50, sun_x + 40, 130],
fill=(255, 220, 100))
# 山脉
draw.polygon([(0, 225), (150 + shift_x, 150), (300 + shift_x, 200),
(450 + shift_x, 160), (600, 220), (600, 225)],
fill=(80, 100, 80))
# 建筑
draw.rectangle([100 + shift_x, 250, 200 + shift_x, 400],
fill=(120, 100, 90))
draw.rectangle([250 + shift_x, 280, 350 + shift_x, 400],
fill=(100, 110, 100))
draw.rectangle([400 + shift_x, 260, 480 + shift_x, 400],
fill=(90, 80, 100))
# 轻微模糊模拟不同焦距
if shift_x > 0:
img = img.filter(ImageFilter.GaussianBlur(radius=0.8))
img.save(path, 'JPEG', quality=85)