4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Selenium/AppiumAdvent Calendar 2019

Day 13

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

Last updated at Posted at 2019-12-12

はじめに

こちらの記事は「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率イマイチだったので特徴点抽出つかって識別しました。

4
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?