imagehash: Create a new API Bits() (#25)

This commit is contained in:
Dong-hee Na 2019-03-17 15:42:07 +09:00 committed by GitHub
parent 84eb1859d0
commit 47321c08d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 11 deletions

View File

@ -39,6 +39,19 @@ func main() {
hash2, _ = goimagehash.DifferenceHash(img2) hash2, _ = goimagehash.DifferenceHash(img2)
distance, _ = hash1.Distance(hash2) distance, _ = hash1.Distance(hash2)
fmt.Printf("Distance between images: %v\n", distance) fmt.Printf("Distance between images: %v\n", distance)
hash3, _ = goimagehash.AverageHashExtend(img1, 16)
hash4, _ = goimagehash.AverageHashExtend(img2, 16)
distance, _ = hash3.Distance(hash4)
fmt.Printf("Distance between images: %v\n", distance)
fmt.Printf("hash3 bit size: %v\n", hash3.Bits())
fmt.Printf("hash4 bit size: %v\n", hash4.Bits())
var b bytes.Buffer
foo := bufio.NewWriter(&b)
_ = hash4.Dump(foo)
foo.Flush()
bar := bufio.NewReader(&b)
hash5, _ := goimagehash.LoadImageHashExtend(bar)
} }
``` ```

View File

@ -29,4 +29,6 @@ func main() {
hash2, _ = goimagehash.PerceptionHash(img2) hash2, _ = goimagehash.PerceptionHash(img2)
distance, _ = hash1.Distance(hash2) distance, _ = hash1.Distance(hash2)
fmt.Printf("Distance between images: %v\n", distance) fmt.Printf("Distance between images: %v\n", distance)
fmt.Println(hash1.Bits())
fmt.Println(hash2.Bits())
} }

View File

@ -4,9 +4,10 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"github.com/corona10/goimagehash"
"image/jpeg" "image/jpeg"
"os" "os"
"github.com/corona10/goimagehash"
) )
func main() { func main() {
@ -20,9 +21,9 @@ func main() {
img2, _ := jpeg.Decode(file2) img2, _ := jpeg.Decode(file2)
hash1, _ := goimagehash.AverageHashExtend(img1, 15) hash1, _ := goimagehash.AverageHashExtend(img1, 15)
hash2, _ := goimagehash.AverageHashExtend(img2, 15) hash2, _ := goimagehash.AverageHashExtend(img2, 15)
hash1024, _ := goimagehash.AverageHashExtend(img2, 32)
distance, _ := hash1.Distance(hash2) distance, _ := hash1.Distance(hash2)
fmt.Printf("Distance between images: %v\n", distance) fmt.Printf("Distance between images: %v\n", distance)
err := hash1.Dump(foo) err := hash1.Dump(foo)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
@ -33,6 +34,8 @@ func main() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
distance, err = hash1.Distance(hash1024)
fmt.Println(err)
distance, _ = hash1.Distance(hash3) distance, _ = hash1.Distance(hash3)
fmt.Printf("Distance between hash1 and hash3: %v\n", distance) fmt.Printf("Distance between hash1 and hash3: %v\n", distance)
distance, _ = hash2.Distance(hash3) distance, _ = hash2.Distance(hash3)
@ -40,4 +43,7 @@ func main() {
fmt.Println(hash1.ToString()) fmt.Println(hash1.ToString())
fmt.Println(hash2.ToString()) fmt.Println(hash2.ToString())
fmt.Println(hash3.ToString()) fmt.Println(hash3.ToString())
fmt.Println(hash1.Bits())
fmt.Println(hash2.Bits())
fmt.Println(hash3.Bits())
} }

View File

@ -112,7 +112,7 @@ func PerceptionHashExtend(img image.Image, hashSize int) (*ExtImageHash, error)
phash[indexOfArray] |= 1 << uint(indexOfBit) phash[indexOfArray] |= 1 << uint(indexOfBit)
} }
} }
return NewExtImageHash(phash, PHash), nil return NewExtImageHash(phash, PHash, imgSize), nil
} }
// AverageHashExtend function returns ahash of which the size can be set larger than uint64 // AverageHashExtend function returns ahash of which the size can be set larger than uint64
@ -142,7 +142,7 @@ func AverageHashExtend(img image.Image, hashSize int) (*ExtImageHash, error) {
ahash[indexOfArray] |= 1 << uint(indexOfBit) ahash[indexOfArray] |= 1 << uint(indexOfBit)
} }
} }
return NewExtImageHash(ahash, AHash), nil return NewExtImageHash(ahash, AHash, imgSize), nil
} }
// DifferenceHashExtend function returns dhash of which the size can be set larger than uint64 // DifferenceHashExtend function returns dhash of which the size can be set larger than uint64
@ -175,5 +175,5 @@ func DifferenceHashExtend(img image.Image, hashSize int) (*ExtImageHash, error)
idx++ idx++
} }
} }
return NewExtImageHash(dhash, DHash), nil return NewExtImageHash(dhash, DHash, imgSize), nil
} }

View File

@ -26,6 +26,7 @@ type ImageHash struct {
type ExtImageHash struct { type ExtImageHash struct {
hash []uint64 hash []uint64
kind Kind kind Kind
bits int
} }
const ( const (
@ -46,6 +47,11 @@ func NewImageHash(hash uint64, kind Kind) *ImageHash {
return &ImageHash{hash: hash, kind: kind} return &ImageHash{hash: hash, kind: kind}
} }
// Bits method returns an actual hash bit size
func (h *ImageHash) Bits() int {
return 64
}
// Distance method returns a distance between two hashes. // Distance method returns a distance between two hashes.
func (h *ImageHash) Distance(other *ImageHash) (int, error) { func (h *ImageHash) Distance(other *ImageHash) (int, error) {
if h.GetKind() != other.GetKind() { if h.GetKind() != other.GetKind() {
@ -146,8 +152,13 @@ func (h *ImageHash) ToString() string {
} }
// NewExtImageHash function creates a new big hash // NewExtImageHash function creates a new big hash
func NewExtImageHash(hash []uint64, kind Kind) *ExtImageHash { func NewExtImageHash(hash []uint64, kind Kind, bits int) *ExtImageHash {
return &ExtImageHash{hash: hash, kind: kind} return &ExtImageHash{hash: hash, kind: kind, bits: bits}
}
// Bits method returns an actual hash bit size
func (h *ExtImageHash) Bits() int {
return h.bits
} }
// Distance method returns a distance between two big hashes // Distance method returns a distance between two big hashes
@ -156,13 +167,18 @@ func (h *ExtImageHash) Distance(other *ExtImageHash) (int, error) {
return -1, errors.New("Extended Image hashes's kind should be identical") return -1, errors.New("Extended Image hashes's kind should be identical")
} }
if h.Bits() != other.Bits() {
msg := fmt.Sprintf("Extended image hash should has an identical bit size but got %v vs %v", h.Bits(), other.Bits())
return -1, errors.New(msg)
}
lHash := h.GetHash() lHash := h.GetHash()
rHash := other.GetHash() rHash := other.GetHash()
if len(lHash) != len(rHash) { if len(lHash) != len(rHash) {
return -1, errors.New("Extended Image hashes's size should be identical") return -1, errors.New("Extended Image hashes's size should be identical")
} }
var distance int distance := 0
for idx, lh := range lHash { for idx, lh := range lHash {
rh := rHash[idx] rh := rHash[idx]
hamming := lh ^ rh hamming := lh ^ rh
@ -186,9 +202,10 @@ func (h *ExtImageHash) Dump(w io.Writer) error {
type D struct { type D struct {
Hash []uint64 Hash []uint64
Kind Kind Kind Kind
Bits int
} }
enc := gob.NewEncoder(w) enc := gob.NewEncoder(w)
err := enc.Encode(D{Hash: h.hash, Kind: h.kind}) err := enc.Encode(D{Hash: h.hash, Kind: h.kind, Bits: h.bits})
if err != nil { if err != nil {
return err return err
} }
@ -200,6 +217,7 @@ func LoadImageHashExtend(b io.Reader) (*ExtImageHash, error) {
type E struct { type E struct {
Hash []uint64 Hash []uint64
Kind Kind Kind Kind
Bits int
} }
var e E var e E
dec := gob.NewDecoder(b) dec := gob.NewDecoder(b)
@ -207,7 +225,7 @@ func LoadImageHashExtend(b io.Reader) (*ExtImageHash, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ExtImageHash{hash: e.Hash, kind: e.Kind}, nil return &ExtImageHash{hash: e.Hash, kind: e.Kind, bits: e.Bits}, nil
} }
const extStrFmt = "%1s:%s" const extStrFmt = "%1s:%s"
@ -248,7 +266,7 @@ func ExtImageHashFromString(s string) (*ExtImageHash, error) {
case "w": case "w":
kind = WHash kind = WHash
} }
return NewExtImageHash(hash, kind), nil return NewExtImageHash(hash, kind, len(hash)*64), nil
} }
// ToString returns a hex representation of big hash // ToString returns a hex representation of big hash

View File

@ -127,6 +127,31 @@ func TestSerialization(t *testing.T) {
} }
} }
func TestDifferentBitSizeHash(t *testing.T) {
checkErr := func(err error) {
if err != nil {
t.Errorf("%v", err)
}
}
file, err := os.Open("_examples/sample1.jpg")
checkErr(err)
defer file.Close()
img, _, err := image.Decode(file)
checkErr(err)
hash1, _ := AverageHashExtend(img, 32)
hash2, _ := DifferenceHashExtend(img, 32)
_, err = hash1.Distance(hash2)
if err == nil {
t.Errorf("Should got error with different kinds of hashes")
}
hash3, _ := AverageHashExtend(img, 31)
_, err = hash1.Distance(hash3)
if err == nil {
t.Errorf("Should got error with different bits of hashes")
}
}
func TestDumpAndLoad(t *testing.T) { func TestDumpAndLoad(t *testing.T) {
checkErr := func(err error) { checkErr := func(err error) {
if err != nil { if err != nil {
@ -168,6 +193,10 @@ func TestDumpAndLoad(t *testing.T) {
if distance != 0 { if distance != 0 {
t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance) t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance)
} }
if hash.Bits() != 64 || reHash.Bits() != 64 {
t.Errorf("Hash bits should be 64 but got, %v, %v", hash.Bits(), reHash.Bits())
}
} }
// test for ExtIExtImageHash // test for ExtIExtImageHash
@ -195,6 +224,10 @@ func TestDumpAndLoad(t *testing.T) {
if distance != 0 { if distance != 0 {
t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance) t.Errorf("Original and unserialized objects should be identical, got distance=%v", distance)
} }
if hash.Bits() != hashSize*hashSize || reHash.Bits() != hashSize*hashSize {
t.Errorf("Hash bits should be 64 but got, %v, %v", hash.Bits(), reHash.Bits())
}
} }
} }
} }