diff --git a/hashcompute.go b/hashcompute.go index d1ca4fb..abf2aae 100644 --- a/hashcompute.go +++ b/hashcompute.go @@ -91,9 +91,7 @@ func PerceptionHashExtend(img image.Image, hashSize int) (*ExtImageHash, error) if img == nil { return nil, errors.New("Image object can not be nil") } - highFreqFactor := 8 - imgSize := hashSize * highFreqFactor - + imgSize := hashSize * hashSize resized := resize.Resize(uint(imgSize), uint(imgSize), img, resize.Bilinear) pixels := transforms.Rgb2Gray(resized) dct := transforms.DCT2D(pixels, imgSize, imgSize) @@ -101,10 +99,9 @@ func PerceptionHashExtend(img image.Image, hashSize int) (*ExtImageHash, error) median := etcs.MedianOfPixels(flattens) lenOfUnit := 64 - lenOfPhash := hashSize * hashSize - phash := make([]uint64, lenOfPhash/lenOfUnit) + phash := make([]uint64, imgSize/lenOfUnit) for idx, p := range flattens { - indexOfArray := (lenOfPhash - 1 - idx) / lenOfUnit + indexOfArray := (imgSize - 1 - idx) / lenOfUnit indexOfBit := idx % lenOfUnit if p > median { phash[indexOfArray] |= 1 << uint(indexOfBit) @@ -112,3 +109,29 @@ func PerceptionHashExtend(img image.Image, hashSize int) (*ExtImageHash, error) } return NewExtImageHash(phash, PHash), nil } + +// AverageHashExtend function returns ahash of which the size can be set larger than uint64 +// Support 64bits ahash (hashSize=8) and 256bits ahash (hashSize=16) +func AverageHashExtend(img image.Image, hashSize int) (*ExtImageHash, error) { + if img == nil { + return nil, errors.New("Image object can not be nil") + } + + imgSize := hashSize * hashSize + + resized := resize.Resize(uint(hashSize), uint(hashSize), img, resize.Bilinear) + pixels := transforms.Rgb2Gray(resized) + flattens := transforms.FlattenPixels(pixels, hashSize, hashSize) + avg := etcs.MeanOfPixels(flattens) + + lenOfUnit := 64 + ahash := make([]uint64, imgSize/lenOfUnit) + for idx, p := range flattens { + indexOfArray := (imgSize - 1 - idx) / lenOfUnit + indexOfBit := idx % lenOfUnit + if p > avg { + ahash[indexOfArray] |= 1 << uint(indexOfBit) + } + } + return NewExtImageHash(ahash, AHash), nil +} diff --git a/hashcompute_test.go b/hashcompute_test.go index b130fd2..b058fb2 100644 --- a/hashcompute_test.go +++ b/hashcompute_test.go @@ -147,22 +147,36 @@ func TestExtImageHashCompute(t *testing.T) { img1 string img2 string hashSize int + method func(img image.Image, hashSize int) (*ExtImageHash, error) name string distance int }{ - {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, "PerceptionHashExtend", 0}, - {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, "PerceptionHashExtend", 0}, - {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, "PerceptionHashExtend", 0}, - {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, "PerceptionHashExtend", 0}, - {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, "PerceptionHashExtend", 32}, - {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, "PerceptionHashExtend", 2}, - {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, "PerceptionHashExtend", 30}, - {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, "PerceptionHashExtend", 34}, - {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, "PerceptionHashExtend", 20}, - {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, "PerceptionHashExtend", 0}, - {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, "PerceptionHashExtend", 0}, - {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, "PerceptionHashExtend", 0}, - {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, "PerceptionHashExtend", 0}, + {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, AverageHashExtend, "AverageHashExtend", 42}, + {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, AverageHashExtend, "AverageHashExtend", 4}, + {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, AverageHashExtend, "AverageHashExtend", 38}, + {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, AverageHashExtend, "AverageHashExtend", 40}, + {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, AverageHashExtend, "AverageHashExtend", 6}, + {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, AverageHashExtend, "AverageHashExtend", 0}, + {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 32}, + {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 2}, + {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 30}, + {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 34}, + {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, PerceptionHashExtend, "PerceptionHashExtend", 20}, + {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, PerceptionHashExtend, "PerceptionHashExtend", 0}, + {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, PerceptionHashExtend, "PerceptionHashExtend", 0}, } { file1, err := os.Open(tt.img1) if err != nil { @@ -186,11 +200,11 @@ func TestExtImageHashCompute(t *testing.T) { t.Errorf("%s", err) } - hash1, err := PerceptionHashExtend(img1, tt.hashSize) + hash1, err := tt.method(img1, tt.hashSize) if err != nil { t.Errorf("%s", err) } - hash2, err := PerceptionHashExtend(img2, tt.hashSize) + hash2, err := tt.method(img2, tt.hashSize) if err != nil { t.Errorf("%s", err) } @@ -212,18 +226,6 @@ func TestExtImageHashCompute(t *testing.T) { 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) } - - if tt.hashSize == 8 { - hash0, err := PerceptionHash(img1) - if err != nil { - t.Errorf("%s", err) - } - hex0 := hash0.ToString() - hex1 := hash1.ToString() - if hex0 != hex1 { - t.Errorf("Hex is expected %v but got %v", hex0, hex1) - } - } } }