started working on vision package

This commit is contained in:
Joel 2021-01-21 19:37:04 +01:00
parent ce1c82a192
commit b06962e955
No known key found for this signature in database
GPG key ID: BDDDBECD0808290E
2 changed files with 150 additions and 0 deletions

View file

@ -20,3 +20,9 @@ pip install sphinx-rtd-theme
[Inline documentation example](https://pythonhosted.org/an_example_pypi_project/sphinx.html#full-code-example)
[reStructured Text](https://pythonhosted.org/an_example_pypi_project/sphinx.html#restructured-text-rest-resources)
# Stream Video
```
sudo raspivid -t 0 -b 10000000 -w 1920 -h 1080 -fps 30 -n -o - | gst-launch-1.0 fdsrc ! video/x-h264,width=1280,height=720,framerate=30/1,noise-reduction=1,profile=high,stream-format=byte-stream ! h264parse ! queue ! flvmux streamable=true ! rtmpsink location=\"rtmp://10.1.1.68/live/stream\"```
```

144
compLib/Vision.py Normal file
View file

@ -0,0 +1,144 @@
import os
import threading
import cv2
from flask import Flask, Response
RTMP_SERVER = os.getenv("RTMP_SERVER", "rtmp://localhost/live/stream")
SERVE_VIDEO = os.getenv("SERVER_SRC", "/live")
app = Flask(__name__)
HTML = """
<html>
<head>
<title>Opencv Output</title>
</head>
<body>
<h1>Opencv Output</h1>
<img src="{{ VIDEO_DST }}">
</body>
</html>
"""
# it would be better to use jinja2 here, but I don't want to blow up the package dependencies...
HTML = HTML.replace("{{ VIDEO_DST }}", SERVE_VIDEO)
class __Streaming:
"""
Private class for opencv stuff.
grab frames -> do your own processing -> publish frame -> view on http server
"""
def __init__(self):
"""
Create instance of __Streaming class
This is done implicitly when importing the vision module and will only fail if you would
create an object of this class. (There can (SHOULD!) only be one VideCapture)
"""
self.__camera_stream = cv2.VideoCapture(RTMP_SERVER)
#self.__camera_stream = cv2.VideoCapture(0)
self.__newest_frame = None
self.__lock = threading.Lock()
def get_frame(self):
"""
Grab the newest frame from the rtmp stream.
:return: An opencv frame
"""
ret, img16 = self.__camera_stream.read()
return img16
def publish_frame(self, image):
"""
Publish an opencv frame to the http webserver.
:param image: Opencv frame that will be published
:return: None
"""
with self.__lock:
self.__newest_frame = image.copy()
def _newest_frame_generator(self):
"""
Private generator which is called directly from flask server.
:return: Yields image/jpeg encoded frames published from publish_frame function.
"""
while True:
# use a buffer frame to copy the newest frame with lock and then freeing it immediately
buffer_frame = None
with self.__lock:
if self.__newest_frame is None:
continue
buffer_frame = self.__newest_frame.copy()
# encode frame for jpeg stream
(flag, encodedImage) = cv2.imencode(".jpg", buffer_frame)
# if there was an error try again with the next frame
if not flag:
continue
# else yield encoded frame with mimetype image/jpeg
yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encodedImage) + b'\r\n')
# instantiate private class __Streaming
Streaming = __Streaming()
@app.route("/live")
def video_feed():
"""
Define route for serving jpeg stream.
:return: Return the response generated along with the specific media.
"""
return Response(Streaming._newest_frame_generator(),
mimetype="multipart/x-mixed-replace; boundary=frame")
@app.route("/")
def __index():
"""
Define route for serving a static http site to view the stream.
:return: Static html page
"""
return HTML
def __start_flask():
"""
Function for running flask server in a thread.
:return:
"""
app.run(host="0.0.0.0", port=9898, debug=True, threaded=True, use_reloader=False)
# start flask service in the background
__webserver_thread = threading.Thread(target=__start_flask)
__webserver_thread.start()
# for debugging and testing start processing frames and detecting a 6 by 9 calibration chessboard
if __name__ == '__main__':
while True:
frame = Streaming.get_frame()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# processing
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# find the chessboard corners
ret, corners = cv2.findChessboardCorners(gray, (6, 9), None)
cv2.drawChessboardCorners(frame, (6, 9), corners, ret)
Streaming.publish_frame(frame)