cut_text_regions_in_panel.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # -*- coding: utf-8 -*-
  2. """
  3. 在格子内检测并切割文字区域
  4. """
  5. import sys
  6. import cv2
  7. import numpy as np
  8. from pathlib import Path
  9. # Windows编码修复
  10. if sys.platform == 'win32':
  11. import io
  12. sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
  13. sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
  14. def cut_text_regions_in_panel(panel_image_path, output_dir):
  15. """
  16. 在格子图片中检测文字区域并切割成小块
  17. 参数:
  18. panel_image_path: 格子图片路径
  19. output_dir: 输出目录
  20. """
  21. panel_image_path = Path(panel_image_path)
  22. output_dir = Path(output_dir)
  23. output_dir.mkdir(parents=True, exist_ok=True)
  24. # 读取格子图片
  25. img_array = np.fromfile(str(panel_image_path), dtype=np.uint8)
  26. img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
  27. if img is None:
  28. raise ValueError(f"无法读取图片: {panel_image_path}")
  29. img_height, img_width = img.shape[:2]
  30. # 转换为灰度图
  31. if len(img.shape) == 3:
  32. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  33. else:
  34. gray = img.copy()
  35. # 使用自适应阈值进行二值化
  36. binary = cv2.adaptiveThreshold(
  37. gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
  38. cv2.THRESH_BINARY_INV, 11, 2
  39. )
  40. # 形态学操作,连接相近的文字
  41. kernel = np.ones((3, 3), np.uint8)
  42. binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2)
  43. binary = cv2.dilate(binary, kernel, iterations=1)
  44. # 查找轮廓
  45. contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  46. # 过滤轮廓,找到文字区域
  47. text_regions = []
  48. min_area = (img_width * img_height) * 0.001 # 最小面积(0.1%)
  49. max_area = (img_width * img_height) * 0.5 # 最大面积(50%)
  50. for contour in contours:
  51. area = cv2.contourArea(contour)
  52. if min_area < area < max_area:
  53. x, y, w, h = cv2.boundingRect(contour)
  54. # 过滤掉太小的区域
  55. if w > 10 and h > 10:
  56. text_regions.append({
  57. 'x': x,
  58. 'y': y,
  59. 'width': w,
  60. 'height': h,
  61. 'center_x': x + w / 2,
  62. 'center_y': y + h / 2
  63. })
  64. # 按照最右边(X坐标最大)最靠前,然后最上面(Y坐标最小)最靠前的原则排序
  65. text_regions.sort(key=lambda r: (-r['center_x'], r['center_y']))
  66. # 切割每个文字区域
  67. panel_name = panel_image_path.stem
  68. cut_files = []
  69. for idx, region in enumerate(text_regions, 1):
  70. x = max(0, region['x'])
  71. y = max(0, region['y'])
  72. w = min(region['width'], img_width - x)
  73. h = min(region['height'], img_height - y)
  74. if w <= 0 or h <= 0:
  75. continue
  76. # 切割文字区域
  77. text_roi = img[y:y+h, x:x+w]
  78. # 保存切割后的图片
  79. output_filename = f"{panel_name}_text{idx}.png"
  80. output_path = output_dir / output_filename
  81. # 使用cv2.imencode处理中文路径
  82. success, encoded_img = cv2.imencode('.png', text_roi)
  83. if success:
  84. encoded_img.tofile(str(output_path))
  85. cut_files.append(str(output_path))
  86. return cut_files
  87. if __name__ == '__main__':
  88. if len(sys.argv) < 3:
  89. print("用法: python cut_text_regions_in_panel.py <格子图片路径> <输出目录>")
  90. sys.exit(1)
  91. panel_image_path = sys.argv[1]
  92. output_dir = sys.argv[2]
  93. try:
  94. cut_files = cut_text_regions_in_panel(panel_image_path, output_dir)
  95. print(f"✅ 成功切割 {len(cut_files)} 个文字区域")
  96. except Exception as e:
  97. print(f"[ERROR] 切割失败: {e}")
  98. import traceback
  99. traceback.print_exc()
  100. sys.exit(1)