Files
Patrick-Ze 5445b4285c 修复recognizeTextAndClick函数偶发识别异常的问题 (#1036)
由于点击的坐标是根据OCR坐标计算出来的,如果click的参数x和y一个是整数,一个是浮点,会报错`Invalid argument specified for parameter 'arg1'`

需要取消catch才能看到报错,不然会被catch而当做找不到文字掩盖
2025-06-09 15:13:02 +08:00

262 lines
10 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 定义所有图标的图像识别对象,每个图片都有自己的识别区域
let ReturnRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Return.png"), 30, 30, 36, 36);
let ControlDevicesRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/ControlDevices.png"), 507, 197, 100, 27);
let RenderingPrecisionRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RenderingPrecision.png"), 507, 591, 99, 27);
let CompatibilityModeRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/CompatibilityMode.png"), 507, 979, 100, 28);
let ComfirmRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Comfirm.png"), 994, 741, 33, 33);
let TipRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Tip.png"), 749, 524, 58, 30);
// 定义名称和图片文件名的映射表
const IconMap = {
"派蒙": "Return.png",
"设置": "ControlDevices.png",
"渲染精度": "RenderingPrecision.png",
"兼容模式": "CompatibilityMode.png",
"确定": "Comfirm.png",
"设置生效": "Tip.png",
// 可以继续添加更多食材的映射
};
// 定义替换映射表
const replacementMap = {
"监": "盐",
"卵": "卯"
};
// 定义一个函数用于识别图像
async function recognizeAndClick(recognitionObject, iconName, timeout = 5000) {
let startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
log.info(`尝试识别图标: ${iconName}`);
// 设置识别阈值和通道
recognitionObject.threshold = 0.85; // 设置识别阈值为 0.85
// recognitionObject.Use3Channels = true; // 使用三通道匹配可能会受原神Bloom自带饱和度影响
let imageResult = captureGameRegion().find(recognitionObject);
if (imageResult) {
// 计算中心坐标
let centerX = imageResult.x + imageResult.width / 2;
let centerY = imageResult.y + imageResult.height / 2;
if (centerX === 0 && centerY === 0) {
log.warn(`图标 ${iconName} 尚未出现?`);
await sleep(1000); // 避免过快log
continue; // 跳过本次循环,继续尝试
}
// log.info(`识别图标: x=${imageResult.x}, y=${imageResult.y}, width=${imageResult.width}, height=${imageResult.height}`);
// log.info(`成功识别图标: ${iconName},点击坐标: x=${centerX}, y=${centerY}`);
// await click(centerX, centerY); // 执行点击图片操作
await sleep(500); // 确保点击后有足够的时间等待
return true;
}
} catch (error) {
log.error(`识别图标时发生异常: ${error.message}`);
if (error.message.includes("PrevConverter is null")) {
log.error("识别对象的 PrevConverter 属性未正确初始化,请检查识别对象的定义");
}
break; // 如果发生异常,退出循环
}
await sleep(500); // 短暂延迟,避免过快循环
}
log.warn(`经过多次尝试,仍然无法识别图标: ${iconName}`);
return false;
}
// 定义一个函数用于识别文字并点击
async function recognizeTextAndClick(targetText, ocrRegion, timeout = 5000) {
let startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
// 尝试 OCR 识别
let resList = captureGameRegion().findMulti(RecognitionObject.ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height)); // 指定识别区域
// 遍历识别结果,检查是否找到目标文本
for (let res of resList) {
// 后处理:根据替换映射表检查和替换错误识别的字符
let correctedText = res.text;
for (let [wrongChar, correctChar] of Object.entries(replacementMap)) {
correctedText = correctedText.replace(new RegExp(wrongChar, 'g'), correctChar);
}
if (correctedText.includes(targetText)) {
// 如果找到目标文本,计算并点击文字的中心坐标
let centerX = Math.round(res.x + res.width / 2);
let centerY = Math.round(res.y + res.height / 2);
log.info(`通过 OCR 识别找到文字: ${targetText}`);
log.info(`中心坐标: x=${centerX}, y=${centerY}`);
await click(centerX, centerY); // 执行点击操作
await sleep(1000); // 确保点击后有足够的时间等待
return true;
}
}
} catch (error) {
log.error(`OCR 识别时发生异常: ${error.message}`);
}
await sleep(500); // 短暂延迟,避免过快循环
}
log.warn(`经过多次尝试,仍然无法识别文字: ${targetText}`);
return false;
}
(async function () {
setGameMetrics(1920, 1080, 1);
await genshin.returnMainUi();
Rendering = settings.Rendering || "0.6";
Quality = settings.Quality || "兼容模式"; // 获取或设置默认值
MotionBlur = settings.MotionBlur || false;
Bloom = settings.Bloom || false;
keyPress("Escape");
await sleep(1000);
// 定义一个函数用于等待识别
async function waitForRecognition(recognitionObject, iconName, timeout = 5000) {
let startTime = Date.now();
while (Date.now() - startTime < timeout) {
if (await recognizeAndClick(recognitionObject, iconName, timeout)) {
return true;
}
await sleep(500); // 短暂延迟,避免过快循环
}
log.warn(`经过多次尝试,仍然无法识别图标: ${iconName}`);
return false;
}
// 定义一个函数用于等待OCR识别
async function waitForTextRecognition(targetText, ocrRegion, timeout = 5000) {
let startTime = Date.now();
while (Date.now() - startTime < timeout) {
if (await recognizeTextAndClick(targetText, ocrRegion, timeout)) {
return true;
}
await sleep(500); // 短暂延迟,避免过快循环
}
log.warn(`经过多次尝试,仍然无法识别文字: ${targetText}`);
return false;
}
// 根据识别到的图标名称,执行相应的点击操作
if (await waitForRecognition(ReturnRo, "派蒙")) {
click(45, 820); // 识别到派蒙,点击
} else {
log.warn("无法识别派蒙图标,尝试继续执行后续步骤...");
}
if (await waitForRecognition(ControlDevicesRo, "设置")) {
click(165, 290); // 识别到设置,点击
} else {
log.warn("无法识别设置图标,尝试继续执行后续步骤...");
}
// 处理画质设置
if (await waitForRecognition(RenderingPrecisionRo, "图像")) {
// 根据 Quality 的值执行不同的操作
if (Quality === "兼容模式") {
moveMouseTo(1821, 1014);
await sleep(50);
leftButtonDown();
await sleep(400);
leftButtonUp();
await sleep(50);
// 兼容模式的逻辑
if (await waitForRecognition(CompatibilityModeRo, "兼容模式")) {
click(1770, 995); // 识别到兼容模式,点击
} else {
log.warn("无法识别兼容模式图标,尝试继续执行后续步骤...");
}
// 只有在兼容模式下才点击确定
if (await waitForRecognition(ComfirmRo, "确定")) {
click(994, 741); // 点击确定
await sleep(500);
} else {
log.warn("无法识别确定图标,尝试继续执行后续步骤...");
}
} else if (Quality === "中" || Quality === "高") {
// 中质量或高质量模式的逻辑
click(1625, 210);
await sleep(1000);
click(1625, Quality === "中" ? 360 : 405);
await sleep(500);
} else {
log.warn("未知的 图像画质: ", Quality);
}
} else {
log.warn("无法识别图像图标,尝试继续执行后续步骤...");
}
// 检查设置是否生效
if (await waitForRecognition(TipRo, "设置生效", 2000)) {
log.info("部分设置生效重启生效"); // 识别到设置生效,记录日志
click(1821, 139);
await sleep(50);
click(1821, 139);
await sleep(50);
moveMouseTo(1821, 139);
await sleep(50);
leftButtonDown();
await sleep(400);
leftButtonUp();
await sleep(50);
} else {
log.warn("未能识别 部分设置生效重启生效,可能需要进一步检查");
}
// 处理渲染精度
if (await waitForRecognition(RenderingPrecisionRo, "渲染精度")) {
click(1625, 465); // 点击帧率选项
await sleep(500);
click(1625, 615); // 点击60
await sleep(1000);
if (Rendering === "1.0") {
click(1625, 615); // 点击精度
await sleep(1000);
click(1625, 800); // 调整到1.0
await sleep(1000);
log.info("已切换至1.0渲染精度");
} else {
click(1625, 615); // 点击精度
await sleep(1000);
click(1625, 650); // 调整到默认0.6
await sleep(1000);
log.warn("采用默认0.6渲染精度");
}
} else {
log.warn("无法识别渲染精度图标,尝试继续执行后续步骤...");
}
// 处理额外设置
if (Quality !== "兼容模式" && (!MotionBlur || !Bloom)) {
moveMouseTo(1821, 1014);
await sleep(100);
leftButtonDown();
await sleep(400);
leftButtonUp();
await sleep(50);
if (await waitForRecognition(CompatibilityModeRo, "额外设置")) {
if (!MotionBlur) {
click(1625, 465);
await sleep(1000);
click(1625, 520);
await sleep(500);
log.info("已关闭动态模糊");
}
if (!Bloom) {
click(1625, 535);
await sleep(1000);
click(1625, 580);
await sleep(500);
log.info("已关闭Bloom");
}
} else {
log.warn("无法识别额外设置,尝试继续执行后续步骤...");
}
}
await sleep(500);
await genshin.returnMainUi();
})();