OpenCV视觉识别与flask转发实现局域网调试
环境准备
- 安装所需的 Python 包:
pip install Flask opencv-python numpy
运行程序
- 将 Python 代码保存为
app.py
文件。
- 将 HTML 代码保存为
templates/index.html
文件。
- 在终端中运行 Flask 应用:
python app.py
访问界面
- 在浏览器中输入
http://<服务器IP>:5000
来访问 Web 应用。
- 默认情况下,系统会使用默认的摄像头进行视频流捕获。
实时查看视频流
- 在网页上查看彩色视频流、红色掩膜、绿色掩膜和蓝色掩膜。
调整颜色阈值
- 使用滑块动态调整红色、绿色和蓝色的 HSV 阈值。
- 点击“Update Thresholds”按钮更新阈值设置,系统会自动使用新的阈值进行颜色检测。
注意事项
- 确保计算机上连接了摄像头。
- 调整阈值时,观察实时效果,找到最佳设置以提高检测准确性。
- 如果遇到性能问题,可以考虑调整图像处理参数或分辨率。
main.py
from flask import Flask, Response, render_template, request
import cv2
import numpy as np
import threading
app = Flask(__name__)
camera = cv2.VideoCapture(0)
thresholds = {
'red': {'lower': np.array([0, 100, 100]), 'upper': np.array([10, 255, 255])},
'green': {'lower': np.array([40, 40, 40]), 'upper': np.array([80, 255, 255])},
'blue': {'lower': np.array([100, 150, 0]), 'upper': np.array([140, 255, 255])}
}
kernel = np.ones((5, 5), np.uint8)
output_frame = None
lock = threading.Lock()
def process_camera_feed():
global output_frame
while True:
success, frame = camera.read()
if not success:
break
annotated_frame = frame.copy()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask_red = cv2.inRange(hsv, thresholds['red']['lower'], thresholds['red']['upper'])
mask_red = cv2.erode(mask_red, kernel, iterations=1)
mask_green = cv2.inRange(hsv, thresholds['green']['lower'], thresholds['green']['upper'])
mask_green = cv2.erode(mask_green, kernel, iterations=1)
mask_blue = cv2.inRange(hsv, thresholds['blue']['lower'], thresholds['blue']['upper'])
mask_blue = cv2.erode(mask_blue, kernel, iterations=1)
circles_red = cv2.HoughCircles(mask_red, cv2.HOUGH_GRADIENT, dp=1.2, minDist=30,
param1=50, param2=30, minRadius=10, maxRadius=100)
circles_green = cv2.HoughCircles(mask_green, cv2.HOUGH_GRADIENT, dp=1.2, minDist=30,
param1=50, param2=30, minRadius=10, maxRadius=100)
circles_blue = cv2.HoughCircles(mask_blue, cv2.HOUGH_GRADIENT, dp=1.2, minDist=30,
param1=50, param2=30, minRadius=10, maxRadius=100)
if circles_red is not None:
circles_red = np.round(circles_red[0, :]).astype("int")
for (x, y, r) in circles_red:
cv2.circle(annotated_frame, (x, y), r, (0, 0, 255), 4)
cv2.circle(annotated_frame, (x, y), 2, (0, 0, 255), 3)
if circles_green is not None:
circles_green = np.round(circles_green[0, :]).astype("int")
for (x, y, r) in circles_green:
cv2.circle(annotated_frame, (x, y), r, (0, 255, 0), 4)
cv2.circle(annotated_frame, (x, y), 2, (0, 255, 0), 3)
if circles_blue is not None:
circles_blue = np.round(circles_blue[0, :]).astype("int")
for (x, y, r) in circles_blue:
cv2.circle(annotated_frame, (x, y), r, (255, 0, 0), 4)
cv2.circle(annotated_frame, (x, y), 2, (255, 0, 0), 3)
with lock:
output_frame = {
'color': annotated_frame,
'red': mask_red,
'green': mask_green,
'blue': mask_blue
}
def generate_frames(color):
global output_frame
while True:
with lock:
if output_frame is None:
continue
ret, buffer = cv2.imencode('.jpg', output_frame[color])
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/')
def index():
return render_template('index.html')
@app.route('/video_feed/color')
def video_feed_color():
return Response(generate_frames('color'),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/video_feed/red')
def video_feed_red():
return Response(generate_frames('red'),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/video_feed/green')
def video_feed_green():
return Response(generate_frames('green'),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/video_feed/blue')
def video_feed_blue():
return Response(generate_frames('blue'),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/update_thresholds', methods=['POST'])
def update_thresholds():
global thresholds
thresholds['red']['lower'] = np.array([int(request.form.get('red_lower_h')),
int(request.form.get('red_lower_s')),
int(request.form.get('red_lower_v'))])
thresholds['red']['upper'] = np.array([int(request.form.get('red_upper_h')),
int(request.form.get('red_upper_s')),
int(request.form.get('red_upper_v'))])
thresholds['green']['lower'] = np.array([int(request.form.get('green_lower_h')),
int(request.form.get('green_lower_s')),
int(request.form.get('green_lower_v'))])
thresholds['green']['upper'] = np.array([int(request.form.get('green_upper_h')),
int(request.form.get('green_upper_s')),
int(request.form.get('green_upper_v'))])
thresholds['blue']['lower'] = np.array([int(request.form.get('blue_lower_h')),
int(request.form.get('blue_lower_s')),
int(request.form.get('blue_lower_v'))])
thresholds['blue']['upper'] = np.array([int(request.form.get('blue_upper_h')),
int(request.form.get('blue_upper_s')),
int(request.form.get('blue_upper_v'))])
return 'Thresholds updated successfully!'
if __name__ == '__main__':
t = threading.Thread(target=process_camera_feed)
t.daemon = True
t.start()
app.run(host='0.0.0.0', port=5000)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Color Ring Detection</title>
<style>
body { display: flex; flex-direction: column; align-items: center; }
.video-container { margin: 20px; }
img { width: 100%; max-width: 600px; }
.thresholds { margin-top: 20px; }
.images { display: flex; justify-content: space-around; width: 100%; max-width: 1200px; }
.image-box { text-align: center; }
.slider-container { display: flex; align-items: center; }
.slider-container label { width: 100px; }
.slider-container span { margin-left: 10px; }
</style>
</head>
<body>
<h1>Color Ring Detection</h1>
<div class="video-container">
<h2>Video Stream</h2>
<img src="/video_feed/color" alt="Video Stream" id="video-stream">
</div>
<div class="images">
<div class="image-box">
<h2>Color Detection</h2>
<img src="/video_feed/color" alt="Color Detection" id="color-detection">
</div>
<div class="image-box">
<h2>Red Mask</h2>
<img src="/video_feed/red" alt="Red Mask" id="red-mask">
</div>
<div class="image-box">
<h2>Green Mask</h2>
<img src="/video_feed/green" alt="Green Mask" id="green-mask">
</div>
<div class="image-box">
<h2>Blue Mask</h2>
<img src="/video_feed/blue" alt="Blue Mask" id="blue-mask">
</div>
</div>
<div class="thresholds">
<h3>Adjust HSV Thresholds</h3>
<form id="thresholds-form">
<h3>Red</h3>
<div class="slider-container">
<label for="red_lower_h">Lower H:</label>
<input type="range" id="red_lower_h" name="red_lower_h" min="0" max="180" value="0" oninput="updateValue(this)">
<span id="red_lower_h_value">0</span>
</div>
<div class="slider-container">
<label for="red_lower_s">Lower S:</label>
<input type="range" id="red_lower_s" name="red_lower_s" min="0" max="255" value="100" oninput="updateValue(this)">
<span id="red_lower_s_value">100</span>
</div>
<div class="slider-container">
<label for="red_lower_v">Lower V:</label>
<input type="range" id="red_lower_v" name="red_lower_v" min="0" max="255" value="100" oninput="updateValue(this)">
<span id="red_lower_v_value">100</span>
</div>
<div class="slider-container">
<label for="red_upper_h">Upper H:</label>
<input type="range" id="red_upper_h" name="red_upper_h" min="0" max="180" value="10" oninput="updateValue(this)">
<span id="red_upper_h_value">10</span>
</div>
<div class="slider-container">
<label for="red_upper_s">Upper S:</label>
<input type="range" id="red_upper_s" name="red_upper_s" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="red_upper_s_value">255</span>
</div>
<div class="slider-container">
<label for="red_upper_v">Upper V:</label>
<input type="range" id="red_upper_v" name="red_upper_v" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="red_upper_v_value">255</span>
</div>
<h3>Green</h3>
<div class="slider-container">
<label for="green_lower_h">Lower H:</label>
<input type="range" id="green_lower_h" name="green_lower_h" min="0" max="180" value="40" oninput="updateValue(this)">
<span id="green_lower_h_value">40</span>
</div>
<div class="slider-container">
<label for="green_lower_s">Lower S:</label>
<input type="range" id="green_lower_s" name="green_lower_s" min="0" max="255" value="40" oninput="updateValue(this)">
<span id="green_lower_s_value">40</span>
</div>
<div class="slider-container">
<label for="green_lower_v">Lower V:</label>
<input type="range" id="green_lower_v" name="green_lower_v" min="0" max="255" value="40" oninput="updateValue(this)">
<span id="green_lower_v_value">40</span>
</div>
<div class="slider-container">
<label for="green_upper_h">Upper H:</label>
<input type="range" id="green_upper_h" name="green_upper_h" min="0" max="180" value="80" oninput="updateValue(this)">
<span id="green_upper_h_value">80</span>
</div>
<div class="slider-container">
<label for="green_upper_s">Upper S:</label>
<input type="range" id="green_upper_s" name="green_upper_s" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="green_upper_s_value">255</span>
</div>
<div class="slider-container">
<label for="green_upper_v">Upper V:</label>
<input type="range" id="green_upper_v" name="green_upper_v" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="green_upper_v_value">255</span>
</div>
<h3>Blue</h3>
<div class="slider-container">
<label for="blue_lower_h">Lower H:</label>
<input type="range" id="blue_lower_h" name="blue_lower_h" min="0" max="180" value="100" oninput="updateValue(this)">
<span id="blue_lower_h_value">100</span>
</div>
<div class="slider-container">
<label for="blue_lower_s">Lower S:</label>
<input type="range" id="blue_lower_s" name="blue_lower_s" min="0" max="255" value="150" oninput="updateValue(this)">
<span id="blue_lower_s_value">150</span>
</div>
<div class="slider-container">
<label for="blue_lower_v">Lower V:</label>
<input type="range" id="blue_lower_v" name="blue_lower_v" min="0" max="255" value="0" oninput="updateValue(this)">
<span id="blue_lower_v_value">0</span>
</div>
<div class="slider-container">
<label for="blue_upper_h">Upper H:</label>
<input type="range" id="blue_upper_h" name="blue_upper_h" min="0" max="180" value="140" oninput="updateValue(this)">
<span id="blue_upper_h_value">140</span>
</div>
<div class="slider-container">
<label for="blue_upper_s">Upper S:</label>
<input type="range" id="blue_upper_s" name="blue_upper_s" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="blue_upper_s_value">255</span>
</div>
<div class="slider-container">
<label for="blue_upper_v">Upper V:</label>
<input type="range" id="blue_upper_v" name="blue_upper_v" min="0" max="255" value="255" oninput="updateValue(this)">
<span id="blue_upper_v_value">255</span>
</div>
<button type="button" onclick="updateThresholds()">Update Thresholds</button>
</form>
</div>
<script>
function updateValue(slider) {
const valueSpan = document.getElementById(slider.id + '_value');
valueSpan.textContent = slider.value;
}
function updateThresholds() {
const formData = new FormData(document.getElementById('thresholds-form'));
fetch('/update_thresholds', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => alert(data))
.catch(error => console.error('Error:', error));
}
</script>
</body>
</html>