예제 #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 extract_digit(img, rect, size, mode, include_gray_channel=False):
    """Extracts a digit (if one exists) from a Sudoku square."""

    digit = cv.cut_from_rect(img,
                             rect)  # Get the digit box from the whole square

    # Use thresholding to expose the digit in the centre of the each box
    digit = grid_square_threshold(digit, mode)

    # Skip digit extraction, depending on the mode
    if 'cell' in mode:
        digit = cv2.resize(digit, (28, 28))
        return digit

    # Use fill feature finding to get the largest feature in middle of the box
    # Margin used to define an area in the middle we would expect to find a pixel belonging to the digit
    h, w = digit.shape[:2]
    margin = int(np.mean([h, w]) / 2.5)
    discard, bbox, seed = cv.find_largest_feature(digit, [margin, margin],
                                                  [w - margin, h - margin])
    digit, bbox = cv.get_bbox_from_seed(digit, seed)

    # Scale and pad the digit so that it fits a square of the digit size we're using for machine learning
    w = bbox[1][0] - bbox[0][0]
    h = bbox[1][1] - bbox[0][1]

    # Ignore any small bounding boxes
    if w > 0 and h > 0 and (w * h) > 100:
        digit = cv.cut_from_rect(digit, bbox)
        digit = cv.scale_and_centre(digit, size, 4)
        if include_gray_channel:
            digit = digit.reshape((size, size, 1))
        return digit
    else:
        return None