├── .gitignore
├── javascript
├── package.json
├── desktop.js
├── index.htm
├── double-click.htm
└── web.js
├── python
├── desktop.py
└── web.py
├── csharp
├── Web
│ ├── Web.csproj
│ └── Program.cs
└── Desktop
│ ├── Desktop.csproj
│ └── Program.cs
├── go
├── desktop.go
└── web.go
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | obj
2 | bin
3 |
--------------------------------------------------------------------------------
/javascript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webcam",
3 | "version": "1.0.0",
4 | "description": "Open webcam in any web browsers",
5 | "main": "web.js",
6 | "author": "yushulx",
7 | "license": "MIT",
8 | "dependencies": {
9 | "opencv4nodejs": "^5.6.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/python/desktop.py:
--------------------------------------------------------------------------------
1 | import cv2
2 |
3 | cap = cv2.VideoCapture(0)
4 |
5 | while True:
6 | ret, frame = cap.read()
7 | cv2.imshow("Webcam", frame)
8 | if cv2.waitKey(1) & 0xFF == 27: # use ESC to quit
9 | break
10 |
11 | cap.release()
12 | cv2.destroyAllWindows()
13 |
14 |
15 |
--------------------------------------------------------------------------------
/csharp/Web/Web.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/csharp/Desktop/Desktop.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/javascript/desktop.js:
--------------------------------------------------------------------------------
1 | const cv = require('opencv4nodejs');
2 |
3 | const vCap = new cv.VideoCapture(0);
4 |
5 | const delay = 10;
6 | while (true) {
7 | let frame = vCap.read();
8 | // loop back to start on end of stream reached
9 | if (frame.empty) {
10 | vCap.reset();
11 | frame = vCap.read();
12 | }
13 |
14 | cv.imshow('OpenCV Node.js', frame);
15 | const key = cv.waitKey(delay); // Press ESC to quit
16 | if (key == 27) {break;}
17 | }
--------------------------------------------------------------------------------
/go/desktop.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "gocv.io/x/gocv"
7 | )
8 |
9 | func main() {
10 | webcam, _ := gocv.OpenVideoCapture(0)
11 | window := gocv.NewWindow("Webcam")
12 | img := gocv.NewMat()
13 |
14 | for {
15 | webcam.Read(&img)
16 | window.IMShow(img)
17 | key := window.WaitKey(10)
18 | if key == 27 { // ESC
19 | break
20 | }
21 | }
22 |
23 | fmt.Println("Exit")
24 |
25 | // must call close() to terminate the program
26 | webcam.Close()
27 | }
28 |
--------------------------------------------------------------------------------
/javascript/index.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Webcam
6 |
7 |
8 |
9 |
10 |
11 |
12 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/javascript/double-click.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Webcam
6 |
7 |
8 |
9 |
10 |
11 |
12 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/csharp/Desktop/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using OpenCvSharp;
3 |
4 | namespace Desktop
5 | {
6 | class Program
7 | {
8 | static void Main(string[] args)
9 | {
10 | VideoCapture capture = new VideoCapture(0);
11 | using (Window window = new Window("Webcam"))
12 | {
13 | using (Mat image = new Mat())
14 | {
15 | while (true)
16 | {
17 | capture.Read(image);
18 | if (image.Empty()) break;
19 | window.ShowImage(image);
20 | int key = Cv2.WaitKey(30);
21 | if (key == 27) break;
22 | }
23 | }
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Xiao Ling
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/javascript/web.js:
--------------------------------------------------------------------------------
1 | const http = require('http');
2 | const cv = require('opencv4nodejs')
3 | const wCap = new cv.VideoCapture(0);
4 | wCap.set(cv.CAP_PROP_FRAME_WIDTH, 640);
5 | wCap.set(cv.CAP_PROP_FRAME_HEIGHT, 480);
6 |
7 | var img = null;
8 | function capture() {
9 | var frame = wCap.read()
10 | if (frame.empty) {
11 | wCap.reset();
12 | frame = wCap.read();
13 | }
14 |
15 | img = cv.imencode('.jpg', frame);
16 | setTimeout(capture, 30);
17 | }
18 |
19 | capture();
20 |
21 | var fs=require("fs");
22 | var html = fs.readFileSync("index.htm", "utf8");
23 |
24 | var server = http.createServer(function (req, res) {
25 | if (req.url === '/' || req.url === '/index.htm') {
26 |
27 | res.writeHead(200, { 'Content-Type': 'text/html' });
28 | res.write(html);
29 | res.end();
30 |
31 | }
32 | else if (req.url.startsWith("/image")) {
33 |
34 | res.writeHead(200, { 'Content-Type': 'image/jpeg' });
35 | res.write(img);
36 | res.end();
37 |
38 | }
39 | else
40 | res.end('Invalid Request!');
41 |
42 | });
43 |
44 | server.listen(2020);
45 |
46 | console.log('Node.js web server is running on port 2020...')
--------------------------------------------------------------------------------
/go/web.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strings"
8 |
9 | "gocv.io/x/gocv"
10 | )
11 |
12 | var webcam *gocv.VideoCapture
13 | var img gocv.Mat
14 |
15 | func handler(w http.ResponseWriter, r *http.Request) {
16 | if r.URL.Path == "/" {
17 | pageData := "" +
18 | "" +
19 | " " +
20 | " HttpListener Example" +
21 | " " +
22 | " " +
23 | "
" +
24 | " " +
25 | " " +
26 | ""
27 |
28 | w.Header().Set("Content-Type", "text/html")
29 | w.Write([]byte(pageData))
30 | } else if strings.HasPrefix(r.URL.Path, "/image") {
31 | webcam.Read(&img)
32 | jpg, _ := gocv.IMEncode(".jpg", img)
33 | w.Write(jpg)
34 | } else {
35 | fmt.Fprintf(w, "Page Not Found")
36 | }
37 |
38 | }
39 |
40 | func main() {
41 | fmt.Println("Running at port 2020...")
42 | webcam, _ = gocv.OpenVideoCapture(0)
43 | img = gocv.NewMat()
44 | http.HandleFunc("/", handler)
45 | log.Fatal(http.ListenAndServe(":2020", nil))
46 | webcam.Close()
47 | }
48 |
--------------------------------------------------------------------------------
/python/web.py:
--------------------------------------------------------------------------------
1 | import http.server
2 | import socketserver
3 | from time import sleep
4 | import cv2
5 | import threading
6 |
7 | PORT = 2020
8 |
9 | pageData = "" + \
10 | "" + \
11 | " " + \
12 | " HttpListener Example" + \
13 | " " + \
14 | " " + \
15 | "
"+ \
16 | " "+ \
17 | " " + \
18 | ""
19 |
20 | class MyHandler(http.server.BaseHTTPRequestHandler):
21 | def do_GET(self):
22 |
23 | if self.path == '/':
24 | self.send_response(200)
25 | self.send_header("Content-type", "text/html")
26 | self.end_headers()
27 | self.wfile.write(bytes(pageData, "utf8"))
28 | elif self.path.startswith('/image'):
29 | self.send_response(200)
30 | self.send_header("Content-type", "image/jpeg")
31 | self.end_headers()
32 |
33 | # ret, frame = cap.read()
34 | # _, jpg = cv2.imencode(".jpg", frame)
35 |
36 | self.wfile.write(jpg)
37 | else:
38 | self.send_response(404)
39 |
40 | # continuously get frames from webcam
41 | cap = cv2.VideoCapture(0)
42 | ret, frame = cap.read()
43 | _, jpg = cv2.imencode(".jpg", frame)
44 |
45 | class FrameThread (threading.Thread):
46 | def __init__(self):
47 | threading.Thread.__init__(self)
48 | self.isRunning = True
49 |
50 | def run(self):
51 | global jpg, cap
52 |
53 | while self.isRunning:
54 | ret, frame = cap.read()
55 | _, jpg = cv2.imencode(".jpg", frame)
56 | sleep(0.03)
57 |
58 | print("Quit thread")
59 |
60 | frame_thread = FrameThread()
61 | frame_thread.start()
62 |
63 | # run the server
64 | with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
65 | print("Serving at port ", PORT)
66 | try:
67 | httpd.serve_forever()
68 | except:
69 | pass
70 |
71 | # quit the app
72 | print('Server is stopped')
73 | frame_thread.isRunning = False
74 | frame_thread.join()
75 | cap.release()
76 |
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Webcam Video Display for Desktop and Web
2 |
3 | The repository contains some simple webcam display programs implemented by using different programming languages and OpenCV. The web camera apps are available for both local and remote access via any web browser.
4 |
5 | ## Programming Language List
6 | - [JavaScript](#JavaScript)
7 | - [C#](#CSharp)
8 | - [Python](#Python)
9 | - [Golang](#Golang)
10 |
11 |
12 | ## JavaScript
13 |
14 |
15 | Install [opencv4nodejs](https://www.npmjs.com/package/opencv4nodejs):
16 |
17 | ```
18 | npm i opencv4nodejs
19 | ```
20 |
21 | #### Desktop
22 |
23 | Run:
24 |
25 | ```
26 | node desktop.js
27 | ```
28 |
29 | #### Web
30 |
31 | 1. Run:
32 |
33 | ```
34 | node web.js
35 | ```
36 | 2. Open `double-click.htm` directly or visit `locahost:2020` in any web browser.
37 |
38 | ## CSharp
39 |
40 | Install [OpenCvSharp](https://github.com/shimat/opencvsharp):
41 |
42 | **For Windows**
43 |
44 | ```
45 | dotnet add package OpenCvSharp4
46 | dotnet add package OpenCvSharp4.runtime.win
47 | ```
48 |
49 | ### Desktop
50 | Run:
51 |
52 | ```
53 | dotnet restore
54 | dotnet run
55 | ```
56 |
57 | ### Web
58 |
59 | 1. Run:
60 |
61 | ```
62 | dotnet restore
63 | dotnet run
64 | ```
65 |
66 | 2. Visit `locahost:2020` in any web browser.
67 |
68 | ## Python
69 |
70 | Install [OpenCV Python](https://pypi.org/project/opencv-python/):
71 |
72 | ```
73 | pip install opencv-python
74 | ```
75 |
76 | ### Desktop
77 | Run:
78 |
79 | ```
80 | python desktop.py
81 | ```
82 |
83 | ### Web
84 | 1. Run:
85 |
86 | ```
87 | python web.py
88 | ```
89 |
90 | 2. Visit `locahost:2020` in any web browser.
91 |
92 | ## Golang
93 | Install [gocv](https://gocv.io/getting-started):
94 |
95 | ```
96 | go get -u -d gocv.io/x/gocv
97 | ```
98 |
99 | **For Windows**
100 |
101 | 1. Install MinGW-W64 [x86_64-7.3.0-posix-seh-rt_v5-rev2](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/7.3.0/)
102 | 2. Install [CMake](https://cmake.org/download/)
103 | 3. Build the OpenCV module:
104 |
105 | ```
106 | chdir %GOPATH%\src\gocv.io\x\gocv
107 | win_build_opencv.cmd
108 | ```
109 | 4. Add `C:\opencv\build\install\x64\mingw\bin` to your system path.
110 |
111 |
112 |
113 | ### Desktop
114 | Run:
115 |
116 | ```
117 | go run desktop.go
118 | ```
119 |
120 | ### Web
121 | 1. Run:
122 |
123 | ```
124 | go run web.go
125 | ```
126 |
127 | 2. Visit `locahost:2020` in any web browser.
128 |
129 | ## Blog
130 | [How to Use OpenCV to Build Simple Webcam Apps for Desktop and Web](https://www.dynamsoft.com/codepool/opencv-webcam-app-desktop-web.html)
131 |
--------------------------------------------------------------------------------
/csharp/Web/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using System.Net;
5 | using System.Threading.Tasks;
6 | using OpenCvSharp;
7 |
8 | namespace Web
9 | {
10 | class Program
11 | {
12 | public static HttpListener listener;
13 | public static string url = "http://localhost:2020/";
14 | public static string pageData =
15 | "" +
16 | "" +
17 | " " +
18 | " HttpListener Example" +
19 | " " +
20 | " " +
21 | "
"+
22 | " "+
23 | " " +
24 | "";
25 |
26 | public static VideoCapture capture = new VideoCapture(0);
27 |
28 | // https://gist.github.com/define-private-public/d05bc52dd0bed1c4699d49e2737e80e7
29 |
30 | public static async Task HandleIncomingConnections()
31 | {
32 | while (true)
33 | {
34 | // Will wait here until we hear from a connection
35 | HttpListenerContext ctx = await listener.GetContextAsync();
36 |
37 | // Peel out the requests and response objects
38 | HttpListenerRequest req = ctx.Request;
39 | HttpListenerResponse resp = ctx.Response;
40 |
41 | // Print out some info about the request
42 | // Console.WriteLine(req.Url.ToString());
43 | // Console.WriteLine(req.HttpMethod);
44 | // Console.WriteLine(req.UserHostName);
45 | // Console.WriteLine(req.UserAgent);
46 | // Console.WriteLine();
47 |
48 | if ((req.HttpMethod == "GET") && (req.Url.AbsolutePath.StartsWith("/image"))) {
49 |
50 | resp.ContentType = "image/jpeg";
51 | using (Mat image = new Mat())
52 | {
53 | capture.Read(image);
54 | Cv2.ImEncode(".jpg", image, out var imageData);
55 | await resp.OutputStream.WriteAsync(imageData, 0, imageData.Length);
56 | resp.Close();
57 | }
58 | }
59 | else {
60 |
61 | // Write the response info
62 | byte[] data = Encoding.UTF8.GetBytes(pageData);
63 | resp.ContentType = "text/html";
64 | resp.ContentEncoding = Encoding.UTF8;
65 | resp.ContentLength64 = data.LongLength;
66 |
67 | // Write out to the response stream (asynchronously), then close it
68 | await resp.OutputStream.WriteAsync(data, 0, data.Length);
69 | resp.Close();
70 | }
71 | }
72 | }
73 |
74 | static void Main(string[] args)
75 | {
76 | // Create a Http server and start listening for incoming connections
77 | listener = new HttpListener();
78 | listener.Prefixes.Add(url);
79 | listener.Start();
80 | Console.WriteLine("Listening for connections on {0}", url);
81 |
82 | // Handle requests
83 | Task listenTask = HandleIncomingConnections();
84 | listenTask.GetAwaiter().GetResult();
85 |
86 | // Close the listener
87 | listener.Close();
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------