Skip to content

Commit c9d77f0

Browse files
committed
Add rotate option
1 parent 37b19fc commit c9d77f0

File tree

8 files changed

+141
-20
lines changed

8 files changed

+141
-20
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ or
1919

2020
Binaries are compiled with static OpenCV/libjpeg-turbo libraries, they should just work:
2121

22-
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-64bit.tar.gz)
23-
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-RPi.tar.gz)
24-
- [RPi3 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3-RPi3.tar.gz)
25-
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.3/cam2ip-1.3.zip)
22+
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-64bit.tar.gz)
23+
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-RPi.tar.gz)
24+
- [RPi3 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-RPi3.tar.gz)
25+
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4.zip)
26+
- [Windows 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.4/cam2ip-1.4-64bit.zip)
2627

2728

2829
### Installation
@@ -49,6 +50,8 @@ Usage of ./cam2ip:
4950
Camera index
5051
-nowebgl
5152
Disable WebGL drawing of images (html handler)
53+
-rotate int
54+
Rotate image, valid values are 90, 180, 270
5255
-video-file string
5356
Use video file instead of camera
5457
```

cam2ip.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
const (
1414
name = "cam2ip"
15-
version = "1.3"
15+
version = "1.4"
1616
)
1717

1818
func main() {
@@ -22,6 +22,7 @@ func main() {
2222
flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds")
2323
flag.Float64Var(&srv.FrameWidth, "width", 640, "Frame width")
2424
flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height")
25+
flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270")
2526
flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)")
2627
flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address")
2728
flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled")
@@ -48,15 +49,15 @@ func main() {
4849
}
4950

5051
if srv.FileName != "" {
51-
vid, err := video.New(srv.FileName)
52+
vid, err := video.New(video.Options{srv.FileName, srv.Rotate})
5253
if err != nil {
5354
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
5455
os.Exit(1)
5556
}
5657

5758
srv.Reader = vid
5859
} else {
59-
cam, err := camera.New(srv.Index)
60+
cam, err := camera.New(camera.Options{srv.Index, srv.Rotate})
6061
if err != nil {
6162
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
6263
os.Exit(1)

camera/camera.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,31 @@ import (
77
"fmt"
88
"image"
99

10+
"github.com/disintegration/imaging"
1011
"github.com/lazywei/go-opencv/opencv"
1112
)
1213

14+
// Options.
15+
type Options struct {
16+
Index int
17+
Rotate int
18+
}
19+
1320
// Camera represents camera.
1421
type Camera struct {
22+
opts Options
1523
camera *opencv.Capture
1624
frame *opencv.IplImage
1725
}
1826

1927
// New returns new Camera for given camera index.
20-
func New(index int) (camera *Camera, err error) {
28+
func New(opts Options) (camera *Camera, err error) {
2129
camera = &Camera{}
30+
camera.opts = opts
2231

23-
camera.camera = opencv.NewCameraCapture(index)
32+
camera.camera = opencv.NewCameraCapture(opts.Index)
2433
if camera.camera == nil {
25-
err = fmt.Errorf("camera: can not open camera %d", index)
34+
err = fmt.Errorf("camera: can not open camera %d", opts.Index)
2635
}
2736

2837
return
@@ -32,7 +41,25 @@ func New(index int) (camera *Camera, err error) {
3241
func (c *Camera) Read() (img image.Image, err error) {
3342
if c.camera.GrabFrame() {
3443
c.frame = c.camera.RetrieveFrame(1)
44+
45+
if c.frame == nil {
46+
err = fmt.Errorf("camera: can not grab frame")
47+
return
48+
}
49+
3550
img = c.frame.ToImage()
51+
if c.opts.Rotate == 0 {
52+
return
53+
}
54+
55+
switch c.opts.Rotate {
56+
case 90:
57+
img = imaging.Rotate90(img)
58+
case 180:
59+
img = imaging.Rotate180(img)
60+
case 270:
61+
img = imaging.Rotate270(img)
62+
}
3663
} else {
3764
err = fmt.Errorf("camera: can not grab frame")
3865
}

camera/camera_cv3.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,34 @@ import (
77
"fmt"
88
"image"
99

10+
"github.com/disintegration/imaging"
1011
"gocv.io/x/gocv"
1112
)
1213

14+
// Options.
15+
type Options struct {
16+
Index int
17+
Rotate int
18+
}
19+
1320
// Camera represents camera.
1421
type Camera struct {
22+
opts Options
1523
camera *gocv.VideoCapture
1624
frame *gocv.Mat
1725
}
1826

1927
// New returns new Camera for given camera index.
20-
func New(index int) (camera *Camera, err error) {
28+
func New(opts Options) (camera *Camera, err error) {
2129
camera = &Camera{}
30+
camera.opts = opts
2231

2332
mat := gocv.NewMat()
2433
camera.frame = &mat
2534

26-
camera.camera, err = gocv.VideoCaptureDevice(index)
35+
camera.camera, err = gocv.VideoCaptureDevice(opts.Index)
2736
if err != nil {
28-
err = fmt.Errorf("camera: can not open camera %d: %s", index, err.Error())
37+
err = fmt.Errorf("camera: can not open camera %d: %s", opts.Index, err.Error())
2938
}
3039

3140
return
@@ -45,6 +54,24 @@ func (c *Camera) Read() (img image.Image, err error) {
4554
return
4655
}
4756

57+
if c.frame == nil {
58+
err = fmt.Errorf("camera: can not grab frame")
59+
return
60+
}
61+
62+
if c.opts.Rotate == 0 {
63+
return
64+
}
65+
66+
switch c.opts.Rotate {
67+
case 90:
68+
img = imaging.Rotate90(img)
69+
case 180:
70+
img = imaging.Rotate180(img)
71+
case 270:
72+
img = imaging.Rotate270(img)
73+
}
74+
4875
return
4976
}
5077

make.bash

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
CHROOT="/usr/x86_64-pc-linux-gnu-static"
44
MINGW="/usr/i686-w64-mingw32"
5+
MINGW64="/usr/x86_64-w64-mingw32"
56
RPI="/usr/armv6j-hardfloat-linux-gnueabi"
67
RPI3="/usr/armv7a-hardfloat-linux-gnueabi"
78

@@ -14,7 +15,6 @@ CGO_LDFLAGS="-L$CHROOT/usr/lib -L$CHROOT/lib" \
1415
CGO_CFLAGS="-I$CHROOT/usr/include" \
1516
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
1617

17-
1818
PKG_CONFIG="/usr/bin/i686-w64-mingw32-pkg-config" \
1919
PKG_CONFIG_PATH="$MINGW/usr/lib/pkgconfig" \
2020
PKG_CONFIG_LIBDIR="$MINGW/usr/lib/pkgconfig" \
@@ -23,6 +23,14 @@ CGO_CFLAGS="-I$MINGW/usr/include" \
2323
CC="i686-w64-mingw32-gcc" CXX="i686-w64-mingw32-g++" \
2424
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
2525

26+
PKG_CONFIG="/usr/bin/x86_64-w64-mingw32-pkg-config" \
27+
PKG_CONFIG_PATH="$MINGW64/usr/lib/pkgconfig" \
28+
PKG_CONFIG_LIBDIR="$MINGW64/usr/lib/pkgconfig" \
29+
CGO_LDFLAGS="-L$MINGW64/usr/lib" \
30+
CGO_CFLAGS="-I$MINGW64/usr/include" \
31+
CC="x86_64-w64-mingw32-gcc" CXX="x86_64-w64-mingw32-g++" \
32+
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
33+
2634
PKG_CONFIG="/usr/bin/armv6j-hardfloat-linux-gnueabi-pkg-config" \
2735
PKG_CONFIG_PATH="$RPI/usr/lib/pkgconfig" \
2836
PKG_CONFIG_LIBDIR="$RPI/usr/lib/pkgconfig" \

server/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type Server struct {
2626
FrameWidth float64
2727
FrameHeight float64
2828

29+
Rotate int
30+
2931
NoWebGL bool
3032

3133
FileName string

video/video.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,31 @@ import (
77
"fmt"
88
"image"
99

10+
"github.com/disintegration/imaging"
1011
"github.com/lazywei/go-opencv/opencv"
1112
)
1213

14+
// Options.
15+
type Options struct {
16+
Filename string
17+
Rotate int
18+
}
19+
1320
// Video represents video.
1421
type Video struct {
22+
opts Options
1523
video *opencv.Capture
1624
frame *opencv.IplImage
1725
}
1826

1927
// New returns new Video for given path.
20-
func New(filename string) (video *Video, err error) {
28+
func New(opts Options) (video *Video, err error) {
2129
video = &Video{}
30+
video.opts = opts
2231

23-
video.video = opencv.NewFileCapture(filename)
32+
video.video = opencv.NewFileCapture(opts.Filename)
2433
if video.video == nil {
25-
err = fmt.Errorf("video: can not open video %s", filename)
34+
err = fmt.Errorf("video: can not open video %s", opts.Filename)
2635
}
2736

2837
return
@@ -32,7 +41,24 @@ func New(filename string) (video *Video, err error) {
3241
func (v *Video) Read() (img image.Image, err error) {
3342
if v.video.GrabFrame() {
3443
v.frame = v.video.RetrieveFrame(1)
44+
if v.frame == nil {
45+
err = fmt.Errorf("video: can not grab frame")
46+
return
47+
}
48+
3549
img = v.frame.ToImage()
50+
if v.opts.Rotate == 0 {
51+
return
52+
}
53+
54+
switch v.opts.Rotate {
55+
case 90:
56+
img = imaging.Rotate90(img)
57+
case 180:
58+
img = imaging.Rotate180(img)
59+
case 270:
60+
img = imaging.Rotate270(img)
61+
}
3662
} else {
3763
err = fmt.Errorf("video: can not grab frame")
3864
}

video/video_cv3.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,34 @@ import (
77
"fmt"
88
"image"
99

10+
"github.com/disintegration/imaging"
1011
"gocv.io/x/gocv"
1112
)
1213

14+
// Options.
15+
type Options struct {
16+
Filename string
17+
Rotate int
18+
}
19+
1320
// Video represents video.
1421
type Video struct {
22+
opts Options
1523
video *gocv.VideoCapture
1624
frame *gocv.Mat
1725
}
1826

1927
// New returns new Video for given path.
20-
func New(filename string) (video *Video, err error) {
28+
func New(opts Options) (video *Video, err error) {
2129
video = &Video{}
30+
video.opts = opts
2231

2332
mat := gocv.NewMat()
2433
video.frame = &mat
2534

26-
video.video, err = gocv.VideoCaptureFile(filename)
35+
video.video, err = gocv.VideoCaptureFile(opts.Filename)
2736
if err != nil {
28-
err = fmt.Errorf("video: can not open video %s: %s", filename, err.Error())
37+
err = fmt.Errorf("video: can not open video %s: %s", opts.Filename, err.Error())
2938
}
3039

3140
return
@@ -39,12 +48,30 @@ func (v *Video) Read() (img image.Image, err error) {
3948
return
4049
}
4150

51+
if v.frame == nil {
52+
err = fmt.Errorf("video: can not grab frame")
53+
return
54+
}
55+
4256
img, e := v.frame.ToImage()
4357
if e != nil {
4458
err = fmt.Errorf("video: %v", e)
4559
return
4660
}
4761

62+
if v.opts.Rotate == 0 {
63+
return
64+
}
65+
66+
switch v.opts.Rotate {
67+
case 90:
68+
img = imaging.Rotate90(img)
69+
case 180:
70+
img = imaging.Rotate180(img)
71+
case 270:
72+
img = imaging.Rotate270(img)
73+
}
74+
4875
return
4976
}
5077

0 commit comments

Comments
 (0)