Skip to content

samuelpratt/Sudoku

Repository files navigation

Sudoku Solver

How do I install it?

https://play.google.com/store/apps/details?id=uk.co.samuelpratt.sudoku

What is this?

Sam's free time project to write a simple Android Sudoku solver App.

The idea is that you will be able to take a picture of the puzzle and the App will extract the puzzle from the image and then solve it.

It doesn't look polished

Please bear in mind that I'm: -

  1. Not an App developer
  2. Not a graphic designer

so please don't judge me too much :-) I know this looks a bit rough! The point was for me to have a play with some fun technologies rather than to produce a polished commercial App.

How does it work?

Extracting the puzzle from the image

This is by far the hardest part. The two best articles I found on this are: -

Cleaning up the image

This involves: -

  • Removing colour
  • Thresholding the image to make it binary using an adaptive threshold to deal with shadows and variations in light
  • Eroding the image (effectivly expanding lines) to fill in small gaps

Finding the Grid

Algorthm

This involves: -

Issues that can occur

The two main issues we get are: -

  • Sometimes the Hough transform detects the edge of the image. Hence the agorthm will discard any lines running within 1 degree of parallel to the edge of the image within 5px of the edge

  • Sometimes the Hough transform detects the diagnoals of the grid as an edge as these go through the corners they tend to get detected as the lowest point in the image. We therefore disguard any lines more than 7 degrees from either Horizontal or Vertical.

Both of these issues can be seen below: -

Extracting the Puzzle

This involves : -

Parsing the Puzzle

Getting the digits

To do this you need to chop the puzzle up into 9x9 chunks. As the digits probably aren't exactly in the right place I've added a border around each area.

The first row is shown below: -

1 2 3 4 5 6 7 8 9

However, as you can see, there are alot of artefacts from bits of the grid and noise that the thresholding didn't remove. These tend to cause issues with the OCR as it thinks some of the larger ones are numbers.

We can help by again removing all but the biggest blob (interconnected area) as this should be the number. If the largest blob is less than a given threshold (currently 1%) of the square it's probably not a number and just an artefact in a blank square so we delete this as well.

The results are shown below: -

1 2 3 4 5 6 7 8 9

Recognising the digits

This is done using Tess-Two (https://github.com/rmtheis/tess-two). All we do is feed the extracted digits into the parser.

In order to assist recognition we hint Tess-Two and tell it we're only expecting numbers

tessBaseAPI.setVariable("tessedit_char_whitelist", "0123456789");

We have to do a little bit of work to convert the OpenCv Mat into a format that Tess-Two understands.

Mat squareMat = getMatForPosition(x, y);

Bitmap squareBmp = Bitmap.createBitmap(squareMat.cols(), squareMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(squareMat, squareBmp);

tessBaseAPI.setImage(squareBmp);
String textFound = tessBaseAPI.getUTF8Text();

Solving the puzzle.

This is pretty easy. You can use a backtracking algorithm which will effectivly brute force the solution by trying every possible combination of numbers until it finds a solution that satisfies the constraints. See the followng links for more information: -

How to build it

Environment

You will need: -

  • Android Studio
  • Android SDK 25 (Nougat)
  • The Android Emulator
  • OpenCV (see below)
  • NDK (see below)
  • Tess-Two (see below)

Installing OpenCV

As I didn't want to check this in you will need to do the following: -

apply plugin: 'com.android.library'

buildscript {
    repositories {
        mavenCentral()
    }
}

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.1"

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 25

        versionCode 3100
        versionName "3.1.0"
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            res.srcDirs = ['res']
            aidl.srcDirs = ['src']
        }
    }
}

Tess-Two

You don't need to do anything to include the library other than add a Mavern reference to it in the build.gradle of the assembly it's used in i.e. : -

compile 'com.rmtheis:tess-two:6.1.1'

However if you want to use this there's a bit of work in getting everything set up correctly as you need to copy the training data to a local directory. I followed the tutorial here http://imperialsoup.com/2016/04/29/simple-ocr-android-app-using-tesseract-tutorial/

The training data is from https://github.com/tesseract-ocr/tessdata. I've only included the english file i.e. https://github.com/tesseract-ocr/tessdata/blob/master/eng.traineddata

//TODO:

  • Work out how to create a basic Android App
  • Take a picture and show a preview
  • Get the image from the SD Card (look at https://developer.android.com/training/camera/photobasics.html#TaskPath)
  • Analyse the image to find the Sudoku grid (See below)
  • Extract the Puzzle and read the numbers from the Sudoku grid
  • Solve the puzzle
  • Wire it all up into a working App
  • Redesign the take a picture activity as it's currently ugly
  • Make it a bit more robust: -
    • Fix the orientation of the Camera
    • Validate the puzzle before we try and solve it
    • Fix the bug where the app crashes when you quit the camera
    • Fix the bug when the PuzzleNotFoundException isn't caught properly when the digits are being extracted
    • Work out why it's crashing when started from the debugger
    • Work out what's going on with the solver: it works from unit tests but returns bad results from the app
  • Upload the app onto the play store
    • Fix the namespace (com.sudoku is taken)
    • Generate the required banner and hi-res icons

Releases

No releases published

Packages

No packages published

Languages