133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright 2014 The Chromium Authors. All rights reserved.
233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Use of this source code is governed by a BSD-style license that can be
333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# found in the LICENSE file.
433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport copy
633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport math
733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport os
833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport unittest
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.core import util
1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.internal.util import external_modules
1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Recktry:
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  np = external_modules.ImportRequiredModule('numpy')
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  cv2 = external_modules.ImportRequiredModule('cv2')
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckexcept (ImportError, NotImplementedError) as err:
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  pass
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckelse:
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  # pylint: disable=protected-access
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  class ScreenFinderTest(unittest.TestCase):
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def __init__(self, *args, **kwargs):
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      super(ScreenFinderTest, self).__init__(*args, **kwargs)
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Import modules with dependencies that may not be preset in test setup so
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # that importing this unit test doesn't cause the test runner to raise an
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # exception.
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      from telemetry.internal.image_processing import fake_frame_generator
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      from telemetry.internal.image_processing import screen_finder
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      from telemetry.internal.image_processing import video_file_frame_generator
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.FakeFrameGenerator = fake_frame_generator.FakeFrameGenerator
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.VideoFileFrameGenerator = \
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          video_file_frame_generator.VideoFileFrameGenerator
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.ScreenFinder = screen_finder.ScreenFinder
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def _GetScreenFinder(self, video_filename):
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      if not video_filename:
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        fg = self.FakeFrameGenerator()
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      else:
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        vid = os.path.join(util.GetUnittestDataDir(), video_filename)
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        fg = self.VideoFileFrameGenerator(vid)
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      return self.ScreenFinder(fg)
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testBasicFunctionality(self):
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      def CheckCorners(corners, expected):
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for i in xrange(len(corners)):
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          for j in xrange(len(corners[i])):
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            self.assertAlmostEqual(corners[i][j], expected[i][j], delta=1.1)
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[314, 60], [168, 58], [162, 274], [311, 276]]
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder('screen_3_frames.mov')
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf.HasNext())
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      screen, corners = sf.GetNext()
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      CheckCorners(corners, expected)
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIsNotNone(screen)
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      height, width = screen.shape[:2]
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertAlmostEqual(height, 226, delta=2)
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertAlmostEqual(width, 156, delta=2)
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf.HasNext())
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      screen, corners = sf.GetNext()
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      CheckCorners(corners, expected)
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIsNotNone(screen)
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      height1, width1 = screen.shape[:2]
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(width, width1)
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(height, height1)
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf.HasNext())
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      screen, corners = sf.GetNext()
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      CheckCorners(corners, expected)
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIsNotNone(screen)
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      height2, width2 = screen.shape[:2]
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(width, width2)
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(height, height2)
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf.HasNext())
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      error = ''
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      try:
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        sf.GetNext()
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      except RuntimeError as e:
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        error = str(e)
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(error, 'No more frames available.')
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testHasMovedFast(self):
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      prev_corners = np.asfarray(([1000, 1000], [0, 1000], [0, 0], [1000, 0]))
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf._HasMovedFast(prev_corners, prev_corners))
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      not_moved = copy.deepcopy(prev_corners)
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      not_moved[0][1] += 1
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      not_moved[1][1] += 1
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      not_moved[3][0] += 0.9
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf._HasMovedFast(not_moved, prev_corners))
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      moved = copy.deepcopy(prev_corners)
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      moved[0][1] += math.sqrt(0.5)
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      moved[0][0] += math.sqrt(0.5)
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      moved[1][1] += 2.1
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf._HasMovedFast(moved, prev_corners))
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testPointConnectsToCorners(self):
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      line1 = np.asfarray(((0, 0, 1, 0)))
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      line2 = np.asfarray(((0, 0, 0, 1)))
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      point = np.asfarray((0, 0))
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      point_info = (point, line1, line2)
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.asfarray(((1, 0), (0, 1)))
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf._PointConnectsToCorners(corners, point_info, 1))
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.append(corners, (100, 1))
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.append(corners, (1, 100))
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = corners.reshape(-1, 2)
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf._PointConnectsToCorners(corners, point_info, 2))
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf._PointConnectsToCorners(corners, point_info, 0.5))
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.append(corners, (100, 0))
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.append(corners, (0, 100))
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = corners.reshape(-1, 2)
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf._PointConnectsToCorners(corners, point_info, 0))
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testFindIntersections(self):
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      def _BuildResult(point, line1, line2):
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return [point, np.asfarray(line1).tolist(), np.asfarray(line2).tolist()]
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      def _IntersectionResultsToList(results):
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        result_list = []
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        for result in results:
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          point, line1, line2 = result
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          p = np.round(point).tolist()
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          l1 = np.round(line1).tolist()
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          l2 = np.round(line2).tolist()
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          result_list.append([p, l1, l2])
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        return result_list
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = []
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines = []
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Box with corners at (0, 0), (1000, 0), (0, 1000), (1000, 1000)
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 1001, 0, -1))))
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((-1, 0, 1001, 0))))
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((1000, 1001, 1000, -1))))
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((-1, 1000, 1001, 1000))))
13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([0, 0], lines[0], lines[1]))
13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([0, 1000], lines[0], lines[3]))
13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([1000, 0], lines[1], lines[2]))
13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([1000, 1000], lines[2], lines[3]))
13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # crosses 2 lines at 45 degrees.
13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 500, 500, 0))))
14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([0, 500], lines[0], lines[4]))
14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([500, 0], lines[1], lines[4]))
14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # crosses 1 line at > 45 degrees, 1 line at < 45 degrees.
14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 400, 600, 0))))
14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected.append(_BuildResult([0, 400], lines[0], lines[5]))
14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Test without previous corner data, all intersections should be found.
14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      results = sf._FindIntersections(lines)
14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      result_list = _IntersectionResultsToList(results)
15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      for e in expected:
15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.assertIn(e, result_list)
15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(len(expected), len(result_list))
15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Now introduce previous corners, but also reset conditions. No
15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # intersections should be lost.
15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = ((1000, 1000), (0, 1000), (0, 0), (1000, 0))
15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._prev_corners = np.asfarray(corners, np.float32)
15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._lost_corner_frames = sf.RESET_AFTER_N_BAD_FRAMES + 1
16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      results = sf._FindIntersections(lines)
16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      result_list = _IntersectionResultsToList(results)
16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      for e in expected:
16433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.assertIn(e, result_list)
16533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(len(expected), len(result_list))
16633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Remove reset conditions, so intersections not near corners will be lost.
16833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._lost_corner_frames = sf.RESET_AFTER_N_BAD_FRAMES
16933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # First 4 intersections are the ones at the old corner locations.
17033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = expected[0:4]
17133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      results = sf._FindIntersections(lines)
17233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      result_list = _IntersectionResultsToList(results)
17333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      for e in expected:
17533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.assertIn(e, result_list)
17633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(len(expected), len(result_list))
17733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testPointIsCloseToPreviousCorners(self):
17933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
18033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = ((1000, 1000), (0, 1000), (0, 0), (1000, 0))
18133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._prev_corners = np.asfarray(corners, np.float32)
18233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      dist = math.sqrt(sf.MAX_INTERFRAME_MOTION)
18333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sidedist1 = math.sqrt(sf.MAX_INTERFRAME_MOTION) / math.sqrt(2) - (1e-13)
18433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sidedist2 = math.sqrt(sf.MAX_INTERFRAME_MOTION) / math.sqrt(2) + (1e-13)
18533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      point1 = (corners[3][0] + dist, corners[3][1])
18633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf._PointIsCloseToPreviousCorners(point1))
18733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      point2 = (corners[3][0] + sidedist1, corners[3][1] + sidedist1)
18833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(sf._PointIsCloseToPreviousCorners(point2))
18933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      point3 = (corners[1][0] + sidedist2, corners[1][1] + sidedist2)
19033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertFalse(sf._PointIsCloseToPreviousCorners(point3))
19133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
19233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testLooksLikeCorner(self):
19333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # TODO: Probably easier to just do end to end tests.
19433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      pass
19533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
19633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testCornerData(self):
19733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd = self.ScreenFinder.CornerData('a', 'b', 'c', 'd', 'e')
19833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(cd.corner_index, 'a')
19933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(cd.corner_location, 'b')
20033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(cd.brightness_score, 'c')
20133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(cd.line1, 'd')
20233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(cd.line2, 'e')
20333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list = []
20433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list.append(self.ScreenFinder.CornerData(0, None, None, None, None))
20533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list.append(self.ScreenFinder.CornerData(3, None, None, None, None))
20633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list.append(self.ScreenFinder.CornerData(1, None, None, None, None))
20733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list.append(self.ScreenFinder.CornerData(2, None, None, None, None))
20833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      cd_list.sort()
20933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      for i in range(len(cd_list)):
21033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.assertEqual(i, cd_list[i].corner_index)
21133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
21233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testFindCorners(self):
21333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # TODO: Probably easier to just do end to end tests.
21433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      pass
21533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
21633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testDeDupCorners(self):
21733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
21833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data = []
21933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines = []
22033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((0, 1001, 0, -1)))
22133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((-1, 0, 1001, 0)))
22233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((1000, 1001, 1000, -1)))
22333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((-1, 1000, 1001, 1000)))
22433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((0, 10, 10, 0)))
22533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray((-1, 1001, 1001, 1001)))
22633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.asfarray(((1000, 1000), (0, 1000), (0, 0),
22733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                             (1000, 0), (0, 10), (10, 0), (1000, 1001)))
22833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(2, corners[2], 100,
22933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[0], lines[1]))
23033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(1, corners[1], 100,
23133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[0], lines[3]))
23233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(3, corners[3], 100,
23333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[1], lines[2]))
23433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(0, corners[0], 100,
23533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[2], lines[3]))
23633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(2, corners[4], 120,
23733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[0], lines[4]))
23833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(2, corners[5], 110,
23933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[1], lines[4]))
24033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      data.append(self.ScreenFinder.CornerData(0, corners[6], 110,
24133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                               lines[2], lines[5]))
24233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      dedup = copy.copy(data)
24333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Tests 2 non-duplicate corners, 1 corner with connected and unconnected
24433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # corners, and 1 corner with two connected corners.
24533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._DeDupCorners(dedup, corners)
24633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(len(dedup), 4)
24733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[0], dedup)
24833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[1], dedup)
24933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[2], dedup)
25033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[6], dedup)
25133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
25233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Same test, but this time the corner with connected and unconnected
25333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # corners now only contains unconnected corners.
25433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      del data[0]
25533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.delete(corners, 2, axis=0)
25633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      dedup2 = copy.copy(data)
25733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._DeDupCorners(dedup2, corners)
25833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(len(dedup2), 4)
25933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[3], dedup2)
26033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[0], dedup2)
26133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[1], dedup2)
26233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertIn(data[5], dedup2)
26333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
26433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testFindExactCorners(self):
26533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
26633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img = np.zeros((3, 3), np.uint8)
26733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img[1][0] = 255
26833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img[0][1] = 255
26933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img[1][2] = 255
27033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img[2][1] = 255
27133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._frame_edges = img
27233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.asfarray([(1, 1), (1, 1), (1, 1), (1, 1)])
27333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = np.asfarray([(2, 0), (0, 0), (0, 2), (2, 2)])
27433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._FindExactCorners(corners)
27533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret, expected)
27633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img2 = np.zeros((3, 3), np.uint8)
27733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img2[1][0] = 255
27833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img2[1][1] = 255
27933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img2[2][2] = 255
28033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      img2[2][1] = 255
28133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._frame_edges = img2
28233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected2 = [(2, 1), (0, 1), (0, 2), (2, 2)]
28333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret2 = sf._FindExactCorners(corners)
28433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret2, expected2)
28533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
28633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testSmoothCorners(self):
28733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
28833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = [[10, 10], [10, 10], [10, 10], [10, 10]]
28933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._SmoothCorners(corners).tolist()
29033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(ret, corners)
29133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = [[0, 0], [0, 0], [0, 0], [0, 0]]
29233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[5, 5], [5, 5], [5, 5], [5, 5]]
29333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._SmoothCorners(corners).tolist()
29433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(ret, expected)
29533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[2.5, 2.5], [2.5, 2.5], [2.5, 2.5], [2.5, 2.5]]
29633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._SmoothCorners(corners).tolist()
29733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(ret, expected)
29833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
29933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testGetTransform(self):
30033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
30133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.array([[100, 1000], [0, 1000], [0, 0], [100, 0]], np.float32)
30233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      transform, w, h = sf._GetTransform(corners, 1)
30333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      transform = np.round(transform, 2)
30433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[1., 0., 1.], [-0., -1., 1001.], [0., -0., 1.]]
30533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(transform.tolist(), expected)
30633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(w, 102)
30733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(h, 1002)
30833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
30933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners = np.array([(200, 2000), (0, 2000), (0, 0), (200, 0)], np.float32)
31033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      transform, w, h = sf._GetTransform(corners, 5)
31133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      transform = np.round(transform, 2)
31233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[0.5, 0.0, 5.0], [-0.0, -0.5, 1005.0], [-0.0, 0.0, 1.0]]
31333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(transform.tolist(), expected)
31433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(w, 110)
31533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(h, 1010)
31633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
31733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    def testNewScreenLocation(self):
31833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf = self._GetScreenFinder(None)
31933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners_2 = np.asfarray([[np.nan, np.nan], [0, 1000], [np.nan, np.nan],
32033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                               [1000, 0]])
32133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners_3 = np.asfarray([[1000, 1000], [0, 1000], [np.nan, np.nan],
32233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                               [1000, 0]])
32333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      corners_4 = np.asfarray([[1000, 1000], [0, 1000], [0, 0], [1000, 0]])
32433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines = []
32533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Box with corners at (0, 0), (1000, 0), (0, 1000), (1000, 1000)
32633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 1001, 0, -1))))
32733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((-1, 0, 1001, 0))))
32833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((1000, 1001, 1000, -1))))
32933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((-1, 1000, 1001, 1000))))
33033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      # Additional intersections near a corner.
33133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 3, 7, 0))))
33233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      lines.append(np.asfarray(((0, 4, 6, 0))))
33333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      intersections = sf._FindIntersections(lines)
33433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      failed = False
33533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      try:
33633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        sf._NewScreenLocation(corners_3, 1, intersections)
33733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      except self.ScreenFinder.ScreenNotFoundError:
33833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        failed = True
33933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertTrue(failed)
34033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
34133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._lost_corner_frames = 10
34233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._lost_corners = [True, True, True, True]
34333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._NewScreenLocation(corners_4, 0, intersections)
34433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret, corners_4)
34533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(sf._lost_corners, [False, False, False, False])
34633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(sf._lost_corner_frames, 0)
34733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
34833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._prev_corners = corners_4
34933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._NewScreenLocation(corners_3, 1, intersections)
35033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = np.round(ret)
35133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret, corners_4)
35233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(sf._lost_corners, [False, False, True, False])
35333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(sf._lost_corner_frames, 1)
35433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
35533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      sf._prev_corners = np.asfarray([(1000, 1000), (0, 1000),
35633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                      (0, 3), (1000, 0)])
35733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._NewScreenLocation(corners_3, 1, intersections)
35833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = np.round(ret)
35933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret, corners_4)
36033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(sf._lost_corners, [False, False, True, False])
36133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(sf._lost_corner_frames, 2)
36233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
36333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = sf._NewScreenLocation(corners_2, 2, intersections)
36433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      ret = np.round(ret)
36533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      expected = [[1000, 1000], [0, 1000], [0, 3], [1000, 0]]
36633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      np.testing.assert_equal(ret, expected)
36733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertListEqual(sf._lost_corners, [True, False, True, False])
36833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.assertEqual(sf._lost_corner_frames, 3)
369