yolov8 tracking编码为web 和 rtsp流输出

1 基础工作

打开cmd
输入 conda env list
输入 conda activate py38
查看 nvidia-smi
查看 nvcc,如下图所示 cuda为11.7 ,为确认可以查看program files 下面的cuda 安装,看到11.7 就行了,读者可以自行确认自己的版本。
在这里插入图片描述
查看nvidia-smi
在这里插入图片描述
打开yolov8 track以后,发现速度超级慢, 打开cpu占用率奇高,gpu为零, 打开cmd
import torch
torch.cuda.is_available()
为false
确认pytorch安装的为cpu版本,重新安装pytorch cuda 版本,去pytorch网站,点开后复制安装命令,把cuda版本改成自己本机的版本。

在这里插入图片描述
输入命令
python yolo\v8\detect\detect_and_trk.py model=yolov8s.pt source=“d:\test.mp4” show=True
在这里插入图片描述
gpu占用率上升到40% 左右。
在这里插入图片描述

2 输出到web

接下来我们要做的工作为rtsp server 编码上传, 为了让其他机器得到结果,我们必须编程并且得到图像结果,让后使用实时传输协议直接转成rtp 流,让本机成为rtsp server,使用vlc 等工具,可以直接拉取到编码后的流。
修改代码,上传结果,先把命令修改成为
python yolo\v8\detect\detect_and_trk.py model=yolov8s.pt source=“d:\test.mp4”
然后在代码里面自己用opencv 来show,也就是增加两行代码

        cv2.imshow("qbshow",im0)cv2.waitKey(3)

没问题show 出来了,也就是im0 是我们在增加了选框的地方,在show 代码的基础上把图片发送出去就行,我们选择使用websocket 发送,或者socket 直接发送都行,这样我们需要一个客户端还是服务端的选择,我们选择让python成为服务端,目的是为了不让python需要断线重连,python 成为服务端有很多好处,
1 是可以直接给web传送图片
2 是可以直接给

    def write_results(self, idx, preds, batch):p, im, im0 = batchlog_string = ""if len(im.shape) == 3:im = im[None]  # expand for batch dimself.seen += 1im0 = im0.copy()if self.webcam:  # batch_size >= 1log_string += f'{idx}: 'frame = self.dataset.countelse:frame = getattr(self.dataset, 'frame', 0)# trackerself.data_path = psave_path = str(self.save_dir / p.name)  # im.jpgself.txt_path = str(self.save_dir / 'labels' / p.stem) + ('' if self.dataset.mode == 'image' else f'_{frame}')log_string += '%gx%g ' % im.shape[2:]  # print stringself.annotator = self.get_annotator(im0)det = preds[idx]self.all_outputs.append(det)if len(det) == 0:return log_stringfor c in det[:, 5].unique():n = (det[:, 5] == c).sum()  # detections per classlog_string += f"{n} {self.model.names[int(c)]}{'s' * (n > 1)}, "# #..................USE TRACK FUNCTION....................dets_to_sort = np.empty((0,6))for x1,y1,x2,y2,conf,detclass in det.cpu().detach().numpy():dets_to_sort = np.vstack((dets_to_sort, np.array([x1, y1, x2, y2, conf, detclass])))tracked_dets = tracker.update(dets_to_sort)tracks =tracker.getTrackers()for track in tracks:[cv2.line(im0, (int(track.centroidarr[i][0]),int(track.centroidarr[i][1])), (int(track.centroidarr[i+1][0]),int(track.centroidarr[i+1][1])),rand_color_list[track.id], thickness=3) for i,_ in  enumerate(track.centroidarr) if i < len(track.centroidarr)-1 ] if len(tracked_dets)>0:bbox_xyxy = tracked_dets[:,:4]identities = tracked_dets[:, 8]categories = tracked_dets[:, 4]draw_boxes(im0, bbox_xyxy, identities, categories, self.model.names)gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwhcv2.imshow("qbshow",im0)cv2.waitKey(3)return log_string

2.1 web中显示

在python中加上websocket server的代码,以下是一个示例代码,读者可以自己测试,但是要应用到python 的图像处理server中,我们要做一些修改

import asyncio
import threading
import websockets
import time
CONNECTIONS = set()async def server_recv(websocket):while True:try:recv_text = await websocket.recv()print("recv:", recv_text)except websockets.ConnectionClosed as e:# 客户端关闭连接,跳出对客户端的读取,结束函数print(e.code)await asyncio.sleep(0.01)breakasync def server_hands(websocket):CONNECTIONS.add(websocket)print(CONNECTIONS)try:await websocket.wait_closed()finally:CONNECTIONS.remove(websocket) def message_all(message):websockets.broadcast(CONNECTIONS, message)   async def handler(websocket, path):# 处理新的 WebSocket 连接print("New WebSocket route is ",path)try:await server_hands(websocket) # 握手加入队列await server_recv(websocket)  # 接收客户端消息并处理except websockets.exceptions.ConnectionClosedError as e:print(f"Connection closed unexpectedly: {e}")finally:pass# 处理完毕,关闭 WebSocket 连接print("WebSocket connection closed")async def sockrun():async with websockets.serve(handler, "", 9090):await asyncio.Future()  # run foreverdef main_thread(): print("main")asyncio.run(sockrun())

在这里插入图片描述

2.2 修改

修改的地方为我们不能让websocket 阻塞主线程,虽然websocket为协程处理,但是依然要放到线程里面

def predict(cfg):init_tracker()random_color_list()cfg.model = cfg.model or "yolov8n.pt"cfg.imgsz = check_imgsz(cfg.imgsz, min_dim=2)  # check image sizecfg.source = cfg.source if cfg.source is not None else ROOT / "assets"predictor = DetectionPredictor(cfg)predictor()if __name__ == "__main__":thread = threading.Thread(target=main_thread)thread.start()predict()

值得注意的地方是:
很多人喜欢把编码做成base64 ,这样没有必要, 服务程序里面把二进制编码成base64, 消耗了cpu, 然后发送还大了很多,实际上我们直接发送二进制就行了,发送时

   cv2.waitKey(3)_, encimg = cv2.imencode('.jpg', im0)bys = np.array(encimg).tobytes()message_all(bys)

web端测试代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>websocket</title></head>
<body><div><button onclick="connecteClient()">开始接收</button></div><br><div><img src="" id="python_img" alt="websock" style="text-align:left; width: 640px; height: 360px;"> </div><script>function connecteClient() {var ws = new WebSocket("ws://127.0.0.1:9090");ws.onopen = function () {console.log("WebSocket 连接成功");};ws.onmessage = function (evt) {var received_msg = evt.data;blobToDataURI(received_msg, function (result) {document.getElementById("python_img").src = result;})};ws.onclose = function () {console.log("连接关闭...");};}function blobToDataURI(blob, callback) {var reader = new FileReader();reader.readAsDataURL(blob);reader.onload = function (e) {callback(e.target.result);}}</script>
</body>
</html>

其中接收到二进制完成以后直接显示,不用服务端编码成base64,下图表明web端可以正常拿到jpg图片显示

在这里插入图片描述

其中message_all 是广播,只要是websocket client 我们就给他发一份,这样做,不但可以发送给web,也可以发送给rtsp server,我们让rtsp server 链接上来,取到jpg后,解码成为rgb24,然后编码成为h264,让vlc 可以链接rtsp server取到rtsp 流

3 rtsp server 编码h264 输出

我们的rtsp server 端使用c++ 编写,为了加快速度,使用了内存共享,而没有使用websocket client,当然是可以的,考虑到这里要解码,又要编码输出,还有可能需要使用硬件编码,为了提高效率,就这么做了,而且还简单,缺点就是这样多了一个问题,rtspserve只能启动在本机上。先编写一个h264Frame, h265 是一样的道理,后面再更改,暂时运行在windows上,等完成了再修改。注意以下代码只能运行在windows上

class H264Frame :public TThreadRunable
{const wchar_t*  sharedMemoryMutex = L"shared_memory_mutex";const wchar_t*  sharedMemoryName = L"shared_memory";LPVOID v_lpBase = NULL;HANDLE v_hMapFile = NULL;HANDLE 	m_shareMutex = NULL;std::shared_ptr<xop::RtspServer> v_server;std::string v_livename;std::wstring v_pathname;std::wstring v_pathmutex_name;int v_fps = 10;Encoder v_encoder;xop::MediaSessionId v_id;int v_init = 0;int v_quality = 28;
public:H264Frame(std::shared_ptr<xop::RtspServer> s, const char* livename, const wchar_t* pathname, xop::MediaSessionId session_id){v_server = s;v_livename = livename;v_pathname = pathname;if (pathname != NULL){v_pathmutex_name = pathname;v_pathmutex_name += L"_mutex";}v_id = session_id;}~H264Frame() {}bool Open(){if (v_pathname.empty())v_hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, NULL, sharedMemoryName);elsev_hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, NULL, v_pathname.c_str());if (v_hMapFile == NULL){//printf(" Waiting shared memory creation......\n");return false;}return true;}void Close(){if (m_shareMutex != NULL)ReleaseMutex(m_shareMutex);if (v_hMapFile != NULL)CloseHandle(v_hMapFile);}bool IsOpened() const{return (v_hMapFile != NULL);}void sendFrame(uint8_t* data ,int size, int sessionid){xop::AVFrame videoFrame = { 0 };videoFrame.type = 0;videoFrame.size = size;// sizeofdata;// frame_size;videoFrame.timestamp = xop::H264Source::GetTimestamp();//videoFrame.notcopy = data;videoFrame.buffer.reset(new uint8_t[videoFrame.size]);std::memcpy(videoFrame.buffer.get(), data, videoFrame.size);v_server->PushFrame(sessionid, xop::channel_0, videoFrame);}int ReadFrame(int sessionid){if (v_hMapFile){v_lpBase = MapViewOfFile(v_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);unsigned char* pMemory = (unsigned char*)v_lpBase;int w = 0, h = 0;int frame_size = 0;std::memcpy(&w, pMemory, 4);std::memcpy(&h, pMemory + 4, 4);std::memcpy(&frame_size, pMemory + 8, 4);//printf("read the width %d height %d framesize %d\n", imageWidth,imageHeight, frame_size);uint8_t* rgb = pMemory + 12;if (v_init == 0){v_encoder.Encoder_Open(v_fps, w, h, w, h, v_quality);v_init = 1;}v_encoder.RGB2YUV(rgb, w, h);AVPacket * pkt = v_encoder.EncodeVideo();//while (!*framebuf++);if (pkt!=NULL) {uint8_t* framebuf = pkt->data;frame_size = pkt->size;uint8_t* spsStart = NULL;int spsLen = 0;uint8_t* ppsStart = NULL;int ppsLen = 0;uint8_t* seStart = NULL;int seLen = 0;uint8_t* frameStart = 0;//非关键帧地址或者关键帧地址int frameLen = 0;AnalyseNalu_no0x((const uint8_t*)framebuf, frame_size, &spsStart, spsLen, &ppsStart, ppsLen, &seStart, seLen, &frameStart, frameLen);if (spsStart != NULL && ppsStart!=NULL){sendFrame(spsStart, spsLen, sessionid);sendFrame(ppsStart, ppsLen, sessionid);}if (frameStart != NULL){sendFrame(frameStart, frameLen, sessionid);}av_packet_free(&pkt);}UnmapViewOfFile(pMemory);}return -1;}void Run(){m_shareMutex = CreateMutexW(NULL, false, sharedMemoryMutex/*v_pathmutex_name.c_str()*/);		v_encoder.Encoder_Open(10, 4096, 1080, 4096, 1080, 27);while (1){if (Open() == true){break;}else{printf("can not open share mem error\n");Sleep(3000);}}printf("wait ok\n");//检查是否改变参数//重新开始int64_t m_start_clock = 0;float delay = 1000000.0f / (float)(v_fps);//微妙//合并的rgbuint8_t * rgb = NULL;uint8_t * cam = NULL;int64_t start_timestamp = av_gettime_relative();//  GetTimestamp32();while (1){if (IsStop())break;//获取一帧//rgb = if (v_hMapFile){//printf("start to lock sharemutex\n");WaitForSingleObject(m_shareMutex, INFINITE);//printf("read frame\n");ReadFrame(v_id);ReleaseMutex(m_shareMutex);}else{printf("Shared memory handle error\n");break;}int64_t tnow = av_gettime_relative();// GetTimestamp32();int64_t total = tnow - start_timestamp; //總共花費的時間int64_t fix_consume = ++m_start_clock * delay;if (total < fix_consume) {int64_t diff = fix_consume - total;if (diff > 0) { //相差5000微妙以上std::this_thread::sleep_for(std::chrono::microseconds(diff));}}}if (v_init == 0){v_encoder.Encoder_Close();v_init = 1;}}};int main(int argc, char **argv)
{	std::string suffix = "live";std::string ip = "127.0.0.1";std::string port = "8554";std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());if (!server->Start("0.0.0.0", atoi(port.c_str()))) {printf("RTSP Server listen on %s failed.\n", port.c_str());return 0;}#ifdef AUTH_CONFIGserver->SetAuthConfig("-_-", "admin", "12345");
#endifxop::MediaSession *session = xop::MediaSession::CreateNew("live"); session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); //session->StartMulticast(); session->AddNotifyConnectedCallback([] (xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port){printf("RTSP client connect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);});session->AddNotifyDisconnectedCallback([](xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port) {printf("RTSP client disconnect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);});xop::MediaSessionId session_id = server->AddSession(session);H264Frame h264frame(server, suffix.c_str(), L"shared_memory",session_id);//std::thread t1(SendFrameThread, server.get(), session_id, &h264_file);//t1.detach(); std::cout << "Play URL: " << rtsp_url << std::endl;h264frame.Start();while (1) {xop::Timer::Sleep(100);}h264frame.Join();getchar();return 0;
}

完成以后,打开python 服务端,打开rtsp服务端,最后打开vlc查看
在这里插入图片描述
这样就完成了python端使用pytorch ,yolo 等等共享给c++ 的内存

其中python端的内存共享示例使用如下

import mmap
import contextlib
import timewhile True:with contextlib.closing(mmap.mmap(-1, 25, tagname='test', access=mmap.ACCESS_READ)) as m:s = m.read(1024)#.replace('\x00', '')print(s)time.sleep(1)

读者可自行完成剩余的代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/588738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【基础】【Python网络爬虫】【2.请求与响应】常用请求报头和常用响应方法

Python网络爬虫基础 爬虫基础请求与相应HTTP/HTTPS 协议HTTP/HTTPS的优缺点HTTP 的缺点HTTPS的优点 请求与响应概述请求请求目标&#xff08;url&#xff09;请求体&#xff08;response&#xff09;常用的请求报头查看请求体&#xff08;requests 模块&#xff09; 响应HTTP响…

PS实现圆角矩形选取

在我们日常的工作当中,经常需要做圆角矩形的图片,因为圆角的图片给人的感觉比较圆润,漂亮,但是PS在这方面显然比较弱智,因此如何做圆角矩形选择,这里给出了两个方法,希望能帮到大家。 进入正题(方法一): 第一步-PS 右上角-打开一张图片 第二步-左列-选择矩形-选择目…

2024新年快乐

今天就不讲题解了&#xff0c;2024年&#xff0c;祝所有博客身体健康&#xff0c;粉丝越多&#xff0c;点赞越高&#xff01;&#xff01;&#xff01; #include<bits/stdc.h> using namespace std; int main(){cout<<"新年快乐!!";return 0&#xff1b;…

汽车信息安全--车规MCU信息安全设计应采用哪种安全架构?

目录 1.问题引入 2.常见网络安全架构简述 2.1 边界防御架构 2.2 纵深防御架构

【小沐学Python】Python实现免费天气预报获取(OpenWeatherMap)

文章目录 1、简介1.1 工具简介1.2 费用1.3 注册1.4 申请key 2、接口说明2.1 One Call 3.02.2 Current Weather and Forecasts collection2.2.1 API 调用2.2.2 API 参数 2.3 Historical Weather collection2.4 Weather Maps collection2.5 Other weather APIs 3、接口测试3.1 例…

JavaFX:MVC模式学习01-使用PropertyValueFactory将模型与视图绑定

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

hyper-v用命令方式创建NAT网络

文章目录 NAT 概述创建 NAT 虚拟网络配置vm的ip地址 NAT 概述 NAT 使用主计算机的 IP 地址和端口通过内部 Hyper-V 虚拟网关向虚拟机授予对网络资源的访问权限。 网络地址转换 (NAT) 是一种网络模式&#xff0c;旨在通过将一个外部 IP 地址和端口映射到更大的内部 IP 地址集来…

IIS服务器发布PHP网站

IIS服务器&#xff0c;相信开发者都不会陌生&#xff0c;它的英文全称是Internet Information Services&#xff0c;是由微软公司提供的基于运行Microsoft Windows的互联网基本服务&#xff0c;常用于Windows系统的Web项目部署&#xff0c;本篇以PHP项目为例&#xff0c;讲解如…

R_handbook_作图专题

ggplot基本作图 1 条形图 library(ggplot2) ggplot(biopics) geom_histogram(aes(x year_release),binwidth1,fill"gray") 2 堆砌柱状图 ggplot(biopics, aes(xyear_release)) geom_bar(aes(fillsubject_sex)) 3 堆砌比例柱状图 ggplot(biopics, aes(xyear_rele…

idea 出现Cannot resolve symbol ‘springframework‘解决方法

Maven手动重新加载 1&#xff09;File–>Invalidate Caches / Restart… 清理缓存&#xff0c;重启idea客户端 2&#xff09;File–>Maven–>Reload project重新从maven中加载工程依赖的组件

51单片机项目(24)——基于51单片机的温控风扇protues仿真

1.功能设计 使用传感器测量温度&#xff0c;并将温度显示在LCD1602上。如果温度超过阈值&#xff0c;那么就打开风扇&#xff0c;否则风扇不打开。&#xff08;仿真的时候&#xff0c;用直流电机模拟风扇&#xff09;。 仿真截图如下&#xff1a; 此时温度是27度&#xff0c;我…

FA组件详解

1、了解FA核心组件以及功能 &#xff08;1&#xff09;TC&#xff08;Thin Client&#xff1a;瘦终端&#xff09;&#xff1a;就是类似于机顶盒的一个小盒子&#xff0c;里面有CPU、内存、USB、MIC、HDMI等接口&#xff0c;可以理解为小型电脑&#xff0c;但是它里面是没有操作…

CSS 文字溢出:多行溢出、一行溢出

CSS 文字溢出&#xff1a;多行溢出、一行溢出 案例请点击查看文章详情。 代码如下&#xff1a; 多行溢出设置&#xff1a; .line-clamp-2{/* height: 52px;line-height: 25px; */overflow: hidden;word-break: break-all;text-overflow: ellipsis;display: -webkit-box;-webkit…

Leetcode的AC指南 —— 字符串:344. 反转字符串

摘要&#xff1a; Leetcode的AC指南 —— 字符串&#xff1a;344. 反转字符串。题目介绍&#xff1a;编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 …

【C#与Redis】--实践案例--案例 1:使用 Redis 实现缓存

在使用 Redis 实现缓存的案例中&#xff0c;我们可以使用 StackExchange.Redis 库&#xff0c;这是一个为 .NET 提供的 Redis 客户端库。以下是一个简单的使用 Redis 缓存的 C# 示例&#xff1a; 首先&#xff0c;你需要安装 StackExchange.Redis 库。可以通过 NuGet 包管理器…

python使用openpyxl操作excel

文章目录 前提读取已有excel创建一个excel工作簿对象创建excel工作簿中的工作表获取工作表第一种&#xff1a;.active 方法第二种&#xff1a;通过工作表名获取指定工作表​​​​​​第三种&#xff1a;.get_sheet_name() 修改工作表的名称数据操作写入数据按单元格写入通过指…

ArkTS语言基础入门学习-鸿蒙开发

文章目录 前言ArkTS简介统一的开发体验ArkTS语言优势ArkTS语言实战演示ArkTS语言的性能与跨平台适配ArkTS和TypeScript区别总结前言 本篇文章将深入介绍鸿蒙开发的主力语言——ArkTS语言,并通过比较传统网页开发模式和ArkTS开发模式,揭示ArkTS语言的独特之处以及其带来的开发…

2021-07-03 51单片机1.高低4位交替8次,2.从0到255,3.1+2+3+4...

缘由求老哥帮做一下单片机题。_嵌入式-CSDN问答 #include "REG52.h" bit k1; void main() {unsigned char Xd0,ss15,cs0;unsigned int ys64000;while(1){P1ss;if(ys0&&cs<8){k~k;cs;ss(k?15:240);ys64000;}} } #include "REG52.h" bit k1; v…

OpenGL ES案例学习-画板

#import "PaintView.h" #import <QuartzCore/QuartzCore.h> #import <GLKit/GLKit.h> #import <OpenGLES/EAGLDrawable.h> #import "debug.h" #import "shaderUtil.h" #import "fileUtil.h" //画笔透明度 #define k…

mobilevit v3 学习笔记

目录 原理讲解:不是特别全,可供参考: torch实现代码: 有预训练: