diff --git a/.gitignore b/.gitignore index 96ce83e..f7be0a5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,6 @@ name.info version.info # Image Tools Log Files -*.debug -*.info -*.err +*.debug* +*.info* +*.err* diff --git a/sample/sample_01_large.jpg b/sample/sample_01_large.jpg new file mode 100644 index 0000000..737a02e Binary files /dev/null and b/sample/sample_01_large.jpg differ diff --git a/sample/sample_01_medium.jpg b/sample/sample_01_medium.jpg new file mode 100644 index 0000000..dd0dad7 Binary files /dev/null and b/sample/sample_01_medium.jpg differ diff --git a/sample/sample_01_small.jpg b/sample/sample_01_small.jpg new file mode 100644 index 0000000..d46adea Binary files /dev/null and b/sample/sample_01_small.jpg differ diff --git a/src/main/resources/default.properties b/src/main/resources/default.properties index a438387..1888b7c 100644 --- a/src/main/resources/default.properties +++ b/src/main/resources/default.properties @@ -16,13 +16,16 @@ image.hash.precision=64 image.ahash.use=true image.ahash.weight=0.70 image.ahash.precision=8 +image.ahash.tolerence=8 image.dhash.use=true image.dhash.weight=0.85 image.dhash.precision=8 +image.dhash.tolerence=8 #set to false if hashing images is taking too long image.phash.use=true image.phash.weight=1.0 image.phash.precision=16 +image.phash.tolerence=8 #Default Thumbnail Settings #Directory where to store thumbnails diff --git a/src/main/scala/com/sothr/imagetools/hash/DHash.scala b/src/main/scala/com/sothr/imagetools/hash/DHash.scala index ae94f33..5f21bd4 100644 --- a/src/main/scala/com/sothr/imagetools/hash/DHash.scala +++ b/src/main/scala/com/sothr/imagetools/hash/DHash.scala @@ -13,7 +13,6 @@ object DHash extends PerceptualHasher with Logging { debug(s"Image data size: ${width}x${height}") var hash = 0L for (row <- 0 until width) { - //println(f"Row: $row%d") var previousPixel = imageData(row)(0) var previousLocation = (row, 0) @@ -26,7 +25,7 @@ object DHash extends PerceptualHasher with Logging { //binary or the current bit based on whether the value //of the current pixel is greater or equal to the previous pixel if (pixel >= previousPixel) hash |= 1 else hash |= 0 - debug(s"hash: hash") + //debug(s"hash: $hash") previousPixel = pixel previousLocation = (row, col) } diff --git a/src/main/scala/com/sothr/imagetools/hash/HashService.scala b/src/main/scala/com/sothr/imagetools/hash/HashService.scala index a65b58d..bc8f987 100644 --- a/src/main/scala/com/sothr/imagetools/hash/HashService.scala +++ b/src/main/scala/com/sothr/imagetools/hash/HashService.scala @@ -2,7 +2,7 @@ package com.sothr.imagetools.hash import grizzled.slf4j.Logging import com.sothr.imagetools.dto.ImageHashDTO -import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService} +import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService, Hamming} import com.sothr.imagetools.ImageService import java.awt.image.BufferedImage import javax.imageio.ImageIO @@ -65,5 +65,26 @@ object HashService extends Logging { val imageData = ImageService.getImageData(resizedImage) PHash.getHash(imageData) } + + def areAhashSimilar(ahash1:Long, ahash2:Long):Boolean = { + val tolerence = PropertiesService.get(PropertiesEnum.AhashTolerence.toString).toInt + val distance = Hamming.getDistance(ahash1, ahash2) + 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.DhashTolerence.toString).toInt + val distance = Hamming.getDistance(dhash1, dhash2) + 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.PhashTolerence.toString).toInt + val distance = Hamming.getDistance(phash1, phash2) + debug(s"hash1: $phash1 hash2: $phash2 tolerence: $tolerence hamming distance: $distance") + if (distance <= tolerence) true else false + } } diff --git a/src/main/scala/com/sothr/imagetools/image/ImageService.scala b/src/main/scala/com/sothr/imagetools/image/ImageService.scala index 86651c3..c6b45fe 100644 --- a/src/main/scala/com/sothr/imagetools/image/ImageService.scala +++ b/src/main/scala/com/sothr/imagetools/image/ImageService.scala @@ -70,9 +70,9 @@ object ImageService extends Logging { var col = 0 debug(s"Processing pixels 0 until $numPixels by $pixelLength") for (pixel <- 0 until numPixels by pixelLength) { - debug(s"Processing pixel: $pixel/${numPixels - 1}") + //debug(s"Processing pixel: $pixel/${numPixels - 1}") val argb:Int = pixels(pixel).toInt //singleChannel - debug(s"Pixel data: $argb") + //debug(s"Pixel data: $argb") result(row)(col) = argb col += 1 if (col == width) { @@ -88,7 +88,7 @@ object ImageService extends Logging { var col = 0 debug(s"Processing pixels 0 until $numPixels by $pixelLength") for (pixel <- 0 until numPixels by pixelLength) { - debug(s"Processing pixel: $pixel/${numPixels - 1}") + //debug(s"Processing pixel: $pixel/${numPixels - 1}") var argb:Int = 0 argb += pixels(pixel).toInt << 24 //alpha argb += pixels(pixel + 1).toInt //blue @@ -108,7 +108,7 @@ object ImageService extends Logging { var col = 0 debug(s"Processing pixels 0 until $numPixels by $pixelLength") for (pixel <- 0 until numPixels by pixelLength) { - debug(s"Processing pixel: $pixel/${numPixels - 1}") + //debug(s"Processing pixel: $pixel/${numPixels - 1}") var argb:Int = 0 argb += -16777216; // 255 alpha argb += pixels(pixel).toInt //blue diff --git a/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala b/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala index b396169..885990d 100644 --- a/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala +++ b/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala @@ -14,12 +14,15 @@ object PropertiesEnum extends Enumeration { val UseAhash = Value("image.ahash.use") val AhashWeight = Value("image.ahash.weight") val AhashPrecision = Value("image.ahash.precision") + val AhashTolerence = Value("image.ahash.tolerence") val UseDhash = Value("image.dhash.use") val DhashWeight = Value("image.dhash.weight") val DhashPrecision = Value("image.dhash.precision") + val DhashTolerence = Value("image.dhash.tolerence") val UsePhash = Value("image.phash.use") val PhashWeight = Value("image.phash.weight") val PhashPrecision = Value("image.phash.precision") + val PhashTolerence = Value("image.phash.tolerence") //Default Thumbnail Settings val ThumbnailDirectory = Value("thumbnail.directory") val ThumbnailSize = Value("thumbnail.size") diff --git a/src/test/resources/default.properties b/src/test/resources/default.properties index 1203614..ffa4755 100644 --- a/src/test/resources/default.properties +++ b/src/test/resources/default.properties @@ -16,13 +16,16 @@ image.hash.precision=64 image.ahash.use=true image.ahash.weight=0.70 image.ahash.precision=8 +image.ahash.tolerence=8 image.dhash.use=true image.dhash.weight=0.85 image.dhash.precision=8 +image.dhash.tolerence=8 #set to false if hashing images is taking too long image.phash.use=true image.phash.weight=1.0 image.phash.precision=16 +image.phash.tolerence=8 #Default Thumbnail Settings #Directory where to store thumbnails diff --git a/src/test/scala/com/sothr/imagetools/TestParams.scala b/src/test/scala/com/sothr/imagetools/TestParams.scala index 80570ec..599ba47 100644 --- a/src/test/scala/com/sothr/imagetools/TestParams.scala +++ b/src/test/scala/com/sothr/imagetools/TestParams.scala @@ -1,7 +1,7 @@ package com.sothr.imagetools object TestParams { - val LargeSampleImage1 = "target/sample/sample_01_large.jpg" - val MediumSampleImage1 = "target/sample/sample_01_medium.jpg" - val SmallSampleImage1 = "target/sample/sample_01_small.jpg" + val LargeSampleImage1 = "sample/sample_01_large.jpg" + val MediumSampleImage1 = "sample/sample_01_medium.jpg" + val SmallSampleImage1 = "sample/sample_01_small.jpg" } \ No newline at end of file diff --git a/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala b/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala index 1b9a1a3..632d7a9 100644 --- a/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala +++ b/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala @@ -9,7 +9,7 @@ import java.io.File */ class HashServiceTest extends BaseTest { - def benchmarkDHashTestCase(filePath:String):Long = { + def dhashTestCase(filePath:String):Long = { val sample = new File(filePath) val image = ImageIO.read(sample) HashService.getDhash(image) @@ -18,27 +18,27 @@ class HashServiceTest extends BaseTest { test("Benchmark DHash") { info("Benchmarking DHash") info("DHash Large Image 3684x2736") - val largeTime1 = getTime { benchmarkDHashTestCase(TestParams.LargeSampleImage1) } - val largeTime2 = getTime { benchmarkDHashTestCase(TestParams.LargeSampleImage1) } - val largeTime3 = getTime { benchmarkDHashTestCase(TestParams.LargeSampleImage1) } - val largeTime4 = getTime { benchmarkDHashTestCase(TestParams.LargeSampleImage1) } - val largeTime5 = getTime { benchmarkDHashTestCase(TestParams.LargeSampleImage1) } + val largeTime1 = getTime { dhashTestCase(TestParams.LargeSampleImage1) } + val largeTime2 = getTime { dhashTestCase(TestParams.LargeSampleImage1) } + val largeTime3 = getTime { dhashTestCase(TestParams.LargeSampleImage1) } + val largeTime4 = getTime { dhashTestCase(TestParams.LargeSampleImage1) } + val largeTime5 = getTime { dhashTestCase(TestParams.LargeSampleImage1) } val largeMean = getMean(largeTime1, largeTime2, largeTime3, largeTime4, largeTime5) info(s"The mean time of 5 tests for large was: $largeMean ms") info("DHash Medium Image 1824x1368") - val mediumTime1 = getTime { benchmarkDHashTestCase(TestParams.MediumSampleImage1) } - val mediumTime2 = getTime { benchmarkDHashTestCase(TestParams.MediumSampleImage1) } - val mediumTime3 = getTime { benchmarkDHashTestCase(TestParams.MediumSampleImage1) } - val mediumTime4 = getTime { benchmarkDHashTestCase(TestParams.MediumSampleImage1) } - val mediumTime5 = getTime { benchmarkDHashTestCase(TestParams.MediumSampleImage1) } + val mediumTime1 = getTime { dhashTestCase(TestParams.MediumSampleImage1) } + val mediumTime2 = getTime { dhashTestCase(TestParams.MediumSampleImage1) } + val mediumTime3 = getTime { dhashTestCase(TestParams.MediumSampleImage1) } + val mediumTime4 = getTime { dhashTestCase(TestParams.MediumSampleImage1) } + val mediumTime5 = getTime { dhashTestCase(TestParams.MediumSampleImage1) } val mediumMean = getMean(mediumTime1, mediumTime2, mediumTime3, mediumTime4, mediumTime5) info(s"The mean time of 5 tests for medium was: $mediumMean ms") info("DHash Small Image 912x684") - val smallTime1 = getTime { benchmarkDHashTestCase(TestParams.SmallSampleImage1) } - val smallTime2 = getTime { benchmarkDHashTestCase(TestParams.SmallSampleImage1) } - val smallTime3 = getTime { benchmarkDHashTestCase(TestParams.SmallSampleImage1) } - val smallTime4 = getTime { benchmarkDHashTestCase(TestParams.SmallSampleImage1) } - val smallTime5 = getTime { benchmarkDHashTestCase(TestParams.SmallSampleImage1) } + val smallTime1 = getTime { dhashTestCase(TestParams.SmallSampleImage1) } + val smallTime2 = getTime { dhashTestCase(TestParams.SmallSampleImage1) } + val smallTime3 = getTime { dhashTestCase(TestParams.SmallSampleImage1) } + val smallTime4 = getTime { dhashTestCase(TestParams.SmallSampleImage1) } + val smallTime5 = getTime { dhashTestCase(TestParams.SmallSampleImage1) } val smallMean = getMean(smallTime1, smallTime2, smallTime3, smallTime4, smallTime5) info(s"The mean time of 5 tests for small was: $smallMean ms") assert(true) @@ -76,5 +76,14 @@ class HashServiceTest extends BaseTest { debug(s"Testing that $hash = -5198299688551933030L") assert(hash == -5198299688551933030L) } + + test("DHash Of Large, Medium, And Small Sample 1 Must Be Similar") { + val largeHash = dhashTestCase(TestParams.LargeSampleImage1) + val mediumHash = dhashTestCase(TestParams.MediumSampleImage1) + val smallHash = dhashTestCase(TestParams.SmallSampleImage1) + assert(HashService.areDhashSimilar(largeHash,mediumHash)) + assert(HashService.areDhashSimilar(largeHash,smallHash)) + assert(HashService.areDhashSimilar(mediumHash,smallHash)) + } }