From eb35ca3333d41080ed15568661b07744f4462374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Ladst=C3=A4tter?= Date: Mon, 18 Jul 2016 21:42:17 +0200 Subject: [PATCH] added template matching test --- .../scala/net/ladstatt/sudoku/SCell.scala | 16 +++++- .../net/ladstatt/sudoku/SRectangle.scala | 9 +++- .../net/ladstatt/sudoku/TemplateLibrary.scala | 4 +- .../net/ladstatt/sudoku/Sudoku4Test.scala | 2 +- .../net/ladstatt/sudoku/SudokuTest.scala | 53 ++++++++++++++++--- 5 files changed, 71 insertions(+), 13 deletions(-) diff --git a/sudoku-core/src/main/scala/net/ladstatt/sudoku/SCell.scala b/sudoku-core/src/main/scala/net/ladstatt/sudoku/SCell.scala index aa8df1b..5e0ad64 100644 --- a/sudoku-core/src/main/scala/net/ladstatt/sudoku/SCell.scala +++ b/sudoku-core/src/main/scala/net/ladstatt/sudoku/SCell.scala @@ -1,5 +1,9 @@ package net.ladstatt.sudoku +import java.io.File +import java.util.UUID + +import net.ladstatt.opencv.OpenCV import net.ladstatt.opencv.OpenCV._ import org.opencv.core.{Mat, Rect} @@ -19,5 +23,15 @@ case class SCell(cellMat: Mat, roi: Rect) { val contour: Option[Mat] = Await.result(extractContour(cellMat), Duration.Inf) - val (value, quality) = Await.result(contour.map(TemplateLibrary.detectNumber).getOrElse(Future.successful((0, 0.0))),Duration.Inf) + val computValueAndQuality: Future[(Int, Double)] = contour.map(TemplateLibrary.detectNumber).getOrElse(Future.successful((0, 0.0))) + + val (value, quality) = Await.result(computValueAndQuality, Duration.Inf) + + //persist() + def persist(): Unit = { + val libraryPath = new File(s"/Users/lad/Documents/sudokufx/sudoku-core/src/test/resources/net/ladstatt/sudoku/library/$value") + libraryPath.mkdirs + OpenCV.persist(cellMat, new File(libraryPath, UUID.randomUUID.toString + ".png")) + } + } diff --git a/sudoku-core/src/main/scala/net/ladstatt/sudoku/SRectangle.scala b/sudoku-core/src/main/scala/net/ladstatt/sudoku/SRectangle.scala index 9f76d4e..50cea2a 100644 --- a/sudoku-core/src/main/scala/net/ladstatt/sudoku/SRectangle.scala +++ b/sudoku-core/src/main/scala/net/ladstatt/sudoku/SRectangle.scala @@ -1,10 +1,13 @@ package net.ladstatt.sudoku +import java.io.File +import java.util.UUID + import net.ladstatt.opencv.OpenCV import net.ladstatt.opencv.OpenCV._ import org.opencv.core._ -import scala.collection.JavaConversions ._ +import scala.collection.JavaConversions._ object SRectangle { @@ -51,7 +54,9 @@ case class SRectangle(frame: Mat, detectedCorners: MatOfPoint2f, destCorners: Ma for (solution <- someSolution) { val values: Array[Int] = solution.map(_.value) for ((s, r) <- values zip cellRois if s != 0) { - copyTo(digitLibrary(s)._2.getOrElse(SudokuUtils.mkFallback(s, digitLibrary).get), normalized, r) + val normalizedCell: Mat = digitLibrary(s)._2.getOrElse(SudokuUtils.mkFallback(s, digitLibrary).get) + + copyTo(normalizedCell, normalized, r) } } normalized diff --git a/sudoku-core/src/main/scala/net/ladstatt/sudoku/TemplateLibrary.scala b/sudoku-core/src/main/scala/net/ladstatt/sudoku/TemplateLibrary.scala index 4b77f19..b1a845f 100644 --- a/sudoku-core/src/main/scala/net/ladstatt/sudoku/TemplateLibrary.scala +++ b/sudoku-core/src/main/scala/net/ladstatt/sudoku/TemplateLibrary.scala @@ -1,6 +1,7 @@ package net.ladstatt.sudoku -import java.io.InputStream +import java.io.{File, InputStream} +import java.util.UUID import net.ladstatt.core.CanLog import net.ladstatt.opencv.OpenCV @@ -45,7 +46,6 @@ object TemplateLibrary extends CanLog { for {(number, quality) <- matchHaystack(number + 1, needle)} yield (number, quality)) } yield s.sortWith((a, b) => a._2 < b._2).head - result } diff --git a/sudoku-core/src/test/scala/net/ladstatt/sudoku/Sudoku4Test.scala b/sudoku-core/src/test/scala/net/ladstatt/sudoku/Sudoku4Test.scala index 4c650bb..977fcb0 100644 --- a/sudoku-core/src/test/scala/net/ladstatt/sudoku/Sudoku4Test.scala +++ b/sudoku-core/src/test/scala/net/ladstatt/sudoku/Sudoku4Test.scala @@ -12,7 +12,7 @@ class Sudoku4Test { OpenCV.loadNativeLib() - @Ignore @Test def testSudoku4(): Unit = { + @Ignore @Test def testSudoku4(): Unit = { val sudoku4 = Imgcodecs.imread("src/test/resources/net/ladstatt/sudoku/sudoku_4.png") val (_, (r, _)) = SudokuTestContext.calculate(sudoku4) r match { diff --git a/sudoku-core/src/test/scala/net/ladstatt/sudoku/SudokuTest.scala b/sudoku-core/src/test/scala/net/ladstatt/sudoku/SudokuTest.scala index e6261ef..a3c7891 100644 --- a/sudoku-core/src/test/scala/net/ladstatt/sudoku/SudokuTest.scala +++ b/sudoku-core/src/test/scala/net/ladstatt/sudoku/SudokuTest.scala @@ -1,20 +1,23 @@ package net.ladstatt.sudoku -import java.io.File +import java.io.{File, FilenameFilter} import net.ladstatt.opencv.OpenCV import org.junit.Assert._ import org.junit.Test +import org.opencv.core.{Mat, Point, Rect} +import org.opencv.imgcodecs.Imgcodecs -import scala.concurrent.duration._ +import scala.collection.mutable +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} import scala.io.Source - /** - * Created by lad on 05.05.14. - */ -class SudokuTest { + * Created by lad on 05.05.14. + */ +class SudokuTest { OpenCV.loadNativeLib("../lib/libopencv_java310.so") @@ -29,7 +32,6 @@ class SudokuTest { // compares individual detection results with a reference file @Test def testDetect(): Unit = { - import scala.concurrent.ExecutionContext.Implicits.global assertEquals(81.toLong, refCellNumbers.size.toLong) val cells: Seq[SCell] = SudokuTestContext.sudoku_1.sRectangle.cells var i = 0 @@ -40,6 +42,43 @@ class SudokuTest { } } + /** + * tests the matching algorithm against a library of individual number pictures + */ + @Test def testTemplateMatching(): Unit = { + val libraryPath = new File("/Users/lad/Documents/sudokufx/sudoku-core/src/test/resources/net/ladstatt/sudoku/library") + for (i <- 0 to 9) { + val dir = new File(libraryPath, i.toString) + val someFiles = Option(dir.listFiles(new FilenameFilter { + override def accept(dir: File, name: String): Boolean = name.endsWith(".png") + })) + someFiles foreach { + case files => + val results: mutable.ArraySeq[(File, (Int, Int, Double))] = + Await.result( + Future.sequence( + for {f <- files} yield { + val image: Mat = Imgcodecs.imread(f.getAbsolutePath) + val rect = new Rect(new Point(0, 0), image.size) + SCell(image, rect).computValueAndQuality.map { + case ((n: Int, q: Double)) => (f, (i, n, q)) + } + }), Duration.Inf) + + val mismatches = results.filter { + case (_, (e,a,_)) => e != a + } + + if (mismatches.nonEmpty) { + mismatches.foreach { + case (f, (expected, actual, q)) if expected != actual => println(s"Image ${f.getAbsolutePath} should be $expected, but was $actual.") + case _ => + } + //fail("Mismatch detected.") + } + } + } + } }