Keep Moving Forward

Friday, May 11, 2018

Seedr - A convenient way to download torrent files online

3:53 PM Posted by Cáp Hữu Quân 1 comment
In this article, I will show you the easy way to download torrent files by using Seedr with Internet Download Manager (IDM).
Peer-2-peer is still going strong and being used by so many users all around the world. Sadly, many network organizations around you block the use of torrent software as it is a huge drain on the network because it connects to many other computers at the same time.
Normally, your ISPs throttle torrents and slow them to a crawl of only a few KB/s. Lucily, the Seedr service can help you to get rid of this restriction.


Seedr is an online torrent client that helps you get the torrent file without installing any torrent client on your PC. It bypasses and keeps you safe from anti-P2P organizations monitoring copyright infringing torrents. Seedr accepts local torrent files, magnet links or a URL of a remote torrent file. You can only transfer one torrent at a time to the Seedr servers but can download multiple completed torrents from Seedr. There’s also a Seedr Chrome extension  for directly adding links.

Currently, Seedr provides the default limit storage 2GB for maximum size of the torrent file you can download. However, you can increase up to over 6GB by accomplishing tasks such as inviting friends, posting a review on Tweeter, or pinning a Seedr image on your Pinterest.
After finishing registration account, you can visit this link to see how you can get the additional storage: https://www.seedr.cc/dynamic/get_space

Download torrent file using Seedr and IDM

First step you need to do is to get the torrent file or link. In this example, I will try to find a torrent link at http://thepiratebay.org/
Let's find an interesting movie. This time, I found Avengers: Age of Ultron with this link: https://thepiratebay.org/torrent/12384452/Avengers__Age_of_Ultron_(2015)_1080p_BrRip_x264_-_YIFY

Next, login to your Seedr account and add ("+" button) the above link to start downloading.


Seedr will fetch your torrent and the result will be

Final step, just click download button and start downloading the torrent file with IDM.

You can also remove the torrent file from your Seedr file if necessary to save storage for next torrent file.
That's all, it's easy as pie! Hope this helps and good luck :) 



Sunday, August 13, 2017

Building a simple SUDOKU Solver from scratch - Part 3: Putting in together

12:16 AM Posted by Cáp Hữu Quân 1 comment
Hi all,
First of all, I am so sorry for keeping you waiting.
I've just finished my second semester and came back for a long trip from Viet Nam.

In part 2 of this series (See part 2), we've discussed how to recognize number from each cell in SUDOKU grid. Now, with the help of SVM, we can easily extract the digit number from SUDOKU image. Base on that recognition result, we can solve the SUDOKU grid by using a backtracking method.

But first, let's form the recognition result to the matrix for more easier to solve.
The recognition result of a SUDOKU picture will be formed as a matrix like an example below.
Fig 1. SUDOKU picture

[0  9  7  0  5  0  2  1  0]
[0  0  0  0  8  0  1  0  0]
[0  0  2  0  9  7  0  6  3]
[0  6  0  0  0  0  3  0  9]
[3  0  0  4  1  9  0  0  6]
[7  0  9  0  0  0  0  2  0]
[8  3  0  2  4  0  9  0  0]
[0  0  6  0  3  0  0  0  0]
[0  5  4  0  7  0  6  3  0]
Matrix of result after recognition (0 means the cell is empty)

Now, we have the result of recognition as a matrix. Next step, we will solve SUDOKU problem base on that result.
The easiest solution to solve SUDOKU matrix is using the Backtracking algorithm.
We can solve SUDOKU by one by one assigning numbers to empty cells. Before assigning a number, we check whether it is safe to assign. We basically check that the same number is not present in current row, current column and current 3X3 subgrid. After checking for safety, we assign the number, and recursively check whether this assignment leads to a solution or not. If the assignment doesn’t lead to a solution, then we try next number for current empty cell. And if none of number (1 to 9) lead to solution, we return false.

This post used the idea from page: http://www.geeksforgeeks.org/backtracking-set-7-suduku/ to solve the SUDOKU problem. I don't have time to explain what backtracking is but I wish I could have time to write an article about basic of backtracking.

Here is the code for solving SUDOKU problem

import numpy as np
#Finding unsige cell
#File name: SUDOKU.py
def FindUnsignedLocation(Board, l):
    for row in range(0,9):
        for col in range(0,9):
            if (Board[row][col] == 0):
                l[0] = row
                l[1] = col
                return True
    return False

# Hàm kiểm tra tính an toàn của những ô trong hàng
def InRow(Board, row, num):
    for i in range(0,9):
        if (Board[row][i] == num):
            return True
    return False

# Hàm kiểm tra tính an toàn của những ô trong cột
def InCol(Board, col, num):
    for i in range(0,9):
        if (Board[i][col] == num):
            return True
    return False

# Hàm kiểm tra tính an toàn của các ô trong một ô lớn 3x3
def InBox(Board, row, col, num):
    for i in range(0,3):
        for j in range(0,3):
            if (Board[i + row][j + col] == num):
                return True
    return False

# Kiểm tra trạng thái an toàn tại một vị trí
def isSafe(Board, row, col, num):
    return not InCol(Board, col, num) and not InRow(Board, row, num) and not InBox(Board, row - row % 3, col - col % 3, num)

def SolveSudoku(Board):
    l=[0,0]
    if (not FindUnsignedLocation(Board, l)):
        return True
    row = l[0]
    col = l[1]
    for num in range(1,10):
        if (isSafe(Board, row, col, num)):
            Board[row][col] = num
            if (SolveSudoku(Board)):
                print Board
                break
            Board[row][col] = 0
    return False

Board = [[0, 9, 7, 0, 5, 0, 2, 1, 0],
 [0, 0, 0, 0, 8, 0, 4, 0, 0],
 [0, 0, 2, 0, 9, 7, 0, 6, 3],
 [0, 6, 0, 0, 0, 0, 3, 0, 9],
 [3, 0, 0, 4, 1, 9, 0, 0, 6],
 [7, 0, 9, 0, 0, 0, 0, 2, 0],
 [8, 3, 0, 2, 4, 0, 9, 0, 0],
 [0, 0, 6, 0, 3, 0, 0, 0, 0],
 [0, 5, 4, 0, 7, 0, 6, 3, 0]]

SolveSudoku(Board)

We use the 9x9 matrix as an input of the above code. You can test with your own matrix with the above code to see the code runs properly.

Combine with the code in Part 2 and the code above. We can now solve the SUDOKU and show the result like this.

Here is the final code

import cv2
import numpy as np
import joblib
import SUDOKU

font = cv2.FONT_HERSHEY_SIMPLEX
ratio2 = 3
kernel_size = 3
lowThreshold = 30
count = 1
clf = joblib.load('classifier.pkl')

is_print = True

cv2.namedWindow("SUDOKU Solver")
vc = cv2.VideoCapture(0)
if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
while rval:
    sudoku1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    sudoku1 = cv2.blur(sudoku1, (1,1))
    edges = cv2.Canny(sudoku1, lowThreshold, lowThreshold*ratio2, kernel_size)
    lines = cv2.HoughLines(edges, 2, cv2.cv.CV_PI /180, 300, 0, 0)
    if (lines is not None):
        lines = lines[0]
        lines = sorted(lines, key=lambda line:line[0])
        diff_ngang = 0
        diff_doc = 0
        lines_1=[]
        Points=[]
        for rho,theta in lines:
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            x1 = int(x0 + 1000*(-b))
            y1 = int(y0 + 1000*(a))
            x2 = int(x0 - 1000*(-b))
            y2 = int(y0 - 1000*(a))
            if (b>0.5):
                if(rho-diff_ngang>10):
                    diff_ngang=rho
                    lines_1.append([rho,theta, 0])
            else:
                if(rho-diff_doc>10):
                    diff_doc=rho
                    lines_1.append([rho,theta, 1])
        for i in range(len(lines_1)):
            if(lines_1[i][2] == 0):
                for j in range(len(lines_1)):
                    if (lines_1[j][2]==1):
                        theta1=lines_1[i][1]
                        theta2=lines_1[j][1]
                        p1=lines_1[i][0]
                        p2=lines_1[j][0]
                        xy = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
                        p = np.array([p1,p2])
                        res = np.linalg.solve(xy, p)
                        Points.append(res)

        if(len(Points)==100):
            result = []
            board = []
            sudoku1 = cv2.adaptiveThreshold(sudoku1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 101, 1)
            for i in range(0,9):
                for j in range(0,9):
                    y1=int(Points[j+i*10][1]+5)
                    y2=int(Points[j+i*10+11][1]-5)
                    x1=int(Points[j+i*10][0]+5)
                    x2=int(Points[j+i*10+11][0]-5)
                    X = sudoku1[y1:y2,x1:x2]
                    if(X.size!=0):
                        X = cv2.resize(X, (36,36))
                        num = clf.predict(np.reshape(X, (1,-1)))
                        
                        #Collect the result
                        result.append(num)
                        board.append(num)

            # Reshape to 9x9 matrix
            result = np.reshape(result, (9,9))
            board = np.reshape(board, (9,9))
            
            # Solve the SUDOKU grid
            if(SUDOKU.SolveSudoku(result)):
                # If it can solve SUDOKU matrix, show the result
                for i in range(0,9):
                    for j in range(0,9):
                        if(array[i][j]==0):
                            cv2.putText(frame,str(result[i][j]),(int(Points[j+i*10+10][0]+15), 
                                                                 int(Points[j+i*10+10][1]-10)),font,1,(225,0,0),2)
                # Show the result picture
                cv2.imshow("Result", frame)
                
    cv2.imshow("SUDOKU Solver", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
vc.release()
cv2.destroyAllWindows()


Here is the end of this SUDOKU Solver series.
It's just the simple SUDOKU solver by taking pictures. I hope that you can improve this method or think about the new thing of applying machine learning and computer vision.

If you have any questions or comments, please feel free to contact me by email of Facebook.
All the training data and source code can be found in this GitHub link: https://github.com/huuquan1994/Sudoku-Solver

Enjoy your time!

References

Sunday, April 23, 2017

Building a simple SUDOKU Solver from scratch - Part 2: Digit Number Recognition using SVM

11:30 PM Posted by Cáp Hữu Quân , , 1 comment
Hello everyone, in this post, we will continue the previous tutorial to recognize digital number were extracted from SUDOKU board. See part 1
In part 1 of this tutorial, we learned how to detect lines and extract the digital number from the SUDOKU board. I think we can easily extract digital number and save it as images by using Python code from part 1. (Uncomment the code from Part 1 to save your own digit blocks). Now, we will talk about training those extracted digital numbers with SVM

With the code in Part 1, we can easily save more than 1 thousand digit blocks in a second. Maybe looks like this:

To train the dataset with a supervised machine learning method like SVM, we need to label the dataset beforehand. With this dataset, we have 10 label (from 0 -> 9). So, the idea is that we will create 10 folders with the name from 0 to 9 and put each image into the corresponding folder.
It's quite cost the time because we have a lot of images and we need to process those images by hand :(
Don't worry! I already created a labeled dataset for you. Check out my GitHub repository to download them: https://github.com/huuquan1994/Sudoku-Solver 
I divided it into 2 parts, training set and testing set. 5000 images in training set (500 images in each folder) and ~3000 test images in testing set.
The training set folder will look like this:

Folder with label as 1 

We have all we need! Now, let's train SVM to recognize digital number.
We will use LinearSVM in Sklearn to train the dataset, using joblib to save the SVM model after training.
For training, first, we resize the size of each training image to [36x36]. After that, we train those resized images with LinearSVM. You can see the code below


import numpy as np
from sklearn.svm import LinearSVC
import os
import cv2
import joblib

# Generate training set
TRAIN_PATH = "Dataset\Train"
list_folder = os.listdir(TRAIN_PATH)
trainset = []
for folder in list_folder:
    flist = os.listdir(os.path.join(TRAIN_PATH, folder))
    for f in flist:
        im = cv2.imread(os.path.join(TRAIN_PATH, folder, f))
        im = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY )
        im = cv2.resize(im, (36,36))
        trainset.append(im)
# Labeling for trainset
train_label = []
for i in range(0,10):
    temp = 500*[i]
    train_label += temp

# Generate testing set
TEST_PATH = "Dataset\Test"
list_folder = os.listdir(TEST_PATH)
testset = []
test_label = []
for folder in list_folder:
    flist = os.listdir(os.path.join(TEST_PATH, folder))
    for f in flist:
        im = cv2.imread(os.path.join(TEST_PATH, folder, f))
        im = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY )
        im = cv2.resize(im, (36,36))
        testset.append(im)
        test_label.append(int(folder))
trainset = np.reshape(trainset, (5000, -1))

# Create an linear SVM object
clf = LinearSVC()

# Perform the training
clf.fit(trainset, train_label)
print("Training finished successfully")

# Testing
testset = np.reshape(testset, (len(testset), -1))
y = clf.predict(testset)
print("Testing accuracy: " + str(clf.score(testset, test_label)))

joblib.dump(clf, "classifier.pkl", compress=3)

After training, we will have a SVM model named: "classifier.pkl". We can use this file to recognize block images.

See this code for more details:

import cv2
import numpy as np
import joblib

font = cv2.FONT_HERSHEY_SIMPLEX
ratio2 = 3
kernel_size = 3
lowThreshold = 30

clf = joblib.load('classifier.pkl')

is_print = True

cv2.namedWindow("SUDOKU Solver")
vc = cv2.VideoCapture(0)
if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
while rval:
    sudoku1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    sudoku1 = cv2.blur(sudoku1, (1,1))
    edges = cv2.Canny(sudoku1, lowThreshold, lowThreshold*ratio2, kernel_size)
    lines = cv2.HoughLines(edges, 2, cv2.cv.CV_PI /180, 300, 0, 0)
    if (lines is not None):
        lines = lines[0]
        lines = sorted(lines, key=lambda line:line[0])
        diff_ngang = 0
        diff_doc = 0
        lines_1=[]
        Points=[]
        for rho,theta in lines:
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            x1 = int(x0 + 1000*(-b))
            y1 = int(y0 + 1000*(a))
            x2 = int(x0 - 1000*(-b))
            y2 = int(y0 - 1000*(a))
            if (b>0.5):
                if(rho-diff_ngang>10):
                    diff_ngang=rho
                    lines_1.append([rho,theta, 0])
            else:
                if(rho-diff_doc>10):
                    diff_doc=rho
                    lines_1.append([rho,theta, 1])
        for i in range(len(lines_1)):
            if(lines_1[i][2] == 0):
                for j in range(len(lines_1)):
                    if (lines_1[j][2]==1):
                        theta1=lines_1[i][1]
                        theta2=lines_1[j][1]
                        p1=lines_1[i][0]
                        p2=lines_1[j][0]
                        xy = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
                        p = np.array([p1,p2])
                        res = np.linalg.solve(xy, p)
                        Points.append(res)
        if(len(Points)==100):
            sudoku1 = cv2.adaptiveThreshold(sudoku1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 101, 1)
            for i in range(0,9):
                for j in range(0,9):
                    y1=int(Points[j+i*10][1]+5)
                    y2=int(Points[j+i*10+11][1]-5)
                    x1=int(Points[j+i*10][0]+5)
                    x2=int(Points[j+i*10+11][0]-5)
                    X = sudoku1[y1:y2,x1:x2]
                    if(X.size!=0):
                        X = cv2.resize(X, (36,36))
                        num = clf.predict(np.reshape(X, (1,-1)))
                        if (num[0] != 0):
                            cv2.putText(frame,str(num[0]),(int(Points[j+i*10+10][0]+10), 
                                                                     int(Points[j+i*10+10][1]-30)),font,1,(225,0,0),2)
                        else:
                            cv2.putText(frame,str(num[0]),(int(Points[j+i*10+10][0]+10), 
                                                                 int(Points[j+i*10+10][1]-15)),font,1,(225,0,0),2)
    cv2.imshow("SUDOKU Solver", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
vc.release()
cv2.destroyAllWindows()

Yeahhhh! Now we know how to train a machine learning method and recognize a digital image. The next article, we will discuss how to solve a SUDOKU matrix by backtracking algorithm.
If you have any questions or comments, please let me know. See ya :)

Sunday, April 9, 2017

Building a simple SUDOKU Solver from scratch - Part 1: Grid Detection & Digit Extraction

10:34 PM Posted by Cáp Hữu Quân , 8 comments
Hi there, today I'm gonna explain how to build a simple SUDOKU Solver by taking the image step-by-step. The result of SUDOKU will be shown in the current image just like this GIF image.

To build this program, we will go through 4 main steps.

1. SUDOKU Grid Detection and Digit Extraction
2. Recognize Number with Support Vector Machine (SVM)
3. Solving SUDOKU with Backtracking Algorithm
4. Completing the simple SUDOKU Solver

This program was built by Python 2.7 and OpenCV 2.4.13 so before you want to follow this post, please install Python 2.7 and OpenCV 2.4.13

1. SUDOKU Gird Detection and Digit Extraction

The most important thing to solve a SUDOKU grid by taking image is detecting SUDOKU grid (or line) on the image. I found many ways to extract digit from SUDOKU on the internet, but I saw this article (http://jponttuset.cat/solving-sudokus-like-a-pro-1/) is the smartest and easy way to extract digit from SUDOKU board. I took the idea from that guy and re-implement by myself in Python.
So, let's get started!

We will use a famous and simple technique called Hough Line Transform to detect lines on the image. If you're not familiar with Hough Line Transform, please check out my previous article about Hough Line Transform 

Note: We can visit this website to print any SUDOKU image for practicing: http://show.websudoku.com/
From a frame in the video, we will convert from RGB to Gray Scale image. After that, using Canny Edge detection to extract edges from images. And then apply Hough Line Transform to detect lines on the image. We use cv2.HoughLines() with `rho` unit `= 2` and minimum length of line to be detected is `300` pixels. It means increasing the accumulator by `2` when a point is satisfied and consider to be a line when the minimum value in the accumulator is `300`.
We will have the result like this:
Fig 1. Line detection using Hough Line Transform
The next step is looking for intersections between these lines. When we know the intersection points, we can extract every block that contains SUDOKU digit.
But wait... Look at that! There are too many lines. Synonymous with there are some redundant lines (some lines are close together). We know the distance of each line to the origin so we can easily remove the redundant lines if the distance of these lines is close together.
Let's say we will remove the redundant lines if the distance between these lines is less than 10.
Firstly, let's sort these line increasingly by the distance (`rho`) and then check the distance of every 2 lines. If the distance is less than 10, remove the second line.
You can read the following code


# HOW TO USE
# Use this with a printed SUDOKU Grid
# Press ESC key to Exit
import cv2
import numpy as np

ratio2 = 3
kernel_size = 3
lowThreshold = 30

cv2.namedWindow("SUDOKU Solver")
vc = cv2.VideoCapture(0)
if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
while rval:
 # Preprocess image, convert from RGB to Gray
    sudoku1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    sudoku1 = cv2.blur(sudoku1, (3,3))
    # Apply Canny edge detection
    edges = cv2.Canny(sudoku1, lowThreshold, lowThreshold*ratio2, kernel_size)
    # Apply Hough Line Transform, return a list of rho and theta
    lines = cv2.HoughLines(edges, 2, cv2.cv.CV_PI /180, 300, 0, 0)
    if (lines is not None):
        lines = lines[0]
        lines = sorted(lines, key=lambda line:line[0])
        # Define the position of horizontal and vertical line
        pos_hori = 0
        pos_vert = 0
        for rho,theta in lines:
         a = np.cos(theta)
         b = np.sin(theta)
         x0 = a*rho
         y0 = b*rho
         x1 = int(x0 + 1000*(-b))
         y1 = int(y0 + 1000*(a))
         x2 = int(x0 - 1000*(-b))
         y2 = int(y0 - 1000*(a))
         # If b > 0.5, the angle must be greater than 45 degree
         # so we consider that line as a vertical line
         if (b>0.5):
          # Check the position
          if(rho-pos_hori>10):
           # Update the position
           pos_hori=rho
           cv2.line(frame,(x1,y1),(x2,y2),(0,0,255),2)
         else:
          if(rho-pos_vert>10):
           pos_vert=rho
           cv2.line(frame,(x1,y1),(x2,y2),(0,0,255),2)

    # Show the result        
    cv2.imshow("SUDOKU Solver", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
     break
vc.release()
cv2.destroyAllWindows()

Now, it looks better than Figure 1.
Fig. 2. SUDOKU Grid after removing redundancy lines


Next, we will find the intersection points based on those lines. Just to recap again, every line is satisfied this equation: `rho = xcostheta + ysintheta   (1)`
We have `rho` and `theta` for each line, so we can easily find the intersection between 2 lines by solving linear equations. In this topic, I use linalg library in `Numpy` to find the intersection points.
You can check out this link to see how to use linalg in Python: https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.solve.html

Just change a bit of code and found the intersection points like this
Fig. 3. Intersection points detection

If we have those point, we also can extract the bouding box of the digit number in SUDOKU board like this
Fig. 4. Bounding block for each digit

Here is the code for digit extraction


# HOW TO USE
# Use this with a printed SUDOKU Grid
# Press ESC key to Exit
import cv2
import numpy as np

ratio2 = 3
kernel_size = 3
lowThreshold = 30

cv2.namedWindow("SUDOKU Solver")
vc = cv2.VideoCapture(0)
if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
while rval:
 # Preprocess image, convert from RGB to Gray
    sudoku1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    sudoku1 = cv2.blur(sudoku1, (3,3))
    # Apply Canny edge detection
    edges = cv2.Canny(sudoku1, lowThreshold, lowThreshold*ratio2, kernel_size)
    # Apply Hough Line Transform, return a list of rho and theta
    lines = cv2.HoughLines(edges, 2, cv2.cv.CV_PI /180, 300, 0, 0)
    if (lines is not None):
        lines = lines[0]
        lines = sorted(lines, key=lambda line:line[0])
        # Define the position of horizontal and vertical line
        pos_hori = 0
        pos_vert = 0
        # Create a list to store new bundle of lines
        New_lines = []
        # Store intersection points
        Points = []
        for rho,theta in lines:
         a = np.cos(theta)
         b = np.sin(theta)
         x0 = a*rho
         y0 = b*rho
         x1 = int(x0 + 1000*(-b))
         y1 = int(y0 + 1000*(a))
         x2 = int(x0 - 1000*(-b))
         y2 = int(y0 - 1000*(a))
         # If b > 0.5, the angle must be greater than 45 degree
         # so we consider that line as a vertical line
         if (b>0.5):
          # Check the position
          if(rho-pos_hori>10):
           # Update the position
           pos_hori=rho
           # Saving new line, 0 is horizontal line, 1 is vertical line
           New_lines.append([rho,theta, 0])
         else:
          if(rho-pos_vert>10):
           pos_vert=rho
           New_lines.append([rho,theta, 1])
        for i in range(len(New_lines)):
            if(New_lines[i][2] == 0):
                for j in range(len(New_lines)):
                    if (New_lines[j][2]==1):
                        theta1=New_lines[i][1]
                        theta2=New_lines[j][1]
                        p1=New_lines[i][0]
                        p2=New_lines[j][0]
                        xy = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
                        p = np.array([p1,p2])
                        res = np.linalg.solve(xy, p)
                        Points.append(res)
        if(len(Points)==100):
            sudoku1 = cv2.adaptiveThreshold(sudoku1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 101, 1)
            for i in range(0,9):
                for j in range(0,9):
                    y1=int(Points[j+i*10][1]+5)
                    y2=int(Points[j+i*10+11][1]-5)
                    x1=int(Points[j+i*10][0]+5)
                    x2=int(Points[j+i*10+11][0]-5)
                    # Saving extracted block for training, uncomment for saving digit blocks
                    # cv2.imwrite(str((i+1)*(j+1))+".jpg", sudoku1[y1: y2,
                    #                                            x1: x2])
                    cv2.rectangle(frame,(x1,y1),
                                  (x2, y2),(0,255,0),2)
    # Show the result        
    cv2.imshow("SUDOKU Solver", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
     break
vc.release()
cv2.destroyAllWindows()

To make sure that we extract the right digit block, I set the condition is when the number of intersection points is equal to 100, we extract the point. You can check with the code above.

Bravo! Now we know how to extract digit number block from SUDOKU board. In the next article, we will recognite those digit numbers with Support Vector Machine algorithm :)