python 基于http方式与基于redis方式传输摄像头图片数据的实现和对比

这篇具有很好参考价值的文章主要介绍了python 基于http方式与基于redis方式传输摄像头图片数据的实现和对比。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0. 需求

在不同进程或者不同语言间传递摄像头图片数据,比如从java实现的代码中获取摄像头画面数据,将其传递给python实现的算法代码中进行处理。这里,提供基于http方式和基于redis方式这两种方式进行实现,并比较两者传输速度。

作为样例,代码均采用python实现,运行环境为ubuntu 18.04。

1. 基于http方式传递图片数据
1.1 发送图片数据
  • 思路:创建两个线程,一个线程利用Opencv通过rtsp地址获得摄像头画面,一个线程将摄像头图片数据转为字节流,并通过http方式发送。

  • 实现

#coding=gb2312
# 文件名:http_send.py
import requests
import base64
import cv2
import time
import threading
from queue import LifoQueue


class rtspRead: # rtsp地址读取
    def __init__(self, rtsp, port):
        self.rtsp = rtsp # 摄像头的rtsp地址
        self.addr = "http://127.0.0.1:{}/image_post".format(port) # 本地http传输地址
        self.frameQueue = LifoQueue() # 视频帧的队列
        self.frameLock = threading.Lock() # 视频帧队列的锁
        
        self.threadFlag = True # 
        
    
    def start(self): # 开始
        t1 = threading.Thread(target=self.sendFrame, args=(), daemon=True)
        t2 = threading.Thread(target=self.readFrame, args=(), daemon=True)
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        
    def sendFrame(self): # 通过http发送图片
        
        num = 0 # 计算100次图片发送到接受的平均时间,以及平均帧数

        while self.threadFlag:
            time.sleep(0.01)
        
            is_get_frame = False # 没有从队列中获得图片
            self.frameLock.acquire()
            if self.frameQueue.qsize():
                frame = self.frameQueue.get()
                is_get_frame = True # 从队列中获得图片
            self.frameLock.release()
            
            if is_get_frame:
            	# frame 是ndarray对象,这里是把原始ndarray转成jpg的字节流,转成其它格式直接替换jpg即可
                img_str = cv2.imencode('.jpg', frame)[1].tobytes()
                #使用b64encode对bytes-like类型对象进行编码(加密)并返回bytes对象
                img_data = base64.b64encode(img_str)
                data = {'img': img_data}
                
                resp = requests.post(self.addr, data=data) # 发送图片数据,并获得http_receive.py的返回信息
                print("结果:", resp.text)
            
        
    def readFrame(self): # 通过rtsp读取图片
        self.cap = cv2.VideoCapture(self.rtsp)
        
        if self.cap.isOpened():
            time.sleep(0.01)
        
            print("成功获得句柄!")
            while self.threadFlag:
                ret, frame = self.cap.read()
                if ret:
                      self.frameLock.acquire()
                      while self.frameQueue.qsize() > 3: # 尽量确保队列中为最新的图片帧
                          self.frameQueue.get()
                      self.frameQueue.put(frame)
                      self.frameLock.release()             
            
        else:
            print("句柄获得失败!")
            self.threadFlag = False
            
        self.cap.release()


if __name__ == '__main__':
    rtsp_read = rtspRead("rtsp://xx:xx@xx", 9322)    
    rtsp_read.start()
1.2 接收图片数据并可视化
  • 思路:通过flask框架接收http请求,并将接收到的图片数据的字节流转为np格式,并进一步转为opencv格式。另起一个线程,接收opencv格式的图片数据,并做显示。

  • 实现

#coding=gb2312
# 文件名:http_receive.py
from flask import Flask, request
import base64
import numpy as np
import cv2
import threading
from queue import LifoQueue
import time

class RtspPlay():
    def __init__(self):
        self.frame = None # 视频帧
        self.threadFlag = True # 
        
    def start(self): # 开始
        t1 = threading.Thread(target=self.play, args=(), daemon=True)
        t1.start()
        #t1.join()
              
    def play(self):
        starttime = time.time()
        
        while self.threadFlag:
            time.sleep(0.01)
            
            print("进入展示线程")
            
            if time.time() - starttime > 260:
                self.threadFlag = False
        
            if self.frame is not None:
                print("展示frame")
                cv2.imshow('http_pic', self.frame)
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break
                    
        cv2.destroyAllWindows()
                    
    def setFrame(self, img):
        print("更新frame")
        self.frame = img.copy()
            
            
rtspPlay = RtspPlay()       
rtspPlay.start()


app = Flask(__name__)
@app.route('/image_post', methods=['POST'])
def img_post():
    if request.method == 'POST':
        # 获取图片数据
        img_base64 = request.form.get('img')
        # 把图片的二进制进行转化
        img_data = base64.b64decode(img_base64) #将拿到的base64的图片转换回来
        img_array = np.fromstring(img_data,np.uint8) # 转换np序列
        img = cv2.imdecode(img_array,cv2.COLOR_BGR2RGB)  # 转换Opencv格式
        mat = cv2.resize(img, (600, 600))
        print(mat.shape)
        
        rtspPlay.setFrame(mat)
        time.sleep(0.01)
  
    return 'receive img sucess'

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=9322)


1.3 测试
# 先开一个terminal窗口,启用接收进程
python http_receive.py

# 再开一个terminal窗口,启用发送进程
python http_send.py
2. 基于redis方式传递图片数据
2.1 发送图片数据
  • 思路:创建两个线程,一个线程利用Opencv通过rtsp地址获得摄像头画面,一个线程将摄像头图片数据转为字节流,并通过redis方式发送。这里的redis方式具体指的是,redis是一个内存数据库,通过键值对存储数据,通过订阅/发布机制传递消息,所以将图片字节流数据存入redis中,并将存入消息发布出去,实现发送效果。

  • 实现

#coding=gb2312
# 文件名:redis_send.py
import redis
import cv2
import time
import base64
import threading
from queue import LifoQueue
        
class redisSendPic: # redis发布者
    def __init__(self, cameraip):
        print("redis init ...")
        self.r = redis.Redis(host='127.0.0.1', port=6379,db=0) # 建立连接
        self.topic = 'img0' # 订阅的主题
        self.cameraip = cameraip
        
    def send(self, img):
        #print("发送图片")
        img_str = cv2.imencode('.jpg', img)[1].tobytes()
        data = base64.b64encode(img_str)
        self.r.set(self.cameraip, data)
        self.r.publish(self.topic, self.cameraip)
        
    def getResult(self,): 
        result = self.r.get('result')        
        return result
        
    def delete(self):
        self.r.delete('result')
        self.r.delete(self.cameraip)
            
class rtspRead: # rtsp地址读取
    def __init__(self, rtsp, cameraip):
        self.rtsp = rtsp
        self.cameraip = cameraip
        self.frameQueue = LifoQueue() # 视频帧的队列
        self.frameLock = threading.Lock() # 视频帧队列的锁
        
        self.threadFlag = True # 
        
    
    def start(self): # 开始
        t1 = threading.Thread(target=self.sendFrame, args=(), daemon=True)
        t2 = threading.Thread(target=self.readFrame, args=(), daemon=True)
        t1.start()
        t2.start()
        t1.join()
        t2.join()

        
        
    def sendFrame(self): # 通过redis发送图片
        self.sendpic = redisSendPic(self.cameraip)
        self.sendpic.r.set('result', 'start')
        
        num = 0 # 计算100次图片发送到接受的平均时间,以及平均帧数
        total_time = 0
    
        while self.threadFlag:
            time.sleep(0.01)
        
            is_get_frame = False # 没有从队列中获得图片
            self.frameLock.acquire()
            if self.frameQueue.qsize():
                frame = self.frameQueue.get()
                is_get_frame = True # 从队列中获得图片
            self.frameLock.release()
            
            result = self.sendpic.getResult() # 从接受进程获得是否中止的信号
            if result is not None and str(result, 'utf-8') == 'stop':
                self.threadFlag = False 
                break
            
            if is_get_frame:
                self.sendpic.r.delete('receive_time') # 删除接受时间
                send_time = time.time() # 发送时间
                self.sendpic.send(frame) # 发送图片
                
                receive_time = self.sendpic.r.get('receive_time') # 获得接受图片时间
                while receive_time is None: # 等待接受图片
                    #print("等待接受")
                    time.sleep(0.01)
                    receive_time = self.sendpic.r.get('receive_time')
                    
                    result = self.sendpic.getResult() # 从接受进程获得是否中止的信号
                    if result is not None and str(result, 'utf-8') == 'stop':
                        self.threadFlag = False 
                        break
                
                if receive_time is not None:
                    total_time += float(str(receive_time, 'utf-8')) - send_time
                #print("图像发送到接受时间:", float(str(receive_time, 'utf-8')) - send_time)
                
                num += 1
                if num > 100:
                    print("发送收发100次,平均耗时{}s,平均速度为{}帧/秒".format(total_time/100, round(100/total_time,2)))
                    num = 0
                    total_time = 0
        
        self.sendpic.delete()
            
        
    def readFrame(self): # 通过rtsp读取图片
        self.cap = cv2.VideoCapture(self.rtsp)
        
        if self.cap.isOpened():
            time.sleep(0.01)
        
            print("成功获得句柄!")
            while self.threadFlag:
                ret, frame = self.cap.read()
                if ret:
                      self.frameLock.acquire()
                      while self.frameQueue.qsize() > 3: # 尽量确保队列中为最新的图片帧
                          self.frameQueue.get()
                      self.frameQueue.put(frame)
                      self.frameLock.release()             
            
        else:
            print("句柄获得失败!")
            self.threadFlag = False
            
        self.cap.release()
        
        
if __name__ == '__main__':
    rtsp_read = rtspRead("rtsp://xx:xx@xx", 'xx')    
    rtsp_read.start()





2.2 接收图片数据并可视化
  • 思路:通过redis数据库的消息监听机制,当接收到数据入库消息,则提取图片字节流数据,并将其处理为opencv格式的图片数据,从而做到显示。

  • 实现

#coding=utf-8
# 文件名:redis_receive.py
import redis
import time
import scipy.misc
import cv2
import base64
from PIL import Image
import io
import time
import scipy.misc
import numpy as np

r = redis.Redis(host='127.0.0.1',port=6379,db=0)
ps = r.pubsub()
charecter = "img"
ps.subscribe(charecter + str(0))

is_first = True

for item in ps.listen():
    print("get message, ", item)
    #r.set("result", str("ok"))
    
    
    if is_first:
        r.set('receive_time', str(time.time())) # 获得可处理图片时间
        is_first = False 
    
    start = time.time()
    if item['type'] == 'message' and item['data'] is not None:
        img_base64 = r.get(str(item['data'], 'utf-8'))
        img_data = base64.b64decode(img_base64) #将拿到的base64的图片转换回来
        img_array = np.fromstring(img_data,np.uint8) # 转换np序列
        img = cv2.imdecode(img_array,cv2.COLOR_BGR2RGB)  # 转换Opencv格式
        r.set('receive_time', str(time.time())) # 获得可处理图片时间
        mat = cv2.resize(img, (600, 600))
        print(mat.shape)
        cv2.imshow('redis_pic', mat)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        #scipy.misc.imsave('D:/video.png', img)
        # frame = cv2.resize(img_data, (0, 0), fx=0.5, fy=0.5)
        #r.delete(charecter + str(0))
        #r.set("result", str("ok"))
        print("cost time:", time.time() - start)
        
cv2.destroyAllWindows()
r.set("result", str("stop"))        

2.3 测试
# 先开一个terminal窗口,启用接收进程
python redis_receive.py

# 再开一个terminal窗口,启用发送进程
python redis_send.py

结束进程直接在显示窗口上按下q键即可。

3. 对比

综合来看,在可视化摄像头画面的前提下,两者均可做到实时显示。其中,采用redis方式速度为14帧/秒左右,采用http方式速度为10帧/秒左右。

若要提高速度,可取消base64的加密过程;若仅考虑传输,可取消其中的可视化部分,传输速度应该会进一步提高。文章来源地址https://www.toymoban.com/news/detail-697822.html

到了这里,关于python 基于http方式与基于redis方式传输摄像头图片数据的实现和对比的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 摄像头录像存储计算方式

    1.存储容量计算公式: 总存储容量(MB) = 码率 / 8 * (小时数 * 3600 + 分钟数 * 60 + 秒数) * 天数 * 通道数 / 0.9 2.带宽计算公式: 带宽 = 码率 / 0.8 * 通道数 3.根据分辨率和编码选择相应的码率: 4.补充: 1)设置帧率对应的是码流的实时性,设置分辨率对应的是图像的大小,而码

    2024年02月11日
    浏览(43)
  • klipper使用webcam设置多个摄像头方式

    使用klipper设置多个摄像头,折腾了好些天,网上资料很少,这里写一个帖子记录一下 参考链接:https://www.cnblogs.com/sjqlwy/p/klipper_webcam.html 我的klipper安装在香橙派上面,系统是debian,使用双摄像头有些卡,建议树莓派3B+以上 首先连接多个摄像头,这是扩展摄像头的第一步,注

    2024年02月06日
    浏览(43)
  • 使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发

    配置: Window10 VS2013 opencv249 如果VS和opencv配置不一样,让版本对应 Opencv与VS版本 1.1 MFC项目搭建 通过这些步骤就创建了一个MFC基础项目。 1.2项目属性配置 本项目因为要使用opencv,所以就要配置以下opencv的环境 首先在opencv官网下载opencv,此次使用opencv2.4.9,下载完并且完成安装 接下

    2024年02月10日
    浏览(45)
  • 基于Qt、PYTHON智能校园防御系统应用程序,实现了摄像头数据采集、人脸识别、口罩识别、 数据统计等功能

    完整项目地址:https://download.csdn.net/download/lijunhcn/88453470 项目结构 环境选型 语言:Python 操作系统:Windows 数据库:MySQL 窗口界面:PyQT API接口:百度AI接口,用以实现人脸登陆与注册 远程MySQL表结构 远程表结构sql脚本 项目背景 智能校园防御软件是实现了一款基于摄像头数据

    2024年02月03日
    浏览(50)
  • 如何让Chrome浏览器允许http网站打开摄像头和麦克风

    问题来源: 本地运行的项目调用摄像头好用 访问线上地址,发现调用摄像头的方法都不存在。 问了度娘,发现该问题与浏览器的安全策略有关。出于安全考虑,浏览器是不允许随便开启摄像头的,https协议下方可开启。 这一项功能要用到谷歌浏览器的实验性功能,谷歌浏览

    2024年02月17日
    浏览(65)
  • 毕设项目——基于Qt、PYTHON智能校园防御系统应用程序,实现了摄像头数据采集、人脸识别、口罩识别、 数据统计等功能

    完整项目地址:https://download.csdn.net/download/lijunhcn/88453470 项目结构 环境选型 语言:Python 操作系统:Windows 数据库:MySQL 窗口界面:PyQT API接口:百度AI接口,用以实现人脸登陆与注册 远程MySQL表结构 远程表结构sql脚本 项目背景 智能校园防御软件是实现了一款基于摄像头数据

    2024年02月04日
    浏览(41)
  • 【爱书不爱输的程序猿】内网的摄像头,远程进行访问的方式方法

    欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享,与更多的人进行学习交流 随着现代生活的快节奏发展,监控设备已经成为我们日常生活中不可或缺的一部分。它们可以帮助我们确保安全、保护财产,并提供可靠的证据用于调查和防范犯罪行为。然而,并非所有

    2024年02月13日
    浏览(41)
  • ubuntu中USB摄像头gstreamer方式图像采集、显示、录像及回放功能设计——(1)

    最近由于项目需求,需要在X86平台及ARM平台中进行USB摄像头视频的采集、显示、录像及回放功能,尝试了许多方式来进行,比如openCV库,mplayer库的方式,虽然它们都能够进行USB摄像头的采集显示,但是实现需求方面总是存在各种问题:(1)性能不行,图像采集的分辨率很低

    2023年04月08日
    浏览(117)
  • Python调用手机摄像头

    1、在手机上安装app:IP摄像头 2、调用代码(前提:电脑连接手机热点) 2.1、如果没有cv2安装包,则需要安装opencv-python库(功能:数字图像处理、人脸检测、视频捕捉,图像旋转等) 和poencv-contrib-python库(功能:图像拼接、CNN人脸识别、特征检测、背景分割,OCR等)。注意

    2024年02月12日
    浏览(53)
  • 网络摄像头rtsp流延迟无法解决,改用Mjpeg流成功保证低延迟稳定传输,并成功解决opencv对Mjpeg流支持问题

    最近做的一个小项目,是需要通过一个网络实时将画面传输给后端进行处理。因为涉及到对运动的捕捉,延迟要求较为严格。我的网络摄像头是Z CAM E2 M4,内置了rtsp流。使用rtsp流时总会产生2秒的延迟。直接使用ffmpeg播放依然存在2s延迟。尝试过修改缓冲大小无果。查阅相机文

    2024年02月07日
    浏览(138)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包