From 643dccc81e6b6607cd28071736ac79fc558eac12 Mon Sep 17 00:00:00 2001 From: lupinelab Date: Sat, 22 Apr 2023 20:01:28 +0100 Subject: [PATCH] feat: replace gocv with image and blackjack with go4vl --- cmd/asciicam.go | 124 +++++++++++++++++++++++++++---------------- go.mod | 17 +++--- go.sum | 67 +++++++++++++++-------- internal/asciify.go | 55 ++++++++++++------- internal/camera.go | 55 +++++++++++-------- internal/settings.go | 57 +++++++------------- 6 files changed, 222 insertions(+), 153 deletions(-) diff --git a/cmd/asciicam.go b/cmd/asciicam.go index 07e9c10..4301438 100644 --- a/cmd/asciicam.go +++ b/cmd/asciicam.go @@ -2,8 +2,11 @@ package cmd import ( "bufio" + "bytes" + "context" "fmt" "image" + _ "image/jpeg" "math" "os" "strconv" @@ -14,7 +17,6 @@ import ( "github.com/gdamore/tcell/v2" "github.com/spf13/cobra" - "gocv.io/x/gocv" ) var asciicamCmd = &cobra.Command{ @@ -23,7 +25,7 @@ var asciicamCmd = &cobra.Command{ Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { // Get camera capabilities - supportedResolutions, err := internal.GetSupportedResolutions(args[0]) + supportedResolutions, pixelFormat, err := internal.GetSupportedResolutions(args[0]) if err != nil { fmt.Println(err) return @@ -87,12 +89,12 @@ var asciicamCmd = &cobra.Command{ // Create a tcell screen to use as a canvas canvas, err := tcell.NewScreen() if err != nil { - fmt.Println(err.Error()) + fmt.Println(err) return } err = canvas.Init() if err != nil { - fmt.Println(err.Error()) + fmt.Println(err) return } defer canvas.Fini() @@ -105,13 +107,24 @@ var asciicamCmd = &cobra.Command{ internal.PrintControls(canvas, defStyle) // Setup the camera - cam, err := internal.NewCamera(args[0], *settings) + cam, err := internal.NewCamera(args[0], pixelFormat, *settings) if err != nil { canvas.Fini() fmt.Println(err) } - defer cam.Capture.Close() + defer cam.Close() + ctx, cancel := context.WithCancel(context.TODO()) + cam.Start(ctx) + if err != nil { + canvas.Fini() + fmt.Println(err) + } + defer func() { + cancel() + cam.Close() + }() + // wait for user to kick things off ready: for { @@ -142,26 +155,26 @@ var asciicamCmd = &cobra.Command{ if control.Key() == tcell.KeyUp { if settings.Brightness < settings.BrightnessCaps["max"] { settings.Brightness += 1 - cam.Capture.Set(gocv.VideoCaptureBrightness, settings.Brightness) + cam.SetControlBrightness(settings.Brightness) } } if control.Key() == tcell.KeyDown { if settings.Brightness > settings.BrightnessCaps["min"] { settings.Brightness -= 1 - cam.Capture.Set(gocv.VideoCaptureBrightness, settings.Brightness) + cam.SetControlBrightness(settings.Brightness) } } // Contrast controls if control.Key() == tcell.KeyRight { if settings.Contrast < settings.ContrastCaps["max"] { settings.Contrast += 1 - cam.Capture.Set(gocv.VideoCaptureContrast, settings.Contrast) + cam.SetControlContrast(settings.Contrast) } } if control.Key() == tcell.KeyLeft { if settings.Contrast > settings.ContrastCaps["min"] { settings.Contrast -= 1 - cam.Capture.Set(gocv.VideoCaptureContrast, settings.Contrast) + cam.SetControlContrast(settings.Contrast) } } // SingleColourMode control @@ -237,9 +250,9 @@ var asciicamCmd = &cobra.Command{ } } }() - + // Do the business - frame := gocv.NewMat() + frames := cam.GetOutput() mainloop: for { select { @@ -247,48 +260,65 @@ var asciicamCmd = &cobra.Command{ canvas.Fini() break mainloop default: - if cam.Capture.Read(&frame) { - termWidth, termHeight := canvas.Size() - scale := math.Min(settings.FrameWidth/float64(termWidth), settings.FrameHeight/float64(termHeight)) - scaledResolution := image.Point{X: int(settings.FrameWidth / scale), Y: int(settings.FrameHeight / (scale * 1.8))} + newFrame := <-frames + if err != nil { + canvas.Fini() + fmt.Println(err) + } - canvas.Clear() - internal.Asciify(&frame, canvas, settings, termWidth, termHeight, scale, scaledResolution, defStyle) + frame, _, err := image.Decode(bytes.NewReader(newFrame)) + if err != nil { + canvas.Fini() + fmt.Println(err) + } - // Show info - if settings.ShowInfo { - for i, r := range fmt.Sprintf("Terminal=%vx%v Capture=%vx%v Scaled=%vx%v Scale=%v ", - termWidth, - termHeight, - settings.FrameWidth, - settings.FrameHeight, - scaledResolution.X, - scaledResolution.Y, - 1/scale) { - canvas.SetContent(i, 0, r, nil, defStyle) - } - for i, r := range fmt.Sprintf("FPS=%v Brightness=%v Contrast=%v Colour=[R]%v[G]%v[B]%v ", - fps, - settings.Brightness, - settings.Contrast, - settings.Colour["R"], - settings.Colour["G"], - settings.Colour["B"]) { - canvas.SetContent(i, 1, r, nil, defStyle) - } + // for y := frame.Bounds().Min.Y; y < frame.Bounds().Max.Y; y++ { + // for x := frame.Bounds().Min.X; x < frame.Bounds().Max.X; x++ { + // r, g, b, _ := frame.At(x, y).RGBA() + // fmt.Println(r >> 8, g >> 8, b >> 8) + // } + // } + + termWidth, termHeight := canvas.Size() + scale := math.Min(settings.FrameWidth/float64(termWidth), settings.FrameHeight/float64(termHeight)) + scaledResolution := image.Point{X: int(settings.FrameWidth / scale), Y: int(settings.FrameHeight / (scale * 1.8))} + + canvas.Clear() + internal.Asciify(frame, canvas, settings, termWidth, termHeight, scale, scaledResolution, defStyle) + + // Show info + if settings.ShowInfo { + for i, r := range fmt.Sprintf("Terminal=%vx%v Capture=%vx%v Scaled=%vx%v Scale=%v ", + termWidth, + termHeight, + settings.FrameWidth, + settings.FrameHeight, + scaledResolution.X, + scaledResolution.Y, + 1/scale) { + canvas.SetContent(i, 0, r, nil, defStyle) + } + for i, r := range fmt.Sprintf("FPS=%v Brightness=%v Contrast=%v Colour=[R]%v[G]%v[B]%v ", + fps, + settings.Brightness, + settings.Contrast, + settings.Colour["R"], + settings.Colour["G"], + settings.Colour["B"]) { + canvas.SetContent(i, 1, r, nil, defStyle) + } - // Show controls - if settings.ShowControls { - for y, l := range internal.Controls { - for x, r := range l { - canvas.SetContent(x, (scaledResolution.Y-len(internal.Controls))+y, r, nil, defStyle) - } + // Show controls + if settings.ShowControls { + for y, l := range internal.Controls { + for x, r := range l { + canvas.SetContent(x, (scaledResolution.Y-len(internal.Controls))+y, r, nil, defStyle) } } } - canvas.Show() - frameCount += 1 } + canvas.Show() + frameCount += 1 } } }, diff --git a/go.mod b/go.mod index b334b27..fefe4c3 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/lupinelab/asciicam go 1.19 require ( - github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165 - github.com/gdamore/tcell/v2 v2.5.3 - github.com/spf13/cobra v1.6.1 - gocv.io/x/gocv v0.31.0 + github.com/disintegration/imaging v1.6.2 + github.com/gdamore/tcell/v2 v2.6.0 + github.com/spf13/cobra v1.7.0 + github.com/vladimirvivien/go4vl v0.0.5 ) require ( @@ -14,9 +14,10 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/rivo/uniseg v0.4.3 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/image v0.7.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index a03d4df..4020aec 100644 --- a/go.sum +++ b/go.sum @@ -1,41 +1,66 @@ -github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165 h1:QsIbRyO2tn5eSJZ/skuDqSTo0GWI5H4G1AT7Mm2H0Nw= -github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0= -github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= -github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg= +github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -gocv.io/x/gocv v0.31.0 h1:BHDtK8v+YPvoSPQTTiZB2fM/7BLg6511JqkruY2z6LQ= -gocv.io/x/gocv v0.31.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= +github.com/vladimirvivien/go4vl v0.0.5 h1:jHuo/CZOAzYGzrSMOc7anOMNDr03uWH5c1B5kQ+Chnc= +github.com/vladimirvivien/go4vl v0.0.5/go.mod h1:FP+/fG/X1DUdbZl9uN+l33vId1QneVn+W80JMc17OL8= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= +golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/asciify.go b/internal/asciify.go index 956c4c9..787a838 100644 --- a/internal/asciify.go +++ b/internal/asciify.go @@ -2,39 +2,58 @@ package internal import ( "image" + "image/color" + "github.com/disintegration/imaging" "github.com/gdamore/tcell/v2" - "gocv.io/x/gocv" ) // var ascii_symbols = []rune(".:-~=+*#%@") var ascii_symbols = []rune(".,;!vlLFE$") -func Asciify(frame *gocv.Mat, canvas tcell.Screen, settings *Settings, termWidth int, termHeight int, scale float64, scaledResolution image.Point, defStyle tcell.Style) { - pixStyle := tcell.StyleDefault. - Background(tcell.ColorReset). - Foreground(tcell.NewRGBColor(settings.Colour["R"], settings.Colour["G"], settings.Colour["B"])) +func Asciify(frame image.Image, canvas tcell.Screen, settings *Settings, termWidth int, termHeight int, scale float64, scaledResolution image.Point, defStyle tcell.Style) { + pixStyle := tcell.StyleDefault.Background(tcell.ColorReset).Foreground( + tcell.NewRGBColor( + settings.Colour["R"], + settings.Colour["G"], + settings.Colour["B"]), + ) - downFrame := gocv.NewMat() - gocv.Resize(*frame, &downFrame, scaledResolution, 0, 0, gocv.InterpolationArea) - - greyFrame := gocv.NewMat() - gocv.CvtColor(downFrame, &greyFrame, gocv.ColorBGRToGray) + downFrame := imaging.Resize(frame, scaledResolution.X, scaledResolution.Y, imaging.NearestNeighbor) + + // canvas.Fini() + // for y := downFrame.Bounds().Min.Y; y < downFrame.Bounds().Max.Y; y++ { + // for x := downFrame.Bounds().Min.X; x < downFrame.Bounds().Max.X; x++ { + // r, g, b, _ := downFrame.At(x, y).RGBA() + // fmt.Println(r >> 8, g >> 8, b >> 8) + // } + // } + + greyPixel := image.NewGray(image.Rect(0, 0, 1, 1)) + // greyFrame := image.NewGray(image.Rect(0, 0, scaledResolution.X, scaledResolution.Y)) + // for y := downFrame.Bounds().Min.Y; y < downFrame.Bounds().Max.Y; y++ { + // for x := downFrame.Bounds().Min.X; x < downFrame.Bounds().Max.X; x++ { + // greyFrame.Set(x, y, color.GrayModel.Convert(downFrame.At(x, y))) + // } + // } switch settings.SingleColourMode { case true: - for y := 0; y < greyFrame.Rows(); y++ { - for x := 0; x < greyFrame.Cols(); x++ { - sym := ascii_symbols[int(float64(greyFrame.GetUCharAt(y, x))/26)] + for y := downFrame.Bounds().Min.Y; y < downFrame.Bounds().Max.Y; y++ { + for x := downFrame.Bounds().Min.X; x < downFrame.Bounds().Max.X; x++ { + greyPixel.Set(0, 0, color.GrayModel.Convert(downFrame.At(x, y))) + lum := greyPixel.GrayAt(0, 0).Y + sym := ascii_symbols[int((lum)/26)] canvas.SetContent(x, y, sym, nil, pixStyle) } } case false: - for y := 0; y < greyFrame.Rows(); y++ { - for x := 0; x < greyFrame.Cols(); x++ { - pixvec := downFrame.GetVecbAt(y, x) - pixelcolour := tcell.NewRGBColor(int32(pixvec[2]), int32(pixvec[1]), int32(pixvec[0])) - sym := ascii_symbols[int(float64(greyFrame.GetUCharAt(y, x))/26)] + for y := downFrame.Bounds().Min.Y; y < frame.Bounds().Max.Y; y++ { + for x := downFrame.Bounds().Min.X; x < frame.Bounds().Max.X; x++ { + pixelcolour := tcell.FromImageColor(downFrame.At(x, y)) + greyPixel.Set(0, 0, color.GrayModel.Convert(downFrame.At(x, y))) + lum := greyPixel.GrayAt(0, 0).Y + sym := ascii_symbols[int((lum)/26)] pixStyle = tcell.StyleDefault. Background(tcell.ColorReset). Foreground(pixelcolour) diff --git a/internal/camera.go b/internal/camera.go index f07b6e0..a000407 100644 --- a/internal/camera.go +++ b/internal/camera.go @@ -1,46 +1,57 @@ package internal import ( - "github.com/blackjack/webcam" - "gocv.io/x/gocv" + "fmt" + + "github.com/vladimirvivien/go4vl/device" + "github.com/vladimirvivien/go4vl/v4l2" ) type Camera struct { - Capture *gocv.VideoCapture + Capture v4l2.Device } -func GetSupportedResolutions(device string) ([]string, error) { - cam_caps, err := webcam.Open(device) - if err != nil { - return nil, err +func GetSupportedResolutions(camDevice string) ([]string, v4l2.FourCCType, error) { + cam_caps, err := device.Open(camDevice) + if err != nil { + return nil, v4l2.PixelFmtMJPEG, err } defer cam_caps.Close() + // supportedFormats, err := v4l2.GetAllFormatDescriptions() + // if err != nil { + // return nil, err + // } + + var pixelFormat v4l2.FourCCType + var resolutions []v4l2.FrameSizeEnum var supportedResolutions []string - resolutions := cam_caps.GetSupportedFrameSizes(webcam.PixelFormat(1196444237)) + + resolutions, _ = v4l2.GetFormatFrameSizes(cam_caps.Fd(), v4l2.PixelFmtMJPEG) + pixelFormat = v4l2.PixelFmtMJPEG if len(resolutions) == 0 { - resolutions = cam_caps.GetSupportedFrameSizes(webcam.PixelFormat(1448695129)) + resolutions, err = v4l2.GetFormatFrameSizes(cam_caps.Fd(), v4l2.PixelFmtYUYV) + if err != nil { + return nil, v4l2.PixelFmtMPEG, err + } + pixelFormat = v4l2.PixelFmtYUYV } for _, fs := range resolutions { - supportedResolutions = append(supportedResolutions, fs.GetString()) + supportedResolutions = append(supportedResolutions, fmt.Sprintf("%vx%v", fs.Size.MaxWidth, fs.Size.MaxHeight)) } - return supportedResolutions, err + return supportedResolutions, pixelFormat, err } -func NewCamera(device string, settings Settings) (*Camera, error) { - capture, err := gocv.OpenVideoCaptureWithAPI(device, 200) +func NewCamera(camDevice string, pixelFormat v4l2.FourCCType, settings Settings) (*device.Device, error) { + cam, err := device.Open( + camDevice, + device.WithPixFormat(v4l2.PixFormat{PixelFormat: pixelFormat, Width: uint32(settings.FrameWidth), Height: uint32(settings.FrameHeight), Field: v4l2.FieldAny}), + device.WithBufferSize(1), + ) if err != nil { return nil, err } - cam := Camera{ - Capture: capture, - } - - cam.Capture.Set(gocv.VideoCaptureFOURCC, cam.Capture.ToCodec("MJPG")) - cam.Capture.Set(gocv.VideoCaptureFrameHeight, settings.FrameHeight) - cam.Capture.Set(gocv.VideoCaptureFrameWidth, settings.FrameWidth) - - return &cam, err + return cam, err } diff --git a/internal/settings.go b/internal/settings.go index 6059873..357a657 100644 --- a/internal/settings.go +++ b/internal/settings.go @@ -1,63 +1,46 @@ package internal import ( - "github.com/blackjack/webcam" + "github.com/vladimirvivien/go4vl/device" + "github.com/vladimirvivien/go4vl/v4l2" ) type Settings struct { FrameHeight float64 FrameWidth float64 - BrightnessCaps map[string]float64 - ContrastCaps map[string]float64 - Brightness float64 - Contrast float64 - // SupportedResolutions []string + BrightnessCaps map[string]int32 + ContrastCaps map[string]int32 + Brightness int32 + Contrast int32 SingleColourMode bool Colour map[string]int32 ShowInfo bool ShowControls bool } -func NewSettings(device string, fH float64, fW float64) (*Settings, error) { +func NewSettings(camDevice string, fH float64, fW float64) (*Settings, error) { s := Settings{} s.FrameHeight = fH s.FrameWidth = fW - cam_caps, err := webcam.Open(device) - if err != nil { + cam_caps, err := device.Open(camDevice) + if err != nil { return nil, err } defer cam_caps.Close() - capmap := cam_caps.GetControls() - - s.BrightnessCaps = make(map[string]float64) - s.BrightnessCaps["min"] = float64(capmap[webcam.ControlID(0x00980900)].Min) - s.BrightnessCaps["max"] = float64(capmap[webcam.ControlID(0x00980900)].Max) - brightness, err := cam_caps.GetControl(webcam.ControlID(0x00980900)) - if err != nil { - return nil, err - } - s.Brightness = float64(brightness) - - s.ContrastCaps = make(map[string]float64) - s.ContrastCaps["min"] = float64(capmap[webcam.ControlID(0x00980901)].Min) - s.ContrastCaps["max"] = float64(capmap[webcam.ControlID(0x00980901)].Max) - contrast, err := cam_caps.GetControl(webcam.ControlID(0x00980901)) - if err != nil { - return nil, err - } - s.Contrast = float64(contrast) - - // s.SupportedResolutions = []string{} - // resolutions := cam_caps.GetSupportedFrameSizes(webcam.PixelFormat(1196444237)) - // if len(resolutions) == 0 { - // resolutions = cam_caps.GetSupportedFrameSizes(webcam.PixelFormat(1448695129)) - // } - // for _, fs := range resolutions { - // s.SupportedResolutions = append(s.SupportedResolutions, fs.GetString()) - // } + s.BrightnessCaps = make(map[string]int32) + brightnessCapInfo, err := cam_caps.GetControl(v4l2.CtrlBrightness) + s.BrightnessCaps["min"] = brightnessCapInfo.Minimum + s.BrightnessCaps["max"] = brightnessCapInfo.Maximum + s.Brightness = brightnessCapInfo.Value + + s.ContrastCaps = make(map[string]int32) + contrastCapInfo, err := cam_caps.GetControl(v4l2.CtrlContrast) + s.ContrastCaps["min"] = contrastCapInfo.Minimum + s.ContrastCaps["max"] = contrastCapInfo.Maximum + s.Contrast = contrastCapInfo.Value s.SingleColourMode = true