updated to version 0.0.3

added vision daemon which runs in the background
added more documentation to vision module
now including opencv dependencies in complib package
This commit is contained in:
Joel 2021-01-21 23:55:26 +01:00
parent b06962e955
commit 77c2354c00
No known key found for this signature in database
GPG key ID: BDDDBECD0808290E
12 changed files with 201 additions and 16 deletions

View file

@ -9,8 +9,25 @@ fpm -s python --python-bin python3 --python-pip pip3 --python-package-name-prefi
--after-install postinstall.sh \
--deb-generate-changes \
--deb-priority "optional" \
--deb-systemd "complib.service" \
-d "python3-pip" \
-v 0.0.2-8 -t deb setup.py
-d "nginx" \
-d "libnginx-mod-rtmp" \
-d "libsystemd-dev" \
-d "python3-systemd" \
-d "gstreamer1.0-tools" \
-d "gstreamer1.0-plugins-bad" \
-d "gstreamer1.0-plugins-base" \
-d "gstreamer1.0-plugins-good" \
-d "gstreamer1.0-omx-rpi" \
-d "gstreamer1.0-omx-rpi-config" \
-d "opencv-dev" \
-d "opencv-libs" \
-d "opencv-licenses" \
-d "opencv-main" \
-d "opencv-python" \
-d "opencv-scripts" \
-v 0.0.3-3 -t deb setup.py
# --deb-changelog changelog \
# --deb-upstream-changelog changelog \

View file

@ -6,6 +6,7 @@ from flask import Flask, Response
RTMP_SERVER = os.getenv("RTMP_SERVER", "rtmp://localhost/live/stream")
SERVE_VIDEO = os.getenv("SERVER_SRC", "/live")
BUILDING_DOCS = os.getenv("BUILDING_DOCS", "false")
app = Flask(__name__)
@ -27,7 +28,12 @@ HTML = HTML.replace("{{ VIDEO_DST }}", SERVE_VIDEO)
class __Streaming:
"""
Private class for opencv stuff.
Class that handles rtmp streaming for opencv.
DO NOT CREATE AN INSTANCE OF THIS CLASS YOURSELF!
This is automatically done when importing this module. Use Vision.Streaming which is
an instance of this class!
grab frames -> do your own processing -> publish frame -> view on http server
"""
@ -40,7 +46,7 @@ class __Streaming:
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.__camera_stream = cv2.VideoCapture(0)
self.__newest_frame = None
self.__lock = threading.Lock()
@ -79,7 +85,7 @@ class __Streaming:
buffer_frame = self.__newest_frame.copy()
# encode frame for jpeg stream
(flag, encodedImage) = cv2.imencode(".jpg", buffer_frame)
(flag, encoded_image) = cv2.imencode(".jpg", buffer_frame)
# if there was an error try again with the next frame
if not flag:
@ -87,15 +93,17 @@ class __Streaming:
# 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')
bytearray(encoded_image) + b'\r\n')
# instantiate private class __Streaming
Streaming = __Streaming()
Streaming = None
if BUILDING_DOCS == "false":
# instantiate private class __Streaming
Streaming = __Streaming()
@app.route("/live")
def video_feed():
def __video_feed():
"""
Define route for serving jpeg stream.
@ -124,12 +132,13 @@ def __start_flask():
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()
if BUILDING_DOCS == "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__':
if __name__ == '__main__' and BUILDING_DOCS == "false":
while True:
frame = Streaming.get_frame()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
@ -140,5 +149,5 @@ if __name__ == '__main__':
# find the chessboard corners
ret, corners = cv2.findChessboardCorners(gray, (6, 9), None)
cv2.drawChessboardCorners(frame, (6, 9), corners, ret)
cv2.drawChessboardCorners(frame, (6, 9), corners, ret)
Streaming.publish_frame(frame)

20
compLib/VisionDaemon.py Normal file
View file

@ -0,0 +1,20 @@
import os
import systemd.daemon
import LogstashLogging
from LogstashLogging import logstash_logger
import logging
__run = """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://localhost/live/stream\""""
if __name__ == '__main__':
try:
systemd.daemon.notify(systemd.daemon.Notification.READY)
except:
logstash_logger.warning("Warning, old systemd version detected")
systemd.daemon.notify('READY=1')
logging.info("starting gstreamer background process")
os.system(__run)
logstash_logger.error("gstreamer stopped...")

View file

@ -1,4 +1,4 @@
__version__ = "0.0.2"
__version__ = "0.0.3"
import compLib.LogstashLogging
import logging

11
complib.service Normal file
View file

@ -0,0 +1,11 @@
[Unit]
Description=Monitoring service
[Service]
ExecStart=/usr/bin/python3 /usr/local/lib/python3.7/dist-packages/compLib/VisionDaemon.py
Environment="debug=False"
Restart=always
RestartSec=5
Type=notify
[Install]
Alias=complib
WantedBy=default.target

102
docs/source/lib/Vision.rst Normal file
View file

@ -0,0 +1,102 @@
.. _lib_vision:
Vision
=====
This module provides an interface for grabbing an rtmp stream and using the images to do some processing in opencv.
How do I use this module?
1. Get frames from the raspberry pi camera
2. -- here comes your own processing --
3. Publish the processed frames on an http server
4. You can view the http stream of your processed images in a web browser
Opencv Stream
*************
Because of the rtmp stream needing to buffer some frames and waiting for P-Frames, importing this module might take up
to 5 Seconds.
.. autoclass:: compLib.Vision.__Streaming
:members:
Examples
*********
Using the Vision Module
---------------------
.. code-block:: python
import cv2
from compLib import Vision
# get newest opencv frame from camera
frame = Vision.Streaming.get_frame()
# do some processing with the frame.....
# publish frame to streaming server
Vision.Streaming.publish_frame(frame)
Connect the raspberry pi to your internet and view the stream at: "http://your_raspi_ip:9898/". This should display
your raspberry pi camera. Note: the stream will lag a little bit BUT the processing of the image will be done in
realtime.
The output on the website should show whatever your raspberry pi cam records:
.. image:: images/opencv_http_stream.png
:width: 680
:alt: Processed frames from opencv
Chessboard Detection
------------------------------------------
In this example we process the captured stream of images and want to detect chessboards. Run this example and
point your raspberry pi camera to a chessboard and it should be detected.
For testing you can point it at this image:
.. image:: images/chessboard.jpg
:width: 680
:alt: Chessboard for opencv processing
.. code-block:: python
import cv2
from compLib import Vision
# get newest opencv frame from camera
frame = Vision.Streaming.get_frame()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# convert image to grayscale image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# find the chessboard corners
ret, corners = cv2.findChessboardCorners(gray, (6, 9), None)
# draw detected chessboard position onto the image
cv2.drawChessboardCorners(frame, (6, 9), corners, ret)
# publish frame to streaming server
Vision.Streaming.publish_frame(frame)
Connect the raspberry pi to your internet and view the stream at: "http://your_raspi_ip:9898/".
The output image should look like this:
.. image:: images/chessboard_detected.jpg
:width: 680
:alt: Processed frames from opencv
Here is a screenshot of the stream website while viewing the chessboard in this documentation.
.. image:: images/opencv_processed.png
:width: 680
:alt: Processed frames from opencv

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View file

@ -11,4 +11,28 @@ install_package() {
install_package "smbus"
install_package "requests"
install_package "python-logstash-async"
install_package "python-logstash-async"
echo "Setting up opencv4"
pkg-config --modversion opencv4
echo "Setting up nginx rtmp server"
sudo /etc/init.d/nginx start
sudo tee /etc/nginx/nginx.conf > /dev/null <<EOT
load_module "modules/ngx_rtmp_module.so";
worker_processes auto;
rtmp_auto_push on;
events {}
rtmp {
server {
listen 1935;
listen [::]:1935 ipv6only=on;
application live {
live on;
record off;
}
}
}
EOT

View file

@ -1,3 +1,4 @@
export BUILDING_DOCS=true
cd docs || exit
rm -rf build
rm -rf gh-pages
@ -18,4 +19,5 @@ git push origin gh-pages
cd ..
rm -rf gh-pages
cd ..
cd ..
export BUILDING_DOCS=false