text: import numpy as np
  import imutils
  import cv2
  from imutils.perspective import four_point_transform
  from skimage.segmentation import clear_boardrder
  from tensorflow.keras.preprocessing.image import img_to_array
  from tensorflow.keras.models import load_model
  from sudoku import solve,show
  
  
  #to locate the puzzle in image
  def find_puzzle(image):
  
  	# convert the image to grayscale and blur it slightly
  	gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
   
      # apply adaptive thresholding and then invert the threshold map
  	thresh = cv2.adaptiveThreshold(gray, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
  	thresh = cv2.bitwise_not(thresh)
  	
  
      # find contours in the thesholded image and sort them by size in
  	# descending order
  	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)
  	# initialize a contour that corresponds to the puzzle outline
  	puzzleCnt = None
  	# loop over the contours
  	for c in cnts:
  		# approximate the contour
  		peri = cv2.arcLength(c, True)
  		approx = cv2.approxPolyDP(c, 0.02 * peri, True)
  		# if our approximated contour has four points, then we can
  		# assume we have found the outline of the puzzle
  		if len(approx) == 4:
  			puzzleCnt = approx
  			break
      # if the puzzle contour is empty then our script could not find
  	# the outline of the Sudoku puzzle so raise an error
  	if puzzleCnt is None:
  		raise Exception(("Could not find Sudoku puzzle outline. "
  			"Try debugging your thresholding and contour steps."))
  
    # apply a four point perspective transform to both the original
  	# image and grayscale image to obtain a top-down bird's eye view
  	# of the puzzle
  	puzzle = four_point_transform(image, puzzleCnt.reshape(4, 2))
  	warped = four_point_transform(gray, puzzleCnt.reshape(4, 2))
  
  	# return a 2-tuple of puzzle in both RGB and grayscale
  	return (puzzle, warped)
  
  
  #read each cell
  def extract_digit(cell):
  	# apply automatic thresholding to the cell and then clear any
  	# connected borders that touch the border of the cell
  	thresh = cv2.threshold(cell, 0, 255,
  		cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
  	thresh = clear_border(thresh)
  
      # find contours in the thresholded cell
  	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)
      # compute the percentage of masked pixels relative to the total
  	# area of the image
  	(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)
  	# return the digit to the calling function
  	return digit
  
  model = load_model('model.h5')
  (puzzleImage, warped) = find_puzzle(cv2.imread('sudoku_sample.jpg'))
  
  # initialize our 9x9 Sudoku board
  board = np.zeros((9, 9), dtype="int")
  # a Sudoku puzzle is a 9x9 grid (81 individual cells), so we can
  # infer the location of each cell by dividing the warped image
  # into a 9x9 grid
  stepX = warped.shape[1] // 9
  stepY = warped.shape[0] // 9
  # initialize a list to store the (x, y)-coordinates of each cell
  # location
  cellLocs = []
  for y in range(0, 9):
  	# initialize the current list of cell locations
  	row = []
  	for x in range(0, 9):
  		# compute the starting and ending (x, y)-coordinates of the
  		# current cell
  		startX = x * stepX
  		startY = y * stepY
  		endX = (x + 1) * stepX
  		endY = (y + 1) * stepY
  		# add the (x, y)-coordinates to our cell locations list
  		row.append((startX, startY, endX, endY))
          # crop the cell from the warped transform image and then
  		# extract the digit from the cell
  		cell = warped[startY:endY, startX:endX]
  		digit = extract_digit(cell)
  		# verify that the digit is not empty
  		if digit is not None:
  			# resize the cell to 28x28 pixels and then prepare the
  			# cell for classification
  			roi = cv2.resize(digit, (28, 28))
  			roi = roi.astype("float") / 255.0
  			roi = img_to_array(roi)
  			roi = np.expand_dims(roi, axis=0)
  			# classify the digit and update the Sudoku board with the
  			# prediction
  			pred = model.predict(roi).argmax(axis=1)[0]
  			board[y, x] = pred
  	# add the row to our cell locations
  	cellLocs.append(row)
   
  # construct a Sudoku puzzle from the board
  print("[INFO] OCR'd Sudoku board:")
  # show(board)
  print("____________________")
  # show(board)
  # solve the Sudoku puzzle
  print("[INFO] solving Sudoku puzzle...")
  solve(board)
  # loop over the cell locations and board
  for (cellRow, boardRow) in zip(cellLocs,board):
  	# loop over individual cell in the row
  	for (box, digit) in zip(cellRow, boardRow):
  		# unpack the cell coordinates
  		startX, startY, endX, endY = box
  		# compute the coordinates of where the digit will be drawn
  		# on the output puzzle image
  		textX = int((endX - startX) * 0.33)
  		textY = int((endY - startY) * -0.2)
  		textX += startX
  		textY += endY
  		# draw the result digit on the Sudoku puzzle image
  		cv2.putText(puzzleImage, str(digit), (textX, textY),
  			cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 255), 2)
  # show the output image
  cv2.imshow(warped)
  cv2.imshow(puzzleImage)