Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?

More than 1 year has passed since last update.

@kazurasaka

【Appium】findElementByImageの実装を追いかけてみた

はじめに

こちらの記事は「Selenium/Appium Advent Calendar 2019」13日分の投稿です。
@kazurasaka がお届けします。

あらすじ

それは数ヶ月前のことだった。転職した先で与えられたのはQAエンジニアの肩書。自社アプリのテスト自動化研究の始まりが訪れ、QA界隈に突如飛び込んだ私は色々と勉強することになる。

課せられた制約は2個
1. 実際に動いているsourceをテストのために変更することはできない
2. 複数タイトルに流用できるテストを構築しなくてはならない

IDで検索する方法は使えない……そんななか一つの記事が目に留まる。

画像による要素検索
http://www.selenium.jp/translation/huaxiangniyoruyaosujiansuopart1

こ、これだーーーー!!

本題

では見ていきましょう。

おもむろにgithubでappium縛りで「findElementByImage」と検索をかけます。
https://github.com/search?q=org%3Aappium+findElementByImage&type=Code

なんとなく関係ありそうなコードってjavaかよってなりながら読みます(javaまともにやったことないからフィーリングで切り抜けます)
https://github.com/appium/java-client/blob/14786471f4abb85a01dfe79879d7a617cd2fc669/src/main/java/io/appium/java_client/FindsByImage.java

default T findElementByImage(String b64Template) {
    return findElement(MobileSelector.IMAGE.toString(), b64Template);
}

次は findElement ね。ふむふむ。

これは探すとjsの実装を見つけられました。
https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/commands/find.js

commands.findElement = async function findElement (strategy, selector) {
  if (strategy === IMAGE_STRATEGY) {
    return await this.findByImage(selector, {multiple: false});
  } else if (strategy === CUSTOM_STRATEGY) {
    return await this.findByCustom(selector, false);
  }

  return await this.findElOrElsWithProcessing(strategy, selector, false);
};

custom も気になりましたが findByImage のほうがそれっぽいので追いかけます。

長いので一部抜粋
https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/commands/find.js#L204

const comparedImage = await this.compareImages(MATCH_TEMPLATE_MODE, b64Screenshot, b64Template, {threshold, visualize});

なんでこの行に目をつけたかって?引数の内容からです。

  • screenshot
  • template
  • threshold

がありますね?

  • screenshot:ベースの画像。探す対象。
  • template:テンプレート画像。この画像をscreenshotから探す。
  • threshold:閾値

です。
ここらへんは読む前にopenCVの画像認識を触っていたのでなんとなくわかりました。

次、 comparedImage を探します。
https://github.com/appium/appium-base-driver/blob/5b12eebcf011cf7676a2987b646a6394ddafb639/lib/basedriver/commands/images.js#L34

case MATCH_TEMPLATE_MODE.toLowerCase():
      // firstImage/img1 is the full image and secondImage/img2 is the partial one
      result = await imageUtil.getImageOccurrence(img1, img2, options);
      break;

TEMPLATE_MODEが引数なのでこの行ですね。
getImageOccurrence を探します。

const matched = await fullImg.matchTemplateAsync(partialImg, cv.TM_CCOEFF_NORMED);

たどり着いたーーーー!ここの実装が肝!なぜなら matchTemplate って openCV のやつだから。
このまま matchTemplateAsync も辿ってみるのもありですが、それは opencv4node.js さんの領分なので今回はここまでです。

ざっと読んでみたところ、 matchTemplate つまりはテンプレートマッチングで対象から検索していますね。なるほど。

なるほど?

オチ

appium + webdriverio + mocha でやってるんですけどfindElementByImageがwebdriverioになかったね!!!!
普通にopencv4node.js直接使って構築しましたとさ。

更に小ネタ

テンプレートマッチングだとやりたい画像ではmatch率イマイチだったので特徴点抽出つかって識別しました。

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What is going on with this article?