Add luminance and monochrome return values to MediaFile.Colors()

This commit is contained in:
Michael Mayer 2019-04-29 01:59:57 +02:00
parent 7ddfb6d9dc
commit 5e1210c508
5 changed files with 64 additions and 21 deletions

View File

@ -18,6 +18,8 @@ type Photo struct {
PhotoArtist string
PhotoColors string
PhotoColor string
PhotoLuminance string
PhotoMonochrome bool
PhotoCanonicalName string
PhotoFavorite bool
PhotoLat float64

View File

@ -2,8 +2,10 @@ package photoprism
import (
"fmt"
"image"
"image/color"
"log"
"math"
"github.com/disintegration/imaging"
"github.com/lucasb-eyer/go-colorful"
@ -12,6 +14,9 @@ import (
type MaterialColor uint16
type MaterialColors []MaterialColor
type Luminance uint8
type LightMap []Luminance
const ColorSampleSize = 3
const (
@ -87,6 +92,18 @@ func (c MaterialColors) Hex() (result string) {
return result
}
func (l Luminance) Hex() string {
return fmt.Sprintf("%X", l)
}
func (m LightMap) Hex() (result string) {
for _, luminance := range m {
result += luminance.Hex()
}
return result
}
var materialColorMap = map[color.RGBA]MaterialColor{
{0x00, 0x00, 0x00, 0xff}: Black,
{0x79, 0x55, 0x48, 0xff}: Brown,
@ -122,28 +139,35 @@ func colorfulToMaterialColor(actualColor colorful.Color) (result MaterialColor)
return result
}
// Colors returns color information for a media file.
func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, err error) {
func (m *MediaFile) Resize(width, height int) (result *image.NRGBA, err error) {
jpeg, err := m.GetJpeg()
if err != nil {
log.Printf("can't find jpeg: %s", err.Error())
return colors, mainColor, err
return nil, err
}
img, err := imaging.Open(jpeg.GetFilename(), imaging.AutoOrientation(true))
img, err:= imaging.Open(jpeg.GetFilename(), imaging.AutoOrientation(true))
if err != nil {
log.Printf("can't open jpeg: %s", err.Error())
return colors, mainColor, err
return nil, err
}
img = imaging.Resize(img, ColorSampleSize, ColorSampleSize, imaging.Box)
return imaging.Resize(img, width, height, imaging.Box), nil
}
// Colors returns color information for a media file.
func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, luminance LightMap, monochrome bool, err error) {
img, err := m.Resize(ColorSampleSize, ColorSampleSize)
if err != nil {
log.Printf("can't open image: %s", err.Error())
return colors, mainColor, luminance, monochrome, err
}
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
monochrome = true
colorCount := make(map[MaterialColor]uint16)
var mainColorCount uint16
@ -166,8 +190,15 @@ func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, er
mainColor = materialColor
}
_, s, l := rgbColor.Hsl()
if s != 0 {
monochrome = false
}
luminance = append(luminance, Luminance(math.Round(l * 16)))
}
}
return colors, mainColor, nil
return colors, mainColor, luminance, monochrome, nil
}

View File

@ -15,11 +15,12 @@ func TestMediaFile_GetColors_Slow(t *testing.T) {
conf.InitializeTestData(t)
if mediaFile2, err := NewMediaFile(conf.ImportPath() + "/iphone/IMG_6788.JPG"); err == nil {
colors, main, err := mediaFile2.Colors()
colors, main, l, m, err := mediaFile2.Colors()
t.Log(colors, main, err)
t.Log(colors, main, l, m, err)
assert.Nil(t, err)
assert.False(t, m)
assert.IsType(t, MaterialColors{}, colors)
assert.Equal(t, "grey", main.Name())
assert.Equal(t, MaterialColors{0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2}, colors)
@ -28,11 +29,12 @@ func TestMediaFile_GetColors_Slow(t *testing.T) {
}
if mediaFile3, err := NewMediaFile(conf.ImportPath() + "/raw/20140717_154212_1EC48F8489.jpg"); err == nil {
colors, main, err := mediaFile3.Colors()
colors, main, l, m, err := mediaFile3.Colors()
t.Log(colors, main, err)
t.Log(colors, main, l, m, err)
assert.Nil(t, err)
assert.False(t, m)
assert.IsType(t, MaterialColors{}, colors)
assert.Equal(t, "grey", main.Name())

View File

@ -13,27 +13,31 @@ func TestMediaFile_GetColors(t *testing.T) {
conf.InitializeTestData(t)
if mediaFile1, err := NewMediaFile(conf.ImportPath() + "/dog.jpg"); err == nil {
colors, main, err := mediaFile1.Colors()
colors, main, l, m, err := mediaFile1.Colors()
t.Log(colors, main, err)
t.Log(colors, main, l, m, err)
assert.Nil(t, err)
assert.False(t, m)
assert.IsType(t, MaterialColors{}, colors)
assert.Equal(t, "grey", main.Name())
assert.Equal(t, MaterialColors{0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0}, colors)
assert.Equal(t, LightMap{5, 9, 7, 10, 9, 5, 5, 6, 2}, l)
} else {
t.Error(err)
}
if mediaFile2, err := NewMediaFile(conf.ImportPath() + "/ape.jpeg"); err == nil {
colors, main, err := mediaFile2.Colors()
colors, main, l, m, err := mediaFile2.Colors()
t.Log(colors, main, err)
t.Log(colors, main, l, m, err)
assert.Nil(t, err)
assert.False(t, m)
assert.IsType(t, MaterialColors{}, colors)
assert.Equal(t, "teal", main.Name())
assert.Equal(t, MaterialColors{0x8, 0x8, 0x2, 0x8, 0x2, 0x1, 0x8, 0x1, 0x2}, colors)
assert.Equal(t, LightMap{8, 8, 7, 7, 7, 5, 8, 6, 8}, l)
} else {
t.Error(err)
}

View File

@ -94,10 +94,12 @@ func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string {
}
// PhotoColors
photoColors, photoColor, _ := jpeg.Colors()
photoColors, photoColor, luminance, monochrome, _ := jpeg.Colors()
photo.PhotoColor = photoColor.Name()
photo.PhotoColors = photoColors.Hex()
photo.PhotoLuminance = luminance.Hex()
photo.PhotoMonochrome = monochrome
// Tags (TensorFlow)
tags = i.getImageTags(jpeg)
@ -163,10 +165,12 @@ func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string {
} else if time.Now().Sub(photo.UpdatedAt).Minutes() > 10 { // If updated more than 10 minutes ago
if jpeg, err := mediaFile.GetJpeg(); err == nil {
// PhotoColors
photoColors, photoColor, _ := jpeg.Colors()
photoColors, photoColor, luminance, monochrome, _ := jpeg.Colors()
photo.PhotoColor = photoColor.Name()
photo.PhotoColors = photoColors.Hex()
photo.PhotoLuminance = luminance.Hex()
photo.PhotoMonochrome = monochrome
photo.Camera = models.NewCamera(mediaFile.GetCameraModel(), mediaFile.GetCameraMake()).FirstOrCreate(i.db)
photo.Lens = models.NewLens(mediaFile.GetLensModel(), mediaFile.GetLensMake()).FirstOrCreate(i.db)