OpenCV视觉识别与flask转发实现局域网调试


OpenCV视觉识别与flask转发实现局域网调试

环境准备

  1. 安装所需的 Python 包:
pip install Flask opencv-python numpy

运行程序

  1. 将 Python 代码保存为 app.py 文件。
  2. 将 HTML 代码保存为 templates/index.html 文件。
  3. 在终端中运行 Flask 应用:
    python app.py

访问界面

  1. 在浏览器中输入 http://<服务器IP>:5000 来访问 Web 应用。
  2. 默认情况下,系统会使用默认的摄像头进行视频流捕获。

实时查看视频流

  1. 在网页上查看彩色视频流、红色掩膜、绿色掩膜和蓝色掩膜。

调整颜色阈值

  1. 使用滑块动态调整红色、绿色和蓝色的 HSV 阈值。
  2. 点击“Update Thresholds”按钮更新阈值设置,系统会自动使用新的阈值进行颜色检测。

注意事项

  1. 确保计算机上连接了摄像头。
  2. 调整阈值时,观察实时效果,找到最佳设置以提高检测准确性。
  3. 如果遇到性能问题,可以考虑调整图像处理参数或分辨率。

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)  # 使用默认摄像头

# 定义颜色阈值(HSV格式)
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格式
        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()

    # 启动Flask服务,访问 http://<服务器IP>:5000 查看识别结果
    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>

文章作者: biubiu选手
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 biubiu选手 !
评论
  目录