当前位置: 首页 > news >正文

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

目录

        • 0. 需求
        • 1. 基于http方式传递图片数据
          • 1.1 发送图片数据
          • 1.2 接收图片数据并可视化
          • 1.3 测试
        • 2. 基于redis方式传递图片数据
          • 2.1 发送图片数据
          • 2.2 接收图片数据并可视化
          • 2.3 测试
        • 3. 对比

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 LifoQueueclass 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 = Falseself.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 timeclass 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 = Falseif self.frame is not None:print("展示frame")cv2.imshow('http_pic', self.frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcv2.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 LifoQueueclass 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 = cameraipdef 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 resultdef delete(self):self.r.delete('result')self.r.delete(self.cameraip)class rtspRead: # rtsp地址读取def __init__(self, rtsp, cameraip):self.rtsp = rtspself.cameraip = cameraipself.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 = 0while 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 breakif 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 breakif 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 += 1if num > 100:print("发送收发100次,平均耗时{}s,平均速度为{}帧/秒".format(total_time/100, round(100/total_time,2)))num = 0total_time = 0self.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 = Falseself.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 npr = redis.Redis(host='127.0.0.1',port=6379,db=0)
ps = r.pubsub()
charecter = "img"
ps.subscribe(charecter + str(0))is_first = Truefor 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的加密过程;若仅考虑传输,可取消其中的可视化部分,传输速度应该会进一步提高。

相关文章:

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

目录 0. 需求1. 基于http方式传递图片数据1.1 发送图片数据1.2 接收图片数据并可视化1.3 测试 2. 基于redis方式传递图片数据2.1 发送图片数据2.2 接收图片数据并可视化2.3 测试 3. 对比 0. 需求 在不同进程或者不同语言间传递摄像头图片数据,比如从java实现的代码…...

快速使用Git完整开发

本系列有两篇文章: 一是本篇,主要说明了关于Git工具的基础使用,包含三板斧(git add、git commit、git push)、Git基本配置、版本回退、分支管理、公钥与私钥、远端仓库和远端分支、忽略文件、命令别名、标签等内容。二…...

鲁棒优化入门(7)—Matlab+Yalmip两阶段鲁棒优化通用编程指南(下)

0.引言 上一篇博客介绍了使用Yalmip工具箱求解单阶段鲁棒优化的方法。这篇文章将和大家一起继续研究如何使用Yalmip工具箱求解两阶段鲁棒优化(默认看到这篇博客时已经有一定的基础了,如果没有可以看看我专栏里的其他文章)。关于两阶段鲁棒优化与列与约束生成算法的原…...

Docker技术--Docker中的网络问题

1.docker中的网络通信 如果想要弄清楚docker中的网络通信问题,其实需要弄清楚这几个问题就可以:容器与容器之间的通信、容器与外部网络之间的通信、外部网络与容器之间的通信。 -a:容器与容器之间的通信,如下所示: 在默认情况下,docker使用网桥(Bridge模式)与NAT通信。这…...

ASP.NET Core 中的两种 Web API

ASP.NET Core 有两种创建 RESTful Web API 的方式: 基于 Controller,使用完整的基于ControllerBase的基类定义接口endpoints。基于 Minimal APIs,使用Lambda表达式定义接口 endpoints。 基于 Controller 的 Web API 可以使用构造函数注入&a…...

【线程池】如何判断线程池中的任务执行完毕(三)

目录 前言 1. isTerminated()方法 2. awaitTermination()方法 3.getTaskCount()方法和executor.getCompletedTaskCount()方法结合使用 4.使用CountDownlatch类 前言 通常我们使用线程池的时候,系统处于运行的状态,而线程池本身就是主要为了线程复用&…...

Qt/C++编写视频监控系统81-Onvif报警抓图和录像并回放

一、前言 视频监控系统中的图文警情模块,是通过Onvif协议的事件订阅拿到的,通过事件订阅后,设备的各种报警事件比如入侵报警/遮挡报警/越界报警/开关量报警等,触发后都会主动往订阅者发送,而且一般都是会发送两次&…...

浅谈安防视频监控平台EasyCVR视频汇聚平台对于夏季可视化智能溺水安全告警平台的重要性

每年夏天都是溺水事故高发的时期,许多未成年人喜欢在有水源的地方嬉戏,这导致了悲剧的发生。常见的溺水事故发生地包括水库、水坑、池塘、河流、溪边和海边等场所。 为了加强溺水风险的提示和预警,完善各类安全防护设施,并及时发现…...

基于单片机的串行通信发射机设计

一、项目介绍 串行通信是一种常见的数据传输方式,允许将数据以比特流的形式在发送端和接收端之间传输。当前实现基于STC89C52单片机的串行通信发射机,通过红外发射管和接收头实现自定义协议的数据无线传输。 二、系统设计 2.1 单片机选择 在本设计中&…...

MySQL数据库——多表查询(3)-自连接、联合查询、子查询

目录 自连接 查询语法 自连接演示 联合查询 查询语法 子查询 介绍 标量子查询 列子查询 行子查询 表子查询 自连接 通过前面的学习,我们对于连接已经有了一定的理解。而自连接,通俗地去理解就是自己连接自己,即一张表查询多次。…...

day53 动规.p14 子序列

- 1143.最长公共子序列 cpp class Solution { public: int longestCommonSubsequence(string text1, string text2) { vector<vector<int>> dp(text1.size() 1, vector<int>(text2.size() 1, 0)); for (int i 1; i < text1.size(…...

将docker打包成镜像并保存到本地

如果想重装系统&#xff0c;又不想破坏docker里面配好的环境&#xff0c;那么可以将docker镜像打包到本地进行保存。 1. 将docker打包成镜像 命令&#xff1a;docker commit 容器id 镜像名:tag 使用docker ps -a即可查看容器相关信息 docker commit dd25c7c6bf17 zm_cu101:c…...

Harmony数据存储工具类

使用的是mmkv 1、安装mmkv ohpm install @ohos/mmkv2、封装 import{MMKV, SerializeBase} from @ohos/mmkv/*** 数据存储工具类*/ class MMKVUtil{private filePath:string = private cachePath:string = private mmkv:MMKVprivate mmapID:string="MMKV"construct…...

ROS 2官方文档(基于humble版本)学习笔记(一)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;一&#xff09; 一、安装ROS 2二、按教程学习1.CLI 工具配置环境使用turtlesim&#xff0c;ros2和rqt安装 turtlesim启动 turtlesim使用 turtlesim安装 rqt使用 rqt重映射关闭turtlesim 由于市面上专门…...

【数据结构】十字链表的画法

十字链表的基本概念 有向边又称为弧 假设顶点 v 指向 w&#xff0c;那么 w 称为弧头&#xff0c;v 称为弧尾 顶点节点采用顺序存储 顶点节点 data&#xff1a;存放顶点的信息firstin&#xff1a;指向以该节点为终点&#xff08;弧头&#xff09;的弧节点firstout&#xff1…...

使用rabbitmq进行支付之后的消息通知

订单服务完成支付后将支付结果发给每一个与订单服务对接的微服务&#xff0c;订单服务将消息发给交换机&#xff0c;由交换机广播消息&#xff0c;每个订阅消息的微服务都可以接收到支付结果. 微服务收到支付结果根据订单的类型去更新自己的业务数据。 相关技术方案 使用消息…...

【100天精通python】Day47:python网络编程_Web开发:web服务器,前端基础以及静态服务器

目录 1 网络编程与web编程 1.1 网络编程 1.2 web编程 1.3 前后端交互的基本原理 2 Web开发基础 2.1 HTTP协议 2.2 Web服务器 2.3 前端基础 2.3.1 HTML&#xff08;超文本标记语言&#xff09; 2. 3.2 CSS&#xff08;层叠样式表&#xff09; 2.3.3 JavaScript 2.…...

Web框架Beego

beego简介第一个beego项目beego项目结构分析bee 工具简介beego参数配置beego路由设置beego控制器介绍beego获取参数beego ORMbeego orm高级查询beego 原生sql查询beego 模板语法指南beego模板处理...

Kubernetes(K8s)基本环境部署

此处只做学习使用&#xff0c;配置单master环境。 一、环境准备 1、ip主机规划&#xff08;准备五台新机&#xff09;>修改各个节点的主机名 注意&#xff1a;关闭防火墙与selinux 节点主机名ip身份joshua1 kubernetes-master.openlab.cn 192.168.134.151masterjoshua2k…...

antd5:form组件底层封装库field-form-1.37.0启动

一开始node版本是18.16.0 npm install发现安装依赖成功 npm start发现启动出错 node:internal/crypto/hash:71this[kHandle] new _Hash(algorithm, xofLen);^Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:71:19)…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...