mirror of
https://github.com/u2takey/ffmpeg-go.git
synced 2025-09-27 12:22:08 +08:00
add example opencv
This commit is contained in:
@@ -25,3 +25,8 @@ func TestExampleReadFrameAsJpeg(t *testing.T) {
|
|||||||
func TestExampleShowProgress(t *testing.T) {
|
func TestExampleShowProgress(t *testing.T) {
|
||||||
ExampleShowProgress("./sample_data/in1.mp4", "./sample_data/out2.mp4")
|
ExampleShowProgress("./sample_data/in1.mp4", "./sample_data/out2.mp4")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExampleOpenCvFaceDetect(t *testing.T) {
|
||||||
|
ExampleFaceDetection("./sample_data/head-pose-face-detection-male-short.mp4",
|
||||||
|
"./sample_data/haarcascade_frontalface_default.xml")
|
||||||
|
}
|
||||||
|
101
examples/opencv.go
Normal file
101
examples/opencv.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package examples
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
ffmpeg "github.com/u2takey/ffmpeg-go"
|
||||||
|
"gocv.io/x/gocv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readProcess(infileName string, writer io.WriteCloser) <-chan error {
|
||||||
|
log.Println("Starting ffmpeg process1")
|
||||||
|
done := make(chan error)
|
||||||
|
go func() {
|
||||||
|
err := ffmpeg.Input(infileName).
|
||||||
|
Output("pipe:",
|
||||||
|
ffmpeg.KwArgs{
|
||||||
|
"format": "rawvideo", "pix_fmt": "rgb24",
|
||||||
|
}).
|
||||||
|
WithOutput(writer).
|
||||||
|
Run()
|
||||||
|
log.Println("ffmpeg process1 done")
|
||||||
|
_ = writer.Close()
|
||||||
|
done <- err
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
return done
|
||||||
|
}
|
||||||
|
|
||||||
|
func openCvProcess(xmlFile string, reader io.ReadCloser, w, h int) {
|
||||||
|
// open display window
|
||||||
|
window := gocv.NewWindow("Face Detect")
|
||||||
|
defer window.Close()
|
||||||
|
|
||||||
|
// color for the rect when faces detected
|
||||||
|
blue := color.RGBA{0, 0, 255, 0}
|
||||||
|
|
||||||
|
classifier := gocv.NewCascadeClassifier()
|
||||||
|
defer classifier.Close()
|
||||||
|
|
||||||
|
if !classifier.Load(xmlFile) {
|
||||||
|
fmt.Printf("Error reading cascade file: %v\n", xmlFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
frameSize := w * h * 3
|
||||||
|
buf := make([]byte, frameSize, frameSize)
|
||||||
|
for {
|
||||||
|
n, err := io.ReadFull(reader, buf)
|
||||||
|
if n == 0 || err == io.EOF {
|
||||||
|
return
|
||||||
|
} else if n != frameSize || err != nil {
|
||||||
|
panic(fmt.Sprintf("read error: %d, %s", n, err))
|
||||||
|
}
|
||||||
|
img, err := gocv.NewMatFromBytes(h, w, gocv.MatTypeCV8UC3, buf)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("decode fail", err)
|
||||||
|
}
|
||||||
|
if img.Empty() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect faces
|
||||||
|
rects := classifier.DetectMultiScale(img)
|
||||||
|
fmt.Printf("found %d faces\n", len(rects))
|
||||||
|
|
||||||
|
// draw a rectangle around each face on the original image,
|
||||||
|
// along with text identifing as "Human"
|
||||||
|
for _, r := range rects {
|
||||||
|
gocv.Rectangle(&img, r, blue, 3)
|
||||||
|
|
||||||
|
size := gocv.GetTextSize("Human", gocv.FontHersheyPlain, 1.2, 2)
|
||||||
|
pt := image.Pt(r.Min.X+(r.Min.X/2)-(size.X/2), r.Min.Y-2)
|
||||||
|
gocv.PutText(&img, "Human", pt, gocv.FontHersheyPlain, 1.2, blue, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the image in the window, and wait 1 millisecond
|
||||||
|
window.IMShow(img)
|
||||||
|
if window.WaitKey(10) >= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFaceDetection(inputFile, xmlFile string) {
|
||||||
|
w, h := getVideoSize(inputFile)
|
||||||
|
log.Println(w, h)
|
||||||
|
|
||||||
|
pr1, pw1 := io.Pipe()
|
||||||
|
done1 := readProcess(inputFile, pw1)
|
||||||
|
openCvProcess(xmlFile, pr1, w, h)
|
||||||
|
err := <-done1
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Println("Done")
|
||||||
|
}
|
33314
examples/sample_data/haarcascade_frontalface_default.xml
Executable file
33314
examples/sample_data/haarcascade_frontalface_default.xml
Executable file
File diff suppressed because it is too large
Load Diff
BIN
examples/sample_data/head-pose-face-detection-male-short.mp4
Normal file
BIN
examples/sample_data/head-pose-face-detection-male-short.mp4
Normal file
Binary file not shown.
1
go.mod
1
go.mod
@@ -7,4 +7,5 @@ require (
|
|||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/tidwall/gjson v1.6.3
|
github.com/tidwall/gjson v1.6.3
|
||||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7
|
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7
|
||||||
|
gocv.io/x/gocv v0.25.0
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@@ -32,6 +32,8 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
|||||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7 h1:PT7mE8HJE1mwaSazrOdSeByJ1FoV33/fHUZrBB+zwVU=
|
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7 h1:PT7mE8HJE1mwaSazrOdSeByJ1FoV33/fHUZrBB+zwVU=
|
||||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7/go.mod h1:ATqKFpgjUIlhGRs8j59gXmu8Cmpo1QQEHV6vwu1hs28=
|
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7/go.mod h1:ATqKFpgjUIlhGRs8j59gXmu8Cmpo1QQEHV6vwu1hs28=
|
||||||
|
gocv.io/x/gocv v0.25.0 h1:vM50jL3v9OEqWSi+urelX5M1ptZeFWA/VhGPvdTqsJU=
|
||||||
|
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
24
graph.go
Normal file
24
graph.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package ffmpeg_go
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// for json spec
|
||||||
|
|
||||||
|
type GraphNode struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
InputStreams []string `json:"input_streams"`
|
||||||
|
OutputStreams []string `json:"output_streams"`
|
||||||
|
Args Args `json:"args"`
|
||||||
|
KwArgs KwArgs `json:"kw_args"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GraphOptions struct {
|
||||||
|
Timeout time.Duration
|
||||||
|
OverWriteOutput bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Graph struct {
|
||||||
|
OutputStream string `json:"output_stream"`
|
||||||
|
GraphOptions GraphOptions `json:"graph_options"`
|
||||||
|
Nodes []GraphNode `json:"nodes"`
|
||||||
|
}
|
5
run.go
5
run.go
@@ -175,17 +175,20 @@ func (s *Stream) GetArgs() []string {
|
|||||||
filterNodes = append(filterNodes, n)
|
filterNodes = append(filterNodes, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// input args from inputNodes
|
||||||
for _, n := range inputNodes {
|
for _, n := range inputNodes {
|
||||||
args = append(args, getInputArgs(n)...)
|
args = append(args, getInputArgs(n)...)
|
||||||
}
|
}
|
||||||
|
// filter args from filterNodes
|
||||||
filterArgs := _getFilterArg(filterNodes, outGoingMap, streamNameMap)
|
filterArgs := _getFilterArg(filterNodes, outGoingMap, streamNameMap)
|
||||||
if filterArgs != "" {
|
if filterArgs != "" {
|
||||||
args = append(args, "-filter_complex", filterArgs)
|
args = append(args, "-filter_complex", filterArgs)
|
||||||
}
|
}
|
||||||
|
// output args from outputNodes
|
||||||
for _, n := range outputNodes {
|
for _, n := range outputNodes {
|
||||||
args = append(args, _getOutputArgs(n, streamNameMap)...)
|
args = append(args, _getOutputArgs(n, streamNameMap)...)
|
||||||
}
|
}
|
||||||
|
// global args with outputNodes
|
||||||
for _, n := range globalNodes {
|
for _, n := range globalNodes {
|
||||||
args = append(args, _getGlobalArgs(n)...)
|
args = append(args, _getGlobalArgs(n)...)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user