Auto.pro 找图适配分辨率(循环找图优化版)

上个版本的适配虽然可以解决问题,但是细节操作过多,大量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()
        })
    )
}

你可能感兴趣的:(Auto.pro 找图适配分辨率(循环找图优化版))