Browse Source

Proper cleaning of similar images. Working on a sane sorting process for the similar images.

master
Drew Short 10 years ago
parent
commit
ab5c39c667
  1. 11
      engine/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
  2. 60
      engine/src/main/scala/com/sothr/imagetools/engine/Engine.scala
  3. 3
      engine/src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala
  4. 16
      engine/src/main/scala/com/sothr/imagetools/engine/image/SimilarImages.scala
  5. 4
      engine/src/test/scala/com/sothr/imagetools/engine/EngineTest.scala
  6. 3
      gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

11
engine/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala

@ -219,7 +219,7 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
*/ */
def checkForResults() = { def checkForResults() = {
try { try {
listener ! SubmitMessage(s"Finished Processing $processed/$processed images")
listener ! SubmitMessage(s"Finished processing $processed/$processed images")
processorsFinished = 0 processorsFinished = 0
toProcess = 0 toProcess = 0
processed = 0 processed = 0
@ -367,7 +367,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
*/ */
def checkIfProcessingIsFinished() = { def checkIfProcessingIsFinished() = {
try { try {
log.debug("Processors Finished {}/{}", processorsFinished, numOfRouters)
log.debug("Processors finished {}/{}", processorsFinished, numOfRouters)
if (processorsFinished >= numOfRouters) sender ! true else sender ! false if (processorsFinished >= numOfRouters) sender ! true else sender ! false
} catch { } catch {
case e: Exception case e: Exception
@ -381,7 +381,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
*/ */
def checkForResults() = { def checkForResults() = {
try { try {
listener ! SubmitMessage(s"Finished Scanning $processed/$processed images")
listener ! SubmitMessage(s"Finished scanning $processed/$processed images")
processorsFinished = 0 processorsFinished = 0
toProcess = 0 toProcess = 0
processed = 0 processed = 0
@ -422,8 +422,9 @@ class ConcurrentEngineSimilarityActor extends Actor with ActorLogging {
} }
//only send a message if we find similar images //only send a message if we find similar images
if (similarImages.length >= 1) { if (similarImages.length >= 1) {
val similarImage = new SimilarImages(command.image1, similarImages.toList)
log.debug(s"Found ${similarImage.similarImages.length} similar images to ${similarImage.rootImage}")
similarImages += command.image1
val similarImage = new SimilarImages(similarImages.toSet)
log.debug(s"Found ${similarImage.similarImages.size} similar images to ${command.image1}")
sender ! EngineCompareImagesComplete(similarImage) sender ! EngineCompareImagesComplete(similarImage)
} else { } else {
log.debug(s"Found no similar images to ${command.image1}") log.debug(s"Found no similar images to ${command.image1}")

60
engine/src/main/scala/com/sothr/imagetools/engine/Engine.scala

@ -3,11 +3,13 @@ package com.sothr.imagetools.engine
import java.io.File import java.io.File
import akka.actor._ import akka.actor._
import com.sothr.imagetools.engine.image.{Image, ImageFilter, ImageService, SimilarImages}
import com.sothr.imagetools.engine.image._
import com.sothr.imagetools.engine.util.DirectoryFilter import com.sothr.imagetools.engine.util.DirectoryFilter
import grizzled.slf4j.Logging import grizzled.slf4j.Logging
import scala.collection.immutable.HashSet
import scala.collection.mutable import scala.collection.mutable
import scala.util.control.Breaks._
/** /**
* Engine definition * Engine definition
@ -87,29 +89,55 @@ abstract class Engine extends Logging {
*/ */
def processSimilarities(similarList: List[SimilarImages]): List[SimilarImages] = { def processSimilarities(similarList: List[SimilarImages]): List[SimilarImages] = {
//process the result into a list we want in cleanedSimilarImages //process the result into a list we want in cleanedSimilarImages
/*
Go through all the images. If a similar image for the image doesn't exist, create it. if it does,
add it to that similar image. The end result is that all images should be grouped according to
their similar images and images that are similar to them.
*/
var count = 0 var count = 0
// similar image mapping to map known images back to their similar set
val similarImageMap = new mutable.HashMap[Image, SimilarImages]()
// List of the actual similar image sets
val cleanedSimilarImages = new mutable.MutableList[SimilarImages]() val cleanedSimilarImages = new mutable.MutableList[SimilarImages]()
val ignoreSet = new mutable.HashSet[Image]()
// loop over all of the similar image sets
for (similarImages <- similarList) { for (similarImages <- similarList) {
count += 1 count += 1
if (count % 25 == 0 || count == similarList.length) debug(s"Cleaning similar image $count/${similarList.length} ${similarList.length - count} left to clean")
if (!ignoreSet.contains(similarImages.rootImage)) {
cleanedSimilarImages += similarImages
ignoreSet += similarImages.rootImage
for (image <- similarImages.similarImages) {
ignoreSet += image
if (count % 25 == 0 || count == similarList.length) {
debug(s"Cleaning similar images. $count/${similarList.length} ${similarList.length - count} left to clean")
this.searchedListener ! SubmitMessage(s"Cleaning similar images. $count/${similarList.length}")
} }
var foundSimilarity = false
var similarity:SimilarImages = null
breakable { for (similarImage <- similarImages.similarImages) {
if (similarImageMap.contains(similarImage)) {
similarity = similarImageMap(similarImage)
foundSimilarity = true
break()
} }
//rewrite todo:
/*
Go through all the images. If a similar image for the image doesn't exist, create it. if it does,
add it to that similar image. The end result is that all images should be grouped according to
their similar images and images that are similar to them.
*/
} }
//if no similarity was found, one should be created
if (!foundSimilarity) {
similarity = new SimilarImages(new HashSet[Image])
// the created similarity is added to the cleaned list
cleanedSimilarImages += similarity
}
// all images should be added to this new similarity
similarity.similarImages = similarity.similarImages ++ similarImages.similarImages
similarImages.similarImages.foreach(img => similarImageMap.put(img, similarity))
} }
//return a non mutable cleaned list
cleanedSimilarImages.toList
//get a count of similar images found
var totalCount = 0
cleanedSimilarImages.foreach(img => totalCount += img.similarImages.size)
debug(s"Found $totalCount images with similarities")
this.searchedListener ! SubmitMessage(s"Found $totalCount images with similarities")
// Sort the similarImages by ?!?!?!? and return
cleanedSimilarImages.toList.sorted(SimilarImagesOrdering)
} }
} }

3
engine/src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala

@ -58,7 +58,8 @@ class SequentialEngine extends Engine with Logging {
} }
} }
if (similarImages.length > 1) { if (similarImages.length > 1) {
val similar = new SimilarImages(rootImage, similarImages.toList)
similarImages += rootImage
val similar = new SimilarImages(similarImages.toSet)
debug(s"Found similar images: ${similar.toString}") debug(s"Found similar images: ${similar.toString}")
allSimilarImages += similar allSimilarImages += similar
} }

16
engine/src/main/scala/com/sothr/imagetools/engine/image/SimilarImages.scala

@ -7,11 +7,11 @@ import grizzled.slf4j.Logging
* *
* Created by drew on 1/26/14. * Created by drew on 1/26/14.
*/ */
class SimilarImages(val rootImage: Image, val similarImages: List[Image]) extends Logging {
class SimilarImages(var similarImages: Set[Image]) extends Logging {
override def hashCode: Int = { override def hashCode: Int = {
val prime = 7 val prime = 7
var result = prime * 1 + rootImage.hashCode
var result = prime * similarImages.size
for (similarImage <- similarImages) { for (similarImage <- similarImages) {
result = prime * result + similarImage.hashCode result = prime * result + similarImage.hashCode
} }
@ -19,8 +19,7 @@ class SimilarImages(val rootImage: Image, val similarImages: List[Image]) extend
} }
override def toString: String = { override def toString: String = {
s"""RootImage: ${rootImage.imagePath}
Similar Images:
s"""Similar Images:
$getPrettySimilarImagesList""".stripMargin $getPrettySimilarImagesList""".stripMargin
} }
@ -33,4 +32,13 @@ class SimilarImages(val rootImage: Image, val similarImages: List[Image]) extend
sb.toString() sb.toString()
} }
def ordering() = {
1 * similarImages.size
similarImages.groupBy(img => img.getImagePath)
}
}
object SimilarImagesOrdering extends Ordering[SimilarImages] {
def compare(a:SimilarImages, b:SimilarImages) = a.ordering() compare b.ordering()
} }

4
engine/src/test/scala/com/sothr/imagetools/engine/EngineTest.scala

@ -20,7 +20,7 @@ class EngineTest extends BaseTest {
similarImages.length similarImages.length
} }
assertResult(2) { assertResult(2) {
similarImages(0).similarImages.length
similarImages(0).similarImages.size
} }
} }
@ -38,7 +38,7 @@ class EngineTest extends BaseTest {
similarImages.length similarImages.length
} }
assertResult(2) { assertResult(2) {
similarImages(0).similarImages.length
similarImages(0).similarImages.size
} }
} }
} }

3
gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

@ -333,8 +333,7 @@ class AppController extends Logging {
val similarImages = engine.getSimilarImagesForDirectory(currentDirectory, recursive = doRecursiveProcessing.isSelected) val similarImages = engine.getSimilarImagesForDirectory(currentDirectory, recursive = doRecursiveProcessing.isSelected)
val tempImages = new mutable.MutableList[Image]() val tempImages = new mutable.MutableList[Image]()
for (similarImage <- similarImages) { for (similarImage <- similarImages) {
debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
tempImages += similarImage.rootImage
debug(s"Adding similar images ${similarImage.toString} to app")
similarImage.similarImages.foreach(image => tempImages += image) similarImage.similarImages.foreach(image => tempImages += image)
} }
tempImages.toList tempImages.toList

Loading…
Cancel
Save