Airtest画像認識原理
11437 ワード
AirtestIDEは、ゲームやAppに適したプラットフォーム間UI自動化テストエディタです.自動化スクリプト録画、ワンタッチ再生、レポート表示、自動化テストプロセス を簡単に実現は画像認識に基づくAirtestフレームワークをサポートし、すべてのAndroidとWindowsゲーム に適用される.はUIコントロール検索に基づくPocoフレームワークをサポートし、Unity 3 d、Cocos 2 d、Android App に適用される.
一言でまとめると、PythonベースのUI自動化テストフレームワークAirtest(スクリーンショットでスクリプトを書く)とPoco(インタフェースUI要素でスクリプトを書く)の2つを発売し、提供したAirtestIDEで自動化テストスクリプトを迅速に作成することができます.
本稿では,Airtestにおける画像認識についてコード走読を行い,画像認識原理の理解を深めることに重点を置く.
1、仕事を準備して、ソースコードをダウンロードするhttps://github.com/AirtestProject/Airtest
2、私たちは最も簡単なtouch方法から着手して、つまりある入ってきた画像をクリックするために、ソースコードはapiにあります.pyの中
この関数がクリック操作を行うのは
posは画像マッチングで返される座標位置で、loop_に重点を置いています.findという関数
まず、携帯電話のスクリーンショットを取得し、スクリプトの入力画像と比較して一致する位置を取得します.
cv.pyでTemplateクラスのmatchを見つけたinメソッド
重要なのはself.cv_match(screen)
ここで入力された画像はズーム変化が必要であり,用例を書くときのスクリーンショットを変換して用例を走るときのスクリーンショットに変換し,マッチング成功率を向上させる.
ここでのマッチング方法は
cv.pyの
3、まず
aircv.find_具体的にはtemplate.py
ポイントは_get_template_result_matrix
ここでは、Airtestも自分ですごいアルゴリズムを研究していないので、直接使うOpenCVのテンプレートマッチング方法を見ることができます.
4、次に別の方法を見る
sift.py
フィーチャーポイントセットの見つけ方に重点を置きます
このsiftはどんなオブジェクトですか?
OpenCVの手法も用いられており、OpenCV 3であれば画像特徴点セットを探す手法が
cv2.xfeatures2d.SIFT_create(edgeThreshold=10).detectAndCompute()
5.まとめると、最終的にはOpenCVの2つの方法、テンプレートマッチングと特徴マッチングが用いられる
1.テンプレートマッチングcv 2.mathTemplate
どちらが優先的にマッチしたかは、直接結果に戻ります
6、まとめ画像認識、uiコントロールで位置決めできない場所に対して、画像認識を使って位置決めし、いくつかのカスタムコントロール、H 5、ウィジェット、ゲームに対して、サポートすることができます. は複数の端末をサポートしており、画像認識を使用するとandroidとiosを1セットのコードで互換性がありますよ.uiコントロールで位置決めするには互換性が必要です. 欠点:背景が透明なボタンまたはコントロールに対して、識別の難易度が 増加する
一言でまとめると、PythonベースのUI自動化テストフレームワークAirtest(スクリーンショットでスクリプトを書く)とPoco(インタフェースUI要素でスクリプトを書く)の2つを発売し、提供したAirtestIDEで自動化テストスクリプトを迅速に作成することができます.
本稿では,Airtestにおける画像認識についてコード走読を行い,画像認識原理の理解を深めることに重点を置く.
1、仕事を準備して、ソースコードをダウンロードするhttps://github.com/AirtestProject/Airtest
2、私たちは最も簡単なtouch方法から着手して、つまりある入ってきた画像をクリックするために、ソースコードはapiにあります.pyの中
@logwrap
def touch(v, times=1, **kwargs):
"""
Perform the touch action on the device screen
:param v: target to touch, either a Template instance or absolute coordinates (x, y)
:param times: how many touches to be performed
:param kwargs: platform specific `kwargs`, please refer to corresponding docs
:return: finial position to be clicked
:platforms: Android, Windows, iOS
"""
if isinstance(v, Template):
pos = loop_find(v, timeout=ST.FIND_TIMEOUT)
else:
try_log_screen()
pos = v
for _ in range(times):
G.DEVICE.touch(pos, **kwargs)
time.sleep(0.05)
delay_after_operation()
return pos
click = touch # click is alias of touch
この関数がクリック操作を行うのは
G.DEVICE.touch(pos, **kwargs)
です.posは画像マッチングで返される座標位置で、loop_に重点を置いています.findという関数
@logwrap
def loop_find(query, timeout=ST.FIND_TIMEOUT, threshold=None, interval=0.5, intervalfunc=None):
"""
Search for image template in the screen until timeout
Args:
query: image template to be found in screenshot
timeout: time interval how long to look for the image template
threshold: default is None
interval: sleep interval before next attempt to find the image template
intervalfunc: function that is executed after unsuccessful attempt to find the image template
Raises:
TargetNotFoundError: when image template is not found in screenshot
Returns:
TargetNotFoundError if image template not found, otherwise returns the position where the image template has
been found in screenshot
"""
G.LOGGING.info("Try finding:
%s", query)
start_time = time.time()
while True:
screen = G.DEVICE.snapshot(filename=None)
if screen is None:
G.LOGGING.warning("Screen is None, may be locked")
else:
if threshold:
query.threshold = threshold
match_pos = query.match_in(screen)
if match_pos:
try_log_screen(screen)
return match_pos
if intervalfunc is not None:
intervalfunc()
# raise, :
if (time.time() - start_time) > timeout:
try_log_screen(screen)
raise TargetNotFoundError('Picture %s not found in screen' % query)
else:
time.sleep(interval)
まず、携帯電話のスクリーンショットを取得し、スクリプトの入力画像と比較して一致する位置を取得します.
match_pos = query.match_in(screen)
cv.pyでTemplateクラスのmatchを見つけたinメソッド
def match_in(self, screen):
match_result = self._cv_match(screen)
G.LOGGING.debug("match result: %s", match_result)
if not match_result:
return None
focus_pos = TargetPos().getXY(match_result, self.target_pos)
return focus_pos
重要なのはself.cv_match(screen)
@logwrap
def _cv_match(self, screen):
# in case image file not exist in current directory:
image = self._imread()
image = self._resize_image(image, screen, ST.RESIZE_METHOD)
ret = None
for method in ST.CVSTRATEGY:
if method == "tpl":
ret = self._try_match(self._find_template, image, screen)
elif method == "sift":
ret = self._try_match(self._find_sift_in_predict_area, image, screen)
if not ret:
ret = self._try_match(self._find_sift, image, screen)
else:
G.LOGGING.warning("Undefined method in CV_STRATEGY: %s", method)
if ret:
break
return ret
ここで入力された画像はズーム変化が必要であり,用例を書くときのスクリーンショットを変換して用例を走るときのスクリーンショットに変換し,マッチング成功率を向上させる.
image = self._resize_image(image, screen, ST.RESIZE_METHOD)
ここでのマッチング方法は
ST.CVSTRATEGY , Setting.py ,
を巡回します CVSTRATEGY = ["tpl", "sift"]
, , 。
_find_sift_in_predict_area _find_sift,
cv.pyの
_find_template _find_sift
def _find_template(self, image, screen):
return aircv.find_template(screen, image, threshold=self.threshold, rgb=self.rgb)
def _find_sift(self, image, screen):
return aircv.find_sift(screen, image, threshold=self.threshold, rgb=self.rgb)
3、まず
aircv.find_具体的にはtemplate.py
def find_template(im_source, im_search, threshold=0.8, rgb=False):
""" : ."""
# :
check_source_larger_than_search(im_source, im_search)
# : res
res = _get_template_result_matrix(im_source, im_search)
# :
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
h, w = im_search.shape[:2]
# :
confidence = _get_confidence_from_matrix(im_source, im_search, max_loc, max_val, w, h, rgb)
# : + :
middle_point, rectangle = _get_target_rectangle(max_loc, w, h)
best_match = generate_result(middle_point, rectangle, confidence)
LOGGING.debug("threshold=%s, result=%s" % (threshold, best_match))
return best_match if confidence >= threshold else None
ポイントは_get_template_result_matrix
def _get_template_result_matrix(im_source, im_search):
""" ."""
# : cv2.matchTemplate( )
s_gray, i_gray = img_mat_rgb_2_gray(im_search), img_mat_rgb_2_gray(im_source)
return cv2.matchTemplate(i_gray, s_gray, cv2.TM_CCOEFF_NORMED)
ここでは、Airtestも自分ですごいアルゴリズムを研究していないので、直接使うOpenCVのテンプレートマッチング方法を見ることができます.
4、次に別の方法を見る
sift.py
def find_sift(im_source, im_search, threshold=0.8, rgb=True, good_ratio=FILTER_RATIO):
""" sift , ."""
# : :
if not check_image_valid(im_source, im_search):
return None
# : : good, pypts, kp_sch, kp_src
kp_sch, kp_src, good = _get_key_points(im_source, im_search, good_ratio)
# : (good), :
if len(good) == 0:
# 0, :
return None
elif len(good) == 1:
# 1, , :
return _handle_one_good_points(kp_src, good, threshold) if ONE_POINT_CONFI >= threshold else None
elif len(good) == 2:
# 2, , :
origin_result = _handle_two_good_points(im_source, im_search, kp_src, kp_sch, good)
if isinstance(origin_result, dict):
return origin_result if ONE_POINT_CONFI >= threshold else None
else:
middle_point, pypts, w_h_range = _handle_two_good_points(im_source, im_search, kp_src, kp_sch, good)
elif len(good) == 3:
# 3, , , :
origin_result = _handle_three_good_points(im_source, im_search, kp_src, kp_sch, good)
if isinstance(origin_result, dict):
return origin_result if ONE_POINT_CONFI >= threshold else None
else:
middle_point, pypts, w_h_range = _handle_three_good_points(im_source, im_search, kp_src, kp_sch, good)
else:
# >= 4 , , :
middle_point, pypts, w_h_range = _many_good_pts(im_source, im_search, kp_sch, kp_src, good)
# : , , :
# : 5 , 5 , raise.
_target_error_check(w_h_range)
# ,
x_min, x_max, y_min, y_max, w, h = w_h_range
target_img = im_source[y_min:y_max, x_min:x_max]
resize_img = cv2.resize(target_img, (w, h))
confidence = _cal_sift_confidence(im_search, resize_img, rgb=rgb)
best_match = generate_result(middle_point, pypts, confidence)
print("[aircv][sift] threshold=%s, result=%s" % (threshold, best_match))
return best_match if confidence >= threshold else None
フィーチャーポイントセットの見つけ方に重点を置きます
def _get_key_points(im_source, im_search, good_ratio):
""" , , ."""
# : sift
sift = _init_sift()
# : , : good, pypts, kp_sch, kp_src
kp_sch, des_sch = sift.detectAndCompute(im_search, None)
kp_src, des_src = sift.detectAndCompute(im_source, None)
# When apply knnmatch , make sure that number of features in both test and
# query image is greater than or equal to number of nearest neighbors in knn match.
if len(kp_sch) < 2 or len(kp_src) < 2:
raise NoSiftMatchPointError("Not enough feature points in input images !")
# ,k=2 2 :
matches = FLANN.knnMatch(des_sch, des_src, k=2)
good = []
# good , , ( )
for m, n in matches:
if m.distance < good_ratio * n.distance:
good.append(m)
# good ,( ) src
# : , ( )
good_diff, diff_good_point = [], [[]]
for m in good:
diff_point = [int(kp_src[m.trainIdx].pt[0]), int(kp_src[m.trainIdx].pt[1])]
if diff_point not in diff_good_point:
good_diff.append(m)
diff_good_point.append(diff_point)
good = good_diff
return kp_sch, kp_src, good
このsiftはどんなオブジェクトですか?
def _init_sift():
"""Make sure that there is SIFT module in OpenCV."""
if cv2.__version__.startswith("3."):
# OpenCV3.x, sift is in contrib module, you need to compile it seperately.
try:
sift = cv2.xfeatures2d.SIFT_create(edgeThreshold=10)
except:
print("to use SIFT, you should build contrib with opencv3.0")
raise NoSIFTModuleError("There is no SIFT module in your OpenCV environment !")
else:
# OpenCV2.x, just use it.
sift = cv2.SIFT(edgeThreshold=10)
return sift
OpenCVの手法も用いられており、OpenCV 3であれば画像特徴点セットを探す手法が
cv2.xfeatures2d.SIFT_create(edgeThreshold=10).detectAndCompute()
5.まとめると、最終的にはOpenCVの2つの方法、テンプレートマッチングと特徴マッチングが用いられる
1.テンプレートマッチングcv 2.mathTemplate
2. cv2.FlannBasedMatcher(index_params,search_params).knnMatch(des1,des2,k=2)
どちらが優先的にマッチしたかは、直接結果に戻ります
6、まとめ