上个版本的适配虽然可以解决问题,但是细节操作过多,大量scale操作也会在循环时增加耗时,这里给出另一种解决方案。
上版本的思路是,分辨率大于设定值1280x720
时,将截图缩小;分辨率小于设定值时,将待查图片缩小;最后再将匹配坐标缩放成屏幕分辨率尺寸,思路比较绕。
这个版本的思路为,在循环找图前将待查图片缩放,截图不做改变。即1280x720
下整理出的图片,在1920x1080
设备上放大成1080/720
倍,在小于1280x720
设备上则缩小。
这样匹配得到的坐标直接就是设备分辨率下的,不需要再做一次坐标适配。坏处是放大待查图片导致了无中生有,匹配度会有略微下降,而且因为没有做设备的截图缩放,在高分辨率下匹配图片会更耗时,因此务必做好region
缓存。
这个版本的细节不多,根据思路应该很容易实现。不过还是放上我的代码,基于RxJS实现,忽略了width、scale等参数的设置过程。
// 缓存region
const cache = {}
// 获取截图,多个找图函数共享该cap$数据
const cap$ = interval(100).pipe(
exhaustMap(_ => {
sleep(30)
let t1 = new Date().getTime()
let cap = action.cap()
let t2 = new Date().getTime()
log('cap cost', t2 - t1)
return of(cap)
// return of(images.captureScreen())
}),
share()
)
/**
* 循环找图,找到后返回坐标
*/
function findImg (param={
path: '',
option: {},
useCache: false,
forEver: false,
eachTime: 100,
nextTime: null
}) {
// 待查图片路径
let path = param.path || ''
// 查询参数
let option = param.option || {}
// 设置是否使用缓存
const useCache = param.useCache || false
const cachePath = param.path + useCache
// 查1次或一直重复查询
const takeNum = param.forEver ? 99999 : 1
// 每次查询间隔
const eachTime = param.eachTime || 100
// 查到一次后,离下次查询的间隔
const nextTime = param.nextTime
// 待查图片
let template = images.read(path)
if (!template) {
return throwError('template path is null')
}
template = images.scale(template, r.scale, r.scale)
let queryOption = {...option}
queryOption.threshold = queryOption.threshold || 0.8
// 如果确认使用缓存,且缓存里已经设置有region的话,直接赋值
if (useCache && cache[cachePath]) {
queryOption.region = cache[cachePath]
} else if (queryOption.region) {
let region = queryOption.region
if (region[0] < 0) {
region[0] = 0
}
if (region[1] < 0) {
region[1] = 0
}
if (region.length == 4) {
let x = region[0] + region[2]
let y = region[1] + region[3]
if (x > width) {
region[2] = width - region[0]
}
if (y > height) {
region[3] = height - region[1]
}
}
queryOption.region = region
}
let pass$ = new BehaviorSubject(true).pipe(
switchMap(v => {
if (v) {
return of(v)
} else {
return timer(nextTime || 500).pipe(
mapTo(true),
startWith(false)
)
}
})
)
return cap$.pipe(
throttleTime(eachTime),
withLatestFrom(pass$),
filter(([img, pass]) => pass),
exhaustMap(([img, pass]) => {
return of(images.matchTemplate(img, template, queryOption).matches)
}),
filter(v => v && v.length > 0),
take(takeNum),
map(res => {
return res.map(p => {
return [
parseInt(p.point['x']),
parseInt(p.point['y'])
]
}).sort((a, b) => {
let absY = Math.abs(a[1] - b[1])
let absX = Math.abs(a[0] - b[0])
if (absY > 4 && a[1] > b[1]) {
return true
}
else if (absY < 4) {
return absX > 4 && a[0] > b[0]
} else {
return false
}
})
}),
tap(res => {
// 如果设置了使用缓存,但缓存内还不含有该路径
if (useCache && !cache[cachePath]) {
let scaleWidth = r.width
let scaleHeight = r.height
let x = Math.max(0, res[0][0] - 10)
let y = Math.max(0, res[0][1] - 10)
let w = template.width + 20
let h = template.height + 20
w = x + w >= scaleWidth ? scaleWidth - x : w
h = y + h >= scaleHeight ? scaleHeight - y : h
cache[cachePath] = [x, y, w, h]
queryOption.region = cache[cachePath]
}
// 如果设置了下次间隔
if (nextTime) {
pass$.next(false)
}
}),
finalize(() => {
// 循环找图结束后,释放待查图片资源
template.recycle()
pass$.complete()
})
)
}
网友评论