在go语言中使用网络摄像头和OpenCV实现即时监控功能示例

2023-06-01 00:00:00 示例 监控 摄像头

在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,如果一切顺利,你应该看到类似这样的东西:

opencv监控.png


注意:

监控属于隐私、私密性很高的东西,请时刻加强你的服务器安全,

设置高强度的秘钥来保护你的监控页面。

相关文章