在go语言中使用网络摄像头和OpenCV实现即时监控功能示例
在go项目中使用现成的网络摄像头,实现并通过base64字符串编码的图像发送至网络浏览器。
它是对以前的教程:
https://www.socketloop.com/tutorials/golang-activate-web-camera-and-broadcast-out-base64-encoded-images
的改进。
主页面中的JavaScript将每2秒自动刷新图像。
它能够识别人脸,并允许用户在发现 "不受欢迎的 "访客时从网络浏览器中播放狗叫声。
首先,下载MP3声音文件和人脸识别的XML文件,网址是:
http://www.orangefreesounds.com/wp-content/uploads/2016/10/Dog-barking-noise.zip
和
https://raw.githubusercontent.com/lazywei/go-opencv/master/samples/haarcascadefrontalfacealt.xml
解压缩文件并提取出MP3文件。
第二,该程序将调用一个命令行MP3播放器。
如果你是在MacOSX上运行这个程序,没有什么需要改变。该程序使用afplay。
如果你使用的是Windows,见
https://lawlessguy.wordpress.com/2015/06/27/update-to-a-command-line-mp3-player-for-windows/
如果你使用的是Linux,将代码中的afplay替换为mper或mpg123
接下来,如果你还没有这样做,你需要得到这些。
对于MacOSX:
>brew install homebrew/science/opencv
最后:
去获取
github.com/lazywei/go-opencv/opencv
示例代码:
package main
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/lazywei/go-opencv/opencv"
"image/png"
"net/http"
"os"
"os/exec"
"os/signal"
"strconv"
"syscall"
)
//全局变量
var (
webCamera = new(opencv.Capture)
cascade = new(opencv.HaarCascade)
)
func bark(w http.ResponseWriter, r *http.Request) {
fmt.Println("Barking!")
// afplay是针对MacOSX的。
// 它是一个命令行音频文件播放器
// 用适合Linux或Windows的播放器来代替。
cmd := exec.Command("afplay", "Dog-barking-noise.mp3")
err := cmd.Run()
if err != nil {
error := `Cannot play mp3 file!`
w.Write([]byte(error))
} else {
html := `<h2>Barked!!</h2>`
w.Write([]byte(html))
}
}
func homepage(w http.ResponseWriter, r *http.Request) {
fmt.Println("Camera recording...")
html := `<!DOCTYPE html>
<body>
<head>
<title>通过OpenCV和base64编码的字符串图像的Golang生存监控</title>
<style type="text/css">
#buttons-area {
font-family: Arial, Helvetica, sans serif;
font-size: 30px;
margin: 50px auto;
letter-spacing: -0.07em;
display: block;
padding: 5px;
border: solid #cdcdcd 1px;
width: 700px;
text-color: white;
background: #f4f4f4;
}
#webcamfeed-area {
margin: 50px auto;
padding: 5px;
border: solid #cdcdcd 1px;
width: 700px;
background: blue;
}
#bark-area {
margin: 50px auto;
padding: 5px;
border: solid #cdcdcd 1px;
width: 700px;
background: linear-gradient(to bottom,#e5e7eb 0,#d8dade 100%);
}
button {
text-align: center;
width: 48%;
height: 40px;
font-size: 18px;
border-radius: 6px;
}
</style>
<div id="webcamfeed-area"></div>
<div id="bark-area"></div>
<div id="buttons-area">
<h1 style="line-height: 1.25em;">Feed from web camera</h1>
<button type="button" onclick="bark()">Play barking sound</button>
</div>
</body>
</html>
<script type="text/javascript">
function bark() {
fetch('/bark').then(function(response) {
return response.text();
}).then(function(text) {
// <!DOCTYPE ....
var barkfeedback = text;
document.getElementById('bark-area').innerHTML = barkfeedback;
}).catch(function(err) {
console.log(err)
});
}
function refresh() {
//fetch API不适用于Safari浏览器...
fetch('/refresh').then(function(response) {
return response.text();
}).then(function(text) {
// <!DOCTYPE ....
var img2html = text;
document.getElementById('webcamfeed-area').innerHTML = img2html;
}).catch(function(err) {
console.log(err)
});
}
refresh(); //在页面加载时运行
setInterval(function() {
refresh() // 每2秒后运行一次
}, 2000);
</script>`
w.Write([]byte(html))
}
func refresh(w http.ResponseWriter, r *http.Request) {
//for {
if webCamera.GrabFrame() {
imgFrame := webCamera.RetrieveFrame(1)
if imgFrame != nil {
//我的网络摄像机是高清的。必须使图像框架
// 小一点,这样就不会把浏览器炸毁。
imgFrame = opencv.Resize(imgFrame, 700, 0, opencv.CV_INTER_LINEAR)
// from https://github.com/lazywei/go-opencv/blob/master/samples/webcam_facedetect.go
// detect faces in image
faces := cascade.DetectObjects(imgFrame)
for _, value := range faces {
//添加一个绿色矩形
opencv.Rectangle(imgFrame,
opencv.Point{value.X() + value.Width(), value.Y()},
opencv.Point{value.X(), value.Y() + value.Height()},
opencv.NewScalar(0, 255, 0, 0.0), 6, 2, 0)
// 添加一个红圈,只是为了好玩
// NewScalar(blue, green, red, alpha)...
opencv.Circle(imgFrame,
opencv.Point{
value.X() + (value.Width() / 2),
value.Y() + (value.Height() / 2),
},
value.Width()/3,
opencv.NewScalar(0, 0, 255, 0.0), 8, 1, 0)
}
//转换IplImage(英特尔图像处理库)
//转换为image.Image
goImgFrame := imgFrame.ToImage()
//然后转换为[]byte
//在png.Encode()函数的帮助下,转换成[]字节。
frameBuffer := new(bytes.Buffer)
//frameBuffer := make([]byte, imgFrame.ImageSize())
err := png.Encode(frameBuffer, goImgFrame)
if err != nil {
panic(err)
}
//将缓冲区的字节转换为base64字符串 - 使用buf.Bytes()处理新图像
imgBase64Str := base64.StdEncoding.EncodeToString(frameBuffer.Bytes())
//嵌入到html中
img2html := "<html><body><img src=\"data:image/png;base64," + imgBase64Str + "\" /></body></html>"
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(fmt.Sprintf(img2html)))
flusher := w.(http.Flusher) // flush everything
flusher.Flush() // out to browser
fmt.Println("Streaming " + strconv.Itoa(len(img2html)) + " bytes.")
}
}
//}
}
func main() {
webCamera = opencv.NewCameraCapture(0)
if webCamera == nil {
panic("Unable to open camera")
}
//从以下网站抓取xml文件
// wget https://raw.githubusercontent.com/lazywei/go-opencv/master/samples/haarcascade_frontalface_alt.xml
cascade = opencv.LoadHaarClassifierCascade("./haarcascade_frontalface_alt.xml")
fmt.Println("Server started. Press Ctrl-C to stop server")
//捕捉kill命令中的Ctrl-C和SIGTERM
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
go func() {
signalType := <-ch
signal.Stop(ch)
fmt.Println("Signal type intercepted : ", signalType)
fmt.Println("Exit command received. Exiting...")
fmt.Println("Cleaning up ...")
webCamera.Release()
os.Exit(0)
}()
fmt.Println("Broadcasting...")
mux := http.NewServeMux()
mux.HandleFunc("/", homepage)
mux.HandleFunc("/refresh", refresh)
mux.HandleFunc("/bark", bark)
http.ListenAndServe(":8080", mux)
}
构建代码并执行二进制文件。
将你的浏览器指向localhost:8080,如果一切顺利,你应该看到类似这样的东西:
注意:
监控属于隐私、私密性很高的东西,请时刻加强你的服务器安全,
设置高强度的秘钥来保护你的监控页面。
相关文章