ssa
1package goroi2
3import (4"fmt"5"image"6"image/color"7"image/draw"8"math"9"os"10"os/exec"11"sort"12
13"github.com/anthonynsimon/bild/adjust"14"github.com/cheggaaa/pb"15pigo "github.com/esimov/pigo/core"16)
17
18type Frame struct {19FileName string20Dets []pigo.Detection21}
22
23func ExtractRGB(Path, FileName string) (R, G, B []float64, Err error) {24
25MakeDir(Path + "in/")26fmt.Println((Path + "in/"))27fmt.Println((Path + FileName))28c := exec.Command(29// ffmpeg -an -y -threads 0 -i in.mp4 -vf "select=not(mod(n\,1))" -vsync vfr in/%4d.png30"ffmpeg", "-an", "-y", "-threads", "0", "-i", Path+FileName, "-vf", `select=not(mod(n\,1))`, "-vsync", "vfr", Path+"in/%4d.png",31//"ffmpeg", "-i", Path+FileName, "-r", "15", Path+"in/%4d.png",32) // "P1LC1-edited2.mp4" "P1LC1-edited.avi" "face.mp4"33c.Stderr = os.Stderr34c.Run()35entries, err := os.ReadDir(Path + "in/")36if err != nil {37return nil, nil, nil, fmt.Errorf("os.ReadDir: %v", err)38}39p, err := NewPigs("cascade/facefinder")40if err != nil {41return nil, nil, nil, fmt.Errorf("NewPigs: %v", err)42}43
44// Выделяем память под слайсы R G B45R = make([]float64, len(entries))46G = make([]float64, len(entries))47B = make([]float64, len(entries))48
49Bar := pb.StartNew(len(entries))50Bar.Prefix(Path + "in/")51for ientries := range entries {52FilePathIn := Path + "in/" + entries[ientries].Name()53
54r, g, b, ErrCoord := p.Coords2(FilePathIn)55if ErrCoord != nil {56fmt.Printf("p.Coords: %v for image [%d/%d] for file %v\n", ErrCoord, ientries, len(entries), entries[ientries].Name())57}58
59R[ientries] = r60G[ientries] = g61B[ientries] = b62
63Bar.Increment()64//break65}66Bar.Finish()67
68return R, G, B, nil69}
70
71func (p *Pigs) Coords(FilePathName string) (R float64, G float64, B float64, Err error) {72Dets := p.getCoords(FilePathName)73sort.Slice(Dets, func(i, j int) bool { // Сортировка по вероятности74return Dets[i].Q > Dets[j].Q75})76
77var Ruint32, Guint32, Buint32 uint3278var sizes uint3279if len(Dets) > 0 {80src, Err := getImageFromFilePath(FilePathName)81if Err != nil {82return 0.0, 0.0, 0.0, fmt.Errorf("getImageFromFilePath: %v", Err)83}84pix := Dets[0].Scale / 285yStart, yEnd := Dets[0].Row-pix, Dets[0].Row+pix86xStart, xEnd := Dets[0].Col-pix, Dets[0].Col+pix87
88for y := yStart; y < yEnd; y++ {89for x := xStart; x < xEnd; x++ {90rgb := src.At(x, y)91r, g, b, _ := rgb.RGBA()92_, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))93hsvH, _, _ := RGB2HSV(float64(r), float64(g), float64(b))94if cb >= 98 && cb <= 142 &&95cr >= 135 && cr <= 177 &&96hsvH >= 0.01 && hsvH <= 0.1 {97Ruint32 += (r >> 8)98Guint32 += (g >> 8)99Buint32 += (b >> 8)100}101}102}103sizes = uint32((yEnd - yStart) * (xEnd - xStart))104}105
106R = float64(Ruint32) / float64(sizes)107G = float64(Guint32) / float64(sizes)108B = float64(Buint32) / float64(sizes)109return R, G, B, nil110}
111
112func getImageFromFilePath(filePath string) (draw.Image, error) {113
114// read file115f, err := os.Open(filePath)116if err != nil {117return nil, err118}119defer f.Close()120
121// convert as image.Image122orig, _, err := image.Decode(f)123
124// convert as usable image125b := orig.Bounds()126img := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))127draw.Draw(img, img.Bounds(), orig, b.Min, draw.Src)128
129return img, err130}
131
132// Рассчёт процентилей
133func illumgray(img image.Image, percentiles int) (float64, float64, float64) {134Rectangle := img.Bounds()135width := Rectangle.Max.X - Rectangle.Min.X136height := Rectangle.Max.Y - Rectangle.Min.Y137// fmt.Printf("\n%+v, (%d;%d)\n", Rectangle, width, height)138// R := make([]uint32, height*width)139// G := make([]uint32, height*width)140// B := make([]uint32, height*width)141R := make([]uint32, 0, height*width+1)142G := make([]uint32, 0, height*width+1)143B := make([]uint32, 0, height*width+1)144for y := 0; y < height; y++ {145for x := 0; x < width; x++ {146r, g, b, _ := img.At(x, y).RGBA()147// R[y*height+width] = r148// G[y*height+width] = g149// B[y*height+width] = b150R = append(G, r)151G = append(G, g)152B = append(G, b)153}154}155R = sortAndREmDub(R)156G = sortAndREmDub(G)157B = sortAndREmDub(B)158
159return float64(len(R) / (height * width)),160float64(len(G) / (height * width)),161float64(len(B) / (height * width))162}
163
164func sortAndREmDub(arr []uint32) []uint32 {165sort.Slice(arr, func(i, j int) bool {166return arr[i] < arr[j]167})168j := 1169for i := 1; i < len(arr); i++ {170if arr[i] != arr[i-1] {171arr[j] = arr[i]172j++173}174}175return arr[:j]176}
177
178func (p *Pigs) Coords2(FilePathName string) (R float64, G float64, B float64, Err error) {179
180Dets := p.getCoords(FilePathName)181sort.Slice(Dets, func(i, j int) bool { // Сортировка по вероятности182return Dets[i].Q > Dets[j].Q183})184
185if len(Dets) > 0 {186f, ErrOpen := os.Open(FilePathName)187if ErrOpen != nil {188return 0.0, 0.0, 0.0, fmt.Errorf("os.Open: picture: %v", ErrOpen)189}190defer f.Close()191
192img, _, ErrDecode := image.Decode(f)193if ErrDecode != nil {194return 0.0, 0.0, 0.0, fmt.Errorf("image.Decode: picture: %v", ErrDecode)195}196
197// fmt.Println(img.Bounds().Max.X - img.Bounds().Min.X)198// fmt.Println(img.Bounds().Max.Y - img.Bounds().Min.Y)199
200// fmt.Println(img.Bounds().Min.X, img.Bounds().Max.X)201// fmt.Println(img.Bounds().Min.Y, img.Bounds().Max.Y)202
203pix := Dets[0].Scale / 2204// yStart, yEnd := Dets[0].Row-pix, Dets[0].Row+pix205// xStart, xEnd := Dets[0].Col-pix, Dets[0].Col+pix206
207// face_image := img.(interface {208// SubImage(r image.Rectangle) image.Image209// }).SubImage(image.Rect(Dets[0].Col-pix, Dets[0].Row-pix,210// Dets[0].Col+pix, Dets[0].Row+pix))211
212// // гамма и прочее213// Rgray, Ggray, Bgray := illumgray(face_image, 10)214// fmt.Println(Rgray, Ggray, Bgray)215
216// Видео-коменсация217img = adjust.Gamma(img, 2.2)218
219var count int220for y := Dets[0].Row - pix; y < Dets[0].Row+pix; y++ {221// fmt.Println(y)222for x := Dets[0].Col - pix; x < Dets[0].Col+pix; x++ {223// for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {224// // fmt.Println(y)225// for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {226rgb := img.At(x, y)227r, g, b, _ := rgb.RGBA()228
229// fmt.Println(uint8(r>>8), uint8(g>>8), uint8(b>>8))230// _, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))231// _, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))232
233// _, cb, cr := ycbcr(r, g, b)234
235// hsvH, _, _ := RGB2HSV(float64(r), float64(g), float64(b))236// h, _, _ := RGBAToHSV(r, g, b, math.MaxInt32)237
238// fmt.Println(r, g, b, "--", cb, cr, h, "=", cr>>8, cr>>16)239
240// h, _, _ := RGBAToHSV(r, g, b, math.MaxUint32)241
242_, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))243h, _, _ := RGB2HSV(float64(r), float64(g), float64(b))244
245if cb >= (98) && cb <= (142) &&246cr >= (135) && cr <= (177) &&247h >= 0.01 && h <= 0.1 {248R += float64(r >> 8)249G += float64(g >> 8)250B += float64(b >> 8)251count++252}253}254}255
256// for y := yStart; y < yEnd; y++ {257// for x := xStart; x < xEnd; x++ {258// rgb := src.At(x, y)259// r, g, b, _ := rgb.RGBA()260// _, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))261// hsvH, _, _ := RGB2HSV(float64(r), float64(g), float64(b))262// if cb >= 98 && cb <= 142 &&263// cr >= 135 && cr <= 177 &&264// hsvH >= 0.01 && hsvH <= 0.1 {265// Ruint32 += (r >> 8)266// Guint32 += (g >> 8)267// Buint32 += (b >> 8)268// }269// }270// }271// output_file, _ := os.Create("tests/output.jpeg")272// jpeg.Encode(output_file, face_image, nil)273
274// sizes := float64((yEnd - yStart) * (xEnd - xStart))275count64 := float64(count)276return R / count64, G / count64, B / count64, nil277}278
279return 0.0, 0.0, 0.0, nil280}
281
282func ycbcr(r, g, b uint32) (uint32, uint32, uint32) {283y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16284
285// The bit twiddling below is equivalent to286//287// cb := (-11056*r - 21712*g + 32768*b + 257<<15) >> 16288// if cb < 0 {289// cb = 0290// } else if cb > 0xff {291// cb = ^int32(0)292// }293//294// but uses fewer branches and is faster.295// Note that the uint8 type conversion in the return296// statement will convert ^int32(0) to 0xff.297// The code below to compute cr uses a similar pattern.298//299// Note that -11056 - 21712 + 32768 equals 0.300cb := 32768*b - 11056*r - 21712*g + 257<<15301if cb&0xff000000 == 0 {302cb >>= 16303} else {304cb = ^(cb >> 31)305}306
307// Note that 32768 - 27440 - 5328 equals 0.308cr := 32768*r - 27440*g - 5328*b + 257<<15309if cr&0xff000000 == 0 {310cr >>= 16311} else {312cr = ^(cr >> 31)313}314return y, cb, cr315}
316
317func RGBAToHSV(rValue, gValue, bValue, aValue uint32) (h, s, v float64) {318
319// The RGBA color components are scaled by the Alpha value, as per:320// https://golang.org/src/image/color/color.go?s=2394:2435#L21321// Since we need RGB values in the [0-1] range, we need to divide322// them by A, making sure it's not 0.323if aValue == 0 {324return h, s, v325}326
327a := float64(aValue)328r := float64(rValue) / a329g := float64(gValue) / a330b := float64(bValue) / a331
332maxValue := math.Max(r, math.Max(g, b))333
334// They're all 0s335if maxValue == 0 {336return 0, 0, 0337}338
339minValue := math.Min(r, math.Min(g, b))340delta := maxValue - minValue341
342// Greyscale, only V can be != 0343if delta == 0 {344return 0, 0, math.Round(maxValue * 100)345}346
347//hue348switch maxValue {349case r:350h = 60 * ((g - b) / delta)351case g:352h = 60 * (((b - r) / delta) + 2)353case b:354h = 60 * (((r - g) / delta) + 4)355}356
357if h < 0 {358h += 360359}360
361h = math.Round(h)362
363//saturation364s = math.Round(100 * delta / maxValue)365
366//value367v = math.Round(maxValue * 100)368return h, s, v369
370}
371