goimagehash/hashcompute_test.go
Dominik Honnef ad2b6ded3b Use bits.OnesCount64 when available
Benchmark on i7-2600k, which has the POPCNT instruction:

name                 old time/op  new time/op  delta
DistanceIdentical-8  5.08ns ± 0%  1.01ns ± 1%  -80.07%  (p=0.008 n=5+5)
DistanceDifferent-8  81.5ns ± 2%   1.0ns ± 0%  -98.76%  (p=0.016 n=5+4)

Benchmark on Cavium Octeon, a MIPS64 platform with no dedicated
instruction:

name                 old time/op  new time/op  delta
DistanceIdentical-2   120ns ± 6%   144ns ± 5%  +19.93%  (p=0.008 n=5+5)
DistanceDifferent-2   656ns ± 4%   144ns ± 4%  -78.09%  (p=0.008 n=5+5)
2018-05-02 23:52:38 +09:00

118 lines
4.1 KiB
Go

// Copyright 2017 The goimagehash Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goimagehash
import (
"image"
"image/jpeg"
"os"
"testing"
)
func TestHashCompute(t *testing.T) {
for _, tt := range []struct {
img1 string
img2 string
method func(img image.Image) (*ImageHash, error)
name string
distance int
}{
{"_examples/sample1.jpg", "_examples/sample1.jpg", AverageHash, "AverageHash", 0},
{"_examples/sample2.jpg", "_examples/sample2.jpg", AverageHash, "AverageHash", 0},
{"_examples/sample3.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 0},
{"_examples/sample4.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 0},
{"_examples/sample1.jpg", "_examples/sample2.jpg", AverageHash, "AverageHash", 42},
{"_examples/sample1.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 4},
{"_examples/sample1.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 38},
{"_examples/sample2.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 40},
{"_examples/sample2.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 6},
{"_examples/sample1.jpg", "_examples/sample1.jpg", DifferenceHash, "DifferenceHash", 0},
{"_examples/sample2.jpg", "_examples/sample2.jpg", DifferenceHash, "DifferenceHash", 0},
{"_examples/sample3.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 0},
{"_examples/sample4.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 0},
{"_examples/sample1.jpg", "_examples/sample2.jpg", DifferenceHash, "DifferenceHash", 43},
{"_examples/sample1.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 0},
{"_examples/sample1.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 37},
{"_examples/sample2.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 43},
{"_examples/sample2.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 16},
{"_examples/sample1.jpg", "_examples/sample1.jpg", PerceptionHash, "PerceptionHash", 0},
{"_examples/sample2.jpg", "_examples/sample2.jpg", PerceptionHash, "PerceptionHash", 0},
{"_examples/sample3.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 0},
{"_examples/sample4.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 0},
{"_examples/sample1.jpg", "_examples/sample2.jpg", PerceptionHash, "PerceptionHash", 34},
{"_examples/sample1.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 7},
{"_examples/sample1.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 31},
{"_examples/sample2.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 31},
{"_examples/sample2.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 23},
} {
file1, err := os.Open(tt.img1)
if err != nil {
}
defer file1.Close()
file2, err := os.Open(tt.img2)
if err != nil {
t.Errorf("%s", err)
}
defer file2.Close()
img1, err := jpeg.Decode(file1)
if err != nil {
t.Errorf("%s", err)
}
img2, err := jpeg.Decode(file2)
if err != nil {
t.Errorf("%s", err)
}
hash1, err := tt.method(img1)
if err != nil {
t.Errorf("%s", err)
}
hash2, err := tt.method(img2)
if err != nil {
t.Errorf("%s", err)
}
dis1, err := hash1.Distance(hash2)
if err != nil {
t.Errorf("%s", err)
}
dis2, err := hash2.Distance(hash1)
if err != nil {
t.Errorf("%s", err)
}
if dis1 != dis2 {
t.Errorf("Distance should be identical %v vs %v", dis1, dis2)
}
if dis1 != tt.distance {
t.Errorf("%s: Distance between %v and %v is expected %v but got %v", tt.name, tt.img1, tt.img2, tt.distance, dis1)
}
}
}
func BenchmarkDistanceIdentical(b *testing.B) {
h1 := &ImageHash{hash: 0xe48ae53c05e502f7}
h2 := &ImageHash{hash: 0xe48ae53c05e502f7}
for i := 0; i < b.N; i++ {
h1.Distance(h2)
}
}
func BenchmarkDistanceDifferent(b *testing.B) {
h1 := &ImageHash{hash: 0xe48ae53c05e502f7}
h2 := &ImageHash{hash: 0x678be53815e510f7} // 8 bits flipped
for i := 0; i < b.N; i++ {
h1.Distance(h2)
}
}