<filename>main.py
import cv2
from utils.processing_utils import *
from utils.sudoku import Sudoku
from utils.number_classifier import NumberClassifier
import time
import argparse


def detect_sudoku_on_image(image_path, font_scale_divisor = 3.5, deskew = False, show=False):
    train_image = cv2.imread("Data/train.png")
    train_image = cv2.cvtColor(train_image, cv2.COLOR_BGR2GRAY)
    classifier = NumberClassifier(train_image,deskew=deskew)
    preprcessor = PreProcessor(classifier, 600, 600)

    img = cv2.imread(image_path)
    start_time = time.time()

    grid = preprcessor.get_grid(img, show)
    #print(grid)
    clues = grid.copy()
    sudoku = Sudoku(clues)
    sudoku.solve("backtrack", max_iterations=1e6)
    final_image = preprcessor.draw_grid(sudoku.cells - grid, img, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor, show=show)

    end_time = time.time()
    print(f"Sudoku solved in {end_time - start_time:0.05} seconds!")
    preprcessor.show_image(final_image)



def live_detect_sudoku(font_scale_divisor = 3.5, deskew = False):
    cap = cv2.VideoCapture(0)
    train_image = cv2.imread("Data/train.png")
    train_image = cv2.cvtColor(train_image, cv2.COLOR_BGR2GRAY)
    classifier = NumberClassifier(train_image, deskew=deskew)
    preprcessor = PreProcessor(classifier, 600, 600)

    correct_sudoku = np.zeros((9,9))
    prev_grid = np.zeros((9,9))
    
    sudoku = Sudoku(np.zeros((9,9))) # Initial Sudoku
    while(True):
        _, frame = cap.read()
        frame = cv2.resize(frame, None, None, fx=0.6, fy=0.6)
        grid = preprcessor.get_grid(frame)
        
        if grid is not None:
            if not np.all(prev_grid == grid): #only solve when the grid changed
                clues = grid.copy()
                sudoku = Sudoku(clues)
                try:
                    sudoku.solve("backtrack", max_iterations=5000)
                except ValueError: #If not solved fast enough show just the frame
                    frame = cv2.resize(frame, None, None, fx=1.5, fy=1.5)
                    cv2.imshow('Sudoku Solver',frame)
                    continue
            else:
                prev_grid = grid.copy()
            if np.sum(sudoku.cells) == 405:
                correct_sudoku = sudoku.cells
                frame = preprcessor.draw_grid(sudoku.cells - grid, frame, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor)
            else:
                frame = preprcessor.draw_grid(correct_sudoku - grid, frame, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor)

        frame = cv2.resize(frame, None, None, fx=1.5, fy=1.5)
        cv2.imshow('Sudoku Solver',frame)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()



parser = argparse.ArgumentParser(description='Input to main file')
parser.add_argument('mode', metavar='image_mode', type=int, default=0,
                    help='if mode is 1 image Mode is selected. if mode is 0 video mode is selected. Default 0 ')
parser.add_argument('--path', dest='image_path', type=str, default="",
                    help='If mode is 1 enter path to the image')
parser.add_argument('--fsd', dest='font_scale_divisor', type=float, default=3.5,
                    help='Changes the fontsize of the added numbers')
parser.add_argument('--deskew', dest='deskew', type=bool, default=False,
                    help='deskews the numbers when detecting. Helps with handwritten numbers or a high skew of the image')
parser.add_argument('--debug', dest='debug', type=bool, default=False,
                    help='Shows all the debug steps inbetween final result works only in image mode')

args = parser.parse_args()

if args.mode == 1:
    if args.image_path == "":
        raise ValueError("Image Mode is selected please enter the path")
    
    detect_sudoku_on_image(args.image_path, font_scale_divisor=args.font_scale_divisor, deskew=args.deskew, show=args.debug)
elif args.mode == 0:
    live_detect_sudoku(font_scale_divisor=args.font_scale_divisor, deskew=args.deskew)
else:
    raise ValueError(f"mode {args.mode} is not availabel please use 0 (video) or 1 (image)")


<filename>main.py
import cv2
from utils.processing_utils import *
from utils.sudoku import Sudoku
from utils.number_classifier import NumberClassifier
import time
import argparse


def detect_sudoku_on_image(image_path, font_scale_divisor = 3.5, deskew = False, show=False):
    train_image = cv2.imread("Data/train.png")
    train_image = cv2.cvtColor(train_image, cv2.COLOR_BGR2GRAY)
    classifier = NumberClassifier(train_image,deskew=deskew)
    preprcessor = PreProcessor(classifier, 600, 600)

    img = cv2.imread(image_path)
    start_time = time.time()

    grid = preprcessor.get_grid(img, show)
    #print(grid)
    clues = grid.copy()
    sudoku = Sudoku(clues)
    sudoku.solve("backtrack", max_iterations=1e6)
    final_image = preprcessor.draw_grid(sudoku.cells - grid, img, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor, show=show)

    end_time = time.time()
    print(f"Sudoku solved in {end_time - start_time:0.05} seconds!")
    preprcessor.show_image(final_image)



def live_detect_sudoku(font_scale_divisor = 3.5, deskew = False):
    cap = cv2.VideoCapture(0)
    train_image = cv2.imread("Data/train.png")
    train_image = cv2.cvtColor(train_image, cv2.COLOR_BGR2GRAY)
    classifier = NumberClassifier(train_image, deskew=deskew)
    preprcessor = PreProcessor(classifier, 600, 600)

    correct_sudoku = np.zeros((9,9))
    prev_grid = np.zeros((9,9))
    
    sudoku = Sudoku(np.zeros((9,9))) # Initial Sudoku
    while(True):
        _, frame = cap.read()
        frame = cv2.resize(frame, None, None, fx=0.6, fy=0.6)
        grid = preprcessor.get_grid(frame)
        
        if grid is not None:
            if not np.all(prev_grid == grid): #only solve when the grid changed
                clues = grid.copy()
                sudoku = Sudoku(clues)
                try:
                    sudoku.solve("backtrack", max_iterations=5000)
                except ValueError: #If not solved fast enough show just the frame
                    frame = cv2.resize(frame, None, None, fx=1.5, fy=1.5)
                    cv2.imshow('Sudoku Solver',frame)
                    continue
            else:
                prev_grid = grid.copy()
            if np.sum(sudoku.cells) == 405:
                correct_sudoku = sudoku.cells
                frame = preprcessor.draw_grid(sudoku.cells - grid, frame, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor)
            else:
                frame = preprcessor.draw_grid(correct_sudoku - grid, frame, x_offset=20, y_offset=15, font_scale_divisor=font_scale_divisor)

        frame = cv2.resize(frame, None, None, fx=1.5, fy=1.5)
        cv2.imshow('Sudoku Solver',frame)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()



parser = argparse.ArgumentParser(description='Input to main file')
parser.add_argument('mode', metavar='image_mode', type=int, default=0,
                    help='if mode is 1 image Mode is selected. if mode is 0 video mode is selected. Default 0 ')
parser.add_argument('--path', dest='image_path', type=str, default="",
                    help='If mode is 1 enter path to the image')
parser.add_argument('--fsd', dest='font_scale_divisor', type=float, default=3.5,
                    help='Changes the fontsize of the added numbers')
parser.add_argument('--deskew', dest='deskew', type=bool, default=False,
                    help='deskews the numbers when detecting. Helps with handwritten numbers or a high skew of the image')
parser.add_argument('--debug', dest='debug', type=bool, default=False,
                    help='Shows all the debug steps inbetween final result works only in image mode')

args = parser.parse_args()

if args.mode == 1:
    if args.image_path == "":
        raise ValueError("Image Mode is selected please enter the path")
    
    detect_sudoku_on_image(args.image_path, font_scale_divisor=args.font_scale_divisor, deskew=args.deskew, show=args.debug)
elif args.mode == 0:
    live_detect_sudoku(font_scale_divisor=args.font_scale_divisor, deskew=args.deskew)
else:
    raise ValueError(f"mode {args.mode} is not availabel please use 0 (video) or 1 (image)")


#print(grid) # Initial Sudoku #only solve when the grid changed #If not solved fast enough show just the frame