Autojs 利用OpenCV识别棋子之天天象棋你马没了

本例子通过代码像你介绍利用OpenCV实现霍尔找圆的方法定位棋子位置
通过autojs脚本实现自动点击棋子 开源地址

https://github.com/Liberations/TtxqYourHorseIsGone/blob/master/main.js
AutoXJs
https://github.com/kkevsekk1/AutoX/releases
auto()
//安卓版本高于Android 9
if (device.sdkInt > 28) {//等待截屏权限申请并同意threads.start(function () {packageName('com.android.systemui').text('立即开始').waitFor()text('立即开始').click()});
}
//申请截屏权限
if (!requestScreenCapture()) {toast("请求截图失败")exit()
}
http.__okhttp__.setTimeout(40 * 1000)//低版本需要加这个
// 创建空的棋盘
// 创建空的棋盘
function createEmptyChessboard() {var temp = [];// 创建一个大小为 10x9 的二维数组,并用空字符串初始化for (var i = 0; i < 10; i++) {temp[i] = Array(9).fill("O");}return temp;
}// 打印二维数组
function printChessboard(chessboard) {for (var i = 0; i < chessboard.length; i++) {var row = chessboard[i].join(" ");log(row);}
}//复制一份新的数组
function copyArray(array) {var newArray = [];for (var i = 0; i < array.length; i++) {var innerArray = array[i];var newInnerArray = innerArray.slice(); // 复制内部数组newArray.push(newInnerArray);}return newArray;
}//将[row,col] 转成字母
function coordinatesToAlgebraic(coordinates) {var row = coordinates[0]var col = coordinates[1]if (isRed) {row = 9 - row;col = col + 'a'.charCodeAt(0);return String.fromCharCode(col) + row.toString();} else {col = 8 - col + 'a'.charCodeAt(0);return String.fromCharCode(col) + row.toString();}}//将字母转成 [row,col]
function algebraicToCoordinates(algebraic) {var col = algebraic.charCodeAt(0) - 'a'.charCodeAt(0);var row = 9 - parseInt(algebraic.substring(1));if (isRed) {//b9 c7 (0,1) (2,2)return [row, col];} else {//b9 c7  (9,7) (7,6)row = 9 - rowcol = 8 - colreturn [row, col];}
}//二维数组旋转180度
function rotateArray180(array) {var rotated = [];for (var i = array.length - 1; i >= 0; i--) {var row = array[i];var rotatedRow = row.slice().reverse();rotated.push(rotatedRow);}return rotated;
}//大小写翻转
function transformString(str) {let transformedString = "";for (let i = 0; i < str.length; i++) {let char = str.charAt(i);if (char === char.toUpperCase()) {transformedString += char.toLowerCase();} else {transformedString += char.toUpperCase();}}return transformedString;
}//释放图片资源
function releaseSouce() {// if (img != null) {//     img.recycle()//     img = null// }if (board_img != null) {board_img.recycle()img = null}
}//通过row col去点击相应的坐标
function clickChess(row, col) {var clickStartX = (2 * col + 1) * chess_piece_radius + boardLeft;var clickStartY = (2 * row + 1) * chess_piece_radius + boardTop;//log("点击位置clickStartX " + clickStartX + " clickStartY " + clickStartY)click(clickStartX, clickStartY);
}//所有的操作都用这个控制
//初始的象棋布局
var defaultChessBoard = [['r', 'n', 'b', 'a', 'k', 'a', 'b', 'n', 'r'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'c', 'O', 'O', 'O', 'O', 'O', 'c', 'O'],['p', 'O', 'p', 'O', 'p', 'O', 'p', 'O', 'p'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['P', 'O', 'P', 'O', 'P', 'O', 'P', 'O', 'P'],['O', 'C', 'O', 'O', 'O', 'O', 'O', 'C', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['R', 'N', 'B', 'A', 'K', 'A', 'B', 'N', 'R']
]//初始化圆的位置
var defaultCircleBoard = [['B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'B', 'O', 'O', 'O', 'O', 'O', 'B', 'O'],['B', 'O', 'B', 'O', 'B', 'O', 'B', 'O', 'B'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['R', 'O', 'R', 'O', 'R', 'O', 'R', 'O', 'R'],['O', 'R', 'O', 'O', 'O', 'O', 'O', 'R', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R']
]var defaultBlackCircleBoard = [['R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'R', 'O', 'O', 'O', 'O', 'O', 'R', 'O'],['R', 'O', 'R', 'O', 'R', 'O', 'R', 'O', 'R'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['B', 'O', 'B', 'O', 'B', 'O', 'B', 'O', 'B'],['O', 'B', 'O', 'O', 'O', 'O', 'O', 'B', 'O'],['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],['B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B']
]var isRed = null
var isSart = true
var isMyStep = false //标志是否我方下棋
var stepCount = 0 //累计步数
var fen = ""
var img = null //每次的截图
var board_img = null //裁剪出来的棋盘
var storage = storages.create("chessStorage");
var boardWidth = 1010 //棋 盘宽度
var boardHeight = 1140  //棋盘高度
var boardTop = 626 //棋盘上边距
var boardLeft = 34 //棋盘左边距
var speekOn = false //棋盘左边距
var chess_piece_radius = 0 //棋子半径
var chess_piece_width = 0 //棋子宽度
var moves = [] //当前移动的fen码
var chessBoard = null
var circleBoard = []
var intervalId = 0
var 开始 = images.read("开始.png")
var 关闭 = images.read("关闭.png")
var 确定 = images.read("确定.png")
var 叉叉 = images.read("叉叉.jpg")
var 对战助手 = images.read("对战助手.jpg")
var 确定退出 = images.read("确定退出.jpg")//删除截图
var imgDir = "img";
files.removeDir(imgDir)
files.create(imgDir + "/")function main() {initStart()isSart = truelog('开始新的对局')while (isSart) {try {sleep(2000)findChess()} catch (e) {log("发生异常" + e)}//isSart = false}}function initStart() {chessBoard = copyArray(defaultChessBoard)circleBoard = copyArray(defaultCircleBoard)isRed = nullisSart = trueisMyStep = false //标志是否我方下棋stepCount = 0 //累计步数fen = ""moves = []lastMove = ""if (intervalId != 0) {clearInterval(intervalId)intervalId = 0}
}function findChess() {img = images.captureScreen()if (!img) {toastLog('截图失败')return}var pos4 = images.findImage(img, 对战助手)if (pos4) {speek("发现对战助手按钮")click(pos4.x, pos4.y)//重新初始化initStart()return}//log("开始findChess")var pos = images.findImage(img, 关闭)if (pos) {speek("发现关闭对局结束")click(pos.x, pos.y)sleep(1000)click(device.width / 2, device.height / 2)//重新初始化initStart()return}var pos1 = images.findImage(img, 开始)if (pos1) {speek("发现开始按钮")click(pos1.x, pos1.y)//重新初始化initStart()return}var pos2 = images.findImage(img, 确定)if (pos2) {speek("发现确定按钮")click(pos2.x, pos2.y)//重新初始化initStart()return}var pos3 = images.findImage(img, 叉叉)if (pos3) {speek("发现叉叉按钮")click(pos3.x, pos3.y)//重新初始化initStart()return}chess_piece_width = boardWidth / 9chess_piece_radius = chess_piece_width / 2board_img = images.clip(img, boardLeft, boardTop, boardWidth, boardHeight)if (isRed == null) {var col = 4var row = 0var centerX = (2 * col + 1) * chess_piece_radius;var centerY = (2 * row + 1) * chess_piece_radius;var left = centerX - chess_piece_radiusvar top = centerY - chess_piece_radiuslet cutImg = images.clip(board_img, left, top, chess_piece_radius * 2, chess_piece_radius * 2)let containRed = images.findColor(cutImg, "#953c28", {threshold: 4})let containBlack = images.findColor(cutImg, "#3a3938", {threshold: 4})if (containRed) {circleBoard = nullcircleBoard = copyArray(defaultBlackCircleBoard)isRed = false} else if (containBlack) {circleBoard = nullcircleBoard = copyArray(defaultCircleBoard)isRed = true} else {log("没找到帅啥也没有")}speek("我方为" + (isRed ? "红方" : "黑方"))}var tempchessboard = createEmptyChessboard()var count = 0;// 找圆min_radius = chess_piece_width / 4max_radius = chess_piece_width / 3// 灰度化图片let gray = images.grayscale(board_img);// 找圆let arr = images.findCircles(gray, {dp: 1,minDst: 30,param1: 50,param2: 30,minRadius: parseInt(min_radius),maxRadius: parseInt(max_radius),});gray.recycle()for (let i = 0; i < arr.length; i++) {let circle = arr[i];let x = circle.x; // 圆心 x 坐标let y = circle.y; // 圆心 y 坐标let radius = circle.radius; // 圆的半径// 裁剪图像let row = parseInt(y / chess_piece_width)let col = parseInt(x / chess_piece_width)var left = x - radius;var top = y - radius;let cutImg = images.clip(board_img, left, top, radius * 2, radius * 2)let containRed = images.findColor(cutImg, "#953c28", {threshold: 4})let containBlack = images.findColor(cutImg, "#3a3938", {threshold: 4})if (containRed) {count++tempchessboard[row][col] = "R"} else if (containBlack) {count++tempchessboard[row][col] = "B"} else {tempchessboard[row][col] = "O"}cutImg.recycle()}//log('总共找到圆' + count)if (stepCount == 0 && count != 32) {log(arr.length + '数量不够' + count)initStart()printChessboard(tempchessboard)releaseSouce()return}if (stepCount < 999) {var pao1start = tempchessboard[7][1]var pao1Mid = tempchessboard[2][1]var pao1end = tempchessboard[0][1]var pao2start = tempchessboard[7][7]var pao2Mid = tempchessboard[2][7]var pao2end = tempchessboard[0][7]if (pao1start != "O" && pao1end != "O" && pao1Mid != "O") {speek("发现炮1")clickChess(7, 1)sleep(50)clickChess(0, 1)speek("你马没了")sleep(2000)stepCount++return}if (pao2start != "O" && pao2end != "O" && pao2Mid != "O") {speek("发现炮2")clickChess(7, 7)sleep(50)clickChess(0, 7)speek("你马没了")sleep(2000)stepCount++return}return}
}function speek(str) {if (true) {TTS.speak(str, TextToSpeech.QUEUE_ADD, null);//自定义语音合成内容} else {log(str)}}//调用系统语音合成
importPackage(android.speech.tts);
importClass(java.util.Locale);
if (TTS != undefined) { TTS.stop(); TTS.shutdown(); }
var TTS = new TextToSpeech(context, function (status) {if (status != TextToSpeech.SUCCESS) {toast("初始化TTS失败");}var r = TTS.setLanguage(Locale.CHINA);if (r < 0) {toast("不支持该语言: " + r);exit();}log("TTS初始化成功");
});
sleep(500);
speek("开始辅助")
// 创建悬浮窗
var window = floaty.window(<vertical><text text="在棋力评测或者积分场快速按钮界面点击开始运行,需要辅助功能模拟点击" textColor="red" w="auto" ></text><button id="toggleButton" text="展开" w="auto" h="auto" /><vertical id="menu" visibility="gone"><button id="startButton" text="开始" w="auto" h="auto" /><button id="stopButton" text="结束" w="auto" h="auto" /></vertical></vertical>
);
var isOpen = false
// 设置悬浮窗位置
window.setPosition(0, device.height / 20);log("我的引擎" + engines.myEngine())
engines.all().forEach(item => {if (item.id != engines.myEngine().id) {log("停止引擎" + item)item.forceStop()}})
function hideMenu() {isOpen = falsewindow.menu.setVisibility(8);window.toggleButton.setText("展开");
}
function expandOrHideMenu() {isOpen = !isOpenif (isOpen) {window.menu.setVisibility(0);window.toggleButton.setText("收起");} else {window.menu.setVisibility(8);window.toggleButton.setText("展开");}
}
// 切换按钮点击事件
window.toggleButton.click(() => {expandOrHideMenu()});// 开始按钮点击事件
window.startButton.click(() => {hideMenu()threads.start(function () {isSart = falsespeek("开始")main()});});// 结束按钮点击事件
window.stopButton.click(() => {isSart = falsethreads.shutDownAll()toastLog("已停止");hideMenu()
});//保持脚本运行
setInterval(() => { }, 1000);

主要函数利用autojs提供的 findCircles函数

images.findCircles(gray, options)
gray {Image} 灰度图片
options {Object} 选项包括:
region {Array} 找圆区域。是一个两个或四个元素的数组。(region[0], region[1])表示找圆区域的左上角;region[2]*region[3]表示找圆区域的宽高。如果只有region只有两个元素,则找圆区域为(region[0], region[1])到图片右下角。如果不指定region选项,则找圆区域为整张图片。
dp {number} dp是累加面与原始图像相比的分辨率的反比参数,dp=2时累计面分辨率是元素图像的一半,宽高都缩减为原来的一半,dp=1时,两者相同。默认为1。
minDst {number} minDist定义了两个圆心之间的最小距离。默认为图片高度的八分之一。
param1 {number} param1是Canny边缘检测的高阈值,低阈值被自动置为高阈值的一半。默认为100,范围为0-255。
param2 {number} param2是累加平面对是否是圆的判定阈值,默认为100。
minRadius {number} 定义了检测到的圆的半径的最小值,默认为0。
maxRadius {number} 定义了检测到的圆的半径的最大值,0为不限制最大值,默认为0。
return {Array}

在图片中寻找圆(做霍夫圆变换)。找到时返回找到的所有圆{x,y,radius}的数组,找不到时返回null。

一个寻找圆的例子:

// 请求截图
requestScreenCapture();
// 截图
let img = captureScreen();
// 灰度化图片
let gray = images.grayscale(img);
// 找圆
let arr = findCircles(gray, {dp: 1,minDst: 80,param1: 100,param2: 100,minRadius: 50,maxRadius: 80,
});
// 回收图片
gray.recycle();

具体看代码 可以在这个基础上实现手机版自动连线功能!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/117837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Plex踩坑——plex web无法找到媒体服务器

现象&#xff1a;之前安装过plex server&#xff0c;然后卸载了。再次重装后&#xff0c;plex web无法找到媒体服务器。 原因&#xff1a;卸载plex server时需要手动将plex的注册表删除&#xff1a;HKEY_CURRENT_USER\Software\Plex, Inc. 原文链接Uninstall Plex Media Serve…

wf-docker集群搭建(未完结)

系列文章目录 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、redis集群二、mysql集群三、nacos集群1. 环境要求2. 拉取镜像2.1. 拉取镜像方式配置集群2.2. 自定义nacos镜像配置集群 3 自定义…

C语言 sizeof 函数内部进行计算

直接看代码 #include <stdio.h> int main() {int i 2;int j;j sizeof(i i);printf("i %d, j %d", i ,j);return 0; }执行结果&#xff1a; 可以看到 i的值一直是没有变的&#xff0c; j 是int类型下 sizeof占用的大小为 4个字节&#xff0c;不是i的 22…

NewStarCTF2023week4-More Fast(GC回收)

打开链接&#xff0c;存在很多个类&#xff0c;很明显是php反序列化漏洞利用&#xff0c;需要构造pop链 &#xff0c; 关于pop链构造的详细步骤教学&#xff0c;请参考我之前的博客&#xff0c;真的讲得很详细也容易理解&#xff1a; http://t.csdnimg.cn/wMYNB 如果你是刚接…

代碼隨想錄算法訓練營|第四十五天|1049. 最后一块石头的重量 II、494. 目标和、474.一和零。刷题心得(c++)

目录 讀題 1049. 最后一块石头的重量 II 自己看到题目的第一想法 看完代码随想录之后的想法 494. 目标和 自己看到题目的第一想法 看完代码随想录之后的想法 474.一和零 自己看到题目的第一想法 看完代码随想录之后的想法 1049. 最后一块石头的重量 II - 實作 思路 …

宏电5G RedCap工业智能网关获首个中国移动5G物联网开放实验室5G及轻量化产品能力认证

10月21日&#xff0c;2023世界物联网博览会——中国移动物联网开发者大会暨物联网产业论坛在无锡圆满举行。宏电股份参与中国移动5G物联网开放实验室5G及轻量化产品能力认证成果授牌仪式&#xff0c;并获得认证证书。 此次认证主要对产品功能、产品性能、RedCap网络兼容性进行测…

sw型材利用父子关系找最新特征

利用父子关系可以找到设计树最新的编辑

复习mysql中的事务

一个事务的开始和结尾必须是 start transaction | commit; rollback 事务特性 1.原子性&#xff1a;多个操作打包成一个整体&#xff0c;要么全部执行&#xff0c;要么一个都不执行。 不过这里的“一个都不执行”并不是真正的全不执行&#xff0c;只是看起来与没执行一样。…

js中循环判断找到满足条件的单项后结束循环

当选择的所有项中&#xff0c;如果有一项不满足条件则返回false&#xff0c;让业务逻辑停止&#xff0c;一般都是使用forEach循环&#xff0c;但是forEach循环有个弊端就是return不能跳出循环&#xff0c;所以这时候就需要使用for循环中的break来跳出循环。 下面是代码示例&am…

redis持久化之AOF(Append Only File)

1 : AOF 是什么 以日志的形式来记录每个写操作&#xff08;增量保存&#xff09;&#xff0c;将redis执行过的所有写指令记录下来&#xff08;读操作不记 录&#xff09;&#xff0c;只允追加文件但不可改写文件&#xff0c;redis启动之初会读取该文件重新构造数据&#xff0c;…

hadoop集群搭建

hadoop有三种部署方式 1、Local (Standalone) Mode&#xff08;单机模式&#xff09; 数据存储在本地 2、Pseudo-Distributed Mode&#xff08;伪集群模式&#xff09; 数据存储在HDFS 3、Fully-Distributed Mode&#xff08;集群模式&#xff09; 集群部署&#xff0c;数据存储…

2.2.3 三层交换机实现VLAN之间的通信

实验2.2.3 三层交换机实现VLAN之间的通信 一、任务描述二、任务分析三、具体要求四、实验拓扑五、任务实施1.划分SW2A的VLAN&#xff0c;并分配接口。2.划分SW3A的VLAN&#xff0c;配置每个VLAN接口的IP地址。3.设计计算机的网关&#xff0c;实现不同VLAN之间和不同网络之间的通…

探索光模块的MSA多源协议

在当今高度互联的世界中&#xff0c;光模块作为网络设备的重要部分&#xff0c;其性能和质量直接影响到整个网络系统的运行。其中光模块由于其灵活性和高效性&#xff0c;已经成为数据中心和云计算领域的主要选择。本文易天光通信将深入探讨光模块的MSA协议&#xff0c;揭示其重…

《算法通关村——双指针妙用》

《算法通关村——双指针妙用》 删除元素 描述 给你一个数组 nums 和一个值 val&#xff0c;你需要原地移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。要求&#xff1a;不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并原地修改输入数组…

Pytorch公共数据集、tensorboard、DataLoader使用

本文将主要介绍torchvision.datasets的使用&#xff0c;并以CIFAR-10为例进行介绍&#xff0c;对可视化工具tensorboard进行介绍&#xff0c;包括安装&#xff0c;使用&#xff0c;可视化过程等&#xff0c;最后介绍DataLoader的使用。希望对你有帮助 Pytorch公共数据集 torc…

深度学习系列52:多目标跟踪

1. 评价指标 1&#xff09;FP&#xff1a;False Positive&#xff0c;即真实情况中没有&#xff0c;但跟踪算法误检出有目标存在。 2&#xff09;FN&#xff1a;False Negative&#xff0c;即真实情况中有&#xff0c;但跟踪算法漏检了。 3&#xff09;IDS&#xff1a;ID Sw…

IntelliJ IDEA 2023.2正式发布,新UI和Profiler转正

你好&#xff0c;我是YourBatman&#xff1a;做爱做之事❣交配交之人。 &#x1f4da;前言 北京时间2023年7月26日&#xff0c;IntelliJ IDEA 2023.2正式发布。老规矩&#xff0c;吃肉之前&#xff0c;可以先把这几碗汤干了&#xff0c;更有助于消化&#xff08;每篇都很顶哦…

mac苹果电脑使用耳机听不到声音

大家在使用耳机收听音乐时候&#xff1f;是否经常遇到声音和音频播放问题的情况。这里小编为大家带来了三种不同的方法&#xff0c;帮助大家解决耳机在macOS系统电脑上怎么听不到任何声音的教程。如果大家对这篇文章感兴趣&#xff0c;那就来看下面的具体步骤吧。 方法一、检查…

【机器学习合集】优化目标与评估指标合集 ->(个人学习记录笔记)

文章目录 优化目标与评估指标1. 优化目标1.1 两类基础任务与常见优化目标1.2 分类任务损失0-1损失交叉熵损失与KL散度softmax损失的理解与改进Hinge损失 1.3 回归任务损失L1/L2距离L1/L2距离的改进 Huber loss 2. 评测指标2.1 分类任务中评测指标准确率(查准率)/召回率(查全率)…

入门人工智能 —— 学习数据持久化、使用 Python 将数据保存到mysql(7)

入门人工智能 —— 学习数据持久化、使用 Python 将数据保存到mysql 什么是数据持久化&#xff1f;使用 Python 进行数据持久化步骤 1: 安装 MySQL步骤 2: 安装必要的 Python 库步骤 3: 连接到 MySQL 数据库步骤 4: 创建数据表步骤 5: 插入数据步骤 6: 查询数据步骤 7: 关闭连接…