From 5de0e78ee6c3bc56ec80000103534fdf8c3d5e62 Mon Sep 17 00:00:00 2001 From: Timmy Welch Date: Fri, 10 May 2024 13:58:04 -0700 Subject: [PATCH] Add debug output for go and python --- cmd/hash.py | 56 ++++++++++++++++++++++++++++ cmd/hash/main.go | 95 ++++++++++++++++++++++++++++++------------------ go.mod | 8 ++-- go.sum | 4 +- 4 files changed, 122 insertions(+), 41 deletions(-) create mode 100644 cmd/hash.py diff --git a/cmd/hash.py b/cmd/hash.py new file mode 100644 index 0000000..b39c872 --- /dev/null +++ b/cmd/hash.py @@ -0,0 +1,56 @@ +from typing import Collection, Sequence +from PIL import Image +import argparse,pathlib,numpy,imagehash + +ap = argparse.ArgumentParser() + +ap.add_argument("--file", type=pathlib.Path) + +opts = ap.parse_args() +opts.file = pathlib.Path(opts.file) + +hash_size = 8 + +image = Image.open(opts.file) +gray = image.copy().convert('L') +resized = gray.copy().resize((hash_size, hash_size), Image.Resampling.LANCZOS) + + +def print_image(image: Image.Image) -> None: + for row in numpy.asarray(image): + print('[ ', end='') + for i in row: + if isinstance(i, Collection): + print('{ ', end='') + for idx, x in enumerate(i): + if idx == len(i)-1: + print(f'{int(x):03d} ', end='') + else: + print(f'{int(x):03d}, ', end='') + print('}, ', end='') + else: + print(f'{int(i):03d}, ', end='') + print(']') + +def bin_str(hash): + return ''.join(str(b) for b in 1 * hash.hash.flatten()) + + +print("rgb") +print_image(image) +print() +image.save("py.rgb.png") + +print("gray") +print_image(gray) +gray.save("py.gray.png") +print() + +print("resized") +print_image(resized) +resized.save("py.resized.png") +print() + +print('ahash: ', bin_str(imagehash.average_hash(image))) +print('dhash: ', bin_str(imagehash.dhash(image))) +print('phash: ', bin_str(imagehash.phash(image))) diff --git a/cmd/hash/main.go b/cmd/hash/main.go index 174772a..2540687 100644 --- a/cmd/hash/main.go +++ b/cmd/hash/main.go @@ -7,21 +7,58 @@ import ( "image/draw" _ "image/gif" _ "image/jpeg" + + // "github.com/pixiv/go-libjpeg/jpeg" "image/png" "log" "os" "strings" - _ "github.com/spakin/netpbm" - "gitea.narnian.us/lordwelch/goimagehash" + "gitea.narnian.us/lordwelch/goimagehash/transforms" "github.com/anthonynsimon/bild/transform" _ "github.com/gen2brain/avif" + _ "github.com/spakin/netpbm" _ "golang.org/x/image/bmp" _ "golang.org/x/image/tiff" _ "golang.org/x/image/webp" ) +func init() { + // image.RegisterFormat("jpeg", "\xff\xd8", func(r io.Reader) (image.Image, error){return jpeg.Decode(r, &jpeg.DecoderOptions{ + // DisableFancyUpsampling: false, + // DisableBlockSmoothing: false, + // DCTMethod: jpeg.DCTFloat, + // })}, jpeg.DecodeConfig) + +} + +func ToGray(img image.Image) *image.Gray { + gray := image.NewGray(image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy())) + gray.Pix = transforms.Rgb2Gray(img) + return gray +} + +func resize(img image.Image, w, h int) *image.Gray { + resized := transform.Resize(img, w, h, transform.Lanczos) + r_gray := image.NewGray(image.Rect(0, 0, resized.Bounds().Dx(), resized.Bounds().Dy())) + draw.Draw(r_gray, resized.Bounds(), resized, resized.Bounds().Min, draw.Src) + return r_gray +} + +func save_image(im image.Image, name string) { + file, err := os.Create(name) + if err != nil { + log.Printf("Failed to open file %s: %s", "tmp.png", err) + return + } + err = png.Encode(file, im) + if err != nil { + panic(err) + } + file.Close() +} + func fmtImage(im image.Image) string { gray, ok := im.(*image.Gray) str := &strings.Builder{} @@ -34,10 +71,7 @@ func fmtImage(im image.Image) string { } else { col := im.At(x, y) r, g, b, _ := col.RGBA() - if uint8(r) == 0x0015 && uint8(g) == 0x0013 && uint8(b) == 0x0012 { - fmt.Fprintf(os.Stderr, "RGB: { %04x, %04x, %04x }\n", uint8(r), uint8(g), uint8(b)) - } - fmt.Fprintf(str, "{ %04x, %04x, %04x }, ", uint8(r), uint8(g), uint8(b)) + fmt.Fprintf(str, "{ %03d, %03d, %03d }, ", uint8(r>>8), uint8(g>>8), uint8(b>>8)) } } str.WriteString("]\n") @@ -46,19 +80,18 @@ func fmtImage(im image.Image) string { } func debugImage(im image.Image, width, height int) { - // gray := image.NewGray(image.Rect(0, 0, im.Bounds().Dx(), im.Bounds().Dy())) - // gray.Pix = transforms.Rgb2Gray(im) - // i_resize := imaging.Resize(im, width, height, imaging.Linear) - resized := transform.Resize(im, 8, 8, transform.Lanczos) - r_gray := image.NewGray(image.Rect(0, 0, resized.Bounds().Dx(), resized.Bounds().Dy())) - draw.Draw(r_gray, resized.Bounds(), resized, resized.Bounds().Min, draw.Src) + gray := ToGray(im) + resized := resize(gray, width, height) - // fmt.Fprintln(os.Stderr, "rgb") - // fmt.Println(fmtImage(im)) - // fmt.Fprintln(os.Stderr, "grayscale") - // fmt.Println(fmtImage(gray)) - // fmt.Println("resized") - fmt.Println(fmtImage(r_gray)) + fmt.Println("rgb") + fmt.Println(fmtImage(im)) + save_image(im, "go.rgb.png") + fmt.Println("gray") + fmt.Println(fmtImage(gray)) + save_image(gray, "go.gray.png") + fmt.Println("resized") + fmt.Println(fmtImage(resized)) + save_image(resized, "go.resized.png") } func main() { @@ -86,6 +119,8 @@ func main() { im = goimagehash.FancyUpscale(im.(*image.YCbCr)) } + debugImage(im, 8, 8) + var ( ahash *goimagehash.ImageHash dhash *goimagehash.ImageHash @@ -98,32 +133,22 @@ func main() { log.Println(msg) return } + dhash, err = goimagehash.DifferenceHash(im) if err != nil { - msg := fmt.Sprintf("Failed to dhash Image: %s", err) + msg := fmt.Sprintf("Failed to ahash Image: %s", err) log.Println(msg) return } + phash, err = goimagehash.PerceptionHash(im) if err != nil { - msg := fmt.Sprintf("Failed to phash Image: %s", err) + msg := fmt.Sprintf("Failed to ahash Image: %s", err) log.Println(msg) return } - gray := goimagehash.ToGray(im) - file2, err := os.Create("tmp.png") - if err != nil { - log.Printf("Failed to open file %s: %s", "tmp.png", err) - return - } - err = png.Encode(file2, gray) - if err != nil { - panic(err) - } - file2.Close() - debugImage(gray, 9, 8) - fmt.Fprintf(os.Stderr, "ahash: %s\n", ahash.String()) - fmt.Fprintf(os.Stderr, "dhash: %s\n", dhash.String()) - fmt.Fprintf(os.Stderr, "phash: %s\n", phash.String()) + fmt.Println("ahash: ", ahash.BinString()) + fmt.Println("dhash: ", dhash.BinString()) + fmt.Println("phash: ", phash.BinString()) } diff --git a/go.mod b/go.mod index 6f1bcbd..502a0d1 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module gitea.narnian.us/lordwelch/image-hasher -go 1.21 +go 1.22.1 -toolchain go1.22.0 +toolchain go1.22.2 require ( gitea.narnian.us/lordwelch/goimagehash v0.0.0-20240502010648-cb5a8237c420 @@ -30,8 +30,8 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/net v0.22.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/text v0.14.0 google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect diff --git a/go.sum b/go.sum index e79ccdd..d8d0ffe 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=