Пример #1
0
def draw_detected(detected_array: np.ndarray, save_name=None):
    blank = cv2.cvtColor(helpers.inverse(np.zeros((800, 800), dtype=np.uint8)),
                         cv2.COLOR_GRAY2BGR)
    dim = blank.shape
    for row in range(9):
        for col in range(9):
            if detected_array[col][row] != 0:
                digit_center_x = dim[1] // 18 + dim[1] // 9 * row
                digit_center_y = dim[0] // 18 + dim[0] // 9 * col
                text = str(detected_array[col][row])
                draw_text_centered(blank, digit_center_x, digit_center_y, text)
    if save_name is not None:
        helpers.save_img(save_name, 'E_DrawDetected', blank)
    else:
        cv2.imshow('drawOutput', blank)
Пример #2
0
def train():
    import time
    start = time.time()

    step = 0
    for epoch in range(config.EPOCHS):
        for i in range(config.steps_per_epoch):
            step += 1
            train_step()
            print('.', end="")
        print()
        print("Epoch", epoch, "done")
        save_img(image, config.SAVE_PATH, str(epoch) + " " + config.FILE_NAME)
    end = time.time()

    print("Total time {:.1f}".format(end - start))
Пример #3
0
def detect_board(thresholded_img: np.ndarray, img: np.ndarray) -> np.ndarray:
    # find contours in the thresholded image, keep only the 10 largest contours
    found_contours = cv2.findContours(thresholded_img, cv2.RETR_TREE,
                                      cv2.CHAIN_APPROX_SIMPLE)
    found_contours = imutils.grab_contours(found_contours)
    found_contours = sorted(found_contours, key=cv2.contourArea,
                            reverse=True)[:10]

    # find largest 4-sided contour
    board_contour = None
    epsilon = 0.015
    for cont in found_contours:
        arclen = cv2.arcLength(cont, True)
        approximated_polygon = cv2.approxPolyDP(cont, epsilon * arclen, True)
        if len(approximated_polygon) == 4:
            board_contour = approximated_polygon
            break

    if debug or save:
        # drawing the largest detected in red (doesn't have to be 4-sided)
        cv2.drawContours(img, [found_contours[0]], -1, (0, 0, 255), 3)
        # draw found board_contour in green
        if board_contour is not None:
            cv2.drawContours(img, [board_contour], -1, (0, 255, 0), 3)
        # prepare new images for debug/save
        thresholded_color_temp = cv2.cvtColor(thresholded_img,
                                              cv2.COLOR_GRAY2BGR)
        to_show = np.hstack((thresholded_color_temp, img))

    if save:
        helpers.save_img(save_name, 'A_Detection', to_show)
        if board_contour is None:
            return None

    if debug:
        thresholded_color_temp = cv2.cvtColor(thresholded_img,
                                              cv2.COLOR_GRAY2BGR)
        to_show = np.hstack((thresholded_color_temp, img))
        cv2.imshow("findBoard", rescale_img(to_show, 600))

    if board_contour is None:
        if debug:
            helpers.wait_for_key_on_value_error("Can not find board on image")
        else:
            raise (ValueError("Can not find board on image"))

    return board_contour
Пример #4
0
def draw_output(detected_array: np.ndarray,
                solved_array: np.ndarray,
                save_name=None):
    warped = rescale_img(warped_saved, 800)
    dim = warped.shape
    for row in range(9):
        for col in range(9):
            if detected_array[col][row] == 0:
                digit_center_x = dim[1] // 18 + dim[1] // 9 * row
                digit_center_y = dim[0] // 18 + dim[0] // 9 * col
                text = str(solved_array[col][row])
                draw_text_centered(warped, digit_center_x, digit_center_y,
                                   text)
    if save_name is not None:
        helpers.save_img(save_name, 'E_DrawOutput', warped)
    else:
        cv2.imshow('drawOutput', warped)
Пример #5
0
def cut_out_fields(warped_original: np.ndarray, save_name=None) -> np.ndarray:
    warped = warped_original.copy()
    y, x, _ = warped.shape
    warped_gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
    sudoku_field_img_array = []

    width = x // 9
    height = y // 9

    for row in range(9):
        sudoku_field_img_array.append([])
        for column in range(9):

            x_min = column * x // 9 + 1
            y_min = row * y // 9 + 1

            # had numerical problems!!! IDK why!
            # x_max = (column + 1) * x // 9 - 1
            # y_max = (row + 1) * y // 9 - 1
            # this works
            x_max = x_min + width - 1
            y_max = y_min + height - 1

            field_img = warped_gray[y_min:y_max, x_min:x_max]

            sudoku_field_img_array[-1].append(field_img)

            if debug or save_name is not None:
                # draw yellow squares for each field (just visualization) and their centers as red circles
                warped = cv2.rectangle(warped, (column * x // 9, row * y // 9),
                                       ((column + 1) * x // 9,
                                        (row + 1) * y // 9), (0, 255, 255), 1)
                warped = cv2.circle(
                    warped,
                    (x // 18 + column * x // 9, y // 18 + row * y // 9),
                    radius=3,
                    color=(0, 0, 255),
                    thickness=1)
    if save_name is not None:
        helpers.save_img(save_name, 'B_Cutting', warped)
    elif debug:
        cv2.imshow('cut board', warped)
    return sudoku_field_img_array
Пример #6
0
def process_fields(sudoku_field_img_array: np.ndarray,
                   enable_save=False,
                   saveName=None) -> np.ndarray:
    recognized_fields = []
    cut_digits_imgs = []
    cut_digits_thresholded_imgs = []
    for row_id in range(len(sudoku_field_img_array)):
        for col_id in range(len(sudoku_field_img_array[row_id])):
            original_img = sudoku_field_img_array[row_id][col_id]
            thresholded_img = threshold_field_image_rom(original_img.copy())
            cut_digits_thresholded_imgs.append(thresholded_img)
            dim = thresholded_img.shape

            contours, _ = cv2.findContours(thresholded_img, cv2.RETR_TREE,
                                           cv2.CHAIN_APPROX_SIMPLE)
            found = None
            if len(contours) != 0:
                for c in contours:
                    x, y, w, h = cv2.boundingRect(c)
                    # if the contour is sufficiently large, it must be a digit
                    # height and width limiters to eliminate grid lines detection
                    if (dim[1] * 3 // 28 < w < dim[1] * 25 // 28
                        and dim[1] * 1 // 28 <= x and x + w <= dim[1] * 27 // 28) \
                            and (dim[0] * 5 // 28 < h < dim[0] * 25 // 28
                                 and dim[0] * 1 // 28 <= y and y + h <= dim[0] * 27 // 28):
                        found = (x, y, w, h)
                        break

            if found is None:
                recognized_fields.append(0)
                if enable_save or debug:
                    cut_digits_imgs.append(
                        np.array(np.zeros(dim, dtype='uint8')))

            else:
                (x, y, w, h) = found
                # marked_contour_img=cv2.cvtColor(thresholded_img, cv2.COLOR_GRAY2BGR)
                # cv2.rectangle(marked_contour_img,(x,y),(x+w,y+h),(255,0,0),1)
                # cv2.imshow('contours',marked_contour_img)
                # cv2.waitKey(0)

                # try to cut the digit with some space around it
                digit_field_for_debug = inverse(np.zeros(dim, dtype='uint8'))
                try:
                    offset_param = 0.15
                    #yo = int(h * offset_param * 0.5)
                    #xo = int(w * offset_param)
                    yo = 3
                    xo = 6
                    digit_field_for_debug[y - yo:y + h + yo, x - xo:x + w +
                                          xo] = original_img[y - yo:y + h + yo,
                                                             x - xo:x + w + xo]
                    cut_digit_for_nn = original_img[y - yo:y + h + yo,
                                                    x - xo:x + w + xo]
                # if it failed then do it then failback to old method
                except ValueError:
                    print(
                        'tried to cut the digit a bit bigger and failed! failback to old method'
                    )
                    digit_field_for_debug[y:y + h,
                                          x:x + w] = original_img[y:y + h,
                                                                  x:x + w]
                    cut_digit_for_nn = original_img[y:y + h, x:x + w]

                if enable_save:
                    # skip digit recognition
                    digit = 1
                else:
                    try:
                        digit = number_recognition.predict(cut_digit_for_nn)
                    except ZeroDivisionError or ValueError:
                        recognized_fields.append(0)
                        if enable_save or debug:
                            cut_digits_imgs.append(
                                np.array(np.zeros(dim, dtype='uint8')))
                        continue
                    if digit == 0:
                        digit = 8
                recognized_fields.append(digit)
                if enable_save or debug:
                    cut_digits_imgs.append(
                        np.array(inverse(digit_field_for_debug)))

    if enable_save or debug:
        cut_digits_imgs = helpers.inverse(
            helpers.many_fields_to_one_img(cut_digits_imgs))
        cut_digits_thresholded_imgs = helpers.inverse(
            helpers.many_fields_to_one_img(cut_digits_thresholded_imgs))
        if enable_save:
            helpers.save_img(saveName, 'C_FieldThreshold',
                             cut_digits_thresholded_imgs)
            helpers.save_img(saveName, 'D_DigitExtraction', cut_digits_imgs)
        elif debug:
            cv2.imshow('cutDigits', cut_digits_imgs)
            cv2.imshow('cutDigitsThresholded', cut_digits_thresholded_imgs)

    return helpers.reshape81to9x9(recognized_fields)