feat: add facepp
CI / changes (push) Successful in 1m31s
CI / ad (push) Successful in 26s
CI / admin (push) Successful in 17s
CI / analysis (push) Successful in 24s
CI / bff (push) Successful in 16s
CI / chore (push) Successful in 14s
CI / equipment (push) Successful in 15s
CI / express (push) Successful in 13s
CI / factory (push) Successful in 13s
CI / message (push) Successful in 10s
CI / order (push) Successful in 10s
CI / payment (push) Successful in 11s
CI / percutaneous (push) Successful in 11s
CI / product (push) Successful in 12s
CI / record (push) Successful in 12s
CI / sale (push) Successful in 11s
CI / store (push) Successful in 11s
CI / support (push) Successful in 11s
CI / task (push) Successful in 10s
CI / user (push) Successful in 18s
CI / water (push) Successful in 13s
CI / wecom (push) Successful in 13s
CI / ws (push) Successful in 6s
CI / changes (push) Successful in 1m31s
CI / ad (push) Successful in 26s
CI / admin (push) Successful in 17s
CI / analysis (push) Successful in 24s
CI / bff (push) Successful in 16s
CI / chore (push) Successful in 14s
CI / equipment (push) Successful in 15s
CI / express (push) Successful in 13s
CI / factory (push) Successful in 13s
CI / message (push) Successful in 10s
CI / order (push) Successful in 10s
CI / payment (push) Successful in 11s
CI / percutaneous (push) Successful in 11s
CI / product (push) Successful in 12s
CI / record (push) Successful in 12s
CI / sale (push) Successful in 11s
CI / store (push) Successful in 11s
CI / support (push) Successful in 11s
CI / task (push) Successful in 10s
CI / user (push) Successful in 18s
CI / water (push) Successful in 13s
CI / wecom (push) Successful in 13s
CI / ws (push) Successful in 6s
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package facepp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
YOLOClassAcne = 0
|
||||
YOLOClassMole = 1
|
||||
YOLOClassBrownSpot = 2
|
||||
)
|
||||
|
||||
type yoloField struct {
|
||||
Key string
|
||||
ClassID int
|
||||
}
|
||||
|
||||
var yoloRectangleFields = []yoloField{
|
||||
{Key: "acne_pustule", ClassID: YOLOClassAcne},
|
||||
{Key: "closed_comedones", ClassID: YOLOClassAcne},
|
||||
{Key: "acne_mark", ClassID: YOLOClassAcne},
|
||||
{Key: "acne", ClassID: YOLOClassAcne},
|
||||
{Key: "acne_nodule", ClassID: YOLOClassAcne},
|
||||
{Key: "mole", ClassID: YOLOClassMole},
|
||||
{Key: "brown_spot", ClassID: YOLOClassBrownSpot},
|
||||
}
|
||||
|
||||
type yoloBox struct {
|
||||
ClassID int
|
||||
XC float64
|
||||
YC float64
|
||||
W float64
|
||||
H float64
|
||||
}
|
||||
|
||||
type yoloRect struct {
|
||||
Top float64 `json:"top"`
|
||||
Left float64 `json:"left"`
|
||||
Width float64 `json:"width"`
|
||||
Height float64 `json:"height"`
|
||||
}
|
||||
|
||||
type yoloLocated struct {
|
||||
Rectangle []yoloRect `json:"rectangle"`
|
||||
Rect []yoloRect `json:"rect"`
|
||||
}
|
||||
|
||||
func ResultToYOLO(result json.RawMessage, imgW, imgH int) (string, error) {
|
||||
if len(result) == 0 || string(result) == "null" {
|
||||
return "", nil
|
||||
}
|
||||
if imgW <= 0 || imgH <= 0 {
|
||||
return "", fmt.Errorf("facepp: invalid image size %dx%d", imgW, imgH)
|
||||
}
|
||||
|
||||
var root map[string]json.RawMessage
|
||||
if err := json.Unmarshal(result, &root); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
imgWf := float64(imgW)
|
||||
imgHf := float64(imgH)
|
||||
var boxes []yoloBox
|
||||
for _, field := range yoloRectangleFields {
|
||||
raw, ok := root[field.Key]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, rect := range locatedRectangles(raw) {
|
||||
box, ok := pixelToYOLO(field.ClassID, rect.Left, rect.Top, rect.Width, rect.Height, imgWf, imgHf)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
boxes = append(boxes, box)
|
||||
}
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
for _, box := range boxes {
|
||||
fmt.Fprintf(&b, "%d %.6f %.6f %.6f %.6f\n", box.ClassID, box.XC, box.YC, box.W, box.H)
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func locatedRectangles(raw json.RawMessage) []yoloRect {
|
||||
var obj yoloLocated
|
||||
if err := json.Unmarshal(raw, &obj); err != nil {
|
||||
return nil
|
||||
}
|
||||
if len(obj.Rectangle) > 0 {
|
||||
return obj.Rectangle
|
||||
}
|
||||
return obj.Rect
|
||||
}
|
||||
|
||||
func pixelToYOLO(classID int, xMin, yMin, boxW, boxH, imgW, imgH float64) (yoloBox, bool) {
|
||||
xMax := xMin + boxW
|
||||
yMax := yMin + boxH
|
||||
if xMin < 0 {
|
||||
xMin = 0
|
||||
}
|
||||
if yMin < 0 {
|
||||
yMin = 0
|
||||
}
|
||||
if xMax > imgW {
|
||||
xMax = imgW
|
||||
}
|
||||
if yMax > imgH {
|
||||
yMax = imgH
|
||||
}
|
||||
|
||||
boxW = xMax - xMin
|
||||
boxH = yMax - yMin
|
||||
if boxW <= 0 || boxH <= 0 {
|
||||
return yoloBox{}, false
|
||||
}
|
||||
|
||||
return yoloBox{
|
||||
ClassID: classID,
|
||||
XC: (xMin + boxW/2) / imgW,
|
||||
YC: (yMin + boxH/2) / imgH,
|
||||
W: boxW / imgW,
|
||||
H: boxH / imgH,
|
||||
}, true
|
||||
}
|
||||
Reference in New Issue
Block a user