Browse Source

Massive improvements in the concurrent engine

master
Drew Short 10 years ago
parent
commit
d474b42952
  1. 4
      pom.xml
  2. 134
      src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala
  3. 9
      src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala
  4. 78
      src/main/scala/com/sothr/imagetools/hash/HashService.scala
  5. 13
      src/main/scala/com/sothr/imagetools/image/Image.scala
  6. 9
      src/main/scala/com/sothr/imagetools/image/SimilarImages.scala
  7. 32
      src/main/scala/com/sothr/imagetools/util/PropertiesService.scala

4
pom.xml

@ -328,7 +328,9 @@
<copy file="${project.build.directory}/version.info" toFile="${basedir}/version.info" overwrite="true" />
<copy file="${project.build.directory}/name.info" toFile="${basedir}/name.info" overwrite="true" />
<copy file="${project.build.directory}/LICENSE" toFile="${basedir}/LICENSE" overwrite="true" />
<copy file="${project.build.directory}/README.md" toFile="${basedir}/README.md" overwrite="true" />
<copy file="${project.build.directory}/README.md" toFile="${basedir}/README.md" overwrite="true" />
<chmod file="${project.build.directory}/startCLI.sh" perm="755"/>
<chmod file="${project.build.directory}/startGUI.sh" perm="755"/>
</tasks>
</configuration>
<goals>

134
src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala

@ -2,7 +2,7 @@ package com.sothr.imagetools
import java.io.File
import akka.actor.{Actor, ActorSystem, Props, ActorLogging}
import akka.routing.{Broadcast, SmallestMailboxRouter}
import akka.routing.{Broadcast, RoundRobinRouter, SmallestMailboxRouter}
import akka.pattern.ask
import akka.util.Timeout
import java.util.concurrent.TimeUnit
@ -55,55 +55,15 @@ class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
images.toList
}
//copied from the sequential engine as the concurrent version has issues currently
def getSimilarImagesForDirectory(directoryPath:String):List[SimilarImages] = {
debug(s"Looking for similar images in directory: $directoryPath")
val images = getImagesForDirectory(directoryPath)
info(s"Searching ${images.length} images for similarities")
val ignoreSet = new mutable.HashSet[Image]()
val allSimilarImages = new mutable.MutableList[SimilarImages]()
var processedCount = 0
var similarCount = 0
for (rootImage <- images) {
if (!ignoreSet.contains(rootImage)) {
if (processedCount % 25 == 0) {
info(s"Processed ${processedCount}/${images.length - ignoreSet.size} About ${images.length - processedCount} images to go")
}
debug(s"Looking for images similar to: ${rootImage.imagePath}")
ignoreSet += rootImage
val similarImages = new mutable.MutableList[Image]()
for (image <- images) {
if (!ignoreSet.contains(image)) {
if (rootImage.isSimilarTo(image)) {
debug(s"Image: ${image.imagePath} is similar")
similarImages += image
ignoreSet += image
similarCount += 1
}
}
}
if (similarImages.length > 1) {
val similar = new SimilarImages(rootImage, similarImages.toList)
debug(s"Found similar images: ${similar.toString}")
allSimilarImages += similar
}
processedCount += 1
}
}
info(s"Finished processing ${images.size} images. Found $similarCount similar images")
allSimilarImages.toList
}
/*
//needs to be rebuilt
def getSimilarImagesForDirectory(directoryPath:String):List[SimilarImages] = {
debug(s"Looking for similar images in directory: $directoryPath")
val images = getImagesForDirectory(directoryPath)
engineSimilarityController ! EngineCompareSetImages(images)
info(s"Searching ${images.length} images for similarities")
val allSimilarImages = new mutable.MutableList[SimilarImages]()
for (rootImage <- images) {
debug(s"Looking for images similar to: ${rootImage.imagePath}")
engineSimilarityController ! EngineCompareImages(rootImage, images, null)
engineSimilarityController ! EngineCompareImages(rootImage)
}
//tell the comparison engine there's nothing left to compare
engineSimilarityController ! EngineNoMoreComparisons
@ -124,16 +84,30 @@ class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
}
val f = engineSimilarityController ? EngineGetSimilarityResults
val result = Await.result(f, timeout.duration).asInstanceOf[List[SimilarImages]]
allSimilarImages ++= result
//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
}
}
}
var similarCount = 0
for (similarImage <- allSimilarImages) {
for (similarImage <- cleanedSimilarImages) {
similarCount += 1 + similarImage.similarImages.size
}
info(s"Finished processing ${images.size} images. Found $similarCount similar images")
allSimilarImages.toList
}*/
cleanedSimilarImages.toList
}
}
@ -166,6 +140,11 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
var processorsFinished = 0
override def preStart() = {
log.info("Staring the controller for processing images")
log.info("Using {} actors to process images", numOfRouters)
}
override def receive = {
case command:EngineProcessFile => processFile(command)
case command:EngineFileProcessed => fileProcessed(command)
@ -189,7 +168,7 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
def fileProcessed(command:EngineFileProcessed) = {
processed += 1
if (processed % 25 == 0) log.info(s"Processed $processed/$toProcess")
if (processed % 25 == 0 || processed == toProcess) log.info(s"Processed $processed/$toProcess")
if (command.image != null) {
log.debug(s"processed image: ${command.image.imagePath}")
images += command.image
@ -267,15 +246,15 @@ class ConcurrentEngineProcessingActor extends Actor with ActorLogging {
}
//finding similarities between images
case class EngineCompareImages(image1:Image,images:List[Image],ignoreList:Set[Image])
case class EngineCompareImages(image1:Image)
case class EngineCompareImagesComplete(similarImages:SimilarImages)
case class EngineCompareSetImages(images:List[Image])
case object EngineNoMoreComparisons
case object EngineIsSimilarityFinished
case object EngineGetSimilarityResults
case object EngineActorCompareImagesFinished
class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
val imageCache = AppConfig.cacheManager.getCache("images")
val numOfRouters = {
val max = PropertiesService.get(PropertiesEnum.ConcurrentSimiliartyLimit.toString).toInt
val processors = Runtime.getRuntime.availableProcessors()
@ -283,18 +262,24 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
if (processors > max) threads = max else if (processors > 1) threads = processors - 1 else threads = 1
threads
}
val router = context.actorOf(Props[ConcurrentEngineSimilarityActor].withRouter(SmallestMailboxRouter(nrOfInstances = numOfRouters)))
val router = context.actorOf(Props[ConcurrentEngineSimilarityActor].withRouter(RoundRobinRouter(nrOfInstances = numOfRouters)))
val allSimilarImages = new mutable.MutableList[SimilarImages]
val ignoreList = new mutable.HashSet[Image]()
var numImages = 0
var toProcess = 0
var processed = 0
var processorsFinished = 0
override def preStart() = {
log.info("Staring the controller for processing similarites between images")
log.info("Using {} actors to process image similarites", numOfRouters)
}
override def receive = {
case command:EngineCompareImages => findSimilarities(command)
case command:EngineCompareImagesComplete => similarityProcessed(command)
case command:EngineCompareSetImages => setImageList(command)
case EngineNoMoreComparisons => requestWrapup()
case EngineActorCompareImagesFinished => actorProcessingFinished()
case EngineIsSimilarityFinished => isProcessingFinished()
@ -302,24 +287,27 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
case _ => log.info("received unknown message")
}
def setImageList(command:EngineCompareSetImages) = {
numImages = command.images.length
router ! Broadcast(command)
}
def findSimilarities(command:EngineCompareImages) = {
log.debug(s"Finding similarities between ${command.image1.imagePath} and ${command.images.length} images")
log.debug(s"Finding similarities between ${command.image1.imagePath} and $numImages images")
toProcess += 1
if (toProcess % 250 == 0 || toProcess == numImages) {
log.info("Sent {}/{} images to be processed for similarites", toProcess, numImages)
}
//just relay the command to our workers
router ! EngineCompareImages(command.image1, command.images, ignoreList.toSet[Image])
router ! EngineCompareImages(command.image1)
}
def similarityProcessed(command:EngineCompareImagesComplete) = {
processed += 1
if (processed % 25 == 0) log.info(s"Processed $processed/$toProcess")
if (processed % 25 == 0 || processed == numImages) log.info(s"Processed $processed/$toProcess")
if (command.similarImages != null) {
if (!ignoreList.contains(command.similarImages.rootImage)) {
log.debug(s"Found similar images: ${command.similarImages}")
allSimilarImages += command.similarImages
//add the similar images to the ignore list so we don't re-process them constantly
ignoreList += command.similarImages.rootImage
ignoreList ++= command.similarImages.similarImages
}
log.debug(s"Found similar images: ${command.similarImages}")
allSimilarImages += command.similarImages
}
}
@ -332,6 +320,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
*/
def actorProcessingFinished() = {
processorsFinished += 1
log.debug("Similarity Processor Reported Finished")
}
/*
@ -339,6 +328,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
*/
def isProcessingFinished() = {
try {
log.debug("Processors Finished {}/{}", processorsFinished, numOfRouters)
if (processorsFinished >= numOfRouters) sender ! true else sender ! false
} catch {
case e: Exception
@ -367,21 +357,30 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
class ConcurrentEngineSimilarityActor extends Actor with ActorLogging {
var ignoreMessages = false
var imageList = new mutable.MutableList[Image]()
override def receive = {
case command:EngineCompareImages => compareImages(command)
case command:EngineCompareSetImages => cloneAndSetImages(command)
case EngineNoMoreComparisons => finishedComparisons()
case EngineActorReactivate => ignoreMessages = false
case _ => log.info("received unknown message")
}
def cloneAndSetImages(command:EngineCompareSetImages) = {
imageList.clear()
for (image <- command.images) {
imageList += image.cloneImage
}
log.debug("Added {} cloned images to internal list", imageList.length)
}
def compareImages(command:EngineCompareImages) = {
if (!ignoreMessages) {
val similarImages = new mutable.MutableList[Image]()
for (image <- command.images) {
if (!command.ignoreList.contains(image) && command.image1 != image) {
for (image <- imageList) {
if (!command.image1.equals(image)) {
if (HashService.areImageHashesSimilar(command.image1.hashes, image.hashes)) {
similarImages += image
var ignoreMessages = false
}
}
}
@ -399,7 +398,10 @@ class ConcurrentEngineSimilarityActor extends Actor with ActorLogging {
def finishedComparisons() = {
if (!ignoreMessages) {
log.info("Commanded to finish processing")
ignoreMessages = true
imageList.clear()
log.debug("Finished processing comparisons")
sender ! EngineActorCompareImagesFinished
}
}

9
src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala

@ -4,6 +4,10 @@ import grizzled.slf4j.Logging
class ImageHashDTO(val ahash:Long, val dhash:Long, val phash:Long, val md5:String) extends Serializable with Logging{
def cloneHashes:ImageHashDTO = {
return new ImageHashDTO(ahash,dhash,phash,md5)
}
override def hashCode():Int = {
var result = 365
result = 41 * result + (this.ahash ^ (this.ahash >>> 32)).toInt
@ -13,9 +17,6 @@ class ImageHashDTO(val ahash:Long, val dhash:Long, val phash:Long, val md5:Strin
}
override def toString:String = {
s"""MD5: $md5
ahash: $ahash
dhash: $dhash
phash: $phash""".stripMargin
s"MD5: $md5 ahash: $ahash dhash: $dhash phash: $phash"
}
}

78
src/main/scala/com/sothr/imagetools/hash/HashService.scala

@ -23,7 +23,7 @@ object HashService extends Logging {
}
def getImageHashes(image:BufferedImage, imagePath:String):ImageHashDTO = {
debug(s"Creating hashes for image")
debug("Creating hashes for an image")
var ahash:Long = 0L
var dhash:Long = 0L
@ -33,13 +33,13 @@ object HashService extends Logging {
//Get Image Data
val grayImage = ImageService.convertToGray(image)
if (PropertiesService.get(PropertiesEnum.UseAhash.toString) == "true") {
if (PropertiesService.useAhash == true) {
ahash = getAhash(grayImage, true)
}
if (PropertiesService.get(PropertiesEnum.UseAhash.toString) == "true") {
if (PropertiesService.useDhash == true) {
dhash = getDhash(grayImage, true)
}
if (PropertiesService.get(PropertiesEnum.UseAhash.toString) == "true") {
if (PropertiesService.usePhash == true) {
phash = getPhash(grayImage, true)
}
@ -57,7 +57,7 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
val resizedImage = ImageService.resize(grayImage, PropertiesService.get(PropertiesEnum.AhashPrecision.toString).toInt, true)
val resizedImage = ImageService.resize(grayImage, PropertiesService.aHashPrecision, true)
val imageData = ImageService.getImageData(resizedImage)
AHash.getHash(imageData)
}
@ -70,7 +70,7 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
val resizedImage = ImageService.resize(grayImage, PropertiesService.get(PropertiesEnum.DhashPrecision.toString).toInt, true)
val resizedImage = ImageService.resize(grayImage, PropertiesService.dHashPrecision, true)
val imageData = ImageService.getImageData(resizedImage)
DHash.getHash(imageData)
}
@ -83,7 +83,7 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
val resizedImage = ImageService.resize(grayImage, PropertiesService.get(PropertiesEnum.PhashPrecision.toString).toInt, true)
val resizedImage = ImageService.resize(grayImage, PropertiesService.pHashPrecision, true)
val imageData = ImageService.getImageData(resizedImage)
PHash.getHash(imageData)
}
@ -93,39 +93,39 @@ object HashService extends Logging {
}
def areAhashSimilar(ahash1:Long, ahash2:Long):Boolean = {
val tolerence = PropertiesService.get(PropertiesEnum.AhashTolerance.toString).toInt
val tolerence = PropertiesService.aHashTolerance
val distance = Hamming.getDistance(ahash1, ahash2)
debug(s"hash1: $ahash1 hash2: $ahash2 tolerence: $tolerence hamming distance: $distance")
//debug(s"hash1: $ahash1 hash2: $ahash2 tolerence: $tolerence hamming distance: $distance")
if (distance <= tolerence) true else false
}
def areDhashSimilar(dhash1:Long, dhash2:Long):Boolean = {
val tolerence = PropertiesService.get(PropertiesEnum.DhashTolerance.toString).toInt
val tolerence = PropertiesService.dHashTolerance
val distance = Hamming.getDistance(dhash1, dhash2)
debug(s"hash1: $dhash1 hash2: $dhash2 tolerence: $tolerence hamming distance: $distance")
//debug(s"hash1: $dhash1 hash2: $dhash2 tolerence: $tolerence hamming distance: $distance")
if (distance <= tolerence) true else false
}
def arePhashSimilar(phash1:Long, phash2:Long):Boolean = {
val tolerence = PropertiesService.get(PropertiesEnum.PhashTolerance.toString).toInt
val tolerence = PropertiesService.pHashTolerance
val distance = Hamming.getDistance(phash1, phash2)
debug(s"hash1: $phash1 hash2: $phash2 tolerence: $tolerence hamming distance: $distance")
//debug(s"hash1: $phash1 hash2: $phash2 tolerence: $tolerence hamming distance: $distance")
if (distance <= tolerence) true else false
}
def getWeightedHashSimilarity(imageHash1:ImageHashDTO, imageHash2:ImageHashDTO):Float = {
//ahash
val aHashTolerance = PropertiesService.get(PropertiesEnum.AhashTolerance.toString).toInt
val aHashWeight = PropertiesService.get(PropertiesEnum.AhashWeight.toString).toFloat
val useAhash = PropertiesService.get(PropertiesEnum.UseAhash.toString).toBoolean
val aHashTolerance = PropertiesService.aHashTolerance
val aHashWeight = PropertiesService.aHashWeight
val useAhash = PropertiesService.useAhash
//dhash
val dHashTolerance = PropertiesService.get(PropertiesEnum.DhashTolerance.toString).toInt
val dHashWeight = PropertiesService.get(PropertiesEnum.DhashWeight.toString).toFloat
val useDhash = PropertiesService.get(PropertiesEnum.UseDhash.toString).toBoolean
val dHashTolerance = PropertiesService.dHashTolerance
val dHashWeight = PropertiesService.dHashWeight
val useDhash = PropertiesService.useAhash
//phash
val pHashTolerance = PropertiesService.get(PropertiesEnum.PhashTolerance.toString).toInt
val pHashWeight = PropertiesService.get(PropertiesEnum.PhashWeight.toString).toFloat
val usePhash = PropertiesService.get(PropertiesEnum.UsePhash.toString).toBoolean
val pHashTolerance = PropertiesService.pHashTolerance
val pHashWeight = PropertiesService.pHashWeight
val usePhash = PropertiesService.useAhash
//calculate weighted values
var weightedHammingTotal:Float = 0
@ -135,41 +135,41 @@ object HashService extends Logging {
{
val hamming = Hamming.getDistance(imageHash1.ahash, imageHash2.ahash)
weightedHammingTotal += hamming * aHashWeight
debug(s"hash1: ${imageHash1.ahash} hash2: ${imageHash1.ahash} tolerence: $aHashTolerance hamming distance: $hamming weight: $aHashWeight")
//debug(s"hash1: ${imageHash1.ahash} hash2: ${imageHash1.ahash} tolerence: $aHashTolerance hamming distance: $hamming weight: $aHashWeight")
methodsTotal+=1
}
if (useDhash)
{
val hamming = Hamming.getDistance(imageHash1.dhash, imageHash2.dhash)
weightedHammingTotal += hamming * dHashWeight
debug(s"hash1: ${imageHash1.dhash} hash2: ${imageHash1.dhash} tolerence: $dHashTolerance hamming distance: $hamming weight: $dHashWeight")
//debug(s"hash1: ${imageHash1.dhash} hash2: ${imageHash1.dhash} tolerence: $dHashTolerance hamming distance: $hamming weight: $dHashWeight")
methodsTotal+=1
}
if (usePhash)
{
val hamming = Hamming.getDistance(imageHash1.phash, imageHash2.phash)
weightedHammingTotal += hamming * pHashWeight
debug(s"hash1: ${imageHash1.phash} hash2: ${imageHash1.phash} tolerence: $pHashTolerance hamming distance: $hamming weight: $pHashWeight")
//debug(s"hash1: ${imageHash1.phash} hash2: ${imageHash1.phash} tolerence: $pHashTolerance hamming distance: $hamming weight: $pHashWeight")
methodsTotal+=1
}
val weightedHammingMean = weightedHammingTotal / methodsTotal
debug(s"Calculated Weighted Hamming Mean: $weightedHammingMean")
//debug(s"Calculated Weighted Hamming Mean: $weightedHammingMean")
weightedHammingMean
}
def getWeightedHashTolerence:Float = {
//ahash
val aHashTolerance = PropertiesService.get(PropertiesEnum.AhashTolerance.toString).toInt
val aHashWeight = PropertiesService.get(PropertiesEnum.AhashWeight.toString).toFloat
val useAhash = PropertiesService.get(PropertiesEnum.UseAhash.toString).toBoolean
val aHashTolerance = PropertiesService.aHashTolerance
val aHashWeight = PropertiesService.aHashWeight
val useAhash = PropertiesService.useAhash
//dhash
val dHashTolerance = PropertiesService.get(PropertiesEnum.DhashTolerance.toString).toInt
val dHashWeight = PropertiesService.get(PropertiesEnum.DhashWeight.toString).toFloat
val useDhash = PropertiesService.get(PropertiesEnum.UseDhash.toString).toBoolean
val dHashTolerance = PropertiesService.dHashTolerance
val dHashWeight = PropertiesService.dHashWeight
val useDhash = PropertiesService.useAhash
//phash
val pHashTolerance = PropertiesService.get(PropertiesEnum.PhashTolerance.toString).toInt
val pHashWeight = PropertiesService.get(PropertiesEnum.PhashWeight.toString).toFloat
val usePhash = PropertiesService.get(PropertiesEnum.UsePhash.toString).toBoolean
val pHashTolerance = PropertiesService.pHashTolerance
val pHashWeight = PropertiesService.pHashWeight
val usePhash = PropertiesService.useAhash
//calculate weighted values
var weightedToleranceTotal:Float = 0
@ -178,23 +178,23 @@ object HashService extends Logging {
if (useAhash)
{
weightedToleranceTotal += aHashTolerance * aHashWeight
debug(s"Ahash Tolerance: $aHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
//debug(s"Ahash Tolerance: $aHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
methodsTotal+=1
}
if (useDhash)
{
weightedToleranceTotal += dHashTolerance * dHashWeight
debug(s"Dhash Tolerance: $dHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
//debug(s"Dhash Tolerance: $dHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
methodsTotal+=1
}
if (usePhash)
{
weightedToleranceTotal += pHashTolerance * pHashWeight
debug(s"Phash Tolerance: $pHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
//debug(s"Phash Tolerance: $pHashTolerance Current Weighted Tolerance: $weightedToleranceTotal")
methodsTotal+=1
}
val weightedTolerance = weightedToleranceTotal / methodsTotal
debug(s"Calculated Weighted Tolerance: $weightedTolerance")
//debug(s"Calculated Weighted Tolerance: $weightedTolerance")
weightedTolerance
}

13
src/main/scala/com/sothr/imagetools/image/Image.scala

@ -9,6 +9,7 @@ class Image(val imagePath:String, val thumbnailPath:String, val imageSize:Tuple2
var imageType:ImageType = ImageType.SingleFrameImage
def isSimilarTo(otherImage:Image):Boolean = {
debug("Checking {} for similarities with {}",imagePath, otherImage.imagePath)
HashService.areImageHashesSimilar(this.hashes,otherImage.hashes)
}
@ -20,10 +21,22 @@ class Image(val imagePath:String, val thumbnailPath:String, val imageSize:Tuple2
}*/
def cloneImage:Image = {
return new Image(imagePath,thumbnailPath,imageSize,hashes.cloneHashes)
}
override def toString:String = {
s"Image: $imagePath Thumbnail: $thumbnailPath Image Size: ${imageSize._1}x${imageSize._2} Hashes: $hashes"
}
override def equals(obj:Any) = {
obj match {
case that:Image =>
that.hashCode.equals(this.hashCode)
case _ => false
}
}
override def hashCode:Int = {
var result = 365
result = 37 * result + imagePath.hashCode

9
src/main/scala/com/sothr/imagetools/image/SimilarImages.scala

@ -15,6 +15,15 @@ class SimilarImages(val rootImage:Image, val similarImages:List[Image]) extends
}
sb.toString()
}
override def hashCode:Int = {
val prime = 7
var result = prime * 1 + rootImage.hashCode
for (similarImage <- similarImages) {
result = prime * result + similarImage.hashCode
}
result
}
override def toString:String = {
s"""RootImage: ${rootImage.imagePath}

32
src/main/scala/com/sothr/imagetools/util/PropertiesService.scala

@ -41,6 +41,22 @@ object PropertiesService extends Logging {
InfoLogEnabled = get(PropertiesEnum.LogInfo.toString).toBoolean
ErrorLogEnabled = get(PropertiesEnum.LogError.toString).toBoolean
TimingEnabled = get(PropertiesEnum.Timed.toString).toBoolean
//ahash
aHashPrecision = PropertiesService.get(PropertiesEnum.AhashPrecision.toString).toInt
aHashTolerance = PropertiesService.get(PropertiesEnum.AhashTolerance.toString).toInt
aHashWeight = PropertiesService.get(PropertiesEnum.AhashWeight.toString).toFloat
useAhash = PropertiesService.get(PropertiesEnum.UseAhash.toString).toBoolean
//dhash
dHashPrecision = PropertiesService.get(PropertiesEnum.DhashPrecision.toString).toInt
dHashTolerance = PropertiesService.get(PropertiesEnum.DhashTolerance.toString).toInt
dHashWeight = PropertiesService.get(PropertiesEnum.DhashWeight.toString).toFloat
useDhash = PropertiesService.get(PropertiesEnum.UseDhash.toString).toBoolean
//phash
pHashPrecision = PropertiesService.get(PropertiesEnum.PhashPrecision.toString).toInt
pHashTolerance = PropertiesService.get(PropertiesEnum.PhashTolerance.toString).toInt
pHashWeight = PropertiesService.get(PropertiesEnum.PhashWeight.toString).toFloat
usePhash = PropertiesService.get(PropertiesEnum.UsePhash.toString).toBoolean
info("Loaded Special Properties")
}
@ -80,5 +96,21 @@ object PropertiesService extends Logging {
var InfoLogEnabled:Boolean = false
var ErrorLogEnabled:Boolean = false
var TimingEnabled:Boolean = false
//ahash
var aHashPrecision = 0
var aHashTolerance = 0
var aHashWeight = 0.0f
var useAhash = false
//dhash
var dHashPrecision = 0
var dHashTolerance = 0
var dHashWeight = 0.0f
var useDhash = false
//phash
var pHashPrecision = 0
var pHashTolerance = 0
var pHashWeight = 0.0f
var usePhash = false
}
Loading…
Cancel
Save