def drawSquaresOnTriangleCells(image, triangle_contours): # Converting the triangle contours into squares for cnt in triangle_contours: # todo: delete if (False): simage = convertToColor(image) simage = cv2.drawContours(simage, [cnt], -1, (0, 255, 0), 5) show(simage) # curr vars cX, cY = getContourCenter(cnt) approx = getContourApprox(cnt) middleVertex, isUpper = getMiddleVertex(approx, (cX, cY)) # twin twin = getTwinContour(cnt, triangle_contours) twinCenterX, twinCenterY = getContourCenter(twin) twinApprox = getContourApprox(twin) twinMiddleVertex, twinIsUpper = getMiddleVertex( twinApprox, (twinCenterX, twinCenterY)) # upper if (isUpper and not twinIsUpper): rightVertex = getRightVertex(approx, middleVertex) leftVertex = getLeftVertex(approx, middleVertex) twinRightVertex = getRightVertex(twinApprox, twinMiddleVertex) twinLeftVertex = getLeftVertex(twinApprox, twinMiddleVertex) topLeft = getTopLeft(leftVertex, twinLeftVertex) bottomRight = getBottomRight(rightVertex, twinRightVertex) # Drawing a square image = drawSquare(image, topLeft, middleVertex[0], bottomRight, twinMiddleVertex[0]) # cv2.circle(image, (topLeft[0], topLeft[1]), 20, (255, 0, 0), -1) # cv2.circle(image, (bottomRight[0], bottomRight[1]), 20, (0, 0, 255), -1) # lower # else: # cv2.circle(image, (middleVertex[0][0], middleVertex[0][1]), 20, (255, 255, 0), -1) # Handling square cells boardSize = image.shape[0] * image.shape[1] # getting all square contours square_contours = getAllSquares(getAllContours(image)) square_contours = list( filter(lambda x: containsAnyContour(x, triangle_contours), square_contours)) # filter the board contour if exists square_contours = list( filter(lambda x: not checkIfFarBiggerThanAreaSize(boardSize, x), square_contours)) # filter contours very below the average (noise contour) contourAvgSize = sum(cv2.contourArea(item) for item in square_contours) / float( len(square_contours)) square_contours = list( filter(lambda x: not checkIfVeryBelowAreaSize(contourAvgSize, x), square_contours)) return square_contours
def handleSquareCells(origCropedImage, squares, triangles): blockedCells, regularCells = [], [] image = convertToGray(origCropedImage.copy()) if (False): stam = convertToColor(image.copy()) stam = cv2.drawContours(stam, squares, -1, (255, 0, 0), 3) show(stam) # excluding all lines and other contours which are not cell square nativeSquares = list( filter(lambda x: not containedByOtherContour(x, squares), squares)) # getting all squares which doesn't contain triangles nativeSquares = list( filter(lambda x: not containsAnyContour(x, triangles), nativeSquares)) if (False): stam = convertToColor(image.copy()) stam = cv2.drawContours(stam, nativeSquares, -1, (255, 0, 0), 3) show(stam) # getting all square contours nativeSquares = list( filter( lambda x: not checkIfFarBiggerThanAreaSize( image.shape[0] * image.shape[1], x), nativeSquares)) ret, thresh = cv2.threshold(image, 170, 255, cv2.THRESH_BINARY) border = 5 for square in nativeSquares: if (False): stam = convertToColor(image.copy()) stam = cv2.drawContours(stam, [square], -1, (255, 0, 0), 3) show(stam) x, y, w, h = getRect(square) cell = thresh[y + border:y + h - border, x + border:x + w - border] if percentageOfWhitePixels(cell) > 30: regularCells.append(square) else: blockedCells.append(square) return blockedCells, regularCells
def convertSemiCellsToCells(image): image = convertToGray(image) #show(image) image = postForTriangles(image) #show(image) #TODO: no converting to color if (False): stam1 = getAllSquares(getAllContours(image)) stam = convertToColor(image) stam = cv2.drawContours(stam, stam1, -1, (0, 255, 0), 5) show(stam) # getting all triangle contours triangle_contours = getAllTriangles(getAllContours(image)) if (False): stam = convertToColor(image) stam = cv2.drawContours(stam, triangle_contours, -1, (0, 255, 0), 5) show(stam) if (len(triangle_contours) == 0): return image, triangle_contours # filter contours very below the average (noise contour) contourAvgSize = sum(cv2.contourArea(item) for item in triangle_contours) / float( len(triangle_contours)) triangle_contours = list( filter(lambda x: not checkIfVeryBelowAreaSize(contourAvgSize, x), triangle_contours)) if (False): simage = convertToColor(image) simage = cv2.drawContours(simage, triangle_contours, -1, (0, 255, 0), 5) show(simage) onlyTriangleSquares = drawSquaresOnTriangleCells(image, triangle_contours) return onlyTriangleSquares, triangle_contours
def getGrid(image, mode): boardCopy = image.copy() # Handling semi cells (triangles) triangles, trianglesDivided = convertSemiCellsToCells(boardCopy.copy()) if (False): # image = convertToColor(image) ssimage = cv2.drawContours(boardCopy, triangles, -1, (255, 0, 0), 3) show(ssimage) if (len(triangles) == 0): #print("Invalid board. number of triangles is: " + str(len(triangles) / 2)) isSquareBoard = False return isSquareBoard, None, None, None #image = convertToGray(boardCopy) #image = threshPost(image)#threshPostAllSquares(image) image = postForTriangles(convertToGray(image)) #show(image) # Handling square cells boardSize = image.shape[0] * image.shape[1] # getting all square contours square_contours = getAllSquares(getAllContours(image)) # filter the board contour if exists square_contours = list( filter(lambda x: not checkIfFarBiggerThanAreaSize(boardSize, x), square_contours)) square_contours = list( filter(lambda x: areaBiggerThan(20 * 20, x), square_contours)) # filter contours very below the average (noise contour) contourAvgSize = sum(cv2.contourArea(item) for item in square_contours) / float( len(square_contours)) regularCells = list( filter(lambda x: not checkIfVeryBelowAreaSize(contourAvgSize, x), square_contours)) if (False): # image = convertToColor(image) ssimage = cv2.drawContours(boardCopy, regularCells, -1, (255, 0, 0), 3) show(ssimage) image = postForBlocked(convertToGray(boardCopy), 90, mode) #show(image) # getting all square contours blockedCells = getAllSquares(getAllContours(image)) if (False): stam = cv2.drawContours(boardCopy, blockedCells, -1, (0, 255, 0), 5) show(stam) # filter the board contour if exists blockedCells = list( filter(lambda x: not checkIfFarBiggerThanAreaSize(boardSize, x), blockedCells)) # filter contours very below the average (noise contour) contourAvgSize = sum(cv2.contourArea(item) for item in blockedCells) / float(len(blockedCells)) blockedCells = list( filter(lambda x: not checkIfVeryBelowAreaSize(contourAvgSize, x), blockedCells)) # excluding other squares blockedCells = list( filter(lambda x: not containsAnyContour(x, regularCells), blockedCells)) if (False): stam = cv2.drawContours(boardCopy, blockedCells, -1, (0, 255, 0), 5) show(stam) allCells = blockedCells + regularCells + triangles rootSize = math.sqrt(len(allCells)) kakuroSize = int(rootSize) if (rootSize != kakuroSize): #print("Invalid board.") #print("number of regular squares is: " + str(len(regularCells))) #print("number of blocking squares is: " + str(len(blockedCells))) #print("number of triangles is: " + str(len(triangles) / 2)) isSquareBoard = False return isSquareBoard, None, None, None else: isSquareBoard = True #print("The board is square of " + str(kakuroSize) + "x" + str(kakuroSize)) if (kakuroSize != 9): isSquareBoard = True return isSquareBoard, None, None, getSolvedJson(kakuroSize) gridCells = getBoardGrid(kakuroSize, allCells) if gridCells == None: isSquareBoard = False return isSquareBoard, None, None, None mnistCells = [] boardCells = [] for i in range(0, kakuroSize): lineCells = [] for j in range(0, kakuroSize): alon = (i, j) result = readCellFromImage( boardCopy, image, gridCells[i][j], (regularCells, blockedCells, trianglesDivided), alon) if (result['valid'] == False): #print("Invalid cell on [" + str(i + 1) + "][" + str(j + 1) + "]") isSquareBoard = False return isSquareBoard, None, None, None else: if ('block' in result): lineCells.append({'block': True}) else: cell = result['cell'] if (cell['value']['hasValue'] == True): lineCells.append({ 'cellType': cell['cellType'], 'value': cell['value'] }) else: mnistCell = (i, j, cell) mnistCells.append(mnistCell) lineCells.append(None) boardCells.append(lineCells) mnistResults = getDigitsFromImages(mnistCells) for cell in mnistResults: i, j, cellType, value = cell['row'], cell['col'], cell['type'], cell[ 'value'] if (boardCells[i][j] == None): boardCell = {} if cellType == 'square': boardCell['cellType'] = 'square' boardCell['value'] = value elif cellType == 'upper': boardCell['cellType'] = 'triangle' boardCell['value'] = {'upper': {'data': value}} elif cellType == 'bottom': boardCell['cellType'] = 'triangle' boardCell['value'] = {'bottom': {'data': value}} boardCells[i][j] = boardCell else: if (cellType == 'square' or (cellType == 'upper' and 'upper' in boardCells[i][j]['value']) or (cellType == 'bottom' and 'bottom' in boardCells[i][j]['value'])): print('Wrong cell input.') isSquareBoard = False return isSquareBoard, None, None, None elif (cellType == 'upper'): boardCells[i][j]['value']['upper'] = {'data': value} elif (cellType == 'bottom'): boardCells[i][j]['value']['bottom'] = {'data': value} return isSquareBoard, boardCells, image, None
def readCellFromImage(origImage, image, cell, allCells, alon): (regularCells, blockCells, triangles) = allCells (contour, rect) = cell if (False): simage = cv2.drawContours(origImage, [contour], -1, (0, 255, 0), 5) show(simage) trianglesInCell = [] for triangle in triangles: if (False): simage = cv2.drawContours(origImage, [triangle], -1, (0, 255, 0), 5) show(simage) triangleCenter = getContourCenter(triangle) if (isPointInContour(triangleCenter, contour)): trianglesInCell.append({ 'contour': triangle, 'center': triangleCenter }) # native square, no triangles if (len(trianglesInCell) == 0): isBlockCell = False for blockCell in blockCells: blockCenter = getContourCenter(blockCell) if (isPointInContour(blockCenter, contour)): isBlockCell = True break if (isBlockCell): return {'valid': True, 'block': True} else: value = handleDigitsFromImage(origImage, image, contour, True, alon) return { 'valid': True, 'cell': { 'cellType': 'square', 'value': value } } elif (len(trianglesInCell) == 2): center1, center2 = trianglesInCell[0]['center'], trianglesInCell[1][ 'center'] # if the triangles are not bottom left and upper right if ((center1[0] < center2[0] and center1[1] < center2[1]) or (center2[0] < center1[0] and center2[1] < center1[1])): return {'valid': False} else: if (center1[0] < center2[0] and center1[1] > center2[1]): bottomLeftTriangle = trianglesInCell[0]['contour'] upperRightTriangle = trianglesInCell[1]['contour'] else: bottomLeftTriangle = trianglesInCell[1]['contour'] upperRightTriangle = trianglesInCell[0]['contour'] bottomValue = handleDigitsFromImage(origImage, image, bottomLeftTriangle, False, alon) upperValue = handleDigitsFromImage(origImage, image, upperRightTriangle, False, alon) return { 'valid': True, 'cell': { 'cellType': 'triangle', 'value': { 'hasValue': bottomValue['hasValue'] and upperValue['hasValue'], 'bottom': bottomValue, 'upper': upperValue } } } else: return {'valid': False}