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()
        })
    )
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,198评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,334评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,643评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,495评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,502评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,156评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,743评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,659评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,200评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,282评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,424评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,107评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,789评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,264评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,798评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,435评论 2 359