blob: 8dcc9e86ea62c47c9f62764a8e307c2854905c0d [file]
// digesttools are utility functions for answering questions about digests.
package digesttools
import (
"math"
"github.com/skia-dev/glog"
"go.skia.org/infra/golden/go/diff"
"go.skia.org/infra/golden/go/expstorage"
"go.skia.org/infra/golden/go/types"
)
// Closest describes one digest that is the closest another digest.
type Closest struct {
Digest string `json:"digest"` // The closest digest, empty if there are no digests to compare to.
Diff float32 `json:"diff"` // A percent value.
DiffPixels float32 `json:"diffPixels"` // A percent value.
MaxRGBA []int `json:"maxRGBA"`
}
func newClosest() *Closest {
return &Closest{
Diff: math.MaxFloat32,
DiffPixels: math.MaxFloat32,
MaxRGBA: []int{},
}
}
// ClosestDigest returns the closest digest of type 'label' to 'digest', or "" if there aren't any positive digests.
//
// If no digest of type 'label' is found then Closest.Digest is the empty string.
func ClosestDigest(test string, digest string, exp *expstorage.Expectations, diffStore diff.DiffStore, label types.Label) *Closest {
ret := newClosest()
selected := []string{}
if e, ok := exp.Tests[test]; ok {
for d, l := range e {
if l == label {
selected = append(selected, d)
}
}
}
if diffMetrics, err := diffStore.Get(digest, selected); err != nil {
glog.Errorf("ClosestDigest: Failed to get diff: %s", err)
return ret
} else {
for digest, diff := range diffMetrics {
if delta := combinedDiffMetric(diff.PixelDiffPercent, diff.MaxRGBADiffs); delta < ret.Diff {
ret.Digest = digest
ret.Diff = delta
ret.DiffPixels = diff.PixelDiffPercent
ret.MaxRGBA = diff.MaxRGBADiffs
}
}
return ret
}
}
// combinedDiffMetric returns a value in [0, 1] that represents how large
// the diff is between two images.
func combinedDiffMetric(pixelDiffPercent float32, maxRGBA []int) float32 {
if len(maxRGBA) == 0 {
return 1.0
}
// Turn maxRGBA into a percent by taking the root mean square difference from
// [0, 0, 0, 0].
sum := 0.0
for _, c := range maxRGBA {
sum += float64(c) * float64(c)
}
normalizedRGBA := math.Sqrt(sum/float64(len(maxRGBA))) / 255.0
// We take the sqrt of (pixelDiffPercent * normalizedRGBA) to straigten out
// the curve, i.e. think about what a plot of x^2 would look like in the
// range [0, 1].
return float32(math.Sqrt(float64(pixelDiffPercent) * normalizedRGBA))
}