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)
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))
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
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)
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
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)