Add rotate option

This commit is contained in:
Milan Nikolic
2018-10-10 04:32:00 +02:00
parent 37b19fcfe8
commit c9d77f03e7
8 changed files with 141 additions and 20 deletions

View File

@@ -19,10 +19,11 @@ or
Binaries are compiled with static OpenCV/libjpeg-turbo libraries, they should just work: Binaries are compiled with static OpenCV/libjpeg-turbo libraries, they should just work:
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-64bit.tar.gz) - [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-64bit.tar.gz)
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-RPi.tar.gz) - [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-RPi.tar.gz)
- [RPi3 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-RPi3.tar.gz) - [RPi3 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-RPi3.tar.gz)
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3.zip) - [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4.zip)
- [Windows 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-64bit.zip)
### Installation ### Installation
@@ -49,6 +50,8 @@ Usage of ./cam2ip:
Camera index Camera index
-nowebgl -nowebgl
Disable WebGL drawing of images (html handler) Disable WebGL drawing of images (html handler)
-rotate int
Rotate image, valid values are 90, 180, 270
-video-file string -video-file string
Use video file instead of camera Use video file instead of camera
``` ```

View File

@@ -12,7 +12,7 @@ import (
const ( const (
name = "cam2ip" name = "cam2ip"
version = "1.3" version = "1.4"
) )
func main() { func main() {
@@ -22,6 +22,7 @@ func main() {
flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds") flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds")
flag.Float64Var(&srv.FrameWidth, "width", 640, "Frame width") flag.Float64Var(&srv.FrameWidth, "width", 640, "Frame width")
flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height") flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height")
flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270")
flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)") flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)")
flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address") flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address")
flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled") flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled")
@@ -48,7 +49,7 @@ func main() {
} }
if srv.FileName != "" { if srv.FileName != "" {
vid, err := video.New(srv.FileName) vid, err := video.New(video.Options{srv.FileName, srv.Rotate})
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1) os.Exit(1)
@@ -56,7 +57,7 @@ func main() {
srv.Reader = vid srv.Reader = vid
} else { } else {
cam, err := camera.New(srv.Index) cam, err := camera.New(camera.Options{srv.Index, srv.Rotate})
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1) os.Exit(1)

View File

@@ -7,22 +7,31 @@ import (
"fmt" "fmt"
"image" "image"
"github.com/disintegration/imaging"
"github.com/lazywei/go-opencv/opencv" "github.com/lazywei/go-opencv/opencv"
) )
// Options.
type Options struct {
Index int
Rotate int
}
// Camera represents camera. // Camera represents camera.
type Camera struct { type Camera struct {
opts Options
camera *opencv.Capture camera *opencv.Capture
frame *opencv.IplImage frame *opencv.IplImage
} }
// New returns new Camera for given camera index. // New returns new Camera for given camera index.
func New(index int) (camera *Camera, err error) { func New(opts Options) (camera *Camera, err error) {
camera = &Camera{} camera = &Camera{}
camera.opts = opts
camera.camera = opencv.NewCameraCapture(index) camera.camera = opencv.NewCameraCapture(opts.Index)
if camera.camera == nil { if camera.camera == nil {
err = fmt.Errorf("camera: can not open camera %d", index) err = fmt.Errorf("camera: can not open camera %d", opts.Index)
} }
return return
@@ -32,7 +41,25 @@ func New(index int) (camera *Camera, err error) {
func (c *Camera) Read() (img image.Image, err error) { func (c *Camera) Read() (img image.Image, err error) {
if c.camera.GrabFrame() { if c.camera.GrabFrame() {
c.frame = c.camera.RetrieveFrame(1) c.frame = c.camera.RetrieveFrame(1)
if c.frame == nil {
err = fmt.Errorf("camera: can not grab frame")
return
}
img = c.frame.ToImage() img = c.frame.ToImage()
if c.opts.Rotate == 0 {
return
}
switch c.opts.Rotate {
case 90:
img = imaging.Rotate90(img)
case 180:
img = imaging.Rotate180(img)
case 270:
img = imaging.Rotate270(img)
}
} else { } else {
err = fmt.Errorf("camera: can not grab frame") err = fmt.Errorf("camera: can not grab frame")
} }

View File

@@ -7,25 +7,34 @@ import (
"fmt" "fmt"
"image" "image"
"github.com/disintegration/imaging"
"gocv.io/x/gocv" "gocv.io/x/gocv"
) )
// Options.
type Options struct {
Index int
Rotate int
}
// Camera represents camera. // Camera represents camera.
type Camera struct { type Camera struct {
opts Options
camera *gocv.VideoCapture camera *gocv.VideoCapture
frame *gocv.Mat frame *gocv.Mat
} }
// New returns new Camera for given camera index. // New returns new Camera for given camera index.
func New(index int) (camera *Camera, err error) { func New(opts Options) (camera *Camera, err error) {
camera = &Camera{} camera = &Camera{}
camera.opts = opts
mat := gocv.NewMat() mat := gocv.NewMat()
camera.frame = &mat camera.frame = &mat
camera.camera, err = gocv.VideoCaptureDevice(index) camera.camera, err = gocv.VideoCaptureDevice(opts.Index)
if err != nil { if err != nil {
err = fmt.Errorf("camera: can not open camera %d: %s", index, err.Error()) err = fmt.Errorf("camera: can not open camera %d: %s", opts.Index, err.Error())
} }
return return
@@ -45,6 +54,24 @@ func (c *Camera) Read() (img image.Image, err error) {
return return
} }
if c.frame == nil {
err = fmt.Errorf("camera: can not grab frame")
return
}
if c.opts.Rotate == 0 {
return
}
switch c.opts.Rotate {
case 90:
img = imaging.Rotate90(img)
case 180:
img = imaging.Rotate180(img)
case 270:
img = imaging.Rotate270(img)
}
return return
} }

View File

@@ -2,6 +2,7 @@
CHROOT="/usr/x86_64-pc-linux-gnu-static" CHROOT="/usr/x86_64-pc-linux-gnu-static"
MINGW="/usr/i686-w64-mingw32" MINGW="/usr/i686-w64-mingw32"
MINGW64="/usr/x86_64-w64-mingw32"
RPI="/usr/armv6j-hardfloat-linux-gnueabi" RPI="/usr/armv6j-hardfloat-linux-gnueabi"
RPI3="/usr/armv7a-hardfloat-linux-gnueabi" RPI3="/usr/armv7a-hardfloat-linux-gnueabi"
@@ -14,7 +15,6 @@ CGO_LDFLAGS="-L$CHROOT/usr/lib -L$CHROOT/lib" \
CGO_CFLAGS="-I$CHROOT/usr/include" \ CGO_CFLAGS="-I$CHROOT/usr/include" \
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -v -x -o build/cam2ip.linux.amd64 -ldflags "-linkmode external -s -w" github.com/gen2brain/cam2ip CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -v -x -o build/cam2ip.linux.amd64 -ldflags "-linkmode external -s -w" github.com/gen2brain/cam2ip
PKG_CONFIG="/usr/bin/i686-w64-mingw32-pkg-config" \ PKG_CONFIG="/usr/bin/i686-w64-mingw32-pkg-config" \
PKG_CONFIG_PATH="$MINGW/usr/lib/pkgconfig" \ PKG_CONFIG_PATH="$MINGW/usr/lib/pkgconfig" \
PKG_CONFIG_LIBDIR="$MINGW/usr/lib/pkgconfig" \ PKG_CONFIG_LIBDIR="$MINGW/usr/lib/pkgconfig" \
@@ -23,6 +23,14 @@ CGO_CFLAGS="-I$MINGW/usr/include" \
CC="i686-w64-mingw32-gcc" CXX="i686-w64-mingw32-g++" \ CC="i686-w64-mingw32-gcc" CXX="i686-w64-mingw32-g++" \
CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -v -x -o build/cam2ip.exe -ldflags "-linkmode external -s -w '-extldflags=-static'" github.com/gen2brain/cam2ip CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -v -x -o build/cam2ip.exe -ldflags "-linkmode external -s -w '-extldflags=-static'" github.com/gen2brain/cam2ip
PKG_CONFIG="/usr/bin/x86_64-w64-mingw32-pkg-config" \
PKG_CONFIG_PATH="$MINGW64/usr/lib/pkgconfig" \
PKG_CONFIG_LIBDIR="$MINGW64/usr/lib/pkgconfig" \
CGO_LDFLAGS="-L$MINGW64/usr/lib" \
CGO_CFLAGS="-I$MINGW64/usr/include" \
CC="x86_64-w64-mingw32-gcc" CXX="x86_64-w64-mingw32-g++" \
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -v -x -o build/cam2ip.exe.amd64 -ldflags "-linkmode external -s -w '-extldflags=-static'" github.com/gen2brain/cam2ip
PKG_CONFIG="/usr/bin/armv6j-hardfloat-linux-gnueabi-pkg-config" \ PKG_CONFIG="/usr/bin/armv6j-hardfloat-linux-gnueabi-pkg-config" \
PKG_CONFIG_PATH="$RPI/usr/lib/pkgconfig" \ PKG_CONFIG_PATH="$RPI/usr/lib/pkgconfig" \
PKG_CONFIG_LIBDIR="$RPI/usr/lib/pkgconfig" \ PKG_CONFIG_LIBDIR="$RPI/usr/lib/pkgconfig" \

View File

@@ -26,6 +26,8 @@ type Server struct {
FrameWidth float64 FrameWidth float64
FrameHeight float64 FrameHeight float64
Rotate int
NoWebGL bool NoWebGL bool
FileName string FileName string

View File

@@ -7,22 +7,31 @@ import (
"fmt" "fmt"
"image" "image"
"github.com/disintegration/imaging"
"github.com/lazywei/go-opencv/opencv" "github.com/lazywei/go-opencv/opencv"
) )
// Options.
type Options struct {
Filename string
Rotate int
}
// Video represents video. // Video represents video.
type Video struct { type Video struct {
opts Options
video *opencv.Capture video *opencv.Capture
frame *opencv.IplImage frame *opencv.IplImage
} }
// New returns new Video for given path. // New returns new Video for given path.
func New(filename string) (video *Video, err error) { func New(opts Options) (video *Video, err error) {
video = &Video{} video = &Video{}
video.opts = opts
video.video = opencv.NewFileCapture(filename) video.video = opencv.NewFileCapture(opts.Filename)
if video.video == nil { if video.video == nil {
err = fmt.Errorf("video: can not open video %s", filename) err = fmt.Errorf("video: can not open video %s", opts.Filename)
} }
return return
@@ -32,7 +41,24 @@ func New(filename string) (video *Video, err error) {
func (v *Video) Read() (img image.Image, err error) { func (v *Video) Read() (img image.Image, err error) {
if v.video.GrabFrame() { if v.video.GrabFrame() {
v.frame = v.video.RetrieveFrame(1) v.frame = v.video.RetrieveFrame(1)
if v.frame == nil {
err = fmt.Errorf("video: can not grab frame")
return
}
img = v.frame.ToImage() img = v.frame.ToImage()
if v.opts.Rotate == 0 {
return
}
switch v.opts.Rotate {
case 90:
img = imaging.Rotate90(img)
case 180:
img = imaging.Rotate180(img)
case 270:
img = imaging.Rotate270(img)
}
} else { } else {
err = fmt.Errorf("video: can not grab frame") err = fmt.Errorf("video: can not grab frame")
} }

View File

@@ -7,25 +7,34 @@ import (
"fmt" "fmt"
"image" "image"
"github.com/disintegration/imaging"
"gocv.io/x/gocv" "gocv.io/x/gocv"
) )
// Options.
type Options struct {
Filename string
Rotate int
}
// Video represents video. // Video represents video.
type Video struct { type Video struct {
opts Options
video *gocv.VideoCapture video *gocv.VideoCapture
frame *gocv.Mat frame *gocv.Mat
} }
// New returns new Video for given path. // New returns new Video for given path.
func New(filename string) (video *Video, err error) { func New(opts Options) (video *Video, err error) {
video = &Video{} video = &Video{}
video.opts = opts
mat := gocv.NewMat() mat := gocv.NewMat()
video.frame = &mat video.frame = &mat
video.video, err = gocv.VideoCaptureFile(filename) video.video, err = gocv.VideoCaptureFile(opts.Filename)
if err != nil { if err != nil {
err = fmt.Errorf("video: can not open video %s: %s", filename, err.Error()) err = fmt.Errorf("video: can not open video %s: %s", opts.Filename, err.Error())
} }
return return
@@ -39,12 +48,30 @@ func (v *Video) Read() (img image.Image, err error) {
return return
} }
if v.frame == nil {
err = fmt.Errorf("video: can not grab frame")
return
}
img, e := v.frame.ToImage() img, e := v.frame.ToImage()
if e != nil { if e != nil {
err = fmt.Errorf("video: %v", e) err = fmt.Errorf("video: %v", e)
return return
} }
if v.opts.Rotate == 0 {
return
}
switch v.opts.Rotate {
case 90:
img = imaging.Rotate90(img)
case 180:
img = imaging.Rotate180(img)
case 270:
img = imaging.Rotate270(img)
}
return return
} }