使用Python+Opencv+Flask将windows端的摄像头变为网络摄像头的方法

36 篇文章 0 订阅

问题描述

为了给半夜实验室的老鼠拍照,想给台式机按一个usb摄像头,并实现对该摄像头的实时远程访问,即将台式机(windows 10)的usb摄像头变成一个网络摄像头。

 

解决方法

使用已有的软件

本以为这个问题是一个很成熟的问题,windows端合适的软件应该有很多,但没想到找了一个小时只找到了收费软件,免费的也有几个

如:

Win IP Camera

IP摄像头

但不知道为什么都不能用,而且更多的app的目的并不是将windows端的usb摄像头变为局域网内网络摄像头,而是使局域网内的网络摄像头能够被windwos电脑直接访问。

 

代码

没能找到现成的软件,便想使用Python和Opencv完成读取视频流、并将其共享到端口,从而实现对该摄像头的实时远程访问。

(暂时只能实现局域网内的访问)

 

事实上,此类任务显然是有人做过的,可以通过搜索关键字"camera-live-streaming"获得更多资料。

本文参考的下面的github库:

https://github.com/akmamun/camera-live-streaming

但该代码只能本机访问,原因是因为flask在debug模式下默认只能本机访问,因此要更改app.run()中的内容才能实现局域网内其他设备的访问。

更改后的代码如下:

app.py

from camera import VideoCamera
from flask import Flask, render_template, Response
import time

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

def gen(camera):
    while True:
        try:
            frame = camera.get_frame()
        except Exception:
            print("Video is finished or empty")
            #return None
            frame = camera.get_heartbeat()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host = '0.0.0.0')

camera.py

import cv2

class VideoCamera(object):
    def __init__(self):
        # Using OpenCV to capture from device 0. If you have trouble capturing
        # from a webcam, comment the line below out and use a video file
        # instead.
        #self.video = cv2.VideoCapture(0)
        # If you decide to use video.mp4, you must have this file in the folder
        # as the main.py.
        # self.video = cv2.VideoCapture('suits_hd.mp4') 
        self.video = cv2.VideoCapture(0)

    def __del__(self):
        self.video.release()

    def get_frame(self):
        success, image = self.video.read()
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video stream.
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

    def get_heartbeat(self):
        # jpeg = cv2.imread('noise-black.jpg')
        image = cv2.imread('noise-green.jpg')
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

网页端

index.html

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

    <title>Live Streaming Demonstration</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-lg-8  offset-lg-2">
            <h3 class="mt-5">Live Streaming</h3>
            <img src="{{ url_for('video_feed') }}" width="100%">
        </div>
    </div>
</div>
</body>
</html>

但目前仍存在两个问题:

1. 每个时刻只允许一台设备访问,不允许多台设备同时访问;

2. 只能在局域网内部访问。

 

问题1 只允许一台设备访问

通过设置多线程app.run(host = '0.0.0.0', threaded=True)即可解决,即将app.py改为:

from camera import VideoCamera
from flask import Flask, render_template, Response
import time

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

def gen(camera):
    while True:
        try:
            frame = camera.get_frame()
        except Exception:
            print("Video is finished or empty")
            #return None
            frame = camera.get_heartbeat()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host = '0.0.0.0', threaded=True)

问题2 只能在局域网内部访问

本来想做内网渗透,但意外发现实验室电脑虽然没有公网的IPv4地址,但是有公网的Ipv6地址,而flask是支持ipv6的,于是将app.py改为如下代码即可:

from camera import VideoCamera
from flask import Flask, render_template, Response
import time

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

def gen(camera):
    while True:
        try:
            frame = camera.get_frame()
        except Exception:
            print("Video is finished or empty")
            #return None
            frame = camera.get_heartbeat()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host = '::', threaded=True) # ipv6

注:访问ipv6时要加[],如:

http://[xxxx:xxx:xxxx:xxx::x:xxxx]:5000/

 

======================================================================================================

原载于 我的博客

如有错误,请联系 rxnlos@126.com

======================================================================================================

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

R.X. NLOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值