Пример #1
0
def crop_grid(img):
    """Identify the Sudoku grid, crop it from the image and skew it into a square to compensate for the camera angle."""
    proc = pre_process_image(img)

    if 'basic' in classification_mode():
        bbox = cv.get_four_corners(cv.find_largest_polygon(proc))
    else:
        # Gets the four corners of the inner contours of the image. Compensates for the grid outline accurately.
        bbox, area, outer, outer_area = cv.find_four_corners_inner(proc)

        # If the inner contours are less than 95% of the outer contour we may be losing valuable information.
        # Image 8 is one such example of this occurring
        # In these cases, use a different algorithm to estimate the width of the Sudoku border
        if (area / outer_area) < 0.95:
            bbox = cv.get_four_corners(outer)
            bbox = inner_sudoku_bbox(
                proc, bbox)  # Estimates the width of the grid outline
            area = outer_area

        # Some images have the Sudoku grid surrounded by a large rectangular box and the contour algorithm will pick that
        # instead of the Sudoku grid. In these cases, using the largest feature algorithm is more reliable. Identify when
        # the contour area meets a threshold ratio of the image size.
        if (area / (proc.shape[0] * proc.shape[1])) > 0.95:
            # Find the largest connected pixel structure, this should be the outer grid for Sudoku
            proc, bbox, seed = cv.find_largest_feature(proc)
            bbox = inner_sudoku_bbox(
                proc, bbox)  # Estimates the width of the grid outline

    # Return a warped version of the image
    return cv.crop_and_warp(img, bbox, square=True)
Пример #2
0
    def draw_numbers(self,
                     numbers,
                     colour=(50, 50, 255),
                     thickness=3,
                     crop=False,
                     show_known=False,
                     show=True,
                     save=None):
        """
        Draws numbers onto the cropped or original Sudoku image and shows it on the screen.

        Args:
            numbers (iterable): Array of size 81 with the numbers to display on the grid.
            colour (tuple): BGR (blue, green, red) values between 0 and 255.
            thickness (int): Thickness of the font in pixels.
            crop (bool): If True, will display the numbers on the cropped and warped image instead of the original.
            show_known (bool): If True, will display the predictions for the given numbers on the board instead of the
                empty cells.
            show (bool): If True, will show the image on the screen.
            save (str): If specified, will save the image to that location.

        Returns:
            np.array: Image with the missing numbers drawn on.
        """
        if self.cropped_color is None:
            self.cropped_color, rect, matrix = cv.crop_and_warp(self.original,
                                                                self.crop_rect,
                                                                square=True)
        img = self.cropped_color.copy()

        scale = int((self.grid_squares[0][1][0] - self.grid_squares[0][0][0]) *
                    0.075)  # Dynamic scale for font
        for i, square in enumerate(self.grid_squares):
            condition = self.board_int[
                i] == 0  # Don't draw numbers given on the board

            if show_known:  # Unless we want to see them
                condition = not condition

            if condition:
                fh, fw = cv2.getTextSize(
                    str(numbers[i]), cv2.FONT_HERSHEY_PLAIN, scale,
                    thickness)[0]  # Get font height and width
                h_pad = int((square[1][0] - square[0][0] - fw) /
                            2)  # Padding to centre the number
                v_pad = int((square[1][1] - square[0][1] - fw) / 2)
                h_pad -= self.border  # No border on the original, so this compensates
                v_pad += self.border
                img = cv2.putText(
                    img,
                    str(numbers[i]),
                    (int(square[0][0]) + h_pad, int(square[1][1]) - v_pad),
                    cv2.FONT_HERSHEY_PLAIN,
                    fontScale=scale,
                    color=colour,
                    thickness=thickness)

        # Display the cropped image and return
        if crop:
            if show:
                cv.show_image(img)
            if save is not None:
                cv2.imwrite(save, img)
            return img

        # Perform an inverse of the crop and warp transformation to put the image back onto the original
        height, width = self.original.shape[:2]
        img = cv2.warpPerspective(img,
                                  self.crop_matrix, (width, height),
                                  flags=cv2.WARP_INVERSE_MAP,
                                  dst=self.original,
                                  borderMode=cv2.BORDER_TRANSPARENT)
        if show:
            cv.show_image(img)

        if save is not None:
            cv2.imwrite(save, img)
        return img