def test_crop(): img = stbt.load_image("action-panel.png") cropped = stbt.crop(img, stbt.Region(x=1045, y=672, right=1081, bottom=691)) reference = stbt.load_image("action-panel-blue-button.png") assert numpy.array_equal(reference, cropped) # It's a view onto the same memory: assert cropped[0, 0, 0] == img[672, 1045, 0] assert img[672, 1045, 0] != 0 cropped[0, 0, 0] = 0 assert img[672, 1045, 0] == 0 assert img.filename == "action-panel.png" assert cropped.filename == img.filename # Region is clipped to the frame boundaries: assert numpy.array_equal( stbt.crop(img, stbt.Region(x=1045, y=672, right=1280, bottom=720)), stbt.crop(img, stbt.Region(x=1045, y=672, right=1281, bottom=721))) assert numpy.array_equal( stbt.crop(img, stbt.Region(x=0, y=0, right=10, bottom=10)), stbt.crop( img, stbt.Region(x=float("-inf"), y=float("-inf"), right=10, bottom=10))) # But a region entirely outside the frame is not allowed: with pytest.raises(TypeError): stbt.crop(img, None) with pytest.raises(ValueError): stbt.crop(img, stbt.Region(x=-10, y=-10, right=0, bottom=0))
def test_matching_greyscale_array_with_greyscale_frame(match_method): assert stbt.match(cv2.cvtColor(stbt.load_image("videotestsrc-redblue.png"), cv2.COLOR_BGR2GRAY), frame=cv2.cvtColor( stbt.load_image("videotestsrc-full-frame.png"), cv2.COLOR_BGR2GRAY), match_parameters=mp(match_method=match_method))
def test_load_image_with_unicode_filename(): print(sys.getfilesystemencoding()) shutil.copyfile(_find_file("Rothlisberger.png"), _find_file("Röthlisberger.png")) assert stbt.load_image(u"Röthlisberger.png") is not None assert stbt.load_image(u"Röthlisberger.png".encode("utf-8")) is not None assert stbt.load_image(u"R\xf6thlisberger.png") is not None
def test_matching_greyscale_array_with_greyscale_frame(match_method): img = stbt.load_image("videotestsrc-redblue.png", color_channels=1) assert img.shape[2] == 1 frame = stbt.load_image("videotestsrc-full-frame.png", color_channels=1) assert frame.shape[2] == 1 assert stbt.match(img, frame, match_parameters=mp(match_method=match_method))
def test_that_load_image_looks_in_callers_directory(): # See also the test with the same name in ../test_core.py assert numpy.array_equal( stbt.load_image("videotestsrc-redblue.png"), cv2.imread( os.path.join(os.path.dirname(__file__), "../videotestsrc-redblue-flipped.png"))) with pytest.raises(IOError): stbt.load_image("info.png")
def test_crop(): f = stbt.load_image("action-panel.png") cropped = stbt.crop(f, stbt.Region(x=1045, y=672, right=1081, bottom=691)) reference = stbt.load_image("action-panel-blue-button.png") assert numpy.array_equal(reference, cropped) # It's a view onto the same memory: assert cropped[0, 0, 0] == f[672, 1045, 0] cropped[0, 0, 0] = 0 assert cropped[0, 0, 0] == f[672, 1045, 0] # Region must be inside the frame (unfortunately this means that you can't # use stbt.Region.ALL): with pytest.raises(ValueError): stbt.crop(f, stbt.Region(x=1045, y=672, right=1281, bottom=721))
def test_that_load_image_looks_in_callers_directory(): # See also the test with the same name in # ./subdirectory/test_load_image_from_subdirectory.py stbt.TEST_PACK_ROOT = os.path.abspath(os.path.dirname(__file__)) f = stbt.load_image("videotestsrc-redblue.png") assert numpy.array_equal( f, cv2.imread(os.path.join(os.path.dirname(__file__), "videotestsrc-redblue.png"))) assert f.filename == "videotestsrc-redblue.png" assert f.relative_filename == "videotestsrc-redblue.png" with pytest.raises(IOError): stbt.load_image("info2.png")
def test_load_image_with_numpy_array(): a = numpy.zeros((720, 1280), dtype=numpy.uint8) img = stbt.load_image(a) assert ( a.__array_interface__["data"][0] == img.__array_interface__["data"][0]) assert img.filename is None assert img.relative_filename is None assert img.absolute_filename is None
def test_match_all_with_transparent_reference_image(): frame = stbt.load_image("buttons-on-blue-background.png") matches = list(m.region for m in stbt.match_all( "button-transparent.png", frame=frame)) print(matches) assert overlapped_button not in matches assert (sorted(plain_buttons + labelled_buttons + [overlapping_button]) == sorted(matches))
def test_that_match_all_obeys_region(match_method): matches = sorted(m.region for m in stbt.match_all( "button.png", frame=stbt.load_image("buttons.png"), match_parameters=mp(match_method=match_method), region=stbt.Region(x=160, y=60, right=340, bottom=190))) print(matches) assert matches == [stbt.Region(x, y, width=135, height=44) for x, y in [ (177, 75), (177, 119)]]
def test_that_match_all_finds_all_matches(match_method): matches = list( m.region for m in stbt.match_all('button.png', frame=stbt.load_image('buttons.png'), match_parameters=mp( match_method=match_method))) print(matches) assert plain_buttons == sorted(matches)
def test_ocr_debug(): # So that the output directory name doesn't depend on how many tests # were run before this one. ImageLogger._frame_number = itertools.count(1) # pylint:disable=protected-access f = stbt.load_image("action-panel.png") r = stbt.Region(0, 370, right=1280, bottom=410) c = (235, 235, 235) with scoped_curdir(), scoped_debug_level(2): stbt.ocr(f) stbt.ocr(f, region=r) stbt.ocr(f, region=r, text_color=c) stbt.match_text("Summary", f) # no match stbt.match_text("Summary", f, region=r) # no match stbt.match_text("Summary", f, region=r, text_color=c) files = subprocess.check_output("find stbt-debug | sort", shell=True) \ .decode("utf-8") assert files == dedent("""\ stbt-debug stbt-debug/00001 stbt-debug/00001/index.html stbt-debug/00001/source.png stbt-debug/00001/tessinput.png stbt-debug/00001/upsampled.png stbt-debug/00002 stbt-debug/00002/index.html stbt-debug/00002/source.png stbt-debug/00002/tessinput.png stbt-debug/00002/upsampled.png stbt-debug/00003 stbt-debug/00003/index.html stbt-debug/00003/source.png stbt-debug/00003/tessinput.png stbt-debug/00003/text_color_difference.png stbt-debug/00003/text_color_threshold.png stbt-debug/00003/upsampled.png stbt-debug/00004 stbt-debug/00004/index.html stbt-debug/00004/source.png stbt-debug/00004/tessinput.png stbt-debug/00004/upsampled.png stbt-debug/00005 stbt-debug/00005/index.html stbt-debug/00005/source.png stbt-debug/00005/tessinput.png stbt-debug/00005/upsampled.png stbt-debug/00006 stbt-debug/00006/index.html stbt-debug/00006/source.png stbt-debug/00006/tessinput.png stbt-debug/00006/text_color_difference.png stbt-debug/00006/text_color_threshold.png stbt-debug/00006/upsampled.png """)
def test_is_screen_black_with_numpy_mask_and_region(): frame = stbt.load_image("videotestsrc-full-frame.png") region = stbt.Region(x=160, y=180, right=320, bottom=240) mask = numpy.zeros((60, 160), dtype=numpy.uint8) mask[:, :80] = 255 assert stbt.is_screen_black(frame, mask, 20, region) mask[:, :] = 255 assert not stbt.is_screen_black(frame, mask, 20, region)
def test_that_match_all_can_find_labelled_matches(match_method): frame = stbt.load_image('buttons.png') matches = list(m.region for m in stbt.match_all( 'button.png', frame=frame, match_parameters=mp(match_method=match_method, confirm_method=stbt.ConfirmMethod.NONE))) print(matches) assert overlapped_button not in matches assert sorted(plain_buttons + labelled_buttons + [overlapping_button]) == \ sorted(matches)
def test_load_image_with_numpy_array(): a = numpy.zeros((720, 1280, 3), dtype=numpy.uint8) img = stbt.load_image(a) assert ( a.__array_interface__["data"][0] == img.__array_interface__["data"][0]) assert img.filename is None assert img.relative_filename is None assert img.absolute_filename is None a = numpy.zeros((720, 1280), dtype=numpy.uint8) b = numpy.zeros((720, 1280, 1), dtype=numpy.uint8) c = numpy.zeros((720, 1280, 3), dtype=numpy.uint8) d = numpy.zeros((720, 1280, 4), dtype=numpy.uint8) channels = [(1, ), (3, ), (4, ), (1, 3), (1, 4), (3, 4), (1, 3, 4)] for x in [a, b, c, d]: for y in channels: img = stbt.load_image(x, color_channels=y) assert img.shape[2] in y assert isinstance(img, stbt.Image)
def test_pyramid_roi_too_small(frame, image, match_method, match_threshold): # This is a regression test for an error that was seen with a particular # frame from a single test-run, with SQDIFF_NORMED: # cv2.error: (-215) _img.size().height <= _templ.size().height && # _img.size().width <= _templ.size().width in function matchTemplate with scoped_debug_level(2): stbt.match(image, frame=stbt.load_image(frame), match_parameters=stbt.MatchParameters( match_method=match_method, match_threshold=match_threshold))
def test_match_all_with_an_image_that_matches_everywhere(match_method): matches = sorted(m.region for m in stbt.match_all( "repeating-pattern.png", frame=stbt.load_image("repeating-pattern-full-frame.png"), match_parameters=mp(match_method=match_method))) expected_matches = sorted([stbt.Region(x, y, width=16, height=16) for x in range(0, 320, 16) for y in range(0, 240, 16)]) print(matches) assert matches == expected_matches
def test_that_match_all_can_be_used_with_ocr_to_read_buttons(): # Demonstrates how match_all can be used with ocr for UIs consisting of text # on buttons frame = stbt.load_image('buttons.png') text = [ stbt.ocr(frame=stbt.crop( frame, m.region.extend(x=30, y=10, right=-30, bottom=-10))) for m in stbt.match_all('button-transparent.png', frame=frame) ] text = sorted([t for t in text if t not in ['', '\\s']]) print(text) assert text == [u'Button 1', u'Button 2', u'Buttons']
def test_that_match_fast_path_is_equivalent(): black_reference = black(10, 10) almost_black_reference = black(10, 10, value=1) black_frame = black(1280, 720) almost_black_frame = black(1280, 720, value=2) images = [ ("videotestsrc-redblue.png", "videotestsrc-full-frame.png"), ("action-panel.png", "action-panel.png"), ("videotestsrc-full-frame.png", "videotestsrc-full-frame.png"), ("videotestsrc-redblue-flipped.png", "videotestsrc-full-frame.png"), ("button.png", "black-full-frame.png"), ("completely-transparent.png", "buttons-on-blue-background.png"), ("action-panel-template.png", "action-panel.png"), ("button.png", "buttons.png"), (black_reference, black_frame), (almost_black_reference, black_frame), (almost_black_reference, almost_black_frame), ("repeating-pattern.png", "repeating-pattern-full-frame.png"), ("button-transparent.png", "buttons.png"), ] for reference, frame in images: if isinstance(frame, string_types): frame = stbt.load_image(frame, cv2.IMREAD_COLOR) reference = stbt.load_image(reference) orig_m = stbt.match(reference, frame=frame) fast_m = stbt.match(reference, frame=frame, region=orig_m.region) assert orig_m.time == fast_m.time assert orig_m.match == fast_m.match assert orig_m.region == fast_m.region assert bool(orig_m) == bool(fast_m) assert orig_m.first_pass_result == pytest.approx( fast_m.first_pass_result, abs=0.0001 if orig_m else 0.05) assert (orig_m.frame == fast_m.frame).all() if isinstance(orig_m.image, numpy.ndarray): assert (orig_m.image == fast_m.image).all() else: assert orig_m.image == fast_m.image
def test_transparent_reference_image_false_negative_caused_by_pyramid( frame, image, expected_region): # This is a regression test for a bug in the pyramid optimisation when # the reference image has a very small number of pixels, or the only non- # transparent pixels are near the edges of reference image: # At the smaller pyramid levels, the pixels near the edge of the reference # image won't match exactly because the corresponding pixels in the # down-scaled frame have been blurred. We also blur the reference image # before down-scaling, but since it doesn't know what's outside its edges, # it won't have the blurring near the edge. frame = stbt.load_image(frame) m = stbt.match(image, frame=frame) assert m assert expected_region.contains(m.region)
def test_load_image_from_filename_with_color_channels(): files = [ "videotestsrc-greyscale.png", "videotestsrc-greyscale-alpha.png", "completely-transparent.png", "with-alpha-but-completely-opaque.png", "uint16.png", ] channels = [(1, ), (3, ), (4, ), (1, 3), (1, 4), (3, 4), (1, 3, 4)] for f in files: for c in channels: print(f, c) img = stbt.load_image(f, color_channels=c) assert img.shape[2] in c assert isinstance(img, stbt.Image)
def test_is_screen_black_debug(): # So that the output directory name doesn't depend on how many tests # were run before this one. ImageLogger._frame_number = itertools.count(1) # pylint:disable=protected-access f = stbt.load_image("videotestsrc-full-frame.png") with scoped_curdir(), scoped_debug_level(2): stbt.is_screen_black(f) stbt.is_screen_black(f, mask="videotestsrc-mask-non-black.png") stbt.is_screen_black(f, mask="videotestsrc-mask-no-video.png") stbt.is_screen_black(f, region=stbt.Region(0, 0, 160, 120)) files = subprocess.check_output("find stbt-debug | sort", shell=True) \ .decode("utf-8") assert files == dedent("""\ stbt-debug stbt-debug/00001 stbt-debug/00001/grey.png stbt-debug/00001/index.html stbt-debug/00001/non_black.png stbt-debug/00001/source.png stbt-debug/00002 stbt-debug/00002/grey.png stbt-debug/00002/index.html stbt-debug/00002/mask.png stbt-debug/00002/non_black.png stbt-debug/00002/source.png stbt-debug/00003 stbt-debug/00003/grey.png stbt-debug/00003/index.html stbt-debug/00003/mask.png stbt-debug/00003/non_black.png stbt-debug/00003/source.png stbt-debug/00004 stbt-debug/00004/grey.png stbt-debug/00004/index.html stbt-debug/00004/non_black.png stbt-debug/00004/source.png """) assert_expected("stbt-debug-expected-output/is_screen_black")
def test_that_results_dont_overlap(match_method): # This is a regression test for a bug seen in an earlier implementation of # `match_all`. frame = stbt.load_image("action-panel.png") all_matches = set() for m in stbt.match_all("action-panel-template.png", frame=frame, match_parameters=mp(match_method=match_method)): print(m) assert m.region not in all_matches, "Match %s already seen:\n %s" % ( m, "\n ".join(str(x) for x in all_matches)) assert all(stbt.Region.intersect(m.region, x) is None for x in all_matches) all_matches.add(m.region) assert all_matches == set([ stbt.Region(x=135, y=433, width=222, height=40), stbt.Region(x=135, y=477, width=222, height=40), stbt.Region(x=135, y=521, width=222, height=40), stbt.Region(x=135, y=565, width=222, height=40), stbt.Region(x=135, y=609, width=222, height=40)])
def test_that_match_rejects_greyscale_array(match_method): grey = cv2.cvtColor(stbt.load_image("black.png"), cv2.COLOR_BGR2GRAY) with pytest.raises(ValueError): stbt.match(grey, frame=black(), match_parameters=mp(match_method=match_method))
def test_match_fast_path(): # This is just an example of typical use assert stbt.match("action-panel-prototype.png", frame=stbt.load_image("action-panel.png"))
def test_matchresult_region_when_first_pyramid_level_fails_to_match(): f = stbt.load_image("videotestsrc-full-frame.png") r = stbt.match("videotestsrc-redblue-flipped.png", frame=f).region assert r.width == 92 assert r.height == 160
def test_transparent_reference_image_with_sqdiff_normed_raises_valueerror(): f = stbt.load_image("buttons-on-blue-background.png") with pytest.raises(ValueError): stbt.match("button-transparent.png", f, match_parameters=mp(stbt.MatchMethod.SQDIFF_NORMED))
def test_match_region(image, expected): frame = stbt.load_image("images/region/frame.png") m = stbt.match("images/region/%s.png" % image, frame=frame) assert m assert m.region == expected
def test_completely_transparent_reference_image(): f = stbt.load_image("buttons-on-blue-background.png") assert len(list(stbt.match_all("completely-transparent.png", frame=f))) == 18
def test_that_if_image_doesnt_match_match_all_returns_empty_array( match_method): assert [] == list( stbt.match_all('button.png', frame=stbt.load_image('black-full-frame.png'), match_parameters=mp(match_method=match_method)))