def _PointIsCloseToPreviousCorners(self, point): """True if the point is close to the previous corners.""" max_dist = self.MAX_INTERFRAME_MOTION if cv_util.SqDistance(self._prev_corners[0], point) <= max_dist or \ cv_util.SqDistance(self._prev_corners[1], point) <= max_dist or \ cv_util.SqDistance(self._prev_corners[2], point) <= max_dist or \ cv_util.SqDistance(self._prev_corners[3], point) <= max_dist: return True return False
def _GetTransform(self, corners, border): """Gets the perspective transform of the screen. Args: corners: The corners of the detected screen. border: The number of pixels of border to crop along with the screen. Returns: A perspective transform and the width and height of the target transform. Raises: ScreenNotFoundError: Something went wrong in detecting the screen.""" if self._screen_size is None: w = np.sqrt(cv_util.SqDistance(corners[1], corners[0])) h = np.sqrt(cv_util.SqDistance(corners[1], corners[2])) if w < 1 or h < 1: raise self.ScreenNotFoundError( 'Screen detected improperly (bad corners)') if min(w, h) < self.MIN_SCREEN_WIDTH: raise self.ScreenNotFoundError( 'Detected screen was too small.') self._screen_size = (w, h) # Extend min line length, if we can, to reduce the number of extraneous # lines the line finder finds. self._min_line_length = max(self._min_line_length, min(w, h) / 1.75) w = self._screen_size[0] h = self._screen_size[1] target = np.zeros((4, 2), np.float32) width = w + border height = h + border target[0] = np.asfarray((width, border)) target[1] = np.asfarray((border, border)) target[2] = np.asfarray((border, height)) target[3] = np.asfarray((width, height)) transform_w = width + border transform_h = height + border transform = cv2.getPerspectiveTransform(corners, target) return transform, transform_w, transform_h
def _PointConnectsToCorners(self, corners, point_info, tolerance=1): """Checks if the lines of an intersection intersect with corners. This is useful to check if the point is part of a rectangle specified by |corners|. Args: point_info: A tuple of (point, line, line) representing an intersection of two lines. corners: corners that (hopefully) make up a rectangle. tolerance: The tolerance (approximately in pixels) of the distance between the corners and the lines for detecting if the point is on the line. Returns: True if each of the two lines that make up the intersection where the point is located connect the point to other corners.""" line1_connected = False line2_connected = False point, line1, line2 = point_info for corner in corners: if corner is None: continue # Filter out points that are too close to one another to be different # corners. sqdist = cv_util.SqDistance(corner, point) if sqdist < self.MIN_SCREEN_WIDTH * self.MIN_SCREEN_WIDTH: continue line1_connected = line1_connected or \ cv_util.IsPointApproxOnLine(corner, line1, tolerance) line2_connected = line2_connected or \ cv_util.IsPointApproxOnLine(corner, line2, tolerance) if line1_connected and line2_connected: return True return False
def _NewScreenLocation(self, new_corners, missing_corners, intersections): """Computes the new screen location with best effort. Creates the final list of corners that represents the best effort attempt to find the new screen location. Handles degenerate cases where 3 or fewer new corners are present, using previous corner and intersection data. Args: new_corners: The corners found by our search for corners. missing_corners: The count of how many corners we're missing. intersections: The intersections of straight lines found in the current frame. Returns: An array of 4 new_corners hopefully representing the screen, or throws an error if this is not possible. Raises: ValueError: Finding the screen location was not possible.""" screen_corners = copy.copy(new_corners) if missing_corners == 0: self._lost_corner_frames = 0 self._lost_corners = [False, False, False, False] return screen_corners if self._prev_corners is None: raise self.ScreenNotFoundError( 'Could not locate screen on frame %d' % self._frame_generator.CurrentFrameNumber) self._lost_corner_frames += 1 if missing_corners > 1: logging.info( 'Unable to properly detect screen corners, making ' 'potentially false assumptions on frame %d', self._frame_generator.CurrentFrameNumber) # Replace missing new_corners with either nearest intersection to previous # corner, or previous corner if no intersections are found. for i in xrange(0, 4): if not np.isnan(new_corners[i][0]): self._lost_corners[i] = False continue self._lost_corners[i] = True min_dist = self.MAX_INTERFRAME_MOTION min_corner = None for isection in intersections: dist = cv_util.SqDistance(isection[0], self._prev_corners[i]) if dist >= min_dist: continue if missing_corners == 1: # We know in this case that we have 3 corners present, meaning # all 4 screen lines, and therefore intersections near screen # corners present, so our new corner must connect to these # other corners. if not self._PointConnectsToCorners( new_corners, isection, 3): continue min_corner = isection[0] min_dist = dist screen_corners[i] = min_corner if min_corner is not None else \ self._prev_corners[i] return screen_corners