hello, OpenCV teams,I want to control more than 5 cameras,and I use python==3.6.9 opencv==4.1.1(jetson tx2 default)
with flask to create a web program
#app.py for flask
import os
import time
import cv2
from flask import Flask, render_template, request, jsonify, Response
from threading import Thread, Lock
import subprocess
import base64
app = Flask(__name__)
camera_config = {
'roix': 0,
'roiy': 0,
'width': 256,
'height': 256,
'fps': 30
}
devices = ['/dev/video0', '/dev/video1', '/dev/video2', '/dev/video3', '/dev/video4', '/dev/video5']
storage_path = './raw'
class CameraThread(Thread):
def __init__(self, device, config, storage_path):
super().__init__()
self.device = device
self.config = config
self.storage_path = storage_path
self.cap = None
self.running = False
self.lock = Lock()
def setup_camera(self):
v4l2_cmds = [
f"v4l2-ctl -d {self.device} --set-ctrl roi_x={self.config['roix']}",
f"v4l2-ctl -d {self.device} --set-ctrl roi_y={self.config['roiy']}",
f"v4l2-ctl -d {self.device} --set-fmt-video=width={self.config['width']},height={self.config['height']},pixelformat=GREY",
f"v4l2-ctl -d {self.device} --set-ctrl frame_rate={self.config['fps']}",
]
for cmd in v4l2_cmds:
subprocess.call(cmd, shell=True)
def open_camera(self):
self.cap = cv2.VideoCapture(self.device)
if self.cap.isOpened():
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.config['width'])
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.config['height'])
self.running = True
else:
print(f"Failed to open {self.device}")
def capture_frame(self):
with self.lock:
if self.cap and self.running:
ret, frame = self.cap.read()
if ret:
timestamp = time.strftime("%Y%m%d-%H%M%S", time.localtime())
filename = os.path.join(self.storage_path, self.device.split('/')[-1], f'{timestamp}.raw')
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'wb') as f:
f.write(frame.tobytes())
def run(self):
self.setup_camera()
self.open_camera()
while self.running:
time.sleep(1 / self.config['fps'])
def stop(self):
with self.lock:
self.running = False
if self.cap:
self.cap.release()
self.cap = None
class CameraManager:
def __init__(self, devices, config, storage_path):
self.devices = devices
self.config = config
self.storage_path = storage_path
self.cameras = {}
def start_all(self):
self.cameras = {device: CameraThread(device, self.config, self.storage_path) for device in self.devices}
for camera in self.cameras.values():
camera.start()
def capture_all(self):
for camera in self.cameras.values():
if camera.running:
camera.capture_frame()
def stop_all(self):
for camera in self.cameras.values():
camera.stop()
camera.join()
self.cameras.clear()
def set_storage_path(self, path):
global storage_path
storage_path = path
for camera in self.cameras.values():
camera.storage_path = path
camera_manager = CameraManager(devices, camera_config, storage_path)
@app.route('/')
def index():
return render_template('index.html',my_list=[0, 6])
@app.route('/start', methods=['POST'])
def start():
camera_manager.start_all()
return jsonify({'status': 'started'})
@app.route('/capture', methods=['POST'])
def capture():
camera_manager.capture_all()
return jsonify({'status': 'captured'})
@app.route('/stop', methods=['POST'])
def stop():
camera_manager.stop_all()
return jsonify({'status': 'stopped'})
@app.route('/set_storage', methods=['POST'])
def set_storage():
path = request.form.get('path', './raw')
camera_manager.set_storage_path(path)
return jsonify({'status': 'storage set', 'path': path})
@app.route('/video_feed/<string:device>')
def video_feed(device):
def generate():
while True:
frames = {}
for camera_device, camera in camera_manager.cameras.items():
if camera.device.split('/')[-1] == device:
with camera.lock:
if camera.cap and camera.running:
ret, frame = camera.cap.read()
if ret:
_, jpeg = cv2.imencode('.jpg', frame)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + jpeg.tobytes() + b'\r\n\r\n')
time.sleep(1 / camera_config['fps'])
return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(threaded=True,debug=True, host='0.0.0.0', port=5000)
and
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-Camera Control</title>
<style>
.camera-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
margin-top: 20px;
}
.camera {
border: 1px solid #ccc;
padding: 10px;
width: 256px;
height: 256px;
overflow: hidden;
}
.camera img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
</head>
<body>
<h1>Multi-Camera Control</h1>
<button id="start">Start Cameras</button>
<button id="capture">Capture Frames</button>
<button id="stop">Stop Cameras</button>
<form id="storage-form">
<label for="storage-path">Storage Path:</label>
<input type="text" id="storage-path" name="path" value="./raw">
<button type="submit">Set Storage Path</button>
</form>
<div id="status"></div>
<div class="camera-container">
<div class="camera" id="video0">
<img src="" alt="Video0">
</div>
<div class="camera" id="video1">
<img src="" alt="Video1">
</div>
<div class="camera" id="video2">
<img src="" alt="Video2">
</div>
<div class="camera" id="video3">
<img src="" alt="Video3">
</div>
<div class="camera" id="video4">
<img src="" alt="Video4">
</div>
<!-- <div class="camera" id="video5">-->
<!-- <img src="" alt="Video5">-->
<!-- </div>-->
</div>
<script>
document.getElementById('start').addEventListener('click', function() {
fetch('/start', { method: 'POST' })
.then(response => response.json())
.then(data => {
document.getElementById('status').innerText = data.status;
// Start video feeds
document.querySelectorAll('.camera img').forEach(img => {
img.src = `/video_feed/${img.parentElement.id}`;
});
});
});
document.getElementById('capture').addEventListener('click', function() {
fetch('/capture', { method: 'POST' })
.then(response => response.json())
.then(data => {
document.getElementById('status').innerText = data.status;
});
});
document.getElementById('stop').addEventListener('click', function() {
fetch('/stop', { method: 'POST' })
.then(response => response.json())
.then(data => {
document.getElementById('status').innerText = data.status;
// Stop video feeds
document.querySelectorAll('.camera img').forEach(img => {
img.src = '';
});
});
});
document.getElementById('storage-form').addEventListener('submit', function(event) {
event.preventDefault();
const path = document.getElementById('storage-path').value;
fetch('/set_storage', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `path=${path}`
})
.then(response => response.json())
.then(data => {
document.getElementById('status').innerText = `Storage set to ${data.path}`;
});
});
</script>
</body>
</html>
when I open 5 cameras at the same time, my program works. but more than 5 cameras ,it not work.
Is this an opencv limitation of only having a maximum of 5 cameras open at the same time? If so, where do I change to remove this restriction?