detect_captcha_edge.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import cv2
  2. import numpy as np
  3. from PIL import Image
  4. import os
  5. import sys
  6. def detect_captcha_left_edge(image_path_or_array, output_path=None):
  7. """
  8. 识别滑块验证码中橙色缺口覆盖层的最左边X坐标,并生成绿线标记图。
  9. 支持传入图片路径(str)或numpy.ndarray(BGR/RGB)。
  10. """
  11. if isinstance(image_path_or_array, str):
  12. img = Image.open(image_path_or_array)
  13. img_np = np.array(img)
  14. else:
  15. img_np = image_path_or_array.copy()
  16. # OpenCV 截图通常是 BGR,转成 RGB
  17. if img_np.shape[2] == 3:
  18. img_np = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)
  19. h, w = img_np.shape[:2]
  20. # 转换为HSV颜色空间
  21. hsv = cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV)
  22. # 检测 peach/orange 覆盖层
  23. # 色调: 10-35 (橙色/桃色), 饱和度: 40-255, 亮度: 140-255
  24. lower = np.array([10, 40, 140])
  25. upper = np.array([35, 255, 255])
  26. mask = cv2.inRange(hsv, lower, upper)
  27. # 形态学操作去噪
  28. kernel = np.ones((5, 5), np.uint8)
  29. mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
  30. mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
  31. # 查找轮廓
  32. contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  33. if not contours:
  34. raise ValueError("未检测到橙色区域")
  35. # 筛选候选区域:
  36. # 1. 轮廓中心位于验证码图片区域内(y + bh/2 在 0.4h ~ 0.65h 之间)
  37. # 2. 面积足够大
  38. # 3. y 范围足够长(bh > 0.2h),排除滑块按钮等短区域
  39. candidates = []
  40. for cnt in contours:
  41. x, y, bw, bh = cv2.boundingRect(cnt)
  42. area = bw * bh
  43. if area < 5000:
  44. continue
  45. center_y = y + bh / 2
  46. if center_y < h * 0.4 or center_y > h * 0.65:
  47. continue
  48. if bh < h * 0.2:
  49. continue
  50. candidates.append((cnt, x, y, bw, bh, area, bh))
  51. if not candidates:
  52. raise ValueError("未检测到拼图覆盖层")
  53. # 选择 y 范围最长的候选
  54. best = max(candidates, key=lambda c: c[6])
  55. _, x, y, bw, bh, area, bh_max = best
  56. # 左边缘 x 坐标
  57. left_x = x
  58. # 在原图上画绿线
  59. canvas = img_np.copy()
  60. cv2.line(canvas, (left_x, 0), (left_x, h), (0, 255, 0), 2)
  61. # 保存绿线标记图
  62. if output_path is None:
  63. base, ext = os.path.splitext(image_path_or_array if isinstance(image_path_or_array, str) else "")
  64. output_path = f"{base}_green.png"
  65. cv2.imwrite(output_path, cv2.cvtColor(canvas, cv2.COLOR_RGB2BGR))
  66. return left_x, output_path
  67. if __name__ == "__main__":
  68. if len(sys.argv) < 2:
  69. print("用法: python detect_captcha_edge.py <图片路径> [输出路径]")
  70. sys.exit(1)
  71. image_path = sys.argv[1]
  72. output_path = sys.argv[2] if len(sys.argv) > 2 else None
  73. left_x, out = detect_captcha_left_edge(image_path, output_path)
  74. print(f"拼图最左边X坐标: {left_x}")
  75. print(f"绿线标记图: {out}")