package org.github.bcolyn.jmediahash.images; import org.ejml.data.DenseMatrix64F; import org.github.bcolyn.jmediahash.util.lucene.OpenBitSet; import org.junit.Test; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.Assert.assertThat; public class DCTImageHashAlgorithmTest { private static final double DEFAULT_THRESHOLD = 15.0; @Test public void testGetHash() throws Exception { URL url = getClass().getResource("/sample/"); File dir = new File(url.toURI()); ImageHashAlgorithm algorithm = new DCTImageHashAlgorithm(); List<OpenBitSet> results = new ArrayList<OpenBitSet>(); for (File file : dir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.toLowerCase().endsWith("jpg"); } })) { BufferedImage bufferedImage = ImageIO.read(file); OpenBitSet hash = algorithm.getHash(bufferedImage); System.out.printf("%s\t%x\n", file.toString(), hash.getBits()[0]); results.add(hash); } double min = Double.MAX_VALUE; for (int i = 0; i < results.size(); i++) { for (int j = i + 1; j < results.size(); j++) { OpenBitSet hash1 = results.get(i); OpenBitSet hash2 = results.get(j); hash1.xor(hash2); double distance = hash1.cardinality(); if (distance < min) min = distance; assertThat(distance, greaterThan(DEFAULT_THRESHOLD)); } } System.out.println("Minimum distance:" + Double.valueOf(min)); } @Test public void testEqual() throws IOException { BufferedImage png = ImageIO.read(getClass().getResource("/sample/IMG_1548.png")); String[] resources = new String[]{ "/sample/IMG_1548.jpg", //just recompressed "/sample/IMG_1548_crayon.jpe", //edited with crayon "/sample/IMG_1548_scaled.jpe", //scaled back a lot "/sample/IMG_1548_cropped.jpe", //cropped - this is tough }; ImageHashAlgorithm algorithm = new DCTImageHashAlgorithm(); OpenBitSet pnghash = algorithm.getHash(png); double max = 0; for (String resource : resources) { BufferedImage jpg = ImageIO.read(getClass().getResource(resource)); OpenBitSet jpghash = algorithm.getHash(jpg); jpghash.xor(pnghash); double distance = jpghash.cardinality(); System.out.printf("Distance for %s = %f\n", resource, distance); if (distance > max) max = distance; assertThat(distance, lessThanOrEqualTo(DEFAULT_THRESHOLD)); } System.out.println("Maxiumum distance:" + Double.valueOf(max)); } @Test public void testSampling() { DCTImageHashAlgorithm service = new DCTImageHashAlgorithm(); DenseMatrix64F result = service.doDct(new DenseMatrix64F(Data.reference_imgdata)); double[] sample = service.extractSample(result, 1, 8); System.out.println(Arrays.toString(Data.reference_sample)); System.out.println(Arrays.toString(sample)); assertEqualsDoubleArray(Data.reference_sample, sample, 0.1); } private void assertEqualsDoubleArray(double[] reference_hash, double[] sample, double tolerance) { assertTrue(reference_hash.length == sample.length); for (int i = 0; i < reference_hash.length; i++) { assertTrue("value not within tolerance:" + Double.toString(sample[i]), Math.abs(reference_hash[i] - sample[i]) < tolerance); } } @Test public void testReferenceHash() { ImageHashAlgorithm algorithm = new DCTImageHashAlgorithm(); OpenBitSet actual = algorithm.getHash(Data.reference_imgdata); OpenBitSet exp = new OpenBitSet(new long[]{Data.reference_hash}, 1); System.out.println(Long.toBinaryString(Data.reference_hash)); System.out.println(Long.toBinaryString(actual.getBits()[0])); assertEquals(exp, actual); } }