最新推送

This commit is contained in:
琉璃月光
2026-03-10 13:58:21 +08:00
parent 032479f558
commit eb16eeada3
97 changed files with 16865 additions and 670 deletions

BIN
muban/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

69
muban/caijian.py Normal file
View File

@ -0,0 +1,69 @@
import os
import cv2
# =========================================================
# 配置
# =========================================================
SRC_DIR = "muban_image" # 原始模板目录
DST_DIR = "muban_image2" # 裁剪后保存目录
# 三个 ROIx, y, w, h
ROI_1 = (782, 614, 164, 128)
ROI_2 = (837, 791, 100, 99)
ROI_3 = (873, 736, 141, 110)
# =========================================================
# 裁剪函数
# =========================================================
def crop_and_save(img_path, save_dir):
img = cv2.imread(img_path)
if img is None:
print(f"[WARN] 读取失败: {img_path}")
return
h_img, w_img = img.shape[:2]
base = os.path.splitext(os.path.basename(img_path))[0]
roi_list = [ROI_1, ROI_2, ROI_3]
for idx, roi in enumerate(roi_list, start=1):
x, y, w, h = roi
# 边界保护
x1 = max(0, x)
y1 = max(0, y)
x2 = min(w_img, x + w)
y2 = min(h_img, y + h)
if x2 <= x1 or y2 <= y1:
print(f"[WARN] ROI_{idx} 超出图像范围: {img_path}")
continue
roi_img = img[y1:y2, x1:x2]
save_name = f"{base}_roi{idx}.png"
save_path = os.path.join(save_dir, save_name)
cv2.imwrite(save_path, roi_img)
print(f"[OK] 保存: {save_path}")
# =========================================================
# main
# =========================================================
if __name__ == "__main__":
if not os.path.isdir(SRC_DIR):
raise RuntimeError(f"源目录不存在: {SRC_DIR}")
os.makedirs(DST_DIR, exist_ok=True)
for fname in os.listdir(SRC_DIR):
if not fname.lower().endswith((".png", ".jpg", ".jpeg", ".bmp")):
continue
img_path = os.path.join(SRC_DIR, fname)
crop_and_save(img_path, DST_DIR)
print("\n[INFO] 所有图片裁剪完成")

46
muban/choose-roi.py Normal file
View File

@ -0,0 +1,46 @@
import cv2
import os
def select_and_output_roi(img_path, save=True, save_dir="roi_output"):
img = cv2.imread(img_path)
if img is None:
raise RuntimeError("无法读取图片")
# OpenCV 自带 ROI 选择工具
roi = cv2.selectROI(
windowName="Select ROI (ENTER or C to confirm, ESC to quit)",
img=img,
showCrosshair=True,
fromCenter=False
)
cv2.destroyAllWindows()
x, y, w, h = roi
print(f"[INFO] ROI = (x={x}, y={y}, w={w}, h={h})")
roi_img = img[y:y+h, x:x+w]
if save:
os.makedirs(save_dir, exist_ok=True)
save_path = os.path.join(save_dir, "roi.png")
cv2.imwrite(save_path, roi_img)
print(f"[INFO] ROI 图像已保存: {save_path}")
return roi, roi_img
# ----------------------------
# main 测试
# ----------------------------
if __name__ == "__main__":
IMAGE_PATH = "test2.png" # 换成你的图片
roi, roi_img = select_and_output_roi(
IMAGE_PATH,
save=True
)
cv2.imshow("ROI Result", roi_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

165
muban/main.py Normal file
View File

@ -0,0 +1,165 @@
import os
import cv2
import numpy as np
# =========================================================
# 全局配置
# =========================================================
TEMPLATE_DIR = "./muban_image1"
# 三个 ROIx, y, w, h
ROI_1 = (782, 614, 164, 128)
ROI_2 = (837, 791, 100, 99)
ROI_3 = (873, 736, 141, 110)
USE_GRAY = False
TM_METHOD = cv2.TM_CCOEFF_NORMED
SCORE_THRESH = 0.4
# =========================================================
# 模板加载
# =========================================================
def load_templates(template_dir):
templates = []
if not os.path.isdir(template_dir):
raise RuntimeError(f"模板目录不存在: {template_dir}")
for fname in os.listdir(template_dir):
if not fname.lower().endswith((".png", ".jpg", ".jpeg", ".bmp")):
continue
path = os.path.join(template_dir, fname)
img = cv2.imread(path)
if img is None:
continue
if USE_GRAY:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h, w = img.shape[:2]
name = os.path.splitext(fname)[0]
templates.append({
"name": name,
"img": img,
"h": h,
"w": w
})
print(f"[INFO] 已加载 {len(templates)} 个模板")
return templates
TEMPLATES = load_templates(TEMPLATE_DIR)
# =========================================================
# ROI 裁剪
# =========================================================
def crop_roi(img, roi):
x, y, w, h = roi
return img[y:y + h, x:x + w]
# =========================================================
# 单 ROI 模板匹配
# =========================================================
def match_one_roi(img, roi):
roi_img = crop_roi(img, roi)
if roi_img.size == 0:
return None, 0.0
if USE_GRAY:
roi_img = cv2.cvtColor(roi_img, cv2.COLOR_BGR2GRAY)
best_name = None
best_score = -1.0
for t in TEMPLATES:
if t["h"] > roi_img.shape[0] or t["w"] > roi_img.shape[1]:
continue
res = cv2.matchTemplate(roi_img, t["img"], TM_METHOD)
_, max_val, _, _ = cv2.minMaxLoc(res)
if max_val > best_score:
best_score = max_val
best_name = t["name"]
if best_score < SCORE_THRESH:
return None, best_score
return best_name, best_score
# =========================================================
# 核心逻辑ROI_1 → ROI_2 → ROI_3
# =========================================================
def match_image(img):
roi_list = [
("roi1", ROI_1),
("roi2", ROI_2),
("roi3", ROI_3),
]
for roi_name, roi in roi_list:
name, score = match_one_roi(img, roi)
if name is not None:
return {
"result": name,
"roi": roi_name,
"score": score
}
return {
"result": None,
"roi": None,
"score": 0.0
}
# =========================================================
# 可视化(只画命中的 ROI
# =========================================================
def draw_result(img, result):
vis = img.copy()
roi_map = {
"roi1": ROI_1,
"roi2": ROI_2,
"roi3": ROI_3
}
if result["roi"] not in roi_map:
return vis
x, y, w, h = roi_map[result["roi"]]
text = f'{result["result"]} {result["score"]:.2f}'
cv2.rectangle(vis, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(
vis, text, (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.7, (0, 255, 0), 2
)
return vis
# =========================================================
# main 测试
# =========================================================
if __name__ == "__main__":
img = cv2.imread("1.png")
if img is None:
raise RuntimeError("测试图片未找到")
result = match_image(img)
print("[RESULT]", result)
vis = draw_result(img, result)
cv2.imshow("template match", vis)
cv2.waitKey(0)
cv2.destroyAllWindows()