-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathsolver.py
More file actions
151 lines (118 loc) · 4.57 KB
/
solver.py
File metadata and controls
151 lines (118 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import cv2
import imutils
from imutils.perspective import four_point_transform
from skimage.segmentation import clear_border
from tensorflow.keras.models import load_model
import numpy as np
from Sudoku import solveSudoku
from tensorflow.keras.preprocessing.image import img_to_array
import matplotlib.pyplot as plt
# Sudoku Solver
model = load_model('model/model_mnist/')
img_path = 'sudoku images/6.png'
img_shape = [28,28]
def find_puzzle(img):
real = img.copy()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(7,7),1)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
thresh = cv2.bitwise_not(thresh)
cnts = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts,key=cv2.contourArea,reverse=True)
puzzle_cnt = None
for c in cnts:
peri = cv2.arcLength(c,True)
approx = cv2.approxPolyDP(c,0.02*peri,True)
if len(approx)==4:
puzzle_cnt=approx
break
if puzzle_cnt is None:
raise Exception(("Could not find Sudoku puzzle outline.Try debugging your thresholding and contour steps."))
cv2.drawContours(real, [puzzle_cnt], -1, (0, 255, 0), 2)
puzzle = four_point_transform(img, puzzle_cnt.reshape(4, 2))
warped = four_point_transform(gray, puzzle_cnt.reshape(4, 2))
return puzzle,warped
def extract_digit(cell):
thresh = cv2.threshold(cell,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)[1]
thresh = clear_border(thresh) #just clear the extra white pixels along the border
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# if no contours were found than this is an empty cell
if len(cnts) == 0:return None
# otherwise, find the largest contour in the cell and create a mask for the contour
c = max(cnts, key=cv2.contourArea)
mask = np.zeros(thresh.shape, dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1)
(h, w) = thresh.shape
percentFilled = cv2.countNonZero(mask) / float(w * h)
# if less than 3% of the mask is filled then we are looking at noise and can safely ignore the contour
if percentFilled < 0.03:return None
# apply the mask to the thresholded cell
digit = cv2.bitwise_and(thresh, thresh, mask=mask)
kernel = np.ones((1,1),np.uint8)
digit = cv2.dilate(digit,kernel,iterations=1)
# return the digit to the calling function
return digit
def display_numbers_on_board(board,puzzle):
x = puzzle.copy()
k = 0
for i in range(9):
for j in range(9):
startX,startY,endX,endY = cell_locs[k]
testX = int((endX - startX) * 0.33)
testY = int((endY - startY) * -0.2)
testX += startX
testY += endY
cv2.putText(x,str(board[i][j]),(testX,testY),cv2.FONT_HERSHEY_SIMPLEX,0.9,(0,0,255),2)
k+=1
plt.figure(figsize=(10,8))
plt.imshow(x)
plt.xticks([])
plt.yticks([])
plt.show()
return x
img = cv2.imread(img_path)
img = imutils.resize(img,width=600)
puzzle,warped = find_puzzle(img)
puzzle = imutils.resize(puzzle,width=600)
warped = imutils.resize(warped,width=600)
step_x = warped.shape[1]//9
step_y = warped.shape[0]//9
board = np.zeros(shape=(9,9),dtype='int')
cell_locs = []
for i in range(9):
for j in range(9):
topleftx = j*step_x
toplefty = i*step_y
rightendx= (j+1)*step_x
rightendy = (i+1)*step_y
cell = warped[toplefty:rightendy, topleftx:rightendx]
digit = extract_digit(cell)
if digit is not None:
roi = cv2.resize(digit,tuple(img_shape))
roi = roi.astype('float')/255.0
roi = img_to_array(roi)
roi = np.expand_dims(roi,axis=0)
pred = model.predict(roi).argmax(axis=1)[0]
board[i,j] = pred
cell_locs.append([topleftx,toplefty,rightendx,rightendy])
_=display_numbers_on_board(board,puzzle)
while 1:
res = input('Are all numbers predicted correctly? (y/n)')
if res=='n':
cx,cy,ele = input('Input row no, col no, correct element of cell For eg. --> 1 2 1: ').split()
try:
board[int(cx),int(cy)] = int(ele)
except:
print('out of range...')
_ = display_numbers_on_board(board,puzzle)
elif res=='y':
break
else:
print('Wrong choice!!!')
solved = solveSudoku(board)
x = display_numbers_on_board(board,puzzle)
cv2.imshow('solved',x)
cv2.waitKey(0)
cv2.destroyAllWindows()