Browse Source

Reorganized a few more files, added a proper searched listener to the GUI to show the number of files to be processed before the actual processing starts.

master
Drew Short 10 years ago
parent
commit
50f87a51ac
  1. 20
      engine/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
  2. 40
      engine/src/main/scala/com/sothr/imagetools/engine/Engine.scala
  3. 2
      engine/src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala
  4. 36
      gui/src/main/scala/com/sothr/imagetools/ui/component/ImageTilePane.scala
  5. 67
      gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

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

@ -20,7 +20,7 @@ class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
implicit val timeout = Timeout(30, TimeUnit.SECONDS)
override def setSearchedListener(listenerRef: ActorRef) = {
this.searchedListener = listenerRef;
}
override def setProcessedListener(listenerRef: ActorRef) = {
@ -61,29 +61,15 @@ class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
}
val f = engineSimilarityController ? EngineGetSimilarityResults
val result = Await.result(f, timeout.duration).asInstanceOf[List[SimilarImages]]
//process the result into a list we want in cleanedSimilarImages
var count = 0
val cleanedSimilarImages = new mutable.MutableList[SimilarImages]()
val ignoreSet = new mutable.HashSet[Image]()
for (similarImages <- result) {
count += 1
if (count % 25 == 0 || count == result.length) debug(s"Cleaning similar image $count/${result.length} ${result.length - count} left to clean")
if (!ignoreSet.contains(similarImages.rootImage)) {
cleanedSimilarImages += similarImages
ignoreSet += similarImages.rootImage
for (image <- similarImages.similarImages) {
ignoreSet += image
}
}
}
val cleanedSimilarImages = this.processSimilarities(result)
var similarCount = 0
for (similarImage <- cleanedSimilarImages) {
similarCount += 1 + similarImage.similarImages.size
}
info(s"Finished processing ${images.size} images. Found $similarCount similar images")
cleanedSimilarImages.toList
cleanedSimilarImages
}
def getImagesForDirectory(directoryPath: String, recursive: Boolean = false, recursiveDepth: Int = 500): List[Image] = {

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

@ -40,13 +40,16 @@ abstract class Engine extends Logging {
val files = directory.listFiles(imageFilter)
if (files != null) {
fileList ++= files
info(s"Found ${files.length} files that are images in directory: $directoryPath")
debug(s"Found ${files.length} files that are images in directory: $directoryPath")
if (recursive) {
val directoryFilter = new DirectoryFilter
val directories = directory.listFiles(directoryFilter)
for (directory <- directories) {
fileList ++= getAllImageFiles(directory.getAbsolutePath, recursive, recursiveDepth - 1)
this.searchedListener ! SubmitMessage(s"Found ${fileList.length} files to process")
}
} else {
this.searchedListener ! SubmitMessage(s"Found ${fileList.length} files to process")
}
}
}
@ -73,6 +76,41 @@ abstract class Engine extends Logging {
deleteImage(image)
}
}
/**
* Go through the list of similarities and group them so that they represent actual similarities
*
* For example. A is similar to B and C is similar to B but A is was not considered similar to C. Therefore A B and C should be considered similar unless otherwise noted.
*
* @param similarList a list of detected similar images
* @return a grouped and combined list of similar images
*/
def processSimilarities(similarList: List[SimilarImages]): List[SimilarImages] = {
//process the result into a list we want in cleanedSimilarImages
var count = 0
val cleanedSimilarImages = new mutable.MutableList[SimilarImages]()
val ignoreSet = new mutable.HashSet[Image]()
for (similarImages <- similarList) {
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
}
}
//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.
*/
}
//return a non mutable cleaned list
cleanedSimilarImages.toList
}
}
case class SubmitMessage(message: String)

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

@ -66,7 +66,7 @@ class SequentialEngine extends Engine with Logging {
}
}
info(s"Finished processing ${images.size} images. Found $similarCount similar images")
allSimilarImages.toList
this.processSimilarities(allSimilarImages.toList)
}
def getImagesForDirectory(directoryPath: String, recursive: Boolean = false, recursiveDepth: Int = 500): List[Image] = {

36
gui/src/main/scala/com/sothr/imagetools/ui/component/ImageTilePane.scala

@ -165,24 +165,6 @@ class ImageTilePaneSelectionModel[ImageTile](parentTilePane: ImageTilePane) exte
this.selectedIndexes.add(0)
}
private def clearSelectionFormatting() = {
val iterator = this.parentTilePane.getChildren.iterator()
while (iterator.hasNext) {
//remove the selection styling
val imageTile: VBox = iterator.next().asInstanceOf[VBox]
imageTile.setBorder(Border.EMPTY)
}
}
private def setSelectionFormatting(index: Int): Unit = {
setSelectionFormatting(this.parentTilePane.getChildren.get(index).asInstanceOf[ImageTile])
}
private def setSelectionFormatting(imageTile: ImageTile) = {
val borderStroke = new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderStroke.THIN)
imageTile.asInstanceOf[VBox].setBorder(new Border(borderStroke))
}
override def selectLast(): Unit = {
clearSelectionFormatting
this.selectedIndexes.clear()
@ -239,6 +221,15 @@ class ImageTilePaneSelectionModel[ImageTile](parentTilePane: ImageTilePane) exte
}
}
private def setSelectionFormatting(index: Int): Unit = {
setSelectionFormatting(this.parentTilePane.getChildren.get(index).asInstanceOf[ImageTile])
}
private def setSelectionFormatting(imageTile: ImageTile) = {
val borderStroke = new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderStroke.THIN)
imageTile.asInstanceOf[VBox].setBorder(new Border(borderStroke))
}
override def select(obj: ImageTile): Unit = {
if (this.parentTilePane.getChildren.contains(obj)) {
clearSelectionFormatting
@ -248,6 +239,15 @@ class ImageTilePaneSelectionModel[ImageTile](parentTilePane: ImageTilePane) exte
}
}
private def clearSelectionFormatting() = {
val iterator = this.parentTilePane.getChildren.iterator()
while (iterator.hasNext) {
//remove the selection styling
val imageTile: VBox = iterator.next().asInstanceOf[VBox]
imageTile.setBorder(Border.EMPTY)
}
}
override def isEmpty: Boolean = {
this.parentTilePane.getChildren.isEmpty
}

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

@ -66,6 +66,7 @@ class AppController extends Logging {
// configure the listener
guiListener ! SetupListener(progressBar, progressLabel)
// tell the engine to use our listener
this.engine.setSearchedListener(guiListener)
this.engine.setProcessedListener(guiListener)
this.engine.setSimilarityListener(guiListener)
// Initialize the progress label
@ -282,44 +283,12 @@ class AppController extends Logging {
}
}
@FXML
def showSimilarImages(event: ActionEvent) = {
resetPaginator()
imageTilePane.getChildren.setAll(new java.util.ArrayList[Node]())
val f: Future[List[Image]] = Future {
val similarImages = engine.getSimilarImagesForDirectory(currentDirectory, recursive = doRecursiveProcessing.isSelected)
val tempImages = new mutable.MutableList[Image]()
for (similarImage <- similarImages) {
debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
tempImages += similarImage.rootImage
similarImage.similarImages.foreach(image => tempImages += image)
}
tempImages.toList
}
f onComplete {
case Success(images) =>
info(s"Displaying ${images.length} similar images")
Platform.runLater(new Runnable() {
override def run() {
setPagesContent(images)
showPage(0)
}
})
case Failure(t) =>
error("An Error Occurred", t)
}
}
//endregion
def resetPaginator() = {
this.paginator.setDisable(true)
this.paginator.setPageCount(1)
}
//todo: include a templating engine for rendering information
//endregion
def setPagesContent(images: List[Image]) = {
this.currentImages = images
@ -330,6 +299,8 @@ class AppController extends Logging {
this.paginator.setDisable(false)
}
//todo: include a templating engine for rendering information
def showPage(pageIndex: Integer) = {
val itemsPerPage = PropertiesService.get("app.ui.thumbsPerPage", "100").toInt
val startIndex = pageIndex * itemsPerPage
@ -353,6 +324,36 @@ class AppController extends Logging {
this.imageTilePane
}
@FXML
def showSimilarImages(event: ActionEvent) = {
resetPaginator()
imageTilePane.getChildren.setAll(new java.util.ArrayList[Node]())
val f: Future[List[Image]] = Future {
val similarImages = engine.getSimilarImagesForDirectory(currentDirectory, recursive = doRecursiveProcessing.isSelected)
val tempImages = new mutable.MutableList[Image]()
for (similarImage <- similarImages) {
debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
tempImages += similarImage.rootImage
similarImage.similarImages.foreach(image => tempImages += image)
}
tempImages.toList
}
f onComplete {
case Success(images) =>
info(s"Displaying ${images.length} similar images")
Platform.runLater(new Runnable() {
override def run() {
setPagesContent(images)
showPage(0)
}
})
case Failure(t) =>
error("An Error Occurred", t)
}
}
/**
* Show a plain text utility dialog
*

Loading…
Cancel
Save