-
Notifications
You must be signed in to change notification settings - Fork 251
python opencv memory input
qiannian edited this page Jun 13, 2026
·
1 revision
使用 SetDisplayInput("mem:...") 把 Python 内存中的原始 BGR 像素作为 OpenCV 匹配输入源,不需要绑定窗口。
import ctypes
import json
import struct
from pathlib import Path
from win32com.client import Dispatch
def fill_rect(pixels, img_w, x1, y1, x2, y2, bgr):
# 按 BGR 顺序填充矩形区域
color = bytes(bgr)
for y in range(y1, y2):
index = (y * img_w + x1) * 3
for _ in range(x2 - x1):
pixels[index:index + 3] = color
index += 3
def draw_button(pixels, img_w, x, y, w, h):
# 画一个带纹理的小按钮,避免纯色模板误匹配
fill_rect(pixels, img_w, x, y, x + w, y + h, (45, 90, 220))
fill_rect(pixels, img_w, x + 3, y + 3, x + w - 3, y + h - 3, (70, 180, 70))
fill_rect(pixels, img_w, x + 9, y + 6, x + w - 9, y + 9, (245, 245, 245))
def save_bmp24(path, pixels, width, height):
# 把 BGR 像素保存成 24 位 BMP,供 CvLoadTemplate 加载
row_stride = ((width * 3 + 3) // 4) * 4
image_size = row_stride * height
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("wb") as file:
file.write(b"BM")
file.write(struct.pack("<IHHI", 54 + image_size, 0, 0, 54))
file.write(struct.pack("<IiiHHIIiiII", 40, width, height, 1, 24, 0, image_size, 0, 0, 0, 0))
padding = b"\0" * (row_stride - width * 3)
for y in range(height - 1, -1, -1):
start = y * width * 3
file.write(pixels[start:start + width * 3])
file.write(padding)
# 创建 op COM 对象
op = Dispatch("op.opsoft")
# 构造一张内存源图,格式是连续 BGR 像素
width, height = 160, 100
source_pixels = bytearray([32, 32, 32] * width * height)
# 构造模板像素,并贴到源图的指定位置
tpl_w, tpl_h = 36, 22
template_pixels = bytearray(tpl_w * tpl_h * 3)
draw_button(template_pixels, tpl_w, 0, 0, tpl_w, tpl_h)
draw_button(source_pixels, width, 58, 34, tpl_w, tpl_h)
# OpenCV 模板接口读取文件,这里临时生成一个模板 BMP
base_dir = Path(__file__).resolve().parent
template_file = base_dir / "assets" / "mem_button.bmp"
save_bmp24(template_file, template_pixels, tpl_w, tpl_h)
# 取得 Python 内存地址,SetDisplayInput 会立即复制这块 BGR 数据
source_buffer = (ctypes.c_ubyte * len(source_pixels)).from_buffer(source_pixels)
source_ptr = ctypes.addressof(source_buffer)
if op.SetDisplayInput(f"mem:{source_ptr},{width},{height},bgr") != 1:
raise RuntimeError("设置内存输入源失败")
try:
# 加载模板并在内存源图中匹配
op.CvLoadTemplate("mem_button", str(template_file))
ret, info = op.CvMatchTemplate(0, 0, width, height, "mem_button", 0.95, 0, 0, 5, 0)
print("匹配结果:", ret)
print(json.dumps(json.loads(info), ensure_ascii=False, indent=2))
finally:
# 清理模板并切回屏幕输入
op.CvRemoveTemplate("mem_button")
op.SetDisplayInput("screen")