'commit'
This commit is contained in:
BIN
Test/Screenshots/chat_result_20260121_113553.jpg
Normal file
BIN
Test/Screenshots/chat_result_20260121_113553.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
BIN
Test/Screenshots/chat_result_analyzed.jpg
Normal file
BIN
Test/Screenshots/chat_result_analyzed.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
215
Test/T1_StartWeiXin.py
Normal file
215
Test/T1_StartWeiXin.py
Normal file
@@ -0,0 +1,215 @@
|
||||
# coding=utf-8
|
||||
import uiautomator2 as u2
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger("TestWeChat")
|
||||
|
||||
def analyze_chat_image(image_path, output_path):
|
||||
"""
|
||||
识别微信聊天截图中的头像并画框
|
||||
"""
|
||||
logger.info(f"正在分析图片: {image_path}")
|
||||
|
||||
# 读取图片
|
||||
# 注意:cv2.imread 不支持中文路径,需要用 np.fromfile 读取
|
||||
try:
|
||||
img_data = np.fromfile(image_path, dtype=np.uint8)
|
||||
img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
|
||||
except Exception as e:
|
||||
logger.error(f"读取图片失败: {e}")
|
||||
return
|
||||
|
||||
if img is None:
|
||||
logger.error("图片读取为空")
|
||||
return
|
||||
|
||||
height, width = img.shape[:2]
|
||||
logger.info(f"图片尺寸: {width}x{height}")
|
||||
|
||||
# 1. 预处理
|
||||
# 转为灰度图
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# 使用自适应阈值二值化
|
||||
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
||||
cv2.THRESH_BINARY_INV, 11, 2)
|
||||
|
||||
# 形态学操作:闭运算,填充内部空洞
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
||||
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
|
||||
|
||||
# 2. 轮廓查找
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
logger.info(f"检测到轮廓数量: {len(contours)}")
|
||||
|
||||
avatar_count = 0
|
||||
|
||||
# 3. 筛选轮廓
|
||||
for contour in contours:
|
||||
# 获取外接矩形
|
||||
x, y, w, h = cv2.boundingRect(contour)
|
||||
|
||||
# 筛选条件优化:
|
||||
# 1. 形状接近正方形 (放宽宽高比限制: 0.8 ~ 1.2)
|
||||
aspect_ratio = float(w) / h
|
||||
|
||||
# 2. 尺寸适中
|
||||
# 假设头像宽度在屏幕宽度的 6% 到 15% 之间
|
||||
min_w = width * 0.06
|
||||
max_w = width * 0.15
|
||||
|
||||
# 3. 位置筛选
|
||||
# 排除底部输入框区域 (假设底部 10% 为输入区域)
|
||||
if y > height * 0.9:
|
||||
continue
|
||||
|
||||
# 左侧头像:靠左边 (x < width * 0.18)
|
||||
# 右侧头像:靠右边 (x > width * 0.82)
|
||||
is_left = x < width * 0.18
|
||||
is_right = x > width * 0.82
|
||||
|
||||
if 0.8 <= aspect_ratio <= 1.2 and min_w < w < max_w:
|
||||
if is_left or is_right:
|
||||
# 确定颜色
|
||||
# 左侧:蓝色 (BGR: 255, 0, 0)
|
||||
# 右侧:黄色 (BGR: 0, 255, 255)
|
||||
color = (255, 0, 0) if is_left else (0, 255, 255)
|
||||
|
||||
# 绘制矩形框,线宽为 3
|
||||
cv2.rectangle(img, (x, y), (x + w, y + h), color, 3)
|
||||
|
||||
label = "Left" if is_left else "Right"
|
||||
avatar_count += 1
|
||||
logger.info(f"找到头像: 位置=({x},{y}), 尺寸={w}x{h}, 侧别={label}")
|
||||
|
||||
logger.info(f"共标记了 {avatar_count} 个头像")
|
||||
|
||||
# 4. 保存结果
|
||||
try:
|
||||
# cv2.imwrite 不支持中文路径,使用 imencode + tofile
|
||||
ext = os.path.splitext(output_path)[1]
|
||||
cv2.imencode(ext, img)[1].tofile(output_path)
|
||||
logger.info(f"✅ 分析结果已保存至: {output_path}")
|
||||
except Exception as e:
|
||||
logger.error(f"保存分析图片失败: {e}")
|
||||
|
||||
def main():
|
||||
logger.info("开始执行微信搜索测试...")
|
||||
|
||||
# 连接设备
|
||||
try:
|
||||
d = u2.connect()
|
||||
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
||||
except Exception as e:
|
||||
logger.error(f"设备连接失败: {e}")
|
||||
return
|
||||
|
||||
# 1. 启动微信
|
||||
logger.info("步骤 1: 启动微信...")
|
||||
d.app_start("com.tencent.mm", stop=True)
|
||||
# 等待微信启动完成
|
||||
time.sleep(5)
|
||||
|
||||
# 获取屏幕尺寸
|
||||
w, h = d.window_size()
|
||||
logger.info(f"屏幕尺寸: {w}x{h}")
|
||||
|
||||
# 2. 点击搜索按钮 (参考 Opener.py 的坐标比例: w * 0.84, h * 0.08)
|
||||
search_x = int(w * 0.84)
|
||||
search_y = int(h * 0.08)
|
||||
logger.info(f"步骤 2: 点击搜索按钮 (坐标: {search_x}, {search_y})...")
|
||||
d.click(search_x, search_y)
|
||||
time.sleep(2)
|
||||
|
||||
# 3. 输入 "糖豆爸爸"
|
||||
target_name = "糖豆爸爸"
|
||||
logger.info(f"步骤 3: 输入搜索内容 '{target_name}'...")
|
||||
|
||||
try:
|
||||
# 启用 FastInputIME 以支持中文输入
|
||||
d.set_input_ime(True)
|
||||
|
||||
# 点击搜索框获取焦点 (参考 Opener.py: w * 0.4, h * 0.08)
|
||||
d.click(int(w * 0.4), int(h * 0.08))
|
||||
time.sleep(1)
|
||||
|
||||
# 输入文字
|
||||
d.send_keys(target_name)
|
||||
time.sleep(2)
|
||||
|
||||
# 恢复输入法
|
||||
d.set_input_ime(False)
|
||||
except Exception as e:
|
||||
logger.error(f"输入文字失败: {e}")
|
||||
try:
|
||||
d(focused=True).set_text(target_name)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 4. 点击搜索结果
|
||||
logger.info("步骤 4: 查找并点击搜索结果...")
|
||||
time.sleep(2)
|
||||
|
||||
found = False
|
||||
|
||||
# 策略 A: 精确匹配文本
|
||||
if d(text=target_name).exists:
|
||||
logger.info(f"找到文本为 '{target_name}' 的元素,点击...")
|
||||
d(text=target_name).click()
|
||||
found = True
|
||||
else:
|
||||
logger.warning(f"未找到文本为 '{target_name}' 的元素,尝试模糊匹配或坐标点击...")
|
||||
|
||||
# 策略 B: 坐标点击 (参考 Opener.py 点击第一个结果: w * 0.5, h * 0.18)
|
||||
result_x = int(w * 0.5)
|
||||
result_y = int(h * 0.18)
|
||||
logger.info(f"尝试点击第一个搜索结果位置 ({result_x}, {result_y})...")
|
||||
d.click(result_x, result_y)
|
||||
found = True
|
||||
|
||||
if found:
|
||||
logger.info("✅ 已执行点击操作,应该已进入对话框。")
|
||||
|
||||
# 5. 截图保存结果
|
||||
logger.info("步骤 5: 截图并分析...")
|
||||
# 等待界面加载稳定
|
||||
time.sleep(3)
|
||||
|
||||
# 创建截图目录
|
||||
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
||||
if not os.path.exists(screenshot_dir):
|
||||
os.makedirs(screenshot_dir)
|
||||
|
||||
# 生成文件名
|
||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"chat_result_{timestamp}.jpg"
|
||||
save_path = os.path.join(screenshot_dir, filename)
|
||||
|
||||
try:
|
||||
d.screenshot(save_path)
|
||||
logger.info(f"✅ 原始截图已保存: {save_path}")
|
||||
|
||||
# 6. 分析截图并标记头像
|
||||
logger.info("步骤 6: 自动标记头像...")
|
||||
analyzed_filename = f"chat_result_{timestamp}_analyzed.jpg"
|
||||
analyzed_path = os.path.join(screenshot_dir, analyzed_filename)
|
||||
|
||||
analyze_chat_image(save_path, analyzed_path)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 截图或分析失败: {e}")
|
||||
|
||||
else:
|
||||
logger.error("❌ 未能定位到搜索结果,跳过截图。")
|
||||
|
||||
logger.info("测试结束。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
153
Test/analyze_chat_avatars.py
Normal file
153
Test/analyze_chat_avatars.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# coding=utf-8
|
||||
import cv2
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
def analyze_chat_image(image_path, output_path):
|
||||
print(f"正在读取图片: {image_path}")
|
||||
|
||||
# 读取图片
|
||||
# 注意:cv2.imread 不支持中文路径,需要用 np.fromfile 读取
|
||||
try:
|
||||
img_data = np.fromfile(image_path, dtype=np.uint8)
|
||||
img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
|
||||
except Exception as e:
|
||||
print(f"读取图片失败: {e}")
|
||||
return
|
||||
|
||||
if img is None:
|
||||
print("图片读取为空")
|
||||
return
|
||||
|
||||
height, width = img.shape[:2]
|
||||
print(f"图片尺寸: {width}x{height}")
|
||||
|
||||
# 1. 预处理
|
||||
# 转为灰度图
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# 使用自适应阈值二值化
|
||||
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
||||
cv2.THRESH_BINARY_INV, 11, 2)
|
||||
|
||||
# 形态学操作:闭运算,填充内部空洞
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
||||
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
|
||||
|
||||
# 2. 轮廓查找
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
|
||||
print(f"检测到轮廓数量: {len(contours)}")
|
||||
|
||||
# 收集所有符合条件的头像
|
||||
avatars = []
|
||||
|
||||
# 3. 筛选轮廓
|
||||
for contour in contours:
|
||||
# 获取外接矩形
|
||||
x, y, w, h = cv2.boundingRect(contour)
|
||||
|
||||
# 筛选条件优化:
|
||||
# 1. 形状接近正方形 (放宽宽高比限制: 0.8 ~ 1.2)
|
||||
aspect_ratio = float(w) / h
|
||||
|
||||
# 2. 尺寸适中
|
||||
# 假设头像宽度在屏幕宽度的 6% 到 15% 之间
|
||||
min_w = width * 0.06
|
||||
max_w = width * 0.15
|
||||
|
||||
# 3. 位置筛选
|
||||
# 排除底部输入框区域 (假设底部 10% 为输入区域)
|
||||
if y > height * 0.9:
|
||||
continue
|
||||
|
||||
# 左侧头像:靠左边 (x < width * 0.18)
|
||||
# 右侧头像:靠右边 (x > width * 0.82)
|
||||
is_left = x < width * 0.18
|
||||
is_right = x > width * 0.82
|
||||
|
||||
if 0.8 <= aspect_ratio <= 1.2 and min_w < w < max_w:
|
||||
if is_left or is_right:
|
||||
side = "Left" if is_left else "Right"
|
||||
avatars.append({
|
||||
'x': x, 'y': y, 'w': w, 'h': h,
|
||||
'side': side
|
||||
})
|
||||
|
||||
# 按 y 坐标排序
|
||||
avatars.sort(key=lambda a: a['y'])
|
||||
|
||||
print(f"找到有效头像数量: {len(avatars)}")
|
||||
|
||||
# 4. 绘制对话内容框 (Green/Red Boxes)
|
||||
# 策略:按顺序遍历头像,如果发现同侧连续,则视为一组。
|
||||
# 从当前组的第一个头像上方开始,直到下一个不同侧的头像上方(或底部)。
|
||||
|
||||
if avatars:
|
||||
i = 0
|
||||
while i < len(avatars):
|
||||
current_group_start = i
|
||||
current_side = avatars[i]['side']
|
||||
|
||||
# 找到当前组的结束位置 (即下一个不同侧头像的索引)
|
||||
j = i + 1
|
||||
while j < len(avatars) and avatars[j]['side'] == current_side:
|
||||
j += 1
|
||||
|
||||
# 当前组范围: avatars[i] ... avatars[j-1]
|
||||
# 确定绘制区域的 Y 轴范围
|
||||
|
||||
# Start Y: 当前组第一个头像的上方 (例如 -10px)
|
||||
start_y = max(0, avatars[i]['y'] - 10)
|
||||
|
||||
# End Y: 下一组第一个头像的上方 (减去较大间距,例如 -30px),或者当前组最后一个头像的底部加上边距
|
||||
# 为了让框之间有明显间隔,我们采取策略:
|
||||
# 如果有下一组,End Y = 下一组第一个头像的 y - 30 (留出间隙)
|
||||
# 如果没有下一组,End Y = 屏幕底部区域上方
|
||||
|
||||
if j < len(avatars):
|
||||
end_y = max(start_y + 10, avatars[j]['y'] - 30)
|
||||
else:
|
||||
end_y = int(height * 0.9) # 到底部输入框上方
|
||||
|
||||
# 绘制大框
|
||||
# 左侧 (Left) -> 对方 -> 绿色 (0, 255, 0)
|
||||
# 右侧 (Right) -> 我 -> 红色 (0, 0, 255)
|
||||
# 注意 OpenCV 颜色是 BGR
|
||||
box_color = (0, 255, 0) if current_side == "Left" else (0, 0, 255)
|
||||
|
||||
# 绘制矩形 (空心,线宽 5)
|
||||
# X 轴范围:0 到 width
|
||||
cv2.rectangle(img, (0, start_y), (width, end_y), box_color, 5)
|
||||
|
||||
print(f"绘制内容框: 侧别={current_side}, 范围 Y={start_y} to {end_y}")
|
||||
|
||||
# 移动到下一组
|
||||
i = j
|
||||
|
||||
# 5. 绘制头像框 (Blue/Yellow Boxes) - 画在内容框之上
|
||||
for av in avatars:
|
||||
x, y, w, h = av['x'], av['y'], av['w'], av['h']
|
||||
# 左侧:蓝色 (BGR: 255, 0, 0)
|
||||
# 右侧:黄色 (BGR: 0, 255, 255)
|
||||
color = (255, 0, 0) if av['side'] == "Left" else (0, 255, 255)
|
||||
|
||||
cv2.rectangle(img, (x, y), (x + w, y + h), color, 10)
|
||||
print(f"绘制头像: 位置=({x},{y}), 侧别={av['side']}")
|
||||
|
||||
# 6. 保存结果
|
||||
try:
|
||||
# cv2.imwrite 不支持中文路径,使用 imencode + tofile
|
||||
ext = os.path.splitext(output_path)[1]
|
||||
cv2.imencode(ext, img)[1].tofile(output_path)
|
||||
print(f"结果已保存至: {output_path}")
|
||||
except Exception as e:
|
||||
print(f"保存图片失败: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 输入文件路径
|
||||
input_file = r"d:\dsWork\aiData\Test\Screenshots\chat_result_20260121_113553.jpg"
|
||||
# 输出文件路径
|
||||
output_file = r"d:\dsWork\aiData\Test\Screenshots\chat_result_analyzed.jpg"
|
||||
|
||||
analyze_chat_image(input_file, output_file)
|
||||
271
Test/testWeXinChat.py
Normal file
271
Test/testWeXinChat.py
Normal file
@@ -0,0 +1,271 @@
|
||||
# coding=utf-8
|
||||
import uiautomator2 as u2
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger("TestWeChat")
|
||||
|
||||
def analyze_chat_image(image_path, output_path):
|
||||
"""
|
||||
识别微信聊天截图中的头像并画框
|
||||
"""
|
||||
logger.info(f"正在分析图片: {image_path}")
|
||||
|
||||
# 读取图片
|
||||
# 注意:cv2.imread 不支持中文路径,需要用 np.fromfile 读取
|
||||
try:
|
||||
img_data = np.fromfile(image_path, dtype=np.uint8)
|
||||
img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
|
||||
except Exception as e:
|
||||
logger.error(f"读取图片失败: {e}")
|
||||
return
|
||||
|
||||
if img is None:
|
||||
logger.error("图片读取为空")
|
||||
return
|
||||
|
||||
height, width = img.shape[:2]
|
||||
logger.info(f"图片尺寸: {width}x{height}")
|
||||
|
||||
# 1. 预处理
|
||||
# 转为灰度图
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# 使用自适应阈值二值化
|
||||
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
||||
cv2.THRESH_BINARY_INV, 11, 2)
|
||||
|
||||
# 形态学操作:闭运算,填充内部空洞
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
||||
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
|
||||
|
||||
# 2. 轮廓查找
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
logger.info(f"检测到轮廓数量: {len(contours)}")
|
||||
|
||||
# 收集所有符合条件的头像
|
||||
avatars = []
|
||||
|
||||
# 3. 筛选轮廓
|
||||
for contour in contours:
|
||||
# 获取外接矩形
|
||||
x, y, w, h = cv2.boundingRect(contour)
|
||||
|
||||
# 筛选条件优化:
|
||||
# 1. 形状接近正方形 (放宽宽高比限制: 0.8 ~ 1.2)
|
||||
aspect_ratio = float(w) / h
|
||||
|
||||
# 2. 尺寸适中
|
||||
# 假设头像宽度在屏幕宽度的 6% 到 15% 之间
|
||||
min_w = width * 0.06
|
||||
max_w = width * 0.15
|
||||
|
||||
# 3. 位置筛选
|
||||
# 排除底部输入框区域 (假设底部 10% 为输入区域)
|
||||
if y > height * 0.9:
|
||||
continue
|
||||
|
||||
# 左侧头像:靠左边 (x < width * 0.18)
|
||||
# 右侧头像:靠右边 (x > width * 0.82)
|
||||
is_left = x < width * 0.18
|
||||
is_right = x > width * 0.82
|
||||
|
||||
if 0.8 <= aspect_ratio <= 1.2 and min_w < w < max_w:
|
||||
if is_left or is_right:
|
||||
side = "Left" if is_left else "Right"
|
||||
avatars.append({
|
||||
'x': x, 'y': y, 'w': w, 'h': h,
|
||||
'side': side
|
||||
})
|
||||
|
||||
# 按 y 坐标排序
|
||||
avatars.sort(key=lambda a: a['y'])
|
||||
|
||||
logger.info(f"找到有效头像数量: {len(avatars)}")
|
||||
|
||||
# 4. 绘制对话内容框 (Green/Red Boxes)
|
||||
# 策略:按顺序遍历头像,如果发现同侧连续,则视为一组。
|
||||
# 从当前组的第一个头像上方开始,直到下一个不同侧的头像上方(或底部)。
|
||||
|
||||
if avatars:
|
||||
i = 0
|
||||
while i < len(avatars):
|
||||
current_group_start = i
|
||||
current_side = avatars[i]['side']
|
||||
|
||||
# 找到当前组的结束位置 (即下一个不同侧头像的索引)
|
||||
j = i + 1
|
||||
while j < len(avatars) and avatars[j]['side'] == current_side:
|
||||
j += 1
|
||||
|
||||
# 当前组范围: avatars[i] ... avatars[j-1]
|
||||
# 确定绘制区域的 Y 轴范围
|
||||
|
||||
# Start Y: 当前组第一个头像的上方 (例如 -10px)
|
||||
start_y = max(0, avatars[i]['y'] - 10)
|
||||
|
||||
# End Y: 下一组第一个头像的上方 (减去较大间距,例如 -30px),或者当前组最后一个头像的底部加上边距
|
||||
# 为了让框之间有明显间隔,我们采取策略:
|
||||
# 如果有下一组,End Y = 下一组第一个头像的 y - 30 (留出间隙)
|
||||
# 如果没有下一组,End Y = 屏幕底部区域上方
|
||||
|
||||
if j < len(avatars):
|
||||
end_y = max(start_y + 10, avatars[j]['y'] - 30)
|
||||
else:
|
||||
end_y = int(height * 0.9) # 到底部输入框上方
|
||||
|
||||
# 绘制大框
|
||||
# 左侧 (Left) -> 对方 -> 绿色 (0, 255, 0)
|
||||
# 右侧 (Right) -> 我 -> 红色 (0, 0, 255)
|
||||
# 注意 OpenCV 颜色是 BGR
|
||||
box_color = (0, 255, 0) if current_side == "Left" else (0, 0, 255)
|
||||
|
||||
# 绘制矩形 (空心,线宽 2)
|
||||
# X 轴范围:0 到 width
|
||||
cv2.rectangle(img, (0, start_y), (width, end_y), box_color, 2)
|
||||
|
||||
logger.info(f"绘制内容框: 侧别={current_side}, 范围 Y={start_y} to {end_y}")
|
||||
|
||||
# 移动到下一组
|
||||
i = j
|
||||
|
||||
# 5. 绘制头像框 (Blue/Yellow Boxes) - 画在内容框之上
|
||||
for av in avatars:
|
||||
x, y, w, h = av['x'], av['y'], av['w'], av['h']
|
||||
# 左侧:蓝色 (BGR: 255, 0, 0)
|
||||
# 右侧:黄色 (BGR: 0, 255, 255)
|
||||
color = (255, 0, 0) if av['side'] == "Left" else (0, 255, 255)
|
||||
|
||||
cv2.rectangle(img, (x, y), (x + w, y + h), color, 3)
|
||||
logger.info(f"绘制头像: 位置=({x},{y}), 侧别={av['side']}")
|
||||
|
||||
logger.info(f"共标记了 {len(avatars)} 个头像")
|
||||
|
||||
# 6. 保存结果
|
||||
try:
|
||||
# cv2.imwrite 不支持中文路径,使用 imencode + tofile
|
||||
ext = os.path.splitext(output_path)[1]
|
||||
cv2.imencode(ext, img)[1].tofile(output_path)
|
||||
logger.info(f"✅ 分析结果已保存至: {output_path}")
|
||||
except Exception as e:
|
||||
logger.error(f"保存分析图片失败: {e}")
|
||||
|
||||
def main():
|
||||
logger.info("开始执行微信搜索测试...")
|
||||
|
||||
# 连接设备
|
||||
try:
|
||||
d = u2.connect()
|
||||
logger.info(f"设备连接成功: {d.info.get('serial')}")
|
||||
except Exception as e:
|
||||
logger.error(f"设备连接失败: {e}")
|
||||
return
|
||||
|
||||
# 1. 启动微信
|
||||
logger.info("步骤 1: 启动微信...")
|
||||
d.app_start("com.tencent.mm", stop=True)
|
||||
# 等待微信启动完成
|
||||
time.sleep(5)
|
||||
|
||||
# 获取屏幕尺寸
|
||||
w, h = d.window_size()
|
||||
logger.info(f"屏幕尺寸: {w}x{h}")
|
||||
|
||||
# 2. 点击搜索按钮 (参考 Opener.py 的坐标比例: w * 0.84, h * 0.08)
|
||||
search_x = int(w * 0.84)
|
||||
search_y = int(h * 0.08)
|
||||
logger.info(f"步骤 2: 点击搜索按钮 (坐标: {search_x}, {search_y})...")
|
||||
d.click(search_x, search_y)
|
||||
time.sleep(2)
|
||||
|
||||
# 3. 输入 "糖豆爸爸"
|
||||
target_name = "糖豆爸爸"
|
||||
logger.info(f"步骤 3: 输入搜索内容 '{target_name}'...")
|
||||
|
||||
try:
|
||||
# 启用 FastInputIME 以支持中文输入
|
||||
d.set_input_ime(True)
|
||||
|
||||
# 点击搜索框获取焦点 (参考 Opener.py: w * 0.4, h * 0.08)
|
||||
d.click(int(w * 0.4), int(h * 0.08))
|
||||
time.sleep(1)
|
||||
|
||||
# 输入文字
|
||||
d.send_keys(target_name)
|
||||
time.sleep(2)
|
||||
|
||||
# 恢复输入法
|
||||
d.set_input_ime(False)
|
||||
except Exception as e:
|
||||
logger.error(f"输入文字失败: {e}")
|
||||
try:
|
||||
d(focused=True).set_text(target_name)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 4. 点击搜索结果
|
||||
logger.info("步骤 4: 查找并点击搜索结果...")
|
||||
time.sleep(2)
|
||||
|
||||
found = False
|
||||
|
||||
# 策略 A: 精确匹配文本
|
||||
if d(text=target_name).exists:
|
||||
logger.info(f"找到文本为 '{target_name}' 的元素,点击...")
|
||||
d(text=target_name).click()
|
||||
found = True
|
||||
else:
|
||||
logger.warning(f"未找到文本为 '{target_name}' 的元素,尝试模糊匹配或坐标点击...")
|
||||
|
||||
# 策略 B: 坐标点击 (参考 Opener.py 点击第一个结果: w * 0.5, h * 0.18)
|
||||
result_x = int(w * 0.5)
|
||||
result_y = int(h * 0.18)
|
||||
logger.info(f"尝试点击第一个搜索结果位置 ({result_x}, {result_y})...")
|
||||
d.click(result_x, result_y)
|
||||
found = True
|
||||
|
||||
if found:
|
||||
logger.info("✅ 已执行点击操作,应该已进入对话框。")
|
||||
|
||||
# 5. 截图保存结果
|
||||
logger.info("步骤 5: 截图并分析...")
|
||||
# 等待界面加载稳定
|
||||
time.sleep(3)
|
||||
|
||||
# 创建截图目录
|
||||
screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots")
|
||||
if not os.path.exists(screenshot_dir):
|
||||
os.makedirs(screenshot_dir)
|
||||
|
||||
# 生成文件名
|
||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"chat_result_{timestamp}.jpg"
|
||||
save_path = os.path.join(screenshot_dir, filename)
|
||||
|
||||
try:
|
||||
d.screenshot(save_path)
|
||||
logger.info(f"✅ 原始截图已保存: {save_path}")
|
||||
|
||||
# 6. 分析截图并标记头像
|
||||
logger.info("步骤 6: 自动标记头像...")
|
||||
analyzed_filename = f"chat_result_{timestamp}_analyzed.jpg"
|
||||
analyzed_path = os.path.join(screenshot_dir, analyzed_filename)
|
||||
|
||||
analyze_chat_image(save_path, analyzed_path)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 截图或分析失败: {e}")
|
||||
|
||||
else:
|
||||
logger.error("❌ 未能定位到搜索结果,跳过截图。")
|
||||
|
||||
logger.info("测试结束。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user