/
githubmirror
/
photoprism
Обзор
Документация
Войти
/
githubmirror
/
photoprism
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
internal/entity/markers.go
191 строка
4 KB
Ömer Duran
XMP: Read face markers and names sidecar files #554 #1570 #747 #5712 #5713
22 июл 2026, 11:32
Не верифицирован
22 июл 2026, 11:32
ab5b9ee
Код
Авторство
О чём код?
package entity import ( "fmt" "github.com/photoprism/photoprism/internal/ai/classify" "github.com/photoprism/photoprism/internal/ai/face" "github.com/photoprism/photoprism/pkg/txt" ) // Markers represents a list of markers. type Markers []Marker // Save stores the markers in the database. func (m Markers) Save(file *File) (count int, err error) { if file == nil { return 0, fmt.Errorf("file required for saving markers") } for i := range m { if m[i].UpdateFile(file) { continue } if created, err := CreateMarkerIfNotExists(&m[i]); err != nil { log.Errorf("markers: %s (save)", err) } else { m[i] = *created } } return file.UpdatePhotoFaceCount() } // Unsaved tests if any marker hasn't been saved yet. func (m Markers) Unsaved() bool { for i := range m { if m[i].Unsaved() { return true } } return false } // Contains returns true if a marker at the same position already exists. func (m Markers) Contains(other Marker) bool { for i := range m { if m[i].OverlapPercent(other) > face.OverlapThreshold { return true } } return false } // Overlapping returns a pointer to the first non-rejected marker that overlaps // other above the face-overlap threshold, or nil when none does. Used to // reconcile an imported XMP region onto an existing marker instead of // discarding the overlap the way Contains does. func (m Markers) Overlapping(other Marker) *Marker { for i := range m { if m[i].MarkerInvalid { continue } if m[i].OverlapPercent(other) > face.OverlapThreshold { return &m[i] } } return nil } // OverlapsInvalid reports whether any rejected marker (MarkerInvalid) overlaps // other above the threshold. An XMP region that lands on a rejected marker must // be skipped so it is not resurrected as a fresh marker at a different thumb hash. func (m Markers) OverlapsInvalid(other Marker) bool { for i := range m { if m[i].MarkerInvalid && m[i].OverlapPercent(other) > face.OverlapThreshold { return true } } return false } // DetectedFaceCount returns the number of automatically detected face markers. func (m Markers) DetectedFaceCount() (count int) { for i := range m { if m[i].DetectedFace() { count++ } } return count } // ValidFaceCount returns the number of valid face markers. func (m Markers) ValidFaceCount() (count int) { for i := range m { if m[i].ValidFace() { count++ } } return count } // SubjectNames returns known subject names. func (m Markers) SubjectNames() (names []string) { for i := range m { if m[i].MarkerInvalid || m[i].MarkerType != MarkerFace { continue } else if n := m[i].SubjectName(); n != "" { names = append(names, n) } } return txt.UniqueNames(names) } // Labels returns a list of matching labels. // TODO: Function is currently unused, decide how to proceed with it. func (m Markers) Labels() (result classify.Labels) { faceCount := 0 labelSrc := SrcImage labelUncertainty := 100 for i := range m { if m[i].ValidFace() { faceCount++ if u := m[i].Uncertainty(); u < labelUncertainty { labelUncertainty = u } if m[i].MarkerSrc != "" { labelSrc = m[i].MarkerSrc } } } if faceCount < 1 { return classify.Labels{} } var rule classify.LabelRule if faceCount == 1 { rule = classify.Rules["portrait"] } else { rule = classify.Rules["people"] } return classify.Labels{classify.Label{ Name: rule.Label, Source: labelSrc, Uncertainty: labelUncertainty, Priority: rule.Priority, Categories: rule.Categories, }} } // Append adds a marker. func (m *Markers) Append(marker Marker) { *m = append(*m, marker) } // AppendWithEmbedding adds a marker with face embedding. func (m *Markers) AppendWithEmbedding(marker Marker) { if !marker.Embeddings().One() { // Ignore markers that don't have exactly one embedding. return } m.Append(marker) } // FindMarkers returns up to 1000 markers for a given file uid. func FindMarkers(fileUid string) (Markers, error) { m := Markers{} err := Db(). Where("file_uid = ?", fileUid). Order("x"). Offset(0).Limit(1000). Find(&m).Error return m, err }