使用opencv计算一个滑块的水平坐标x的例子

56 阅读1分钟
import cv2
import numpy as np
import io
import base64
from PIL import Image
from snap_rpas.utils.logger import log


def find_slider_x(target_data, background_data, data_type='binary'):
    # 根据数据类型处理输入,支持二进制和 base64
    log.info(f"开始处理输入数据,数据类型: {data_type}")
    if data_type == 'base64':
        target_bytes = base64.b64decode(target_data.encode('utf-8'))
        background_bytes = base64.b64decode(background_data.encode('utf-8'))
        log.info("输入数据已从 base64 解码")
    else:
        target_bytes = target_data
        background_bytes = background_data

    # 将字节数据转换为 OpenCV 图像格式
    log.info("将字节数据转换为 OpenCV 图像格式")
    target = Image.open(io.BytesIO(target_bytes)).convert('L')
    background = Image.open(io.BytesIO(background_bytes)).convert('L')
    target = np.array(target)
    background = np.array(background)

    # 调整滑块大小,确保与背景图像中的比例匹配
    scales = [1.0, 0.9, 1.1]  # 尝试不同的缩放比例
    best_match = None
    best_val = -1
    best_loc = (0, 0)
    log.info(f"开始模板匹配,尝试不同的缩放比例: {scales}")

    for scale in scales:
        log.info(f"尝试缩放比例: {scale}")
        resized_target = cv2.resize(target, (int(target.shape[1] * scale), int(target.shape[0] * scale)))
        result = cv2.matchTemplate(background, resized_target, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
        log.info(f"当前缩放比例的匹配值: {max_val}")
        if max_val > best_val:
            best_val = max_val
            best_match = resized_target
            best_loc = max_loc
            log.info(f"找到更好的匹配,匹配值: {max_val}, 位置: {max_loc}")

    # 获取滑块位置的 x 坐标
    x = best_loc[0]
    log.info(f"滑块的 x 位置为: {x}")

    # 在匹配的位置上绘制矩形(用于调试)
    h, w = best_match.shape[:2]
    matched_image = cv2.cvtColor(background, cv2.COLOR_GRAY2BGR)
    cv2.rectangle(matched_image, best_loc, (best_loc[0] + w, best_loc[1] + h), (0, 0, 255), 2)

    # 保存匹配结果以便查看(用于调试)
    cv2.imwrite("matched_result.png", matched_image)
    log.info("匹配结果已保存为 matched_result.png")

    return x


# 示例用法
if __name__ == "__main__":
    with open('/Users/luzihang/Downloads/3滑块.png', 'rb') as f:
        target_bytes = f.read()

    with open('/Users/luzihang/Downloads/3背景图.png', 'rb') as f:
        background_bytes = f.read()

    try:
        x_position = find_slider_x(target_bytes, background_bytes, data_type='binary')
        print(f"滑块的 x 位置为: {x_position}")
    except FileNotFoundError as e:
        log.error(f"文件未找到: {e}")