import cv2
import numpy as np
import subprocess
import time
import os
import pytesseract
from PIL import Image
import re
# ================== 配置 ==================
PHONE_NUMBERS = ["18868091626","18868091626"]
VLC_PATH = r"E:\vlc_vlc\VLC\vlc.exe"
AUDIO_FILE = r"C:\Users\Lenovo\Desktop\20250615_162636.m4a"
SCREENSHOT_PATH = r"screenshots"
pytesseract.pytesseract.tesseract_cmd = r"E:\tt-ocr\tesseract.exe"
# 使用完整路径的 adb.exe
ADB_PATH = r"E:\androidplatformADB\platform-tools\adb.exe"
THRESHOLD = 30 # 图像差异阈值
# ================== 核心函数 ==================
def adb_call(number):
"""通过 ADB 拨打电话"""
print(f"正在拨打号码: {number}")
encoded_number = number.replace("#", "%23").replace("+", "%2B").replace(" ", "%20")
cmd = f'"{ADB_PATH}" shell am start -a android.intent.action.CALL -d tel:{encoded_number}'
subprocess.run(cmd, shell=True)
time.sleep(1) # 等待1秒后开始截图监控
def take_screenshot(filename):
"""截取当前手机屏幕并保存"""
path = os.path.join(SCREENSHOT_PATH, filename)
print(f"正在截图到: {path}")
# 创建截图目录(如果不存在)
os.makedirs(SCREENSHOT_PATH, exist_ok=True)
# 执行截图命令
cmd = f'"{ADB_PATH}" exec-out screencap -p > "{path}"'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
# 检查文件是否存在且非空
if not os.path.exists(path) or os.path.getsize(path) == 0:
raise FileNotFoundError(f"截图失败,文件未生成或为空: {path}")
# 可选:图像预处理增强 OCR 效果
preprocess_image(path)
return path
def preprocess_image(image_path):
"""
图像预处理:灰度化 + 二值化 + 去噪
提高 OCR 准确率
"""
img = cv2.imread(image_path, 0) # 灰度图
_, img_bin = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 自动二值化
kernel = np.ones((1, 1), np.uint8)
img_bin = cv2.dilate(img_bin, kernel, iterations=1)
img_bin = cv2.erode(img_bin, kernel, iterations=1)
cv2.imwrite(image_path, img_bin) # 覆盖原图
return image_path
def compare_images(img1_path, img2_path):
"""比较两张图片是否发生变化"""
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
if img1 is None or img2 is None:
raise ValueError(f"图像读取失败:{img1_path} 或 {img2_path}")
if img1.shape != img2.shape:
raise ValueError("两张图片尺寸不一致,无法比较")
diff = cv2.absdiff(img1, img2)
_, thresh = cv2.threshold(diff, THRESHOLD, 255, cv2.THRESH_BINARY)
non_zero = cv2.countNonZero(thresh)
return non_zero > 100 # 根据像素变化数量判断是否有变化
def play_audio_with_vlc():
"""使用 VLC 播放音频文件"""
print("播放音频...")
process = subprocess.Popen([VLC_PATH, "--play-and-exit", AUDIO_FILE])
process.wait() # 等待音频播放完成
print("音频播放完毕")
def detect_text(image_path, pattern=r"\b\d{2}:\d{2}\b"):
"""
使用 OCR 检测图像中是否包含符合时间格式(如 00:00)的文本。
:param image_path: 图像文件路径
:param pattern: 正则表达式,默认是 \b\d{2}:\d{2}\b 表示两位数:两位数格式
:return: True 如果检测到匹配的文本
"""
print(f"OCR 检测图像中的文本:{image_path}")
try:
image = Image.open(image_path)
text = pytesseract.image_to_string(image, lang='eng') # eng 表示英文+数字
match = re.search(pattern, text)
if match:
print(f"检测到符合 '{pattern}' 格式的文本!内容为:{match.group()}")
return True
else:
print("未检测到目标文本格式。")
return False
except Exception as e:
print(f"OCR 识别出错: {e}")
return False
def monitor_screen_changes(max_attempts=5):
"""
在首次截图前等2秒,之后每隔3秒截图一次,
并两两比较是否有屏幕变化,若变化中有 'dd:dd' 格式文本,则播放音频。
如果连续 max_attempts 次没有检测到目标文本,则主动挂断电话。
"""
print("等待 2 秒后开始第一次截图...")
time.sleep(2) # 拨号后首次截图延迟 2 秒
prev_img = take_screenshot("s0.png")
no_match_count = 0 # 用于记录未匹配目标文本的次数
while True:
time.sleep(3) # 每次截图间隔 3 秒
curr_img = take_screenshot(f"s{int(time.time())}.png") # 使用时间戳命名避免冲突
if compare_images(prev_img, curr_img):
print("检测到屏幕元素发生变化!")
if detect_text(curr_img): # 默认检测 dd:dd 格式
print("检测到 'dd:dd' 格式字样,触发音频播放")
play_audio_with_vlc()
break
else:
no_match_count += 1
print(f"未检测到目标文本,连续失败次数:{no_match_count}/{max_attempts}")
else:
print("屏幕无明显变化,跳过OCR识别")
no_match_count += 1
print(f"无有效变化,连续失败次数:{no_match_count}/{max_attempts}")
# 判断是否达到最大失败次数
if no_match_count >= max_attempts:
print(f"连续 {max_attempts} 次未检测到目标文本,主动挂断电话")
hang_up_call()
return False # 表示未成功播放音频
prev_img = curr_img
return True # 表示成功播放了音频
def hang_up_call():
"""挂断电话"""
print("挂断电话...")
cmd = f'"{ADB_PATH}" shell input keyevent KEYCODE_ENDCALL'
subprocess.run(cmd, shell=True)
time.sleep(1)
def main():
# 创建截图目录
os.makedirs(SCREENSHOT_PATH, exist_ok=True)
for number in PHONE_NUMBERS:
print(f"=== 开始拨打号码: {number} ===")
adb_call(number)
# 开始监控屏幕变化(首次截图前等2秒)
try:
monitor_screen_changes()
except Exception as e:
print(f"发生异常: {e}")
hang_up_call()
print(f"=== 结束拨打号码: {number} ===\n")
if __name__ == "__main__":
main()