flask响应前端请求,返回摄像头图片

原有的程序可以采集视频流,但不能多路并行,问题应该就是这个yield,独占式运行

app = Flask(__name__)
 
#相机推流
def gen(camera):
    while True:
        frame = camera.get_frame()
        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')

前端可以直接引用

  <img id="bg" src="{{ url_for('video_feed') }}">

查阅文档,仔细看看yield的影响

python中return和yield的区别_一只静静的独角兽~的博客-CSDN博客_python yield和return的区别

大致意思是,yield是迭代器,会独占式不断运行,所以当一个程序运行起来后,把资源都独占了,其他线程没机会运行。

我们重新改成前后端分离的桩体,后端多线程多设备的不断更新产生当前图片,前端不断请求读取

前端代码:

<script src="static/jquery-3.5.1/jquery-3.5.1.min.js"></script>
        <script type="text/javascript">
        window.setInterval(update1, 10);
       

        function update1(){
        var element1 = document.getElementById('video1')
        var element2 = document.getElementById('video2')

        var message = {
                "cmd": "update"
            }
            $.ajax({
            url: "http://127.0.0.1:7001/video",
            type: "GET",
            data: message,
            success: function(data) {
                var result = JSON.stringify(data)
                var obj = JSON.parse(result)
               
           //     console.log("result1", obj.video1)
           //    console.log("result2", obj.video2)
                element1.src = "data:image/jpg;base64,"+obj.video1;
                element2.src = "data:image/jpg;base64,"+obj.video2;

            },
            error: function() {
                alert("命令发送失败")
            }
        })    
        
        console.log("video1 update.");
        }
       
        
        </script>

首先是定时任务,然后定义任务向后台请求图片数据,收到的base64图片数据进行解析,并更新到img的源。

后端响应代码:

app = Flask(__name__,template_folder='/home/hy/kxwell/faceid2.0/templates',static_folder="/home/hy/kxwell/faceid2.0/templates/static")
 
#相机推流
def gen(camera):
    
        frame = camera.get_frame()
        return base64.b64encode(frame)
        
@app.route("/video",methods=['GET','POST'])
def img_update():
    cmd=request.args.get('cmd')
    print("get update channel:",cmd)
    if cmd=='update':
        frame1 = gen(V1)
        frame2 = gen(V2)
    
        return jsonify({"video1":frame1,"video2":frame2})
    


#当前实时相机画面
@app.route('/')
def cur_camera():
    return render_template('index.html')

前端摄像头处理的代码要把图片转换成bytes数据格式

class VideoCamera(object):
    def __init__(self,ch):
        # 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.ch=ch
        
        
        # If you decide to use video.mp4, you must have this file in the folder
        # as the main.py.
        # self.video = cv2.VideoCapture('video.mp4')
    
    def __del__(self):
        self.video.release()
    
    def live(self):
        cascPath ='/home/hy/kxwell/py3/lib/python3.6/site-packages/cv2/data/haarcascade_frontalface_alt2.xml'
        faceCascade = cv2.CascadeClassifier(cascPath)
            
        self.video = cv2.VideoCapture(self.ch)
        while True:
            ret, image = self.video.read()
            if ret != True:
                print("read frame null ")
                break
        # 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)
    #    cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    
     #   cv2.imshow("image",image)
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            faces = faceCascade.detectMultiScale(gray,scaleFactor=1.1,
                                             minNeighbors=5,
                                             minSize=(30, 30)
                                           #  flags=cv2.cv.CV_HAAR_SCALE_IMAGE
                                             )
            for (x, y, w, h) in faces:
                cv2.rectangle(image, (x-50, y-50), (x+w+50, y+h+50), (0, 255, 0), 2)
                cv2.putText(image,'customer',(x,y),cv2.FONT_HERSHEY_COMPLEX,2.0,(100, 200, 200),5)
        #    cv2.imshow("monitor"+str(self.ch),image)
            
            self.currentIMG=image
       #    cv2.waitKey(20)

    def get_frame(self):
        ret, jpeg = cv2.imencode('.jpg', self.currentIMG)
        return jpeg.tobytes()

主程序还需要考虑多线程启动

if __name__ == '__main__':
    host='0.0.0.0'
    port=7001
    debug=False
    V1=VideoCamera(0)
    V2=VideoCamera(3)
    
    

    TH2=threading.Thread(target=V1.live)
    
    
    TH3=threading.Thread(target=V2.live)
    TH1=threading.Thread(target=app.run,args=(host,port,debug))
    
    TH2.start()
    TH3.start()
   

   # time.sleep(1)
    
    TH1.start()

还有个遗留问题,就是如果在对象定义中,把图像监看打开imshow就会爆线程错误,暂时还没解决。

由于环境问题,可能会出现json包发送和解析错误。

此时,应将返回做个解码到string的操作

return jsonify({"video1":frame1,"video2":frame2})

改为

return jsonify({"video1":frame1.decode(),"video2":frame2.decode()})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

海里的鱼2022

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

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

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

打赏作者

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

抵扣说明:

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

余额充值