In this article, I am going to implement something interesting! I am interested to implement image processing in the images from the raspi camera. Because we can install python virtualenv and manage libraries in isolation, it makes vary easy to use the power of opencv in raspberry pi.
Creating Virtualenv
sudo apt install python3-pip sudo pip3 install virtualenv virtualenv VENV #Activate source VENV/bin/activate #deactivate deactivate
Installation of Opencv
sudo apt install python3-opencv #activate Virtual Environment
source VENV/bin/activate
pip3 install numpy
pip3 install opencv-python
pip3 install opencv-contrib-python
pip3 install imutils
deactivate
Installation of Flask
pip3 install flask
pip3 install flask-socketio (optional, needed for websocket)
I have written a class with the help of ChatGPT, to read images from webcam and serve.
import cv2
import threading
class Camera:
def __init__(self) -> None:
# Global camera object and lock
self.camera = None
self.camera_lock = threading.Lock()
self.active_clients = 0
self.camera_address=0
def open_camera(self):
if self.camera is None:
self.camera = cv2.VideoCapture(self.camera_address)
def close_camera(self):
if self.camera is not None:
self.camera.release()
self.camera = None
def generate_frames(self):
# Lock the camera and increment active client count
with self.camera_lock:
self.active_clients += 1
self.open_camera()
try:
while True:
with self.camera_lock:
# Capture frame-by-frame
success, frame = self.camera.read()
if not success:
break
else:
# Encode frame in JPEG format
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
# Send the frame to the client
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
except GeneratorExit:
# This block is executed when the generator is closed
with self.camera_lock:
self.active_clients -= 1
if self.active_clients == 0:
self.close_camera()
print(f"Client disconnected. Active clients: {self.active_clients}")
We call the method “generate_frames” in route, and return it as a response. This route endpoint can be placed in html in <img> tag. This will display the image frames obtained from the webcam. The reading of images from camera is stopped when the browser is closed which is crucial for a low resources device like raspi. This implementation of stopping reading images when no browsers are active, kept raspi from overheating and shutting down.
In routes.py
@app.route('/video_feed')
def video_feed():
# Stream video frames to the client
return Response(camera.generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
In index.html
<img src="{{ url_for('app.video_feed')}}"></p>
So, the index.html page will show the videos obtained from the webcam.
Running the App
app.py
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True, debug=True)
“python app.py” will run the flask and the content is available in port 5000, can be accessed locally using the following link
The index.html will be server with the videos obtained from webcam.
FAQs
- How to get the camera address?
- How to check if the camera is working?