├── flask
├── .dockerignore
├── run.py
├── app
│ ├── __init__.py
│ ├── templates
│ │ └── index.html
│ └── views.py
├── app.ini
├── requirements.txt
└── Dockerfile
├── nginx
├── nginx.conf
└── Dockerfile
├── docker-compose.yml
├── README.md
└── .gitignore
/flask/.dockerignore:
--------------------------------------------------------------------------------
1 | env/
2 | __pycache__/
--------------------------------------------------------------------------------
/flask/run.py:
--------------------------------------------------------------------------------
1 | from app import app
2 |
3 | if __name__ == "__main__":
4 | app.run()
--------------------------------------------------------------------------------
/flask/app/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 | from app import views
--------------------------------------------------------------------------------
/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 |
3 | listen 80;
4 |
5 | location / {
6 | include uwsgi_params;
7 | uwsgi_pass flask:8080;
8 | }
9 |
10 | }
--------------------------------------------------------------------------------
/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx
2 |
3 | # Remove the default nginx.conf
4 | RUN rm /etc/nginx/conf.d/default.conf
5 |
6 | # Replace with our own nginx.conf
7 | COPY nginx.conf /etc/nginx/conf.d/
--------------------------------------------------------------------------------
/flask/app.ini:
--------------------------------------------------------------------------------
1 | [uwsgi]
2 | wsgi-file = run.py
3 | callable = app
4 | socket = :8080
5 | processes = 4
6 | threads = 2
7 | master = true
8 | chmod-socket = 660
9 | vacuum = true
10 | die-on-term = true
--------------------------------------------------------------------------------
/flask/requirements.txt:
--------------------------------------------------------------------------------
1 | click==7.1.2
2 | Flask==1.1.2
3 | itsdangerous==1.1.0
4 | Jinja2==2.11.2
5 | MarkupSafe==1.1.1
6 | numpy==1.19.1
7 | opencv-python==4.4.0.42
8 | uWSGI==2.0.19.1
9 | Werkzeug==1.0.1
10 |
--------------------------------------------------------------------------------
/flask/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 |
3 | services:
4 |
5 | flask:
6 | build: ./flask
7 | container_name: flask
8 | environment:
9 | - APP_NAME=flask-app
10 | - CAMERA_STREAM_URL=0
11 | expose:
12 | - 8080
13 |
14 | nginx:
15 | build: ./nginx
16 | container_name: nginx
17 | ports:
18 | - "80:80"
--------------------------------------------------------------------------------
/flask/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the Python3.7.2 image
2 | FROM python:3.7.2
3 |
4 | # Set the working directory to /app
5 | WORKDIR /app
6 |
7 | # Copy the current directory contents into the container at /app
8 | ADD . /app
9 |
10 | RUN apt-get update
11 | RUN apt-get install 'libgl1-mesa-dev' -y
12 | # Install the dependencies
13 | RUN pip install -r requirements.txt
14 |
15 | # run the command to start uWSGI
16 | CMD ["uwsgi", "app.ini"]
17 |
--------------------------------------------------------------------------------
/flask/app/views.py:
--------------------------------------------------------------------------------
1 | from app import app
2 | from flask import Flask, render_template, Response
3 | import os
4 | import cv2
5 |
6 | # paste camera stream url in quotations ("url") or use 0 to use webcam
7 | cam_url = os.getenv('CAMERA_STREAM_URL', '0')
8 |
9 |
10 | def process_frame(frame):
11 | # do the image processing here
12 | return frame
13 |
14 |
15 | @app.route('/')
16 | def home():
17 | return render_template('index.html')
18 |
19 |
20 | def stream():
21 | cap = cv2.VideoCapture(cam_url)
22 | while True:
23 | cv2.waitKey(1)
24 | success, frame = cap.read()
25 | frame = process_frame(frame)
26 | if success:
27 | _, buffer = cv2.imencode('.jpg', frame)
28 | frame = buffer.tobytes()
29 | yield (b'--frame\r\n'
30 | b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
31 |
32 |
33 | @app.route('/live_stream/', methods=["GET"])
34 | def live_stream():
35 | """Video streaming route. Put this in the src attribute of an img tag."""
36 | return Response(stream(),
37 | mimetype='multipart/x-mixed-replace; boundary=frame')
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flask-OpenCV-Docker
2 | Stream IP camera frames in local network using Flask, Docker and OpenCV.
3 |
4 | ## Overview
5 | this is a simple Flask web app running on top of a Docker container. The app also has Nginx configured which lets users in your local network access the app using your local IP address.
6 |
7 | ## Requirements
8 | If you want to run the app on docker the only thing you need is Docker-ce and Docker-compose.
9 | follow the official [guide]("https://docs.docker.com/engine/install/ubuntu/") on installing Docker on Ubuntu.
10 |
11 | If you only want to run the python program use the following command to install requirements.
12 |
13 | ```
14 | cd flask/
15 | pip install -r requirements.txt
16 | ```
17 | ### Run
18 | Flask web app only: cd to `flask` directory and run the following:
19 |
20 | ```
21 | python run.py
22 | ```
23 | Run the whole thing on Docker and Nginx: cd to the project root directory and run:
24 |
25 | ```
26 | docker-compose up
27 | ```
28 | **Note**: Make sure you change the `CAMERA_STREAM_URL` in docker compose file under Flask service. Default is 0 but webcams are not accessible from a Docker container out of the box! So an RTSP url is required.
29 |
30 | It might take some time to download required docker images and then it will run the containers and you and other users in the local network can access the page on any device. Just type the local IP address of your machine in the browser and that's it!
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Skip to content
2 | Search or jump to…
3 |
4 | Pull requests
5 | Issues
6 | Marketplace
7 | Explore
8 |
9 | @AryanSh98
10 | github
11 | /
12 | gitignore
13 | 3.2k
14 | 108k58k
15 | Code
16 | Pull requests
17 | 200
18 | Actions
19 | Projects
20 | Security
21 | Insights
22 | gitignore/Python.gitignore
23 | @pradyunsg
24 | pradyunsg Remove pip-wheel-metadata/ from Python.gitignore (#3364)
25 | …
26 | Latest commit 14f8a8b on Apr 12
27 | History
28 | 83 contributors
29 | @arcresu@shiftkey@Lucretiel@Harrison-G@jwg4@GabrielC101@misaelnieto@pmsosa@svkampen@vltr@thedrow@matheussl
30 | 138 lines (112 sloc) 1.99 KB
31 |
32 | # Byte-compiled / optimized / DLL files
33 | __pycache__/
34 | *.py[cod]
35 | *$py.class
36 |
37 | # C extensions
38 | *.so
39 |
40 | # Distribution / packaging
41 | .Python
42 | build/
43 | develop-eggs/
44 | dist/
45 | downloads/
46 | eggs/
47 | .eggs/
48 | lib/
49 | lib64/
50 | parts/
51 | sdist/
52 | var/
53 | wheels/
54 | share/python-wheels/
55 | *.egg-info/
56 | .installed.cfg
57 | *.egg
58 | MANIFEST
59 |
60 | # PyInstaller
61 | # Usually these files are written by a python script from a template
62 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
63 | *.manifest
64 | *.spec
65 |
66 | # Installer logs
67 | pip-log.txt
68 | pip-delete-this-directory.txt
69 |
70 | # Unit test / coverage reports
71 | htmlcov/
72 | .tox/
73 | .nox/
74 | .coverage
75 | .coverage.*
76 | .cache
77 | nosetests.xml
78 | coverage.xml
79 | *.cover
80 | *.py,cover
81 | .hypothesis/
82 | .pytest_cache/
83 | cover/
84 |
85 | # Translations
86 | *.mo
87 | *.pot
88 |
89 | # Django stuff:
90 | *.log
91 | local_settings.py
92 | db.sqlite3
93 | db.sqlite3-journal
94 |
95 | # Flask stuff:
96 | instance/
97 | .webassets-cache
98 |
99 | # Scrapy stuff:
100 | .scrapy
101 |
102 | # Sphinx documentation
103 | docs/_build/
104 |
105 | # PyBuilder
106 | .pybuilder/
107 | target/
108 |
109 | # Jupyter Notebook
110 | .ipynb_checkpoints
111 |
112 | # IPython
113 | profile_default/
114 | ipython_config.py
115 |
116 | # pyenv
117 | # For a library or package, you might want to ignore these files since the code is
118 | # intended to run in multiple environments; otherwise, check them in:
119 | # .python-version
120 |
121 | # pipenv
122 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
123 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
124 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
125 | # install all needed dependencies.
126 | #Pipfile.lock
127 |
128 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
129 | __pypackages__/
130 |
131 | # Celery stuff
132 | celerybeat-schedule
133 | celerybeat.pid
134 |
135 | # SageMath parsed files
136 | *.sage.py
137 |
138 | # Environments
139 | .env
140 | .venv
141 | env/
142 | venv/
143 | ENV/
144 | env.bak/
145 | venv.bak/
146 |
147 | # Spyder project settings
148 | .spyderproject
149 | .spyproject
150 |
151 | # Rope project settings
152 | .ropeproject
153 |
154 | # mkdocs documentation
155 | /site
156 |
157 | # mypy
158 | .mypy_cache/
159 | .dmypy.json
160 | dmypy.json
161 |
162 | # Pyre type checker
163 | .pyre/
164 |
165 | # pytype static type analyzer
166 | .pytype/
167 |
168 | # Cython debug symbols
169 | cython_debug/
170 | © 2020 GitHub, Inc.
171 | Terms
172 | Privacy
173 | Security
174 | Status
175 | Help
176 | Contact GitHub
177 | Pricing
178 | API
179 | Training
180 | Blog
181 | About
182 |
183 | .vscode/
184 | .idea/
--------------------------------------------------------------------------------