2
\$\begingroup\$

I have some code in Go that is attempting to compare two images and determine how different they are. The method is fairly crude, but it is fast enough. Basically it just compares both images pixel by pixel and for each pixel it determines how different they are by comparing the RGBA values separately and using the absolute value of the difference (summed across the 4 channels) as the difference value for the current pixel. It sums together all these difference values and uses that number as the final result (that is then printed).

Does anyone have any comment on how this can be improved? Specifically for accuracy, as I mentioned, performance is "good enough" for now, though I'm not opposed to comments on efficiency as well.

package main

import (
    "os"
    "log"
    "image"
    "image/color"
    "math"
    "fmt"

    _ "image/png"
)

func main () {
    // open the target file
    target_file, err := os.Open("/home/gregg/workspace/Fueled/imagefilters/www/test_images/nashville.png")
    if (err != nil) {
        log.Fatal(err)
    }
    defer target_file.Close()

    // open the source file
    source_file, err := os.Open("/home/gregg/workspace/Fueled/imagefilters/www/test_images/out.png")
    if (err != nil) {
        log.Fatal(err)
    }
    defer source_file.Close()

    // decode the target file
    target, _, err := image.Decode(target_file)
    if (err != nil) {
        log.Fatal(err)
    }

    // decode the source file
    source, _, err := image.Decode(source_file)
    if (err != nil) {
        log.Fatal(err)
    }

    // check to make sure Bounds match
    target_bounds := target.Bounds()
    source_bounds := source.Bounds()
    if (!boundsMatch(target_bounds, source_bounds)) {
        log.Fatal("Image sizes don't match!")
    }

    var diff int64
    for y := target_bounds.Min.Y; y < target_bounds.Max.Y; y++ {
        for x := target_bounds.Min.X; x < target_bounds.Max.X; x++ {
            diff += compareColor(target.At(x, y), source.At(x, y))
        }
    }
    fmt.Printf("%d\n", diff)
}

func compareColor(a, b color.Color) (diff int64) {
    r1, g1, b1, a1 := a.RGBA()
    r2, g2, b2, a2 := b.RGBA()

    diff += int64(math.Abs(float64(r1-r2)))
    diff += int64(math.Abs(float64(g1-g2)))
    diff += int64(math.Abs(float64(b1-b2)))
    diff += int64(math.Abs(float64(a1-a2)))
    return diff
}

func boundsMatch(a, b image.Rectangle) bool {
    return a.Min.X == b.Min.X && a.Min.Y == b.Min.Y && a.Max.X == b.Max.X && a.Max.Y == b.Max.Y
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I wouldn't use rgba for this kind of difference but a color model more natural, like HSL. \$\endgroup\$ – Denys Séguret Jun 18 '12 at 15:30
  • \$\begingroup\$ I'm going to give that a try and see how it works, but int he mean time, do you have any specific justification? \$\endgroup\$ – gregghz Jun 18 '12 at 15:46
  • 2
    \$\begingroup\$ Look for "Use in image analysis" in this page. It's also my experience that HSL gives good results especially when looking for contrast, distance, and color merging (and probably other domains but my personal experience in image analysis is limited). \$\endgroup\$ – Denys Séguret Jun 18 '12 at 15:51
  • \$\begingroup\$ That page also says: "While HSL, HSV, and related spaces serve well enough to, for instance, choose a single color, they ignore much of the complexity of color appearance." How might that affect comparing two pixels? will that be irrelevant in this case? \$\endgroup\$ – gregghz Jun 18 '12 at 16:05
  • \$\begingroup\$ It depends on your goal. Why a pixel by pixel comparison ? What kind of similarity are you looking for ? \$\endgroup\$ – Denys Séguret Jun 18 '12 at 16:09
5
\$\begingroup\$

Though I didn't check the whole program and, according to you, performance is good enough, I do have one performance related suggestion:

avoid int64(math.Abs(float64(var1-var2))). Casting between int and float types is not free. Just read about Two's complement for ints and how floats are represented in the IEEE 754 standard. That conversion is not trivial!

As Go (as far as I know) doesn't have an abs method for int-like types, this may provide inspiration on how to calculate the abs for signed ints.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.