

发布于 2025-11-11 17:26973浏览在屏幕上(或指定区域内)查找该图片的所有匹配位置,并返回去重后的中心坐标列表。
import xbot
from xbot import print, sleep
import os
import cv2
import numpy as np
from PIL import Image
from sklearn.cluster import DBSCAN
import pyautogui # 显式导入,避免之前的隐式依赖问题
def find_image_by_path(template_path, region=None, threshold=0.8, cluster_eps=20):
"""
通过手动传入的模板图片路径,在屏幕中查找匹配位置
Args:
template_path (str): 模板图片的完整路径或相对路径
region (tuple, optional): 查找区域,格式为 (x1, y1, x2, y2),默认为整个屏幕
threshold (float, optional): 模板匹配阈值,范围0-1,值越高匹配越严格,默认为0.8
cluster_eps (int, optional): 位置聚类距离,相近的点会被合并,默认为20像素
Returns:
list: 匹配位置的中心坐标列表,格式为 [(x1, y1), (x2, y2), ...]
"""
try:
# 检查传入的图片路径是否存在
if not os.path.exists(template_path):
raise FileNotFoundError(f"模板图片不存在: {template_path}")
# 读取模板图片并转换格式
pil_image = Image.open(template_path)
template = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
if template is None or template.size == 0:
raise ValueError(f"无法读取图片: {template_path}")
# 捕获屏幕并转换格式
screen = pyautogui.screenshot()
screen = cv2.cvtColor(np.array(screen), cv2.COLOR_RGB2BGR)
# 转换为灰度图以提高匹配效率
screen_gray = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY)
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
# 获取模板尺寸(用于计算中心坐标)
h, w = template_gray.shape
# 执行模板匹配
result = cv2.matchTemplate(screen_gray, template_gray, cv2.TM_CCOEFF_NORMED)
# 提取匹配度超过阈值的位置
locations = np.where(result >= threshold)
positions = []
# 计算每个匹配位置的中心坐标,并过滤区域
for pt in zip(*locations[::-1]):
center_x = pt[0] + w // 2 # 左上角x + 模板宽的一半 = 中心x
center_y = pt[1] + h // 2 # 左上角y + 模板高的一半 = 中心y
# 检查是否在指定区域内
if region is not None:
x1, y1, x2, y2 = region
if center_x >= x1 and center_x <= x2 and center_y >= y1 and center_y <= y2:
positions.append((center_x, center_y))
else:
positions.append((center_x, center_y))
# 对相近位置聚类去重(避免同一目标被多次匹配)
if positions:
positions_array = np.array(positions)
clustering = DBSCAN(eps=cluster_eps, min_samples=1).fit(positions_array)
labels = clustering.labels_
unique_labels = set(labels)
clustered_positions = []
for label in unique_labels:
cluster_points = positions_array[labels == label]
# 取聚类中心作为最终坐标
center_x = int(np.mean(cluster_points[:, 0]))
center_y = int(np.mean(cluster_points[:, 1]))
clustered_positions.append((center_x, center_y))
return clustered_positions
else:
print(f"未找到与模板图片匹配的位置: {template_path}")
return []
except FileNotFoundError as e:
print(f"文件错误: {str(e)}")
return []
except Exception as e:
print(f"查找图片时出错: {str(e)}")
return []# 查找桌面上的"test.png"图片,在整个屏幕范围内匹配
matches = find_image_by_path(r"C:\Users\user\Desktop\test.png")
print("匹配位置:", matches)
# 在指定区域(x1=100, y1=100, x2=500, y2=500)内查找
matches = find_image_by_path("relative/path/to/image.jpg", region=(100, 100, 500, 500), threshold=0.85)这段代码的主要作用是在屏幕上自动查找并点击所有与指定图片匹配的区域,同时避免重复点击距离过近的区域,实现批量自动点击的功能。
import pyautogui
import time
from PIL import Image
from math import sqrt
def get_image_dimensions(image_path):
with Image.open(image_path) as img:
return img.size
def is_close_to_existing_positions(new_position, existing_positions, min_distance):
for pos in existing_positions:
distance = sqrt((new_position.x - pos.x) ** 2 + (new_position.y - pos.y) ** 2)
# print(f"Distance between {new_position} and {pos}: {distance:.2f}")
if distance <= min_distance:
return True
return False
def click_all_images_on_screen(image_path):
# 等待几秒让操作者有时间切换窗口等
time.sleep(3)
try:
# 在屏幕上寻找所有匹配的图片
locations = list(pyautogui.locateAllOnScreen(image_path, confidence=0.85))
# 以图像的短边作为阈值
min_distance=0
width, height = get_image_dimensions(image_path)
if width>height:
min_distance =round(height,2)
else:
min_distance =round(width,2)
print(f"阈值是{min_distance}")
# 按照 x 和 y 坐标分组
locations.sort(key=lambda loc: (loc.left, loc.top))
locations = list(locations)
# print(locations)
n=0
clicked_positions = []
for location in locations:
center = pyautogui.center(location)
# print(f"Found location: {location}, center: {center}")
is_clicked=is_close_to_existing_positions(center, clicked_positions, min_distance)
# print(is_clicked)
# 检查当前位置是否已经点击过
if not is_clicked:
time.sleep(2)
pyautogui.click(center)
print(f"点击了位置: {center}")
clicked_positions.append(center)
n+=1
print(f"点击了{n}个位置")
except Exception as e:
print(f"未在屏幕上找到任何匹配的图片,报错信息是{e}")
file_path = r"D:\desktop\dian.png"
# 调用函数
click_all_images_on_screen(file_path)
在一张大图里找到与小图相似的部分,然后告诉你这些相似部分的中心位置在哪里,可用于图像识别、自动化操作中定位目标等场景。
https://www.bilibili.com/video/BV1JV4y1R7Em/
pip install opencv-python# 使用提醒:
# 1. xbot包提供软件自动化、数据表格、Excel、日志、AI等功能
# 2. package包提供访问当前应用数据的功能,如获取元素、访问全局变量、获取资源文件等功能
# 3. 当此模块作为流程独立运行时执行main函数
# 4. 可视化流程中可以通过"调用模块"的指令使用此模块
import xbot
from xbot import print, sleep
from .import package
from .package import variables as glv
def main(args):
pass
from pathlib import Path
import numpy
import cv2
class Image:
def __init__(self, image):
self.image = cv2.imread(image, cv2.IMREAD_UNCHANGED)
@property
def width(self):
return self.image.shape[1]
@property
def height(self):
return self.image.shape[0]
class MatchImg(object):
def __init__(self, source, template, threshod=0.95):
"""
匹配一个图片,是否是另一个图片的局部图。source是大图,template是小图。即判断小图是否是大图的一部分。
:param source:
:param template:
:param threshod: 匹配程度,值越大,匹配程度要求就越高,最好不要太小
"""
self.source_img = source
self.template_img = template
self.threshod = threshod
def match_template(self, method=cv2.TM_CCOEFF_NORMED):
"""
返回小图左上角的点,在大图中的坐标。
:param method:
:return: list[tuple(x,y),...]
"""
try:
result = cv2.matchTemplate(self.source_img.image, self.template_img.image, method)
locations = numpy.where(result >= self.threshod)
res = list(zip(locations[1], locations[0])) # 返回的是匹配到的template左上角那个坐标点在image中的位置,可能有多个值
return res
except cv2.error as e:
print(e)
def get_template_position(self):
"""
获取小图在大图中,左上角和右下角的坐标
:return: List[list[x,y,x,y],...]
"""
res = self.match_template()
new_pos = []
for r in res:
r = list(r)
r.append(r[0]+self.template_img.width)
r.append(r[1]+self.template_img.height)
new_pos.append(r)
return new_pos
def get_img_center(self):
"""
获取大图中,每个小图中心点所在的坐标
:return:
"""
pos = self.match_template()
points = []
for p in pos:
x, y = p[0]+int(self.template_img.width/2), p[1]+int(self.template_img.height/2)
points.append((x, y))
return points
def load_image_file(path):
path = Path(path)
if not path.exists():
print('not exist file')
try:
image = Image(str(path))
return image
except cv2.error as e:
print(e)
def 区域找图返回中心点(大图,小图,相识度):#相识度是小数哦
img1 = load_image_file(大图)
img2 = load_image_file(小图)
process = MatchImg(img1, img2, 相识度)#这里改相识度
points = process.get_img_center()
# print(process)
# print(points)
return list(points[0])
# 区域找图返回中心点("D:\\daa.png","C:\\xiao.png")